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 }