github.com/FusionFoundation/efsn/v4@v4.2.0/core/vm/fsncontract.go (about)

     1  package vm
     2  
     3  import (
     4  	"errors"
     5  	"math/big"
     6  
     7  	"github.com/FusionFoundation/efsn/v4/common"
     8  	"github.com/FusionFoundation/efsn/v4/params"
     9  )
    10  
    11  var (
    12  	FSNContractAddress = common.HexToAddress("0x9999999999999999999999999999999999999999")
    13  
    14  	ErrUnknownFunc            = errors.New("unknown func type")
    15  	ErrNotEnoughBalance       = errors.New("not enough balance")
    16  	ErrWrongTimeRange         = errors.New("wrong time range")
    17  	ErrValueOverflow          = errors.New("value overflow")
    18  	ErrWrongLenOfInput        = errors.New("wrong length of input")
    19  	ErrFcInvalidSendAssetFlag = errors.New("invalid send asset flag")
    20  )
    21  
    22  type FcFuncType uint8
    23  
    24  const (
    25  	FcUnknownFunc FcFuncType = iota
    26  	FcSendAsset              // 1
    27  )
    28  
    29  func (f FcFuncType) Name() string {
    30  	switch f {
    31  	case FcSendAsset:
    32  		return "sendAsset"
    33  	}
    34  	return "unknown"
    35  }
    36  
    37  type FSNContract struct {
    38  	evm            *EVM
    39  	from           common.Address
    40  	parentContract bool
    41  	input          []byte
    42  }
    43  
    44  func NewFSNContract(evm *EVM, from common.Address, parentContract bool) *FSNContract {
    45  	return &FSNContract{
    46  		evm:            evm,
    47  		from:           from,
    48  		parentContract: parentContract,
    49  	}
    50  }
    51  
    52  func (c *FSNContract) RequiredGas(input []byte) uint64 {
    53  	return params.FsnContractGas
    54  }
    55  
    56  func (c *FSNContract) Run(input []byte) (ret []byte, err error) {
    57  	c.input = input
    58  	err = ErrUnknownFunc
    59  	funcType := FcUnknownFunc
    60  	if len(c.input) >= 32 {
    61  		funcType = FcFuncType(c.getBigInt(0).Uint64())
    62  		switch funcType {
    63  		case FcSendAsset:
    64  			ret, err = c.sendAsset()
    65  		}
    66  	}
    67  	if err != nil {
    68  		common.DebugInfo("Run FSNContract error",
    69  			"func", funcType.Name(),
    70  			"input", input,
    71  			"err", err,
    72  		)
    73  		return toErrData(err), err
    74  	}
    75  	return ret, err
    76  }
    77  
    78  func (c *FSNContract) sendAsset() ([]byte, error) {
    79  	if !c.parentContract {
    80  		return nil, ErrMustCallByContract
    81  	}
    82  	p, err := c.parseParams()
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	from := c.from
    87  	to := p.address
    88  
    89  	tranferTimeLockParam := &common.TransferTimeLockParam{
    90  		AssetID:     p.asset,
    91  		StartTime:   p.start,
    92  		EndTime:     p.end,
    93  		Timestamp:   c.evm.Context.Time.Uint64(),
    94  		Flag:        p.flag,
    95  		Value:       p.value,
    96  		GasValue:    nil,
    97  		BlockNumber: c.evm.Context.BlockNumber,
    98  		IsReceive:   false,
    99  	}
   100  
   101  	state := c.evm.StateDB
   102  	if !c.evm.Context.CanTransferTimeLock(state, from, tranferTimeLockParam) {
   103  		return nil, ErrNotEnoughBalance
   104  	}
   105  	c.evm.Context.TransferTimeLock(state, from, to, tranferTimeLockParam)
   106  
   107  	return toOKData("sendAsset"), nil
   108  }
   109  
   110  func (c *FSNContract) getBigInt(pos uint64) *big.Int {
   111  	return new(big.Int).SetBytes(getData(c.input, pos, 32))
   112  }
   113  
   114  func (c *FSNContract) getUint64(pos uint64) (uint64, bool) {
   115  	return common.GetUint64(c.input, pos, 32)
   116  }
   117  
   118  type FcParams struct {
   119  	asset   common.Hash
   120  	address common.Address
   121  	value   *big.Int
   122  	start   uint64
   123  	end     uint64
   124  	flag    common.FcSendAssetFlag
   125  }
   126  
   127  func (c *FSNContract) parseParams() (*FcParams, error) {
   128  	p := &FcParams{}
   129  	var overflow bool
   130  
   131  	pos := uint64(32)
   132  	p.asset = common.BytesToHash(getData(c.input, pos, 32))
   133  	pos += 32
   134  	p.address = common.BytesToAddress(getData(c.input, pos, 32))
   135  	pos += 32
   136  	p.value = c.getBigInt(pos)
   137  	pos += 32
   138  	if p.start, overflow = c.getUint64(pos); overflow {
   139  		return nil, ErrValueOverflow
   140  	}
   141  	pos += 32
   142  	if p.end, overflow = c.getUint64(pos); overflow {
   143  		return nil, ErrValueOverflow
   144  	}
   145  	pos += 32
   146  	biFlag := c.getBigInt(pos)
   147  	pos += 32
   148  	if biFlag.Cmp(big.NewInt(int64(common.FcInvalidSendAssetFlag))) >= 0 {
   149  		return nil, ErrFcInvalidSendAssetFlag
   150  	}
   151  	p.flag = common.FcSendAssetFlag(biFlag.Uint64())
   152  
   153  	if uint64(len(c.input)) != pos {
   154  		return nil, ErrWrongLenOfInput
   155  	}
   156  
   157  	// adjust
   158  	timestamp := c.evm.Context.Time.Uint64()
   159  	if p.start < timestamp {
   160  		p.start = timestamp
   161  	}
   162  	if p.end == 0 {
   163  		p.end = common.TimeLockForever
   164  	}
   165  
   166  	// check
   167  	if p.start > p.end {
   168  		return nil, ErrWrongTimeRange
   169  	}
   170  	return p, nil
   171  }
   172  
   173  func toOKData(str string) []byte {
   174  	return []byte("Ok: " + str)
   175  }
   176  
   177  func toErrData(err error) []byte {
   178  	return []byte("Error: " + err.Error())
   179  }