github.com/iotexproject/iotex-core@v1.14.1-rc1/action/depositreward.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package action
     7  
     8  import (
     9  	"bytes"
    10  	"math/big"
    11  	"strings"
    12  
    13  	"github.com/ethereum/go-ethereum/accounts/abi"
    14  	"github.com/ethereum/go-ethereum/core/types"
    15  	"github.com/pkg/errors"
    16  	"google.golang.org/protobuf/proto"
    17  
    18  	"github.com/iotexproject/iotex-core/pkg/util/byteutil"
    19  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    20  )
    21  
    22  const _depositRewardInterfaceABI = `[
    23  	{
    24  		"inputs": [
    25  			{
    26  				"internalType": "uint256",
    27  				"name": "amount",
    28  				"type": "uint256"
    29  			},
    30  			{
    31  				"internalType": "uint8[]",
    32  				"name": "data",
    33  				"type": "uint8[]"
    34  			}
    35  		],
    36  		"name": "deposit",
    37  		"outputs": [],
    38  		"stateMutability": "payable",
    39  		"type": "function"
    40  	}
    41  ]`
    42  
    43  var (
    44  	// DepositToRewardingFundBaseGas represents the base intrinsic gas for depositToRewardingFund
    45  	DepositToRewardingFundBaseGas = uint64(10000)
    46  	// DepositToRewardingFundGasPerByte represents the depositToRewardingFund payload gas per uint
    47  	DepositToRewardingFundGasPerByte = uint64(100)
    48  
    49  	_depositRewardMethod abi.Method
    50  	_                    EthCompatibleAction = (*DepositToRewardingFund)(nil)
    51  )
    52  
    53  func init() {
    54  	depositRewardInterface, err := abi.JSON(strings.NewReader(_depositRewardInterfaceABI))
    55  	if err != nil {
    56  		panic(err)
    57  	}
    58  	var ok bool
    59  	_depositRewardMethod, ok = depositRewardInterface.Methods["deposit"]
    60  	if !ok {
    61  		panic("fail to load the deposit method")
    62  	}
    63  }
    64  
    65  // DepositToRewardingFund is the action to deposit to the rewarding fund
    66  type DepositToRewardingFund struct {
    67  	AbstractAction
    68  
    69  	amount *big.Int
    70  	data   []byte
    71  }
    72  
    73  // Amount returns the amount to deposit
    74  func (d *DepositToRewardingFund) Amount() *big.Int { return d.amount }
    75  
    76  // Data returns the additional data
    77  func (d *DepositToRewardingFund) Data() []byte { return d.data }
    78  
    79  // Serialize returns a raw byte stream of a deposit action
    80  func (d *DepositToRewardingFund) Serialize() []byte {
    81  	return byteutil.Must(proto.Marshal(d.Proto()))
    82  }
    83  
    84  // Proto converts a deposit action struct to a deposit action protobuf
    85  func (d *DepositToRewardingFund) Proto() *iotextypes.DepositToRewardingFund {
    86  	return &iotextypes.DepositToRewardingFund{
    87  		Amount: d.amount.String(),
    88  		Data:   d.data,
    89  	}
    90  }
    91  
    92  // LoadProto converts a deposit action protobuf to a deposit action struct
    93  func (d *DepositToRewardingFund) LoadProto(deposit *iotextypes.DepositToRewardingFund) error {
    94  	*d = DepositToRewardingFund{}
    95  	amount, ok := new(big.Int).SetString(deposit.Amount, 10)
    96  	if !ok {
    97  		return errors.New("failed to set deposit amount")
    98  	}
    99  	d.amount = amount
   100  	d.data = deposit.Data
   101  	return nil
   102  }
   103  
   104  // IntrinsicGas returns the intrinsic gas of a deposit action
   105  func (d *DepositToRewardingFund) IntrinsicGas() (uint64, error) {
   106  	dataLen := uint64(len(d.Data()))
   107  	return CalculateIntrinsicGas(DepositToRewardingFundBaseGas, DepositToRewardingFundGasPerByte, dataLen)
   108  }
   109  
   110  // Cost returns the total cost of a deposit action
   111  func (d *DepositToRewardingFund) Cost() (*big.Int, error) {
   112  	intrinsicGas, err := d.IntrinsicGas()
   113  	if err != nil {
   114  		return nil, errors.Wrap(err, "error when getting intrinsic gas for the deposit action")
   115  	}
   116  	return big.NewInt(0).Mul(d.GasPrice(), big.NewInt(0).SetUint64(intrinsicGas)), nil
   117  }
   118  
   119  // SanityCheck validates the variables in the action
   120  func (d *DepositToRewardingFund) SanityCheck() error {
   121  	if d.Amount().Sign() < 0 {
   122  		return ErrNegativeValue
   123  	}
   124  
   125  	return d.AbstractAction.SanityCheck()
   126  }
   127  
   128  // DepositToRewardingFundBuilder is the struct to build DepositToRewardingFund
   129  type DepositToRewardingFundBuilder struct {
   130  	Builder
   131  	deposit DepositToRewardingFund
   132  }
   133  
   134  // SetAmount sets the amount to deposit
   135  func (b *DepositToRewardingFundBuilder) SetAmount(amount *big.Int) *DepositToRewardingFundBuilder {
   136  	b.deposit.amount = amount
   137  	return b
   138  }
   139  
   140  // SetData sets the additional data
   141  func (b *DepositToRewardingFundBuilder) SetData(data []byte) *DepositToRewardingFundBuilder {
   142  	b.deposit.data = data
   143  	return b
   144  }
   145  
   146  // Build builds a new deposit to rewarding fund action
   147  func (b *DepositToRewardingFundBuilder) Build() DepositToRewardingFund {
   148  	b.deposit.AbstractAction = b.Builder.Build()
   149  	return b.deposit
   150  }
   151  
   152  // encodeABIBinary encodes data in abi encoding
   153  func (d *DepositToRewardingFund) encodeABIBinary() ([]byte, error) {
   154  	data, err := _depositRewardMethod.Inputs.Pack(d.Amount(), d.Data())
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	return append(_depositRewardMethod.ID, data...), nil
   159  }
   160  
   161  // ToEthTx converts action to eth-compatible tx
   162  func (d *DepositToRewardingFund) ToEthTx(_ uint32) (*types.Transaction, error) {
   163  	data, err := d.encodeABIBinary()
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	return types.NewTx(&types.LegacyTx{
   168  		Nonce:    d.Nonce(),
   169  		GasPrice: d.GasPrice(),
   170  		Gas:      d.GasLimit(),
   171  		To:       &_rewardingProtocolEthAddr,
   172  		Value:    big.NewInt(0),
   173  		Data:     data,
   174  	}), nil
   175  }
   176  
   177  // NewDepositToRewardingFundFromABIBinary decodes data into action
   178  func NewDepositToRewardingFundFromABIBinary(data []byte) (*DepositToRewardingFund, error) {
   179  	var (
   180  		paramsMap = map[string]interface{}{}
   181  		ok        bool
   182  		ac        DepositToRewardingFund
   183  	)
   184  	// sanity check
   185  	if len(data) <= 4 || !bytes.Equal(_depositRewardMethod.ID[:], data[:4]) {
   186  		return nil, errDecodeFailure
   187  	}
   188  	if err := _depositRewardMethod.Inputs.UnpackIntoMap(paramsMap, data[4:]); err != nil {
   189  		return nil, err
   190  	}
   191  	if ac.amount, ok = paramsMap["amount"].(*big.Int); !ok {
   192  		return nil, errDecodeFailure
   193  	}
   194  	if ac.data, ok = paramsMap["data"].([]byte); !ok {
   195  		return nil, errDecodeFailure
   196  	}
   197  	return &ac, nil
   198  }