API

contract

Import peth and create an instance for FTM chain.

In [1]: from peth import Peth

In [2]: p = Peth.get_or_create('ftm')

Bind your signer by the private key.

In [3]: p.signer

In [4]: p.bind_signer('<Your private key>')

In [5]: p.signer
Out[5]: <eth_account.signers.local.LocalAccount at 0x10491c550>

Create a contract caller instance in which Peth will automatically bind the ABI from the explorer if the contract is open-sourced. Let us take WFTM contract as an instance.

In [6]: wftm = p.contract('0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83')

Call name() and balanceOf().

In [7]: wftm.name
Out[7]: Function(function name() view returns (string ))

In [8]: wftm.name()
Out[8]: 'Wrapped Fantom'

In [9]: wftm.balanceOf(p.signer.address)
Out[9]: 0

Send transaction which calls deposit().

In [10]: wftm.deposit
Out[10]: Function(function deposit() payable returns (uint256 ))

In [11]: wftm.deposit(value=1)
Out[11]: 
AttributeDict({'blockHash': HexBytes('0x00...'),
    ...
 'status': 1,
 'transactionHash': HexBytes('0x00...'),
 'transactionIndex': 2,
 'type': '0x0'})

In [12]: wftm.balanceOf(p.signer.address)
Out[12]: 1

Call transfer() to send ERC20 token.

In [13]: wftm.transfer(p.signer.address, 1)
Out[13]: 
AttributeDict({
    ....
 'status': 1,
    ....
 })

call

Handle contract without ABI. Let us assume that 0x21be37.. is an non-open-source ERC20 token.

In [1]: from peth import Peth

In [2]: p = Peth.get_or_create('ftm')

In [3]: p.call('0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83', 'name()')
Out[3]: '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e577261707065642046616e746f6d000000000000000000000000000000000000'

In [4]: p.call('0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83', 'name()->(string)')
Out[4]: 'Wrapped Fantom'

In [5]: p.call('0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83', 'balanceOf(address)->(uint256)', ['0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83'])
Out[5]: 5913518704387658333840

ABI

In [1]: from peth import Peth

In [2]: p = Peth.get_or_create('ftm')

In [3]: abi_raw = p.scan.get_abi('0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83')

In [4]: abi_raw
Out[4]: 
[{'inputs': [],
  'payable': False,
  'stateMutability': 'nonpayable',
  'type': 'constructor'},
 {'anonymous': False,
  'inputs': [{'indexed': True,
    'internalType': 'address',
    ...
    
In [5]: from peth.eth.abi import ABI

In [6]: abi = ABI(abi_raw)

In [7]: abi
Out[7]: <peth.eth.abi.abi.ABI at 0x10420cf40>

In [8]: abi.functions
Out[8]: 
{'ERR_INVALID_ZERO_VALUE': function ERR_INVALID_ZERO_VALUE() view returns (uint256 ),
 'ERR_NO_ERROR': function ERR_NO_ERROR() view returns (uint256 ),
 'addPauser': function addPauser(address account) nonpayable returns (),
 'allowance': function allowance(address owner, address spender) view returns (uint256 ),
 'approve': function approve(address spender, uint256 value) nonpayable returns (bool ),
 'balanceOf': function balanceOf(address account) view returns (uint256 ),
  ...

In [9]: abi.transfer
Out[9]: function transfer(address to, uint256 value) nonpayable returns (bool )

In [10]: abi['0xa9059cbb']
Out[10]: function transfer(address to, uint256 value) nonpayable returns (bool )

In [11]: abi['transfer(address,uint256)']
Out[11]: function transfer(address to, uint256 value) nonpayable returns (bool )

In [12]: transfer = abi.transfer

In [13]: transfer.signature
Out[13]: 'transfer(address,uint256)'

In [14]: transfer.func_type
Out[14]: 'nonpayable'

In [15]: transfer.selector
Out[15]: HexBytes('0xa9059cbb')

In [16]: transfer.simple
Out[16]: 'transfer(address,uint256)->(bool) nonpayable'

In [17]: transfer.full
Out[17]: 'function transfer(address to, uint256 value) nonpayable returns (bool )'

In [18]: calldata = abi.transfer.encode_input(['0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 10])

In [19]: calldata
Out[19]: HexBytes('0xa9059cbb000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000000000000000000000000000000000000000000a')

In [20]: values = abi.transfer.decode_input(calldata)

In [21]: values
Out[21]: ('0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 10)

In [22]: transfer.map_values(values)
Out[22]: [('to', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'), ('value', 10)]

In [23]: transfer.extract_value('to', values)
Out[23]: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'

In [24]: transfer.explain_calldata('to: {{to}} value: {{value}}', calldata)
Out[24]: 'to: 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee value: 10'

Etherscan

In [1]: WFTM = '0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83'

In [2]: scan = p.scan

In [3]: scan.get_contract_info(WFTM).keys()
Out[3]: dict_keys(['SourceCode', 'ABI', 'ContractName', 'CompilerVersion', 'OptimizationUsed', 'Runs', 'ConstructorArguments', 'EVMVersion', 'Library', 'LicenseType', 'Proxy', 'Implementation', 'SwarmSource'])

In [4]: scan.get_contract_name(WFTM)
Out[4]: 'WrappedFtm'

In [5]: scan.get_source(WFTM)[:100]
Out[5]: 'pragma solidity ^0.5.0;\r\n\r\ncontract Context {\r\n    // Empty internal constructor, to prevent people '

In [6]: name, ver, std_input = scan.get_standard_json_input(WFTM)

In [7]: name
Out[7]: 'WrappedFtm'

In [8]: ver
Out[8]: '0.5.17'

In [9]: std_input.keys()
Out[9]: dict_keys(['language', 'sources', 'settings'])

In [10]: import solcx

In [11]: out = solcx.compile_standard(std_input, solc_version=ver)

In [12]: out.keys()
Out[12]: dict_keys(['contracts', 'sources'])

In [13]: out["contracts"].keys()
Out[13]: dict_keys(['WrappedFtm.sol'])

In [14]: out["contracts"]['WrappedFtm.sol'].keys()
Out[14]: dict_keys(['Context', 'ERC20', 'ERC20Detailed', 'ERC20Pausable', 'IERC20', 'Pausable', 'PauserRole', 'Roles', 'SafeMath', 'WrappedFtm'])


In [15]: out["contracts"]['WrappedFtm.sol']["WrappedFtm"].keys()
Out[15]: dict_keys(['abi', 'devdoc', 'evm', 'metadata', 'userdoc'])

In [16]: out["contracts"]['WrappedFtm.sol']["WrappedFtm"]["evm"].keys()
Out[16]: dict_keys(['bytecode', 'deployedBytecode'])

In [17]: out["contracts"]['WrappedFtm.sol']["WrappedFtm"]["evm"]["bytecode"].keys()
Out[17]: dict_keys(['linkReferences', 'object', 'opcodes', 'sourceMap'])

In [18]: out["contracts"]['WrappedFtm.sol']["WrappedFtm"]["evm"]["bytecode"]["object"]
Out[18]: '60806040523480156200001157600080fd5b50604080518082018252600e81526d577261707065642046616e746f6d60901b6020808301918252835180850190945260048452635746544d60e01b90840152815191929160129162000068916003919062000210565b5081516200007e90600490602085019062000210565b506005805460ff191660ff9290921691909117905550620000b39050620000a4620000c3565b6001600160e01b ...