Open JamesSmartCell opened 3 years ago
function contractURI() returns(string metaData)
Ok, but note that this is at the contract level so name and image are for the contract, not for the individual token types or token instances. (ie. we can use this to show that single row in the Wallet tab only), so if decimals is included here, we can't use it since there would be more than 1 token type (with 0 or more decimals
value) in this same ERC1155 token-holding contract. [1]
Sometimes the URL (maybe just from Rarible?) have an {address}
variable embedded. We'll need to substitute it with the contract address:
https://api-mainnet.rarible.com/contractMetadata/{address}
function uri(1) returns(string token Description Metadata for token index 1)
While the contracts I came across use uri()
, the ERC1155 standard defines tokenURI()
, so we'll have to support both.
Like I mentioned separately, I couldn't find a way to tell them apart, given an _id
. (maybe if decimals
is included in the uri()
/tokenURI()
data? But I haven't found any fungible to verify against yet).
We'll have to use event logs to figure this out. But blockscout.com (at least for xDai) supports getting ERC1155 transfers.
Couple of unknowns:
safeBatchTransferFrom()
are included and if they are, how they are included in the results. So this approach might not workSample contract: https://blockscout.com/xdai/mainnet/tokens/0x93d0c9a35c43f6BC999416A06aaDF21E68B29EBA/read-contract Transfers: https://blockscout.com/xdai/mainnet/tokens/0x93d0c9a35c43f6BC999416A06aaDF21E68B29EBA/token-transfers One of them: https://blockscout.com/xdai/mainnet/tx/0xb5d96a979406faff272cc68b9a143575dcc79f462bcaa38b6edb8b2b5a1ab7a3
GET(s):
Sender:
curl 'https://blockscout.com/xdai/mainnet/api?&module=account&action=tokentx&address=0x2a58ab26538a905f08ac7838b83c1c160430e744&sort=desc' | json_pp | clip
Receipient:
curl 'https://blockscout.com/xdai/mainnet/api?&module=account&action=tokentx&address=0x61cd76d2dab94cbf81ad45a8451f1467cead23fe&sort=desc' | json_pp | clip
(they both includes transaction 0xa5c15de2c4bff26810ebc3dd7df64d2c4a7afdff9ffb255c7905f501c7e80b86)
{
"name" : "TransferSingle",
"inputs" : [
{
"type" : "address",
"indexed" : true,
"name" : "_operator"
},
{
"type" : "address",
"indexed" : true,
"name" : "_from"
},
{
"type" : "address",
"indexed" : true,
"name" : "_to"
},
{
"type" : "uint256",
"name" : "_id",
"indexed" : false
},
{
"type" : "uint256",
"name" : "_value",
"indexed" : false
}
],
"type" : "event",
"anonymous" : false
},
{
"name" : "TransferBatch",
"inputs" : [
{
"type" : "address",
"indexed" : true,
"name" : "_operator"
},
{
"type" : "address",
"indexed" : true,
"name" : "_from"
},
{
"type" : "address",
"indexed" : true,
"name" : "_to"
},
{
"type" : "uint256[]",
"name" : "_ids",
"indexed" : false
},
{
"type" : "uint256[]",
"name" : "_values",
"indexed" : false
}
],
"type" : "event",
"anonymous" : false
}
TransferSingle
:
contractInstance1.getPastEvents('TransferSingle', {
filter: {
_to: owner,
},
fromBlock: 0,
toBlock: 'latest'
}, function(error, events){ console.log(error, events); })
TransferBatch
:
contractInstance1.getPastEvents('TransferBatch', {
filter: {
_to: owner,
},
fromBlock: 0,
toBlock: 'latest'
}, function(error, events){ console.log(error, events); })
Will need to filter for _from
for both events too.
Referring to Tomek's designs where "Mathilde Cretier" the collection name is displayed. We wouldn't get such a representative name, it'll be something like "Enjin" or "Rarible" instead, because it is at the contract level, not at the collection/token type level.
[1] So if there's a fungible representing fiat (fractional dollars) instead of gold (discrete pieces), I don't know how to get/provide decimals
for the fiat type... maybe it is included uri()
or tokenURI()
So based on the collection, collection name and contractURI()
things we talked about, and referring to Tomek's design https://projects.invisionapp.com/share/HD10WWZ5JXA5#/screens, the UI flow would be the same, but the data displayed is slightly different because we can't tell multi-collections/multi-verse from collections. We have to treat each ERC1155 as a single multi-collection like that:
contractURI()
, otherwise try name()
(ouch Enjin doesn't have that too!), otherwise display the contract name.Added section on "Event logs" above
Some notes for prosperity:
As for the collection name and contractURI()
:
So for GenSys.X, contractURI()
returns https://api-mainnet.rarible.com/contractMetadata/{address}
, sub in the contract and we get https://api-mainnet.rarible.com/contractMetadata/0x3ec057be60db3a2d416e14a6e3ab7f37ffccd7b8
which mentions "GenSys.X". So yes, this ERC1155 contract does indeed only hold 1 collection, can verify visually here too: https://rarible.com/gensysx.
Not the case for Enjin's which holds multiple collection, so contractURI()
can't return anything meaningful except "Enjin". But looks like they don't implement contractURI()
at all. So we'll have to hardcode the Enjin's contract to display "Enjin" like this https://opensea.io/collection/enjin or this https://opensea.io/assets/0xfaafdc07907ff5120a76b34b731b278c38d6043c/50659039041325876706985198754860174267763181649547768479226185909848571379712
Added sections:
Summarize the way ERC1155 transfers/tokens can be fetched:
mainnet + Rinkeby only
All
Presumably all chains that are available on Blockscout, but verified with xDai so far and verified to exclude TransferBatch
, eg. https://blockscout.com/xdai/mainnet/tx/0x29a7352220c725e94d3ef2e17b6b4ca9250779264a571e8e2741c62ac356c098/logs. So it can't be used
@JamesSmartCell
Did you say that you figured out how to tell which "collection" a token (tokenId/id) in a ERC1155 is grouped in?
If you use events and not OpenSea, are you able to get the tokenURI/uri() for this token in the following wallet, as well as the image?
@hboon re-looking at this, I provided all this info in a separate issue in the iOS repo.
Good to close? Or do you need more info on the heuristic? It won't catch 100% percent of groups, but it won't put the wrong NFTs together into groups, as it's quite conservative. It does help reduce the clutter a lot. I can provide a few more test collections I tested against.
Good to close? Or do you need more info on the heuristic?
Good to close, but could you like link to that iOS issue you mentioned? We aren't implementing the heuristics for now, but might check back later.
@hboon Some notes on ERC1155 specifically for tracking balances and URI I made:
Check the Ethereum standard https://eips.ethereum.org/EIPS/eip-1155
Token name and symbol are usually the same as ERC20/ERC721:
However the ERC1155 spec in openzeppelin doesn't indicate these are required. Name is also supplied in the contractURI:
Here is an example of an overall contract URI metadata, however this route may or may not be present.
-->
From the Ethereum standard:
Note the
decimals
field above!Note that
image
is the equivalent of the token image in ERC721, so in the example of a print run of 50, theimage
is the actual print.Here is an example of specific tokenUri
-->
Balance events:
_operator
: the sender of the transaction_from
,_to
: as expected_id
: token Identifier_value
: as expectedAs above, but note the array fields for
_ids
and_values
Is emitted when the URI for a token changes. TODO: Find out if the unindexed string gives the actual string or is the hash value. If it's the actual string then it can be used to re-load the metadata.
Interface spec