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  }