contract_transaction.py (2436B)
1 # standard imports 2 import os 3 4 # external imports 5 from crypto_dev_signer.keystore.dict import DictKeystore 6 from crypto_dev_signer.eth.signer import ReferenceSigner as EIP155Signer 7 from hexathon import ( 8 add_0x, 9 strip_0x, 10 ) 11 12 # local imports 13 from chainlib.chain import ChainSpec 14 from chainlib.eth.nonce import OverrideNonceOracle 15 from chainlib.eth.gas import OverrideGasOracle 16 from chainlib.eth.tx import ( 17 TxFactory, 18 TxFormat, 19 unpack, 20 pack, 21 raw, 22 ) 23 from chainlib.eth.contract import ( 24 ABIContractEncoder, 25 ABIContractDecoder, 26 ABIContractType, 27 ) 28 29 # eth transactions need an explicit chain parameter as part of their signature 30 chain_spec = ChainSpec.from_chain_str('evm:ethereum:1') 31 32 # create keystore and signer 33 keystore = DictKeystore() 34 signer = EIP155Signer(keystore) 35 sender_address = keystore.new() 36 recipient_address = keystore.new() 37 38 # explicitly set nonce and gas parameters on this transaction 39 nonce_oracle = OverrideNonceOracle(sender_address, 0) 40 gas_oracle = OverrideGasOracle(price=1000000000, limit=21000) 41 42 # encode the contract parameters 43 enc = ABIContractEncoder() 44 enc.method('fooBar') 45 enc.typ(ABIContractType.ADDRESS) 46 enc.typ(ABIContractType.UINT256) 47 enc.address(recipient_address) 48 enc.uint256(42) 49 data = enc.get() 50 51 # create a new transaction, but output in raw rlp format 52 tx_factory = TxFactory(chain_spec, signer=signer, nonce_oracle=nonce_oracle, gas_oracle=gas_oracle) 53 tx = tx_factory.template(sender_address, recipient_address, use_nonce=True) 54 tx = tx_factory.set_code(tx, data) 55 (tx_hash, tx_signed_raw) = tx_factory.finalize(tx, tx_format=TxFormat.RLP_SIGNED) 56 57 print('contract transaction: {}'.format(tx)) 58 59 # retrieve the input data from the transaction 60 tx_src = unpack(bytes.fromhex(strip_0x(tx_signed_raw)), chain_spec) 61 data_recovered = strip_0x(tx_src['data']) 62 63 # decode the contract parameters 64 dec = ABIContractDecoder() 65 dec.typ(ABIContractType.ADDRESS) 66 dec.typ(ABIContractType.UINT256) 67 # (yes, this interface needs to be vastly improved, it should take the whole buffer and advance with cursor itself) 68 cursor = 8 # the method signature is 8 characters long. input data to the solidity function starts after that 69 dec.val(data_recovered[cursor:cursor+64]) 70 cursor += 64 71 dec.val(data_recovered[cursor:cursor+64]) 72 r = dec.decode() 73 74 print('contract param 1 {}'.format(r[0])) 75 print('contract param 2 {}'.format(r[1]))