NFT price attribution
Problem
When NFTs first appeared, it was relatively easy to properly attribute NFT prices because most transactions involved the transfer of just a single NFT. As a result, we could be confident all payments that occured within a given transaction were related to the same NFT transfer.
However as time goes by, NFT transactions are becoming increasingly complicated with the emergence of things like bundle mints and sales, swaps, circular trades and so on. In addition to multiple tokens being transfered back and forth in single transactions, we also are seeing more parties participating in a single transaction aside from the initial owner and the final recipient. All of these practices make price attribution for individual NFTs an increasingly complicated task.
For example, in June 2022, there were 13.38 million NFT transfers on Ethereum. Only 29.6% of those were single NFT transfers. The rest of these transfers were "bundles" where multiple NFTs were transfered in a single transaction. For comparison, in June 2019 68% of NFT transfers were single token transfers.
How Mnemonic approaches price attribution
Mnemonic indexes various transfers on the blockchain, detects payments, exchanges, and other types of transactions between accounts involving fungible and non-fungible tokens. As a next step Mnemonic applies pricing attribution algorithms to that data, enabling us to provide our end users with accurate and easy-to-use pricing data for individual NFT tokens.
Our algorithm accounts for the following unique transaction edge cases to name just a few:
- Batch mints of NFTs;
- Bundle sales (both single- and multi-contract);
- Transfers via intermediate addresses;
- ERC-1155 tokens with multiple quantities;
- Bi-directional payments;
- and many others...
In the vast majority of cases, we are able to provide accurate pricing attribution for NFTs. We also provide a dedicated endpoint that returns a full, detailed breakdown of all NFTs and payments involved in any given transaction.
Using Mnemonic's Transfer Insights endpoints to get NFT prices
Our "Transfer Insights" provide the ability to get a list of NFT transfers filtered by various fields. For the GetNftTransfers
endpoint, the response aside from the regular information about transfers will contain details related to pricing attribution. At the same time GetAllTransfersByTxHash
endpoint will allow you to get a full breakdown.
Pricing details
Note: Field names provided are for Ethereum and may differ for other blockchains.
For each NFT transfer returned, the response contains the senderReceived
and recipientPaid
sub-objects with the following structure:
totalEth
- total amount attributed to this transfer, converted to ETH (if the payment or part of the payment has been made by non-eth fungilbe tokens);totalUsd
- total amount converted to USD according to the exchange rate at the transfer time;ethTransfersTotal
- total for the portion of payments made natively in ETH;erc20TransfersTotal
- total for the portion of payments made native in ERC20 and converted to ETH.
Basically the totalEth
field is a sum of ethTransfersTotal
and erc20TransfersTotal
, the latter is provided solely for your convenience.
It is worth noting that if the pricing attribution was impossible for either the sender or recipient of a transfer, the whole object will be equal to null
. Such cases include, for example, a zero-quantity ERC-1155 transfer or transfers where multiple tokens are being burned at the same time.
Another possible case is if the erc20TransfersTotal
field (and as a result also totalEth
and totalUsd
) begins equal to null
, which means that the transfer included fungible tokens, that either do not fully conform to the ERC20 standard or do not have an exchange rate to ETH.
Example with a mixed payment
Let's take a look at a sample transfer which illustrates the fields mentioned above. In this case, you can see that the seller has been paid in solely in ERC-20 tokens, while the purchaser paid partially in ERC-20 and partially in native ETH.
{
"blockchainEvent": {
"txHash": "0x0ca31a30b9a828d5e8022f925db13ce220d067acc9e882e189c1fca628ee6620",
"logIndex": 427,
"seqIndex": 0,
"blockNumber": 15129373,
"blockTimestamp": "2022-07-12 18:05:44+00"
},
"contractAddress": "0x2ee6af0dff3a1ce3f7e3414c52c48fd50d73691e",
"tokenId": "4802",
"tokenType": "TYPE_ERC721",
"transferType": "TRANSFER_TYPE_REGULAR",
"quantity": "1",
"sender": {
"address": "0x910baeba92c30a1bf3d9a23d9eb0e645a88135fd",
"type": "TYPE_OWNER"
},
"senderReceived": {
"totalEth": "0.13636656005335413952",
"totalUsd": "146.80918416606025558869750243225024",
"ethTransfersTotal": "0",
"erc20TransfersTotal": "0.13636656005335413952"
},
"recipient": {
"address": "0x512a966f39775225850f447b87e36699a12dd516",
"type": "TYPE_OWNER"
},
"recipientPaid": {
"totalEth": "0.1549743640150963025024",
"totalUsd": "166.8419291269694475347252231256271488",
"ethTransfersTotal": "0.050432",
"erc20TransfersTotal": "0.1045423640150963025024"
}
}
Sender/recipient Types
Another helpful field returned in the response is type
within the sender
and recipient
objects. This field helps to detect transfers via intermediate contracts. It can take one of the following values:
TYPE_OWNER
- the address is either the initial owner or the final recipient of the NFT;TYPE_INTERMEDIATE
- the address is an intermediary and neither the initial owner nor the final recipient.
In cases where either the sender or recipient is marked as intermediate, respective pricing details object will be equal to null
because the above mentioned entity does not buy or sell NFTs in the transaction.
Example
Let's take a look at another example where an NFT transfer occurs via intermediate party (GemSwap).
[
{
"blockchainEvent": {
"txHash": "0xa9ac922d5816b4575ba91f833429ca952a70b9df824c55ba784cf70dbdf01d74",
"logIndex": 136,
"seqIndex": 0,
"blockNumber": 15129929,
"blockTimestamp": "2022-07-12 20:11:01+00"
},
"contractAddress": "0xeccae88ff31e9f823f25beb404cbf2110e81f1fa",
"tokenId": "7254",
"tokenType": "TYPE_ERC721",
"transferType": "TRANSFER_TYPE_TRANSFER",
"quantity": "1",
"sender": {
"address": "0x3b267a2664256a0102ad2d4d182e80ff797d991c",
"type": "TYPE_OWNER"
},
"senderReceived": {
"totalEth": "0.028855",
"totalUsd": "30.043725466467958947",
"ethTransfersTotal": "0.028855",
"erc20TransfersTotal": "0"
},
"recipient": {
"address": "0x83c8f28c26bf6aaca652df1dbbe0e1b56f8baba2",
"type": "TYPE_INTERMEDIATE"
},
"recipientPaid": null
},
{
"blockchainEvent": {
"txHash": "0xa9ac922d5816b4575ba91f833429ca952a70b9df824c55ba784cf70dbdf01d74",
"logIndex": 140,
"seqIndex": 0,
"blockNumber": 15129929,
"blockTimestamp": "2022-07-12 20:11:01+00"
},
"contractAddress": "0xeccae88ff31e9f823f25beb404cbf2110e81f1fa",
"tokenId": "7254",
"tokenType": "TYPE_ERC721",
"transferType": "TRANSFER_TYPE_TRANSFER",
"quantity": "1",
"sender": {
"address": "0x83c8f28c26bf6aaca652df1dbbe0e1b56f8baba2",
"type": "TYPE_INTERMEDIATE"
},
"senderReceived": null,
"recipient": {
"address": "0x0e6bb4218c44668051fda95c94fcbf11f3fca08f",
"type": "TYPE_OWNER"
},
"recipientPaid": {
"totalEth": "0.029",
"totalUsd": "30.1946989612743306",
"ethTransfersTotal": "0.029",
"erc20TransfersTotal": "0"
}
}
]
All transfers by transaction
In addition to returning attributed prices, our Transfer Insights endpoints allow you to get a full breakdown of all transfers (NFT, ERC20, ETH, and/or others depending on the blockchain) within a transaction — via GetAllTransfersByTxHash
endpoint.
This endpoint returns txHash
as input and returns a set of lists for each type of transfer within to the requested transaction.
Example
Let's take a look at the following example:
{
"nftTransfers": [
{
"blockchainEvent": {
"txHash": "0x4441fe5daceeb0a10d7682a445abdd5b6c4806d43fc6def186575a882f9f599c",
"logIndex": 271,
"seqIndex": 0,
"blockNumber": 15120950,
"blockTimestamp": "2022-07-11 10:51:17+00"
},
"contractAddress": "0xd46c8648f2ac4ce1a1aace620460fbd24f640853",
"tokenId": "5779",
"tokenType": "TYPE_ERC721",
"transferType": "TRANSFER_TYPE_BURN",
"quantity": "1",
"sender": {
"address": "0x962871224822525c963d2d397b728a2aead83a1b",
"type": "TYPE_OWNER"
},
"senderReceived": null,
"recipient": {
"address": "0x0000000000000000000000000000000000000000",
"type": "TYPE_OWNER"
},
"recipientPaid": null
}
# ...more transfers...
],
"ethTransfers": [
{
"fromAddress": "0x962871224822525c963d2d397b728a2aead83a1b",
"toAddress": "0x3b968d2d299b895a5fcf3bba7a64ad0f566e6f88",
"valueRaw": "2941445554065432573",
"valueNormalized": "2.941445554065432573"
}
# ...more transfers...
],
"erc20Transfers": [
{
"fromAddress": "0x0000000000000000000000000000000000000000",
"toAddress": "0x43078abfb76bd24885fd64effb22049f92a8c495",
"contractAddress": "0xed1840223484483c0cb050e6fc344d1ebf0778a9",
"valueRaw": "340841025061864773",
"valueNormalized": "0.3408410250618648",
"valueEth": null
}
# ...more transfers...
]
}
Using the Collection Analytics API to get pricing data
Mnemonic is the only NFT data solution on the market that provides accurate pricing information for all existing collections on the blockchain as a time-series. The data is updated every 15 minutes for every collection on the blockchain (ERC721 and ERC1155) and is aggregated into 1h time periods.
The provided data covers all transactions from across the entire blockchain regardless of which marketplace the trade was executed on.
There is no limit to how far back the historical data can be retrieved.
All price values are converted into ETH according to the exchange rate at the time of the transaction if payments were made in ERC20 tokens.
Below is an example of pricing time-series data returned for the BAYC contract for the last 7 days aggregated into 1h time periods (trimmed for the purpose of this example).
The data is zero-padded to make charting the graph easier.
{
"dataPoints": [
{
"timestamp": "2022-05-25T05:00:00Z",
"min": "95",
"max": "105",
"avg": "98.6666666666666667"
},
{
"timestamp": "2022-05-25T06:00:00Z",
"min": "",
"max": "",
"avg": ""
},
{
"timestamp": "2022-05-25T07:00:00Z",
"min": "109",
"max": "109",
"avg": "109"
},
{
"timestamp": "2022-05-25T08:00:00Z",
"min": "",
"max": "",
"avg": ""
},
{
"timestamp": "2022-05-25T09:00:00Z",
"min": "",
"max": "",
"avg": ""
},
{
"timestamp": "2022-05-25T10:00:00Z",
"min": "",
"max": "",
"avg": ""
},
{
"timestamp": "2022-05-25T11:00:00Z",
"min": "86.0901233378872304",
"max": "86.0901233378872304",
"avg": "86.0901233378872304"
}
...
<trimmed>
]
}
Try using Mnemonic's Collection Analytics API to get the accurate time-series data for you project.
ERC20 Conversion
Mnemonic automatically converts ERC-20 token values into native ETH value according to the exchange rate at the time of the transaction.
The following ERC-20 tokens are currently converted automatically for Ethereum:
Symbol | Token address |
---|---|
WETH | 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 |
LINK | 0x514910771af9ca656af840dff83e8264ecf986ca |
USDC | 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 |
SAND | 0x3845badade8e6dff049820680d1f14bd3903a5d0 |
SUSHI | 0x6b3595068778dd592e39a122f4f5a5cf09c90fe2 |
DAI | 0x6b175474e89094c44da98b954eedeac495271d0f |
USDT | 0xdac17f958d2ee523a2206206994597c13d831ec7 |
ENJ | 0xf629cbd94d3791c9250152bd8dfbdf380e2a3b9c |
COVAL | 0x3d658390460295fb963f54dc0899cfb1c30776df |
DEGO | 0x88ef27e69108b2633f8e1c184cc37940a075cc02 |
SHIB | 0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce |
WBTC | 0x2260fac5e5542a773aa44fbcfedf7c193bc2c599 |
CRO | 0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b |
APE | 0x4d224452801aced8b2f0aebe155379bb5d594381 |
GALA | 0x15d4c048f83bd7e37d49ea4c83a07267ec4203da |
The following ERC-20 tokens are currently converted automatically for Polygon:
Symbol | Token address |
---|---|
MATIC | 0x0000000000000000000000000000000000001010 |
WETH | 0x7ceb23fd6bc0add59e62ac25578270cff1b9f619 |
WMATIC | 0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270 |
USDC | 0x2791bca1f2de4661ed88a30c99a7a9449aa84174 |
USDT | 0xc2132d05d31c914a87c6611c10748aeb04b58e8f |
DAI | 0x8f3cf7ad23cd3cadbd9735aff958023239c6a063 |
QUICK | 0x831753dd7087cac61ab5644b308642cc1c33dc13 |
CHI | 0x0000000000004946c0e9f43f4dee607b0ef1fa1c |