Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for erc1155 tokens #437

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ First extract token addresses from `contracts.json`
(Exported with [export_contracts](#export_contracts)):

```bash
> ethereumetl filter_items -i contracts.json -p "item['is_erc20'] or item['is_erc721']" | \
> ethereumetl filter_items -i contracts.json -p "item['is_erc20'] or item['is_erc721']" or item['is_erc1155']" | \
ethereumetl extract_field -f address -o token_addresses.txt
```

Then export ERC20 / ERC721 tokens:
Then export ERC20 / ERC721 / ERC 1155 tokens:

```bash
> ethereumetl export_tokens --token-addresses token_addresses.txt \
Expand Down
2 changes: 1 addition & 1 deletion docs/limitations.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Limitation

- In case the contract is a proxy, which forwards all calls to a delegate, interface detection doesn’t work,
which means `is_erc20` and `is_erc721` will always be false for proxy contracts and they will be missing in the `tokens`
which means `is_erc20`, `is_erc721` and `is_erc1155` will always be false for proxy contracts and they will be missing in the `tokens`
table.
- The metadata methods (`symbol`, `name`, `decimals`, `total_supply`) for ERC20 are optional, so around 10% of the
contracts are missing this data. Also some contracts (EOS) implement these methods but with wrong return type,
Expand Down
1 change: 1 addition & 0 deletions docs/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ bytecode | hex_string |
function_sighashes | string |
is_erc20 | boolean |
is_erc721 | boolean |
is_erc1155 | boolean |
block_number | bigint |

---
Expand Down
1 change: 1 addition & 0 deletions ethereumetl/domain/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ def __init__(self):
self.function_sighashes = []
self.is_erc20 = False
self.is_erc721 = False
self.is_erc1155 = False
self.block_number = None
1 change: 1 addition & 0 deletions ethereumetl/jobs/export_contracts_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def _get_contract(self, contract_address, rpc_result):
contract.function_sighashes = function_sighashes
contract.is_erc20 = self.contract_service.is_erc20_contract(function_sighashes)
contract.is_erc721 = self.contract_service.is_erc721_contract(function_sighashes)
contract.is_erc1155 = self.contract_service.is_erc1155_contract(function_sighashes)

return contract

Expand Down
1 change: 1 addition & 0 deletions ethereumetl/jobs/exporters/contracts_item_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
'function_sighashes',
'is_erc20',
'is_erc721',
'is_erc1155',
'block_number',
]

Expand Down
1 change: 1 addition & 0 deletions ethereumetl/jobs/extract_contracts_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def _extract_contracts(self, traces):
contract.function_sighashes = function_sighashes
contract.is_erc20 = self.contract_service.is_erc20_contract(function_sighashes)
contract.is_erc721 = self.contract_service.is_erc721_contract(function_sighashes)
contract.is_erc1155 = self.contract_service.is_erc1155_contract(function_sighashes)

contracts.append(contract)

Expand Down
2 changes: 1 addition & 1 deletion ethereumetl/jobs/extract_tokens_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def _export(self):
self.batch_work_executor.execute(self.contracts_iterable, self._export_tokens_from_contracts)

def _export_tokens_from_contracts(self, contracts):
tokens = [contract for contract in contracts if contract.get('is_erc20') or contract.get('is_erc721')]
tokens = [contract for contract in contracts if contract.get('is_erc20') or contract.get('is_erc721') or contract.get('is_erc1155')]

for token in tokens:
self._export_token(token_address=token['address'], block_number=token['block_number'])
Expand Down
1 change: 1 addition & 0 deletions ethereumetl/mappers/contract_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ def contract_to_dict(self, contract):
'function_sighashes': contract.function_sighashes,
'is_erc20': contract.is_erc20,
'is_erc721': contract.is_erc721,
'is_erc1155': contract.is_erc1155,
'block_number': contract.block_number
}
25 changes: 23 additions & 2 deletions ethereumetl/service/eth_contract_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,23 @@ class EthContractService:

def get_function_sighashes(self, bytecode):
bytecode = clean_bytecode(bytecode)
function_sighashes = []
if bytecode is not None:
evm_code = EvmCode(contract=Contract(bytecode=bytecode), static_analysis=False, dynamic_analysis=False)
evm_code.disassemble(bytecode)
basic_blocks = evm_code.basicblocks
if basic_blocks and len(basic_blocks) > 0:
init_block = basic_blocks[0]
instructions = init_block.instructions
push4_instructions = [inst for inst in instructions if inst.name == 'PUSH4']
return sorted(list(set('0x' + inst.operand for inst in push4_instructions)))
for inst in instructions:
# Special case when balanceOf(address,uint256) becomes PUSH3 due to optimization
# https://github.com/blockchain-etl/ethereum-etl/issues/349#issuecomment-1243352201
if inst.name == "PUSH3" and inst.operand == "fdd58e":
function_sighashes.append("0x00" + inst.operand)
if inst.name == "PUSH4":
function_sighashes.append("0x" + inst.operand)

return sorted(list(set(function_sighashes)))
else:
return []
else:
Expand Down Expand Up @@ -69,6 +77,19 @@ def is_erc721_contract(self, function_sighashes):
c.implements_any_of('transfer(address,uint256)', 'transferFrom(address,address,uint256)') and \
c.implements('approve(address,uint256)')

# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
# https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol
def is_erc1155_contract(self, function_sighashes):
c = ContractWrapper(function_sighashes)
return (
c.implements("balanceOf(address, uint256)") and \
c.implements("balanceOfBatch(address[],uint256[])") and \
c.implements("setApprovalForAll(address, bool)") and \
c.implements("isApprovedForAll(address,address)") and \
c.implements("safeTransferFrom(address,address,uint256,uint256,bytes)") and \
c.implements("safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)")
)


def clean_bytecode(bytecode):
if bytecode is None or bytecode == '0x':
Expand Down
1 change: 1 addition & 0 deletions ethereumetl/streaming/enrich.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ def enrich_contracts(blocks, contracts):
'function_sighashes',
'is_erc20',
'is_erc721',
'is_erc1155',
'block_number'
],
[
Expand Down
1 change: 1 addition & 0 deletions ethereumetl/streaming/postgres_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
Column('function_sighashes', ARRAY(String)),
Column('is_erc20', Boolean),
Column('is_erc721', Boolean),
Column('is_erc1155', Boolean),
Column('block_number', BigInteger),
PrimaryKeyConstraint('address', 'block_number', name='contracts_pk'),
)
1 change: 1 addition & 0 deletions schemas/aws/contracts.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ CREATE EXTERNAL TABLE IF NOT EXISTS contracts (
function_sighashes STRING,
is_erc20 BOOLEAN,
is_erc721 BOOLEAN
is_erc1155 BOOLEAN
)
PARTITIONED BY (date STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"type": "contract", "address": "0xdbdacfc9eb9d42559ac1efbdb40460c728139e6a", "bytecode": "0x6060604052361561008d5760e060020a600035046306fdde03811461008f578063095ea7b3146100a557806318160ddd1461012457806323b872dd1461012f578063313ce567146101dc578063475a9fa9146101f057806370a0823114610215578063721a37d21461024357806395d89b411461008f578063a9059cbb14610268578063dd62ed3e146102e7575b005b61031d6040805160208101909152600081525b90565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db63c6605267600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b6102316003546100a2565b61038b60043560243560443560008054604080517fa00bfa1100000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a038781166024830152868116604483015260648201869052929092166084830152517319ee743d2e356d5f0e4d97cc09b96d06e933d0db9163a00bfa119160a482810192602092919082900301818660325a03f4156100025750506040515195945050505050565b604080516000815290519081900360200190f35b61038b6004356024356000805433600160a060020a0390811691161461039f57610002565b600160a060020a03600435166000908152600160205260409020545b60408051918252519081900360200190f35b61038b6004356024356000805433600160a060020a039081169116146103ce57610002565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db6388d5fecb600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b610231600435602435600160a060020a038281166000908152600260209081526040808320938516835292905220545b92915050565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561037d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080519115158252519081900360200190f35b50600160a060020a03821660009081526001602081905260409091208054830190556003805483019055610317565b600160a060020a038316600090815260016020526040902054821161040a57506040600020805482900390556003805482900390556001610317565b50600061031756", "function_sighashes": ["0x06fdde03", "0x095ea7b3", "0x18160ddd", "0x23b872dd", "0x313ce567", "0x475a9fa9", "0x70a08231", "0x721a37d2", "0x95d89b41", "0xa9059cbb", "0xdd62ed3e"], "is_erc20": true, "is_erc721": false, "block_number": 2112234, "block_timestamp": 1471774428, "block_hash": "0xd279067d9852394d6b6c00b13c49696503c9618d3ed3b23c6b1b1321857ddd92", "item_id": "contract_2112234_0xdbdacfc9eb9d42559ac1efbdb40460c728139e6a", "item_timestamp": "2016-08-21T10:13:48Z"}
{"type": "contract", "address": "0xdbdacfc9eb9d42559ac1efbdb40460c728139e6a", "bytecode": "0x6060604052361561008d5760e060020a600035046306fdde03811461008f578063095ea7b3146100a557806318160ddd1461012457806323b872dd1461012f578063313ce567146101dc578063475a9fa9146101f057806370a0823114610215578063721a37d21461024357806395d89b411461008f578063a9059cbb14610268578063dd62ed3e146102e7575b005b61031d6040805160208101909152600081525b90565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db63c6605267600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b6102316003546100a2565b61038b60043560243560443560008054604080517fa00bfa1100000000000000000000000000000000000000000000000000000000815260016004820152600160a060020a038781166024830152868116604483015260648201869052929092166084830152517319ee743d2e356d5f0e4d97cc09b96d06e933d0db9163a00bfa119160a482810192602092919082900301818660325a03f4156100025750506040515195945050505050565b604080516000815290519081900360200190f35b61038b6004356024356000805433600160a060020a0390811691161461039f57610002565b600160a060020a03600435166000908152600160205260409020545b60408051918252519081900360200190f35b61038b6004356024356000805433600160a060020a039081169116146103ce57610002565b61038b60043560243560007319ee743d2e356d5f0e4d97cc09b96d06e933d0db6388d5fecb600160005085856040518460e060020a0281526004018084815260200183600160a060020a0316815260200182815260200193505050506020604051808303818660325a03f4156100025750506040515191506103179050565b610231600435602435600160a060020a038281166000908152600260209081526040808320938516835292905220545b92915050565b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561037d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b604080519115158252519081900360200190f35b50600160a060020a03821660009081526001602081905260409091208054830190556003805483019055610317565b600160a060020a038316600090815260016020526040902054821161040a57506040600020805482900390556003805482900390556001610317565b50600061031756", "function_sighashes": ["0x06fdde03", "0x095ea7b3", "0x18160ddd", "0x23b872dd", "0x313ce567", "0x475a9fa9", "0x70a08231", "0x721a37d2", "0x95d89b41", "0xa9059cbb", "0xdd62ed3e"], "is_erc20": true, "is_erc721": false, "is_erc1155": false, "block_number": 2112234, "block_timestamp": 1471774428, "block_hash": "0xd279067d9852394d6b6c00b13c49696503c9618d3ed3b23c6b1b1321857ddd92", "item_id": "contract_2112234_0xdbdacfc9eb9d42559ac1efbdb40460c728139e6a", "item_timestamp": "2016-08-21T10:13:48Z"}
Loading