github.com/onflow/flow-go@v0.33.17/fvm/evm/testutils/contract.go (about) 1 package testutils 2 3 import ( 4 "encoding/hex" 5 "math" 6 "math/big" 7 "strings" 8 "testing" 9 10 gethABI "github.com/ethereum/go-ethereum/accounts/abi" 11 gethCommon "github.com/ethereum/go-ethereum/common" 12 "github.com/stretchr/testify/require" 13 14 "github.com/onflow/atree" 15 16 "github.com/onflow/flow-go/fvm/evm/emulator" 17 "github.com/onflow/flow-go/fvm/evm/types" 18 "github.com/onflow/flow-go/model/flow" 19 ) 20 21 type TestContract struct { 22 Code string 23 ABI string 24 ByteCode []byte 25 DeployedAt types.Address 26 } 27 28 func (tc *TestContract) MakeCallData(t testing.TB, name string, args ...interface{}) []byte { 29 abi, err := gethABI.JSON(strings.NewReader(tc.ABI)) 30 require.NoError(t, err) 31 call, err := abi.Pack(name, args...) 32 require.NoError(t, err) 33 return call 34 } 35 36 func (tc *TestContract) SetDeployedAt(deployedAt types.Address) { 37 tc.DeployedAt = deployedAt 38 } 39 40 func GetStorageTestContract(tb testing.TB) *TestContract { 41 byteCodes, err := hex.DecodeString("608060405261022c806100136000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80632e64cec11461005c57806348b151661461007a57806357e871e7146100985780636057361d146100b657806385df51fd146100d2575b600080fd5b610064610102565b6040516100719190610149565b60405180910390f35b61008261010b565b60405161008f9190610149565b60405180910390f35b6100a0610113565b6040516100ad9190610149565b60405180910390f35b6100d060048036038101906100cb9190610195565b61011b565b005b6100ec60048036038101906100e79190610195565b610125565b6040516100f991906101db565b60405180910390f35b60008054905090565b600042905090565b600043905090565b8060008190555050565b600081409050919050565b6000819050919050565b61014381610130565b82525050565b600060208201905061015e600083018461013a565b92915050565b600080fd5b61017281610130565b811461017d57600080fd5b50565b60008135905061018f81610169565b92915050565b6000602082840312156101ab576101aa610164565b5b60006101b984828501610180565b91505092915050565b6000819050919050565b6101d5816101c2565b82525050565b60006020820190506101f060008301846101cc565b9291505056fea26469706673582212203ee61567a25f0b1848386ae6b8fdbd7733c8a502c83b5ed305b921b7933f4e8164736f6c63430008120033") 42 require.NoError(tb, err) 43 return &TestContract{ 44 Code: ` 45 contract Storage { 46 uint256 number; 47 constructor() payable { 48 } 49 function store(uint256 num) public { 50 number = num; 51 } 52 function retrieve() public view returns (uint256){ 53 return number; 54 } 55 function blockNumber() public view returns (uint256) { 56 return block.number; 57 } 58 function blockTime() public view returns (uint) { 59 return block.timestamp; 60 } 61 function blockHash(uint num) public view returns (bytes32) { 62 return blockhash(num); 63 } 64 } 65 `, 66 67 ABI: ` 68 [ 69 { 70 "inputs": [], 71 "stateMutability": "payable", 72 "type": "constructor" 73 }, 74 { 75 "inputs": [ 76 { 77 "internalType": "uint256", 78 "name": "num", 79 "type": "uint256" 80 } 81 ], 82 "name": "blockHash", 83 "outputs": [ 84 { 85 "internalType": "bytes32", 86 "name": "", 87 "type": "bytes32" 88 } 89 ], 90 "stateMutability": "view", 91 "type": "function" 92 }, 93 { 94 "inputs": [], 95 "name": "blockNumber", 96 "outputs": [ 97 { 98 "internalType": "uint256", 99 "name": "", 100 "type": "uint256" 101 } 102 ], 103 "stateMutability": "view", 104 "type": "function" 105 }, 106 { 107 "inputs": [], 108 "name": "blockTime", 109 "outputs": [ 110 { 111 "internalType": "uint256", 112 "name": "", 113 "type": "uint256" 114 } 115 ], 116 "stateMutability": "view", 117 "type": "function" 118 }, 119 { 120 "inputs": [], 121 "name": "retrieve", 122 "outputs": [ 123 { 124 "internalType": "uint256", 125 "name": "", 126 "type": "uint256" 127 } 128 ], 129 "stateMutability": "view", 130 "type": "function" 131 }, 132 { 133 "inputs": [ 134 { 135 "internalType": "uint256", 136 "name": "num", 137 "type": "uint256" 138 } 139 ], 140 "name": "store", 141 "outputs": [], 142 "stateMutability": "nonpayable", 143 "type": "function" 144 } 145 ] 146 `, 147 ByteCode: byteCodes, 148 } 149 } 150 151 func GetDummyKittyTestContract(t testing.TB) *TestContract { 152 byteCodes, err := hex.DecodeString("608060405234801561001057600080fd5b506107dd806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063a45f4bfc14610046578063d0b169d114610076578063ddf252ad146100a6575b600080fd5b610060600480360381019061005b91906104e4565b6100c2565b60405161006d9190610552565b60405180910390f35b610090600480360381019061008b919061056d565b6100f5565b60405161009d91906105e3565b60405180910390f35b6100c060048036038101906100bb919061062a565b610338565b005b60026020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008463ffffffff16851461010957600080fd5b8363ffffffff16841461011b57600080fd5b8261ffff16831461012b57600080fd5b60006040518060a001604052808481526020014267ffffffffffffffff1681526020018763ffffffff1681526020018663ffffffff1681526020018561ffff16815250905060018190806001815401808255809150506001900390600052602060002090600202016000909190919091506000820151816000015560208201518160010160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060408201518160010160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548161ffff021916908361ffff16021790555050507fc1e409485f45287e73ab1623a8f2ef17af5eac1b4c792ee9ec466e8795e7c09133600054836040015163ffffffff16846060015163ffffffff16856000015160405161029995949392919061067d565b60405180910390a13073ffffffffffffffffffffffffffffffffffffffff1663ddf252ad6000336000546040518463ffffffff1660e01b81526004016102e1939291906106d0565b600060405180830381600087803b1580156102fb57600080fd5b505af115801561030f573d6000803e3d6000fd5b5050505060008081548092919061032590610736565b9190505550600054915050949350505050565b600360008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600081548092919061038890610736565b9190505550816002600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161461046957600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906104639061077e565b91905055505b7feaf1c4b3ce0f4f62a2bae7eb3e68225c75f7e6ff4422073b7437b9a78d25f17083838360405161049c939291906106d0565b60405180910390a1505050565b600080fd5b6000819050919050565b6104c1816104ae565b81146104cc57600080fd5b50565b6000813590506104de816104b8565b92915050565b6000602082840312156104fa576104f96104a9565b5b6000610508848285016104cf565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061053c82610511565b9050919050565b61054c81610531565b82525050565b60006020820190506105676000830184610543565b92915050565b60008060008060808587031215610587576105866104a9565b5b6000610595878288016104cf565b94505060206105a6878288016104cf565b93505060406105b7878288016104cf565b92505060606105c8878288016104cf565b91505092959194509250565b6105dd816104ae565b82525050565b60006020820190506105f860008301846105d4565b92915050565b61060781610531565b811461061257600080fd5b50565b600081359050610624816105fe565b92915050565b600080600060608486031215610643576106426104a9565b5b600061065186828701610615565b935050602061066286828701610615565b9250506040610673868287016104cf565b9150509250925092565b600060a0820190506106926000830188610543565b61069f60208301876105d4565b6106ac60408301866105d4565b6106b960608301856105d4565b6106c660808301846105d4565b9695505050505050565b60006060820190506106e56000830186610543565b6106f26020830185610543565b6106ff60408301846105d4565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610741826104ae565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361077357610772610707565b5b600182019050919050565b6000610789826104ae565b91506000820361079c5761079b610707565b5b60018203905091905056fea2646970667358221220ab35c07ec72cc064a663de06ec7f5f919b1a499a25cf6ef0c63a45fdd4a1e91e64736f6c63430008120033") 153 require.NoError(t, err) 154 return &TestContract{ 155 Code: ` 156 contract DummyKitty { 157 158 event BirthEvent(address owner, uint256 kittyId, uint256 matronId, uint256 sireId, uint256 genes); 159 event TransferEvent(address from, address to, uint256 tokenId); 160 161 struct Kitty { 162 uint256 genes; 163 uint64 birthTime; 164 uint32 matronId; 165 uint32 sireId; 166 uint16 generation; 167 } 168 169 uint256 idCounter; 170 171 // @dev all kitties 172 Kitty[] kitties; 173 174 /// @dev a mapping from cat IDs to the address that owns them. 175 mapping (uint256 => address) public kittyIndexToOwner; 176 177 // @dev a mapping from owner address to count of tokens that address owns. 178 mapping (address => uint256) ownershipTokenCount; 179 180 /// @dev a method to transfer kitty 181 function Transfer(address _from, address _to, uint256 _tokenId) external { 182 // Since the number of kittens is capped to 2^32 we can't overflow this 183 ownershipTokenCount[_to]++; 184 // transfer ownership 185 kittyIndexToOwner[_tokenId] = _to; 186 // When creating new kittens _from is 0x0, but we can't account that address. 187 if (_from != address(0)) { 188 ownershipTokenCount[_from]--; 189 } 190 // Emit the transfer event. 191 emit TransferEvent(_from, _to, _tokenId); 192 } 193 194 /// @dev a method callable by anyone to create a kitty 195 function CreateKitty( 196 uint256 _matronId, 197 uint256 _sireId, 198 uint256 _generation, 199 uint256 _genes 200 ) 201 external 202 returns (uint) 203 { 204 205 require(_matronId == uint256(uint32(_matronId))); 206 require(_sireId == uint256(uint32(_sireId))); 207 require(_generation == uint256(uint16(_generation))); 208 209 Kitty memory _kitty = Kitty({ 210 genes: _genes, 211 birthTime: uint64(block.timestamp), 212 matronId: uint32(_matronId), 213 sireId: uint32(_sireId), 214 generation: uint16(_generation) 215 }); 216 217 kitties.push(_kitty); 218 219 emit BirthEvent( 220 msg.sender, 221 idCounter, 222 uint256(_kitty.matronId), 223 uint256(_kitty.sireId), 224 _kitty.genes 225 ); 226 227 this.Transfer(address(0), msg.sender, idCounter); 228 229 idCounter++; 230 231 return idCounter; 232 } 233 } 234 `, 235 236 ABI: ` 237 [ 238 { 239 "anonymous": false, 240 "inputs": [ 241 { 242 "indexed": false, 243 "internalType": "address", 244 "name": "owner", 245 "type": "address" 246 }, 247 { 248 "indexed": false, 249 "internalType": "uint256", 250 "name": "kittyId", 251 "type": "uint256" 252 }, 253 { 254 "indexed": false, 255 "internalType": "uint256", 256 "name": "matronId", 257 "type": "uint256" 258 }, 259 { 260 "indexed": false, 261 "internalType": "uint256", 262 "name": "sireId", 263 "type": "uint256" 264 }, 265 { 266 "indexed": false, 267 "internalType": "uint256", 268 "name": "genes", 269 "type": "uint256" 270 } 271 ], 272 "name": "BirthEvent", 273 "type": "event" 274 }, 275 { 276 "anonymous": false, 277 "inputs": [ 278 { 279 "indexed": false, 280 "internalType": "address", 281 "name": "from", 282 "type": "address" 283 }, 284 { 285 "indexed": false, 286 "internalType": "address", 287 "name": "to", 288 "type": "address" 289 }, 290 { 291 "indexed": false, 292 "internalType": "uint256", 293 "name": "tokenId", 294 "type": "uint256" 295 } 296 ], 297 "name": "TransferEvent", 298 "type": "event" 299 }, 300 { 301 "inputs": [ 302 { 303 "internalType": "uint256", 304 "name": "_matronId", 305 "type": "uint256" 306 }, 307 { 308 "internalType": "uint256", 309 "name": "_sireId", 310 "type": "uint256" 311 }, 312 { 313 "internalType": "uint256", 314 "name": "_generation", 315 "type": "uint256" 316 }, 317 { 318 "internalType": "uint256", 319 "name": "_genes", 320 "type": "uint256" 321 } 322 ], 323 "name": "CreateKitty", 324 "outputs": [ 325 { 326 "internalType": "uint256", 327 "name": "", 328 "type": "uint256" 329 } 330 ], 331 "stateMutability": "nonpayable", 332 "type": "function" 333 }, 334 { 335 "inputs": [ 336 { 337 "internalType": "address", 338 "name": "_from", 339 "type": "address" 340 }, 341 { 342 "internalType": "address", 343 "name": "_to", 344 "type": "address" 345 }, 346 { 347 "internalType": "uint256", 348 "name": "_tokenId", 349 "type": "uint256" 350 } 351 ], 352 "name": "Transfer", 353 "outputs": [], 354 "stateMutability": "nonpayable", 355 "type": "function" 356 }, 357 { 358 "inputs": [ 359 { 360 "internalType": "uint256", 361 "name": "", 362 "type": "uint256" 363 } 364 ], 365 "name": "kittyIndexToOwner", 366 "outputs": [ 367 { 368 "internalType": "address", 369 "name": "", 370 "type": "address" 371 } 372 ], 373 "stateMutability": "view", 374 "type": "function" 375 } 376 ] 377 `, 378 ByteCode: byteCodes, 379 } 380 } 381 382 func RunWithDeployedContract(t testing.TB, tc *TestContract, led atree.Ledger, flowEVMRootAddress flow.Address, f func(*TestContract)) { 383 DeployContract(t, tc, led, flowEVMRootAddress) 384 f(tc) 385 } 386 387 func DeployContract(t testing.TB, tc *TestContract, led atree.Ledger, flowEVMRootAddress flow.Address) { 388 // deploy contract 389 e := emulator.NewEmulator(led, flowEVMRootAddress) 390 391 blk, err := e.NewBlockView(types.NewDefaultBlockContext(2)) 392 require.NoError(t, err) 393 394 caller := types.NewAddress(gethCommon.Address{}) 395 _, err = blk.DirectCall( 396 types.NewDepositCall( 397 caller, 398 new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1000)), 399 ), 400 ) 401 require.NoError(t, err) 402 403 blk2, err := e.NewBlockView(types.NewDefaultBlockContext(3)) 404 require.NoError(t, err) 405 406 res, err := blk2.DirectCall( 407 types.NewDeployCall( 408 caller, 409 tc.ByteCode, 410 math.MaxUint64, 411 big.NewInt(0), 412 ), 413 ) 414 require.NoError(t, err) 415 416 tc.SetDeployedAt(res.DeployedContractAddress) 417 }