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

[r2r] NFT integration poc #1652

Merged
merged 62 commits into from
Mar 7, 2023
Merged

[r2r] NFT integration poc #1652

merged 62 commits into from
Mar 7, 2023

Conversation

laruh
Copy link
Member

@laruh laruh commented Feb 12, 2023

related to #900

The current implementation provides support for the following functionality:

  • get_nft_list
    This function returns list of NFTs on ETH or/and BSC chains owned by user. Mocks
get_nft_list req example
{
  "userpass": "userpass",
  "mmrpc": "2.0",
  "method": "get_nft_list",
  "params": {
    "chains": [
      "ETH",
      "BSC"
    ]
  }
}
get_nft_list res example
{
  "mmrpc": "2.0",
  "result": {
    "count": 3,
    "nfts": [
      {
        "chain": "ETH",
        "token_address": "0x63ad7cd8ad28102aaee0d6abd538e60c9cacc22a",
        "token_id": "201",
        "amount": "1",
        "owner_of": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "token_hash": "5af75272a39714801e76bd12d997d5ec",
        "block_number_minted": 13336357,
        "block_number": 13336357,
        "contract_type": "ERC721",
        "name": "Ether  Ghosts",
        "symbol": "GHOSTS",
        "token_uri": "https://ipfs.moralis.io:2053/ipfs/QmS612yMoGTt1FpTWWNaCd8kTHm1afwFK25tGW4rGnFeqk/201",
        "metadata": "{\"name\":\"Ether  Ghosts #201\",\"description\":\"10,000 Ether Ghosts have just landed on the Ethereum network. These spooky creatures will keep your wallet safe while you are sleeping\",\"attributes\":[{\"trait_type\":\"Void\",\"value\":\"Ethereal Being\"},{\"trait_type\":\"Background\",\"value\":\"Light Purple\"},{\"trait_type\":\"Type\",\"value\":\"Ghost\"},{\"trait_type\":\"Skin Color\",\"value\":\"Teal Body\"},{\"trait_type\":\"Complexion\",\"value\":\"Default\"},{\"trait_type\":\"Eyes\",\"value\":\"Bored\"},{\"trait_type\":\"Clothes\",\"value\":\"Basic\"},{\"trait_type\":\"Accessory\",\"value\":\"Sword\"}],\"image\":\"ipfs://Qma7mE5CA1MrX2MHZ9N6HefWL5kcYCPsat99gxQfqUSRGb/201.png\",\"image_url\":\"ipfs://Qma7mE5CA1MrX2MHZ9N6HefWL5kcYCPsat99gxQfqUSRGb/201.png\"}",
        "last_token_uri_sync": "2022-05-18T10:12:31.695Z",
        "last_metadata_sync": "2023-02-12T07:55:35.266Z",
        "minter_address": "0xa239c13c054e498b9be633262574862676d73f7f"
      },
      {
        "chain": "ETH",
        "token_address": "0x495f947276749ce646f68ac8c248420045cb7b5e",
        "token_id": "71508368311469929077051951161112205629360977807816813562618393986376478490625",
        "amount": "1",
        "owner_of": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "token_hash": "95c29484506f60d018a995fc764d9fa2",
        "block_number_minted": 13437165,
        "block_number": 13437165,
        "contract_type": "ERC1155",
        "name": "OpenSea Shared Storefront",
        "symbol": "OPENSTORE",
        "token_uri": "https://api.opensea.io/api/v1/metadata/0x495f947276749Ce646f68AC8c248420045cb7b5e/0x9e184d5baa4e52222fd9e6acd72a9364d7b9166e0000000000000d0000000001",
        "metadata": "{\"name\":\"#11 Intern\",\"description\":null,\"external_link\":\"https://a16z.com/crypto/\",\"image\":\"https://i.seadn.io/gae/HiHsFy8vmXS-XXWKKOQpm95Ks_jfV05Z-2bO-U9oPnNWpx9Q_FbiSRccf2qaTr7KIuU2UzvdrgwCS3gEJWKHXYv8QImvlWtRxKa8?w=500&auto=format\",\"animation_url\":\"https://openseauserdata.com/files/4f771b983499dd4faca1547cfea0a956.mp4\"}",
        "last_token_uri_sync": "2022-12-08T04:46:42.531Z",
        "last_metadata_sync": "2022-12-08T04:46:44.983Z",
        "minter_address": "ERC1155 tokens don't have a single minter"
      },
      {
        "chain": "BSC",
        "token_address": "0x36f8f51f65fe200311f709b797baf4e193dd0b0d",
        "token_id": "12",
        "amount": "1",
        "owner_of": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "token_hash": "fae04ab508314903c33a7bcad362156c",
        "block_number_minted": 9607444,
        "block_number": 19116577,
        "contract_type": "ERC1155",
        "name": "Treat NFT Minter",
        "symbol": "TreatNFTMinter",
        "token_uri": "https://treatdao.com/api/nft/12",
        "metadata": "{\"name\":\"Treat Me Right So I can Treat You Right\",\"image\":\"https://i.imgur.com/ojp3yGj.jpg\",\"description\":\"Beginnings are always exciting. But they are exciting only when they have an end. Let’s make the time between the two to last forever.\",\"properties\":{\"_id\":12,\"external_url\":\"https://treatdao.com/\",\"model\":{\"handle\":\"@nftdevan\",\"address\":\"0xDa88E03eCB64B068fe3C7a029A481f9E75a28DaE\"},\"createdAt\":\"2021-04-06T20:44:14.790Z\",\"tags\":[\"SFW\",\"Artistic\",\"Glamour\",\"Natural\",\"Solo\",\"Exclusive\"]},\"attributes\":[{\"trait_type\":\"Model\",\"value\":\"@nftdevan\",\"_id\":\"606cc81ecc8b31000879d054\"},{\"trait_type\":\"Max Supply\",\"value\":\"1000000\",\"_id\":\"606cc81ecc8b31000879d055\"}]}",
        "last_token_uri_sync": "2022-07-24T12:57:17.251Z",
        "last_metadata_sync": "2022-07-24T13:00:17.824Z",
        "minter_address": "ERC1155 tokens don't have a single minter"
      }
    ]
  },
  "id": null
}
  • get_nft_metadata
    This function returns info of one specific NFT. Current implementation sends request to Moralis.
    One moment, that NFT json from moralis for Get NFT metadata has one additional param like "transfer_index": [11362111, 125, 160, 0]. You can see it in Moralis mocks for Get NFT metadata. In response for Get NFT list by wallet NFTs dont have this field. I omitted this parameter and used the same NFT structure in result that I use for get_nft_list. I did it, to be able to first try to fetch data from the list cache before sending new request to moralis.
get_nft_metadata req example
{
  "userpass": "userpass",
  "mmrpc": "2.0",
  "method": "get_nft_metadata",
  "params": {
    "token_address": "0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB",
    "token_id": 1,
    "chain": "ETH"
  }
}
get_nft_metadata res example
{
  "mmrpc": "2.0",
  "result": {
    "chain": "ETH",
    "token_address": "0xb47e3cd837ddf8e4c57f05d70ab865de6e193bbb",
    "token_id": "1",
    "amount": "1",
    "owner_of": "0xb88f61e6fbda83fbfffabe364112137480398018",
    "token_hash": "a99d02058e62e327e79aabd57e0b88a3",
    "block_number_minted": 3934590,
    "block_number": 11362111,
    "contract_type": null,
    "name": "CRYPTOPUNKS",
    "symbol": "Ͼ",
    "token_uri": null,
    "metadata": "{\"image\":\"https://www.larvalabs.com/cryptopunks/cryptopunk001.png\",\"name\":\"CryptoPunk 001\",\"attributes\":[\"Smile\",\"Mohawk\"],\"description\":\"Male\"}",
    "last_token_uri_sync": "2023-02-11T19:23:36.655Z",
    "last_metadata_sync": "2022-08-22T13:27:58.122Z",
    "minter_address": null
  },
  "id": null
}
  • get_nft_transfers
    This function returns a transfer history of NFTs on ETH or/and BSC chains owned by user. Mocks
get_nft_transfers req example
{
  "userpass": "userpass",
  "mmrpc": "2.0",
  "method": "get_nft_transfers",
  "params": {
    "chains": [
      "BSC",
      "ETH"
    ]
  }
}
get_nft_transfers res example
{
  "mmrpc": "2.0",
  "result": {
    "count": 4,
    "transfer_history": [
      {
        "chain": "BSC",
        "block_number": 20379028,
        "block_timestamp": "2022-08-12T14:36:31.000Z",
        "block_hash": "0x9917f0ccd96655c3a93f9dafb59b36d99013f7135fa34246f98b324377b1efc7",
        "transaction_hash": "0x9b727d45a5dfae25111d45743cdd89295de9dee981c8b5a6242c1c1f1cc1905a",
        "transaction_index": 50,
        "log_index": 218,
        "value": "0",
        "contract_type": "ERC1155",
        "transaction_type": "Single",
        "token_address": "0x67af3a5765299a3e2f869c3002204c749bd185e9",
        "token_id": "41371",
        "from_address": "0x1019da05c30ece5d329af38e32e044590c13a0c1",
        "to_address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "amount": "1",
        "verified": 1,
        "operator": "0x1019da05c30ece5d329af38e32e044590c13a0c1"
      },
      {
        "chain": "BSC",
        "block_number": 19357744,
        "block_timestamp": "2022-07-08T01:39:37.000Z",
        "block_hash": "0x6d6b7efbcac98e96590c2d37b8f96f365010a930cbb45d8fe7ac196c1b3a2fc0",
        "transaction_hash": "0xac2d856630eb80270a3b75538977832ac6d7c19100f41b804d3c100958bcb3ab",
        "transaction_index": 96,
        "log_index": 229,
        "value": "0",
        "contract_type": "ERC721",
        "transaction_type": "Single",
        "token_address": "0x999017cb5652caf5f324a8e44f813903ba3c46eb",
        "token_id": "36957",
        "from_address": "0x0000000000000000000000000000000000000000",
        "to_address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "amount": "1",
        "verified": 1,
        "operator": null
      },
      {
        "chain": "ETH",
        "block_number": 16554884,
        "block_timestamp": "2023-02-04T10:40:59.000Z",
        "block_hash": "0x36c6be8af50d46c9ddeb3cd05c4dca870e11e4d52fce528c1c8605bb4708e201",
        "transaction_hash": "0x7436a277730a75079e1481888227da49e9c04fb90605f17be26b577322379d80",
        "transaction_index": 64,
        "log_index": 82,
        "value": "0",
        "contract_type": "ERC721",
        "transaction_type": "Single",
        "token_address": "0x26021ca5f9d35cbc4e984fca0c3a27b47f561d23",
        "token_id": "503",
        "from_address": "0x302ee7e96dbc6ddead7a3fdbe4352990f48baa01",
        "to_address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "amount": "1",
        "verified": 1,
        "operator": null
      },
      {
        "chain": "ETH",
        "block_number": 16552748,
        "block_timestamp": "2023-02-04T03:29:59.000Z",
        "block_hash": "0x0c442de675d1058196199ce6b39a918cb383ca8c07544872ec3b3e9ea321a578",
        "transaction_hash": "0xeb8c405f477d1af99a841702775ab8649b49bba03fefc82e632af568aec8008e",
        "transaction_index": 116,
        "log_index": 198,
        "value": "0",
        "contract_type": "ERC721",
        "transaction_type": "Single",
        "token_address": "0x700f045de43fce6d2c25df0288b41669b7566bbe",
        "token_id": "725",
        "from_address": "0x958c20a43f5206f186b0195ccb61acb724b2ee1e",
        "to_address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        "amount": "1",
        "verified": 1,
        "operator": null
      }
    ]
  },
  "id": null
}
  • get_my_address
    This function returns wallet address for necessary coin without its activation. Currently supports only coins with ETH protocol type.
get_my_address req example
{
  "userpass": "userpass",
  "mmrpc": "2.0",
  "method": "get_my_address",
  "params": {
    "coin": "ETH"
  }
}
get_my_address res example
{
  "mmrpc": "2.0",
  "result": {
    "coin":"ETH",
    "wallet_address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
  },
  "id": null
}

Current withdraw_nft implementation
(dont forget to enable native coin of chain)

withdraw_nft req example
{
  "userpass": "${USERPASS}",
  "method": "withdraw_nft",
  "mmrpc": "2.0",
  "params": {
    "type": "WithdrawErc721",
    "withdraw_data": {
      "chain": "BSC",
      "from": "0xf622a6C52C94b500542E2AE6bcAD24C53Bc5b6a2",
      "to": "0x6FAD0eC6bb76914b2a2a800686acc22970645820",
      "token_address": "0xfd913a305d70a60aac4faac70c739563738e1f81",
      "token_id": "214300047252"
    }
  }
}
withdraw_nft res example
{
  "mmrpc": "2.0",
  "result": {
    "tx_hex": "f8cb0585012a05f200830180b494fd913a305d70a60aac4faac70c739563738e1f8180b86442842e0e000000000000000000000000f622a6c52c94b500542e2ae6bcad24c53bc5b6a20000000000000000000000006fad0ec6bb76914b2a2a800686acc2297064582000000000000000000000000000000000000000000000000000000031e54737948194a001d4374def9ee63ae913d3321757478789e498d979d0f873f38d4027cc9bd4cba035ed0f9f1f4d4fa06b5b7183ad9ed041ebf0a96dfddac2eeec6ceb3b342a0268",
    "tx_hash": "0ec4bb9b330b1befb7c531e0f2ef4af69126e0fc5c699b82fe4a45a23841ade8",
    "from": [
      "0xf622a6C52C94b500542E2AE6bcAD24C53Bc5b6a2"
    ],
    "to": [
      "0x6FAD0eC6bb76914b2a2a800686acc22970645820"
    ],
    "contract_type": "ERC721",
    "token_address": "0xfd913a305d70a60aac4faac70c739563738e1f81",
    "token_id": "214300047252",
    "amount": "1",
    "fee_details": {
      "type": "Eth",
      "coin": "BNB",
      "gas": 98484,
      "gas_price": "0.000000005",
      "total_fee": "0.00049242"
    },
    "coin": "BNB",
    "block_height": 0,
    "timestamp": 1677336094,
    "internal_id": 0,
    "transaction_type": "NftTransfer"
  },
  "id": null
}

Use send_raw_transaction to check that withdraw_nft works correctly (for erc721)

send_raw_transaction req
{
  "method": "send_raw_transaction",
  "coin": "BNB",
  "tx_hex": "f8cb0585012a05f200830180b494fd913a305d70a60aac4faac70c739563738e1f8180b86442842e0e000000000000000000000000f622a6c52c94b500542e2ae6bcad24c53bc5b6a20000000000000000000000006fad0ec6bb76914b2a2a800686acc2297064582000000000000000000000000000000000000000000000000000000031e54737948194a001d4374def9ee63ae913d3321757478789e498d979d0f873f38d4027cc9bd4cba035ed0f9f1f4d4fa06b5b7183ad9ed041ebf0a96dfddac2eeec6ceb3b342a0268",
  "userpass": "${USERPASS}"
}
send_raw_transaction res
{"tx_hash":"0ec4bb9b330b1befb7c531e0f2ef4af69126e0fc5c699b82fe4a45a23841ade8"}

result on bscscan

Notes:
Current implementation uses api-key which is set in parameters in MM config as "api_key".
Withdrawing erc1155 support will be implemented later. Aslo adding caching is in plans.
Feature enable-nft-integration was added. To compile binary please use command cargo build --bin mm2 --features enable-nft-integration

@laruh laruh changed the title [wip] NFT integration poc [r2r] NFT integration poc Feb 22, 2023
@laruh laruh changed the title [r2r] NFT integration poc [wip] NFT integration poc Feb 22, 2023
@laruh laruh changed the title [wip] NFT integration poc [r2r] NFT integration poc Feb 22, 2023
shamardy
shamardy previously approved these changes Feb 22, 2023
Copy link
Collaborator

@shamardy shamardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great Work 🔥 !

sergei-boiko
sergei-boiko previously approved these changes Feb 23, 2023
Copy link

@sergei-boiko sergei-boiko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thank you!

onur-ozkan
onur-ozkan previously approved these changes Feb 24, 2023
Copy link
Member

@onur-ozkan onur-ozkan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@onur-ozkan
Copy link
Member

We should keep in mind that this implementation needs quite few integration/unit tests. Maybe fill an issue or add TODO to codebase? @laruh

@laruh
Copy link
Member Author

laruh commented Feb 24, 2023

We should keep in mind that this implementation needs quite few integration/unit tests. Maybe fill an issue or add TODO to codebase? @laruh

I added todo plan to the issue.
Well I think I can add unit tests for nft list and tx history of NFTs owned by test address.
As for withdrawing, moralis needs some time to update the data. I'm not sure that the check for sending and receiving will pass in one test. This will be an unstable test. Will add unit tests in todo.

@onur-ozkan
Copy link
Member

onur-ozkan commented Feb 24, 2023

As for withdrawing, moralis needs some time to update the data.

How much data is needed for dummy address?

I'm not sure that the check for sending and receiving will pass in one test. This will be an unstable test. Will add unit tests in todo.

What is the blocker for it? Why it can't pass in one test? If multiple operations are executed in mm2 for performing it, it will be more suitable as an integration test(like swap tests).

@laruh
Copy link
Member Author

laruh commented Feb 24, 2023

How much data is needed for dummy address?

If we are talking about just checking nft list and tx history, we need one test address that does not send or receive NFT but simply stores 1 NFT. With this test we check that moralis didt change a response structure.

For withdrawing, we need two more test addresses that send 1 NFT to each other.

What is the blocker for it? Why it can't pass in one test?

After withdrawing, moralis can still show transferred NFT in list and also not show new transfer in history just in time. After some more seconds moralis starts updating and you have to wait the response. It can be a situation that we dont get the response right now and wait timeout check and it fails, just bcz moralis needed some more time.

@onur-ozkan
Copy link
Member

How much data is needed for dummy address?

If we are talking about just checking nft list and tx history, we need one test address that does not send or receive NFT but simply stores 1 NFT. With this test we check that moralis didt change a response structure.

For withdrawing, we need two more test addresses that send 1 NFT to each other.

What is the blocker for it? Why it can't pass in one test?

After withdrawing, moralis can still show transferred NFT in list and also not show new transfer in history just in time. After some more seconds moralis starts updating and you have to wait the response. It can be a situation that we dont get the response right now and wait timeout check and it fails, just bcz moralis needed some more time.

A loop with with an interval and timeout can be applied just like in swap tests.

Like: https://github.com/KomodoPlatform/atomicDEX-API/blob/f4484f2d646435657ff889e50ad3b76faccf7b60/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs#L196-L198

@laruh
Copy link
Member Author

laruh commented Feb 24, 2023

Like:

https://github.com/KomodoPlatform/atomicDEX-API/blob/f4484f2d646435657ff889e50ad3b76faccf7b60/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs#L196-L198

Oh, I see. So lets add tests after gui-auth adding, to avoid using api key in mm config.

@laruh laruh changed the title [r2r] NFT integration poc [wip] NFT integration poc Feb 25, 2023
@laruh laruh changed the title [wip] NFT integration poc [r2r] NFT integration poc Feb 25, 2023
@laruh
Copy link
Member Author

laruh commented Feb 27, 2023

@ozkanonur @shamardy @sergei-boiko I fixed merge conflicts, could you re-approve please?

@shamardy shamardy merged commit 49e620e into dev Mar 7, 2023
@shamardy shamardy deleted the NFT-integration-poc branch March 7, 2023 15:07
@ca333 ca333 mentioned this pull request Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants