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

handle re-orgs for ft and nft metadata #721

Closed
wants to merge 44 commits into from
Closed
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
0665444
docs: add schema for token metadata
asimm241 May 4, 2021
c0b6bf5
chore: add sample response for token metadata
asimm241 May 4, 2021
6811031
chore: wip: write template for contract handler
asimm241 May 10, 2021
5fa6340
refactor: refactor ft and nft names
asimm241 May 17, 2021
4073766
feat: handle FT/NFT compliance contract deployment for metadata
asimm241 May 27, 2021
4d93503
chore: add symbol and decimals field in FT metadata table
asimm241 May 27, 2021
14e346a
refactor: change function name
asimm241 Jun 10, 2021
c8e2278
chore: handle ft token uri and metadata differently
asimm241 Jun 16, 2021
e26b5d1
test: add integration and datastore test cases for token metadata
asimm241 Jun 16, 2021
24b4a2d
refactor: change directory name
asimm241 Jul 7, 2021
8b96411
chore: miscellaneous fixes
asimm241 Jul 7, 2021
2fa0510
chore: added tokens test to github actions
asimm241 Jul 7, 2021
ad74db0
feat: initial contract token handler queue
zone117x Jul 7, 2021
e61a046
test: add tokensUpdate event to test the contract functionality
asimm241 Jul 7, 2021
3419087
chore: use URL instead of uri-js and support ipns
asimm241 Jul 7, 2021
576d398
refactor: removed unwanted log
asimm241 Jul 7, 2021
d1f307b
chore: rebase fix
zone117x Jul 7, 2021
73854eb
chore: fix NFT/FT variable casing
zone117x Jul 7, 2021
38781b7
chore: store token_uri in db, fix image_canonical_uri value
zone117x Jul 7, 2021
49a8b60
fix: add token-uri in datastore tests
asimm241 Jul 8, 2021
a94d53c
feat: support Data URLs for json metadata and token images
zone117x Jul 9, 2021
1c8f75f
chore: add max fetch byte size for metadata files
zone117x Jul 9, 2021
a60819f
feat: added a route to enumerate the list of ft and nft tokens
asimm241 Jul 14, 2021
a643cd9
test: fixed test cases with mock responses and added test cases for t…
asimm241 Jul 14, 2021
b7e34fd
docs: update docs for ft and nft metadata endpoints
asimm241 Jul 15, 2021
dd6b449
test: add unit test case to mock and test large response payload
asimm241 Jul 16, 2021
48b67be
test: generate random data run time instead of a file to test large p…
asimm241 Jul 19, 2021
cd02763
fix: fix rebase issue
asimm241 Jul 19, 2021
d905fe0
fix: make fungible tokens handling fail safe
asimm241 Jul 27, 2021
1821740
chore: added tx_id and deployers address in tokens
asimm241 Aug 12, 2021
16bb080
chore(test): minor test fixes
zone117x Aug 12, 2021
54194c7
chore: less strict metadata image property parsing due to inconsisten…
zone117x Aug 12, 2021
f6949ee
chore: increase fault tolerance when fetching readonly contract data
zone117x Aug 12, 2021
c7c149d
chore: add notification events to the token process instance
zone117x Aug 12, 2021
35cf616
chore: add metadata fetch timeout
zone117x Aug 12, 2021
26ec4af
feat: implement external image processor script for use with ingestin…
zone117x Aug 13, 2021
46edd6f
chore: fix token metadata tx_id postgres data type
zone117x Aug 13, 2021
9ccc42b
feat: implement token contract queue in postgres to fix metadata proc…
zone117x Aug 19, 2021
8bf8496
chore: simplify initial version of nft-class metadata fetching
zone117x Aug 19, 2021
0f0b046
chore: add shutdown config for the token metadata processor
zone117x Aug 20, 2021
7a58c7a
chore: cleanup token json schema examples
zone117x Aug 20, 2021
b9b5984
chore: cleanup unused imports
zone117x Aug 20, 2021
2515bcf
feat: handle re-org for ft and nft metadata
asimm241 Aug 24, 2021
c1212ca
chore: remove microblock_hash and microblock_sequence from metadata r…
asimm241 Aug 25, 2021
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
10 changes: 10 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,13 @@ MAINNET_SEND_MANY_CONTRACT_ID=SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.send-man

# Override the default file path for the proxy cache control file
# STACKS_API_PROXY_CACHE_CONTROL_FILE=/path/to/.proxy-cache-control.json

# Configure a script to handle image URLs during token metadata processing.
# This example script uses the `imgix.net` service to create CDN URLs.
# Must be an executable script that accepts the URL as the first program argument
# and outputs a result URL to stdout.
# STACKS_API_IMAGE_CACHE_PROCESSOR=./config/token-metadata-image-cache-imgix.js
# Env vars needed for the above sample `imgix` script:
# IMGIX_DOMAIN=https://<your domain>.imgix.net
# IMGIX_TOKEN=<your token>

1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ src/tests-rosetta/
src/tests-rosetta-cli/
src/tests-bns/
client/src/
config/
37 changes: 37 additions & 0 deletions .github/workflows/stacks-blockchain-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,43 @@ jobs:
uses: codecov/codecov-action@v1
if: always()

test-tokens:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '14.x'

- name: Install deps
run: npm install

- name: Setup env vars
run: echo "STACKS_CORE_EVENT_HOST=http://0.0.0.0" >> $GITHUB_ENV

- name: Setup integration environment
run: |
sudo ufw disable
npm run devenv:deploy -- -d
npm run devenv:logs -- --no-color &> docker-compose-logs.txt &

- name: Run tokens tests
run: npm run test:tokens

- name: Print integration environment logs
run: cat docker-compose-logs.txt
if: failure()

- name: Teardown integration environment
run: npm run devenv:stop
if: always()

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
if: always()

build-publish:
runs-on: ubuntu-latest
needs:
Expand Down
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,23 @@
"preLaunchTask": "stacks-node:deploy-dev",
"postDebugTask": "stacks-node:stop-dev"
},
{
"type": "node",
"request": "launch",
"name": "Jest: Tokens",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [
"--testTimeout=3600000",
"--runInBand",
"--no-cache",
"--config",
"${workspaceRoot}/jest.config.tokens.js"
],
"outputCapture": "std",
"console": "integratedTerminal",
"preLaunchTask": "stacks-node:deploy-dev",
"postDebugTask": "stacks-node:stop-dev"
},
{
"type": "node",
"request": "launch",
Expand Down
7 changes: 7 additions & 0 deletions config/token-metadata-image-cache-imgix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env node
const imgUrl = process.argv[2];
const encodedUrl = encodeURIComponent(imgUrl);
const [imgixDomain, imgixToken] = [process.env['IMGIX_DOMAIN'], process.env['IMGIX_TOKEN']];
const signature = require('crypto').createHash('md5').update(imgixToken + '/' + encodedUrl).digest('hex');
const resultUrl = new URL(encodedUrl + '?s=' + signature, imgixDomain);
console.log(resultUrl.toString());
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"limit": 1,
"offset": 0,
"total": 500,
"results": [
{
"token_uri": "https://heystack.xyz/token-metadata.json",
"name": "Heystack",
"description": "Heystack is a SIP-010-compliant fungible token on the Stacks Blockchain, used on the Heystack app",
"image_uri": "https://heystack.xyz/assets/Stacks128w.png",
"image_canonical_uri": "https://heystack.xyz/assets/Stacks128w.png",
"tx_id": "0xef2ac1126e16f46843228b1dk4830e19eb7599129e4jf392cab9e65ae83a45c0",
"sender_address": "ST399W7Z9WS0GMSNQGJGME5JAENKN56D65VGMGKGA",
"symbol": "HEY",
"decimals": 5
}
]
}
33 changes: 33 additions & 0 deletions docs/api/tokens/get-fungible-tokens-metadata-list.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "List of fungible tokens metadata",
"title": "FungibleTokensMetadataList",
"type": "object",
"required": [
"results",
"limit",
"offset",
"total"
],
"properties": {
"limit": {
"type": "integer",
"maximum": 200,
"description": "The number of tokens metadata to return"
},
"offset": {
"type": "integer",
"description": "The number to tokens metadata to skip (starting at `0`)"
},
"total": {
"type": "integer",
"description": "The number of tokens metadata available"
},
"results": {
"type": "array",
"items": {
"$ref": "../../entities/tokens/fungible-token.schema.json"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"limit": 1,
"offset": 0,
"total": 500,
"results": [
{
"token_uri": "https://pool.friedger.de/nft.json",
"name": "Friedger Pool",
"description": "Enjoying the stacking pool.",
"image_uri": "https://pool.friedger.de/nft.webp",
"image_canonical_uri": "https://pool.friedger.de/nft.webp",
"tx_id": "0xef2ac1126e16f46843228b1dk4830e19eb7599129e4jf392cab9e65ae83a45c0",
"sender_address": "ST399W7Z9WS0GMSNQGJGME5JAENKN56D65VGMGKGA"
}
]
}
33 changes: 33 additions & 0 deletions docs/api/tokens/get-non-fungible-tokens-metadata-list.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "List of non fungible tokens metadata",
"title": "NonFungibleTokensMetadataList",
"type": "object",
"required": [
"results",
"limit",
"offset",
"total"
],
"properties": {
"limit": {
"type": "integer",
"maximum": 200,
"description": "The number of tokens metadata to return"
},
"offset": {
"type": "integer",
"description": "The number to tokens metadata to skip (starting at `0`)"
},
"total": {
"type": "integer",
"description": "The number of tokens metadata available"
},
"results": {
"type": "array",
"items": {
"$ref": "../../entities/tokens/non-fungible-token.schema.json"
}
}
}
}
13 changes: 13 additions & 0 deletions docs/entities/tokens/fungible-token.schema.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"token_uri": "https://heystack.xyz/token-metadata.json",
"name": "Heystack",
"description": "Heystack is a SIP-010-compliant fungible token on the Stacks Blockchain, used on the Heystack app",
"image_uri": "https://heystack.xyz/assets/Stacks128w.png",
"image_canonical_uri": "https://heystack.xyz/assets/Stacks128w.png",
"tx_id": "0xef2ac1126e16f46843228b1dk4830e19eb7599129e4jf392cab9e65ae83a45c0",
"sender_address": "ST399W7Z9WS0GMSNQGJGME5JAENKN56D65VGMGKGA",
"symbol": "HEY",
"decimals": 5,
"microblock_hash": "0x",
"microblock_sequence": "-1"
asimm241 marked this conversation as resolved.
Show resolved Hide resolved
}
66 changes: 66 additions & 0 deletions docs/entities/tokens/fungible-token.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "fungible-token-metadata",
"title": "FungibleTokenMetadata",
"type": "object",
"additionalProperties": false,
"required": [
"token_uri",
"name",
"description",
"image_uri",
"image_canonical_uri",
"symbol",
"decimals",
"tx_id",
"sender_address",
"microblock_hash",
"microblock_sequence"
],
"properties": {
"token_uri": {
"type": "string",
"description": "An optional string that is a valid URI which resolves to this token's metadata. Can be empty."
},
"name": {
"type": "string",
"description": "Identifies the asset to which this token represents"
},
"description": {
"type": "string",
"description": "Describes the asset to which this token represents"
},
"image_uri": {
"type": "string",
"description": "A URI pointing to a resource with mime type image/* representing the asset to which this token represents. The API may provide a URI to a cached resource, dependending on configuration. Otherwise, this can be the same value as the canonical image URI."
},
"image_canonical_uri": {
"type": "string",
"description": "The original image URI specified by the contract. A URI pointing to a resource with mime type image/* representing the asset to which this token represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
},
"symbol": {
"type": "string",
"description": "A shorter representation of a token. This is sometimes referred to as a \"ticker\". Examples: \"STX\", \"COOL\", etc. Typically, a token could be referred to as $SYMBOL when referencing it in writing."
},
"decimals": {
"type": "number",
"description": "The number of decimal places in a token."
},
"tx_id": {
"type": "string",
"description": "Tx id that deployed the contract"
},
"sender_address": {
"type": "string",
"description": "principle that deployed the contract"
},
"microblock_hash": {
"type": "string",
"description": "The microblock hash that this transaction was streamed in. If the transaction was batched in an anchor block (not included within a microblock) then this value will be an empty string."
},
"microblock_sequence": {
"type": "integer",
"description": "The microblock sequence number that this transaction was streamed in. If the transaction was batched in an anchor block (not included within a microblock) then this value will be 2147483647 (0x7fffffff, the max int32 value), this value preserves logical transaction ordering on (block_height, microblock_sequence, tx_index)."
}
}
}
11 changes: 11 additions & 0 deletions docs/entities/tokens/non-fungible-token.schema.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"token_uri": "https://pool.friedger.de/nft.json",
"name": "Friedger Pool",
"description": "Enjoying the stacking pool.",
"image_uri": "https://pool.friedger.de/nft.webp",
"image_canonical_uri": "https://pool.friedger.de/nft.webp",
"tx_id": "0xef2ac1126e16f46843228b1dk4830e19eb7599129e4jf392cab9e65ae83a45c0",
"sender_address": "ST399W7Z9WS0GMSNQGJGME5JAENKN56D65VGMGKGA",
"microblock_hash": "0x",
"microblock_sequence": "-1"
}
56 changes: 56 additions & 0 deletions docs/entities/tokens/non-fungible-token.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "non-fungible-token-metadata",
"title": "NonFungibleTokenMetadata",
"type": "object",
"additionalProperties": false,
"required": [
"token_uri",
"name",
"description",
"image_uri",
"image_canonical_uri",
"tx_id",
"sender_address",
"microblock_hash",
"microblock_sequence"
],
"properties": {
"token_uri": {
"type": "string",
"description": "An optional string that is a valid URI which resolves to this token's metadata. Can be empty."
},
"name": {
"type": "string",
"description": "Identifies the asset to which this token represents"
},
"description": {
"type": "string",
"description": "Describes the asset to which this token represents"
},
"image_uri": {
"type": "string",
"description": "A URI pointing to a resource with mime type image/* representing the asset to which this token represents. The API may provide a URI to a cached resource, dependending on configuration. Otherwise, this can be the same value as the canonical image URI."
},
"image_canonical_uri": {
"type": "string",
"description": "The original image URI specified by the contract. A URI pointing to a resource with mime type image/* representing the asset to which this token represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
},
"tx_id": {
"type": "string",
"description": "Tx id that deployed the contract"
},
"sender_address": {
"type": "string",
"description": "principle that deployed the contract"
},
"microblock_hash": {
"type": "string",
"description": "The microblock hash that this transaction was streamed in. If the transaction was batched in an anchor block (not included within a microblock) then this value will be an empty string."
},
"microblock_sequence": {
"type": "integer",
"description": "The microblock sequence number that this transaction was streamed in. If the transaction was batched in an anchor block (not included within a microblock) then this value will be 2147483647 (0x7fffffff, the max int32 value), this value preserves logical transaction ordering on (block_height, microblock_sequence, tx_index)."
}
}
}
Loading