KIP-37 is a Multi Token (MT) standard in Kaia. KIP-37 supports both NFTs (Non-Fungible Tokens) and FTs (Fungible Tokens).
The KIP-37 API allows you to create/manage KIP-37 tokens with convenience. Its main features include deployment of KIP-37 contracts, minting/burning/sending of tokens, and browsing ownership history.
In this tuturial, we will explain how to deploy contracts and mint/send/burn tokens using the various endpoints of the KIP-37 API. For more details, please refer to KAS KIP-37 API Reference
Deploying a KIP-37 Contract
The KIP-37 API deploys and manages MT contracts that follow the KIP-37 standard.
info
For more details on the functions of the KIP-37 contract and the source code, please refer to KIP-37 Standard and klaytn/klaytn-contracts.
API Request
You can deploy a KIP-37 contract via the following curl
command:
curl --location --request POST "https://kip37-api.klaytnapi.com/v2/contract" \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key} \
--data-raw '{
"alias": "my-first-kip37-contract",
"uri": "https://token-cdn-domain/{id}.json",
"options": {
"enableGlobalFeePayer": true
}
}'
const result = await caver.kas.kip37.deploy(
"https://token-cdn-domain/{id}.json",
"my-first-kip37-contract"
);
String alias = "my-first-kip37-contract";
String uri = "https://token-cdn-domain/{id}.json";
Kip37FeePayerOptions option = new Kip37FeePayerOptions();
option.setEnableGlobalFeePayer(false);
Kip37DeployResponse deployResponse = caver.kas.kip37.deploy(uri, alias, option);
Let's break down the curl
command. You can execute the Deploy Contract API via POST /v2/contract
. And since the KIP-37 API is provided by https://kip37-api.klaytnapi.com
, the request URL of the curl
request must be https://kip37-api.klaytnapi.com/v2/contract
, and the request type POST (—-request POST
).
Upon receiving the POST request, the Deploy Contract API requires the following JSON data:
{
"alias": "my-first-kip37-contract",
"uri": "https://token-cdn-domain/{id}.json",
"options": {
"enableGlobalFeePayer": true
}
}
Brief descriptions of each field:
-
Alias (
alias
): A nickname for the contract that can be used in place of the contract address, when using other APIs also. It can include lowercase letters, numbers and hyphens, but the first letter is restricted to a lowercase letter. -
URI (
uri
): Identifier for the token's metadata. Enter the token ID (hexadecimal without the0x
prefix) for{id}
. For example, the metadata of a token with the ID0x1
can be accessed viahttps://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json
. -
Options(
options
): The field to select the payment method of transaction fees. This tutorial uses KAS Global FeePayer. For more details, please refer to Fee Payer Options .
info
All KIP-37 APIs require an x-chain-id
header. Valid values are 1001 for Kairos, and 8217 for Kaia Mainnet.
- Authentication
info
All APIs supported by KAS require credentials consisting of access-key-id
and secret-access-key
. To learn more about creating and obtaining credentials, please follow this link.
API Response
Executing the Deploy Contract curl
command returns the following result:
{
"status": "Submitted",
"transactionHash": "0xca97254ab324a5a205538e83b5559c469cdc3f366659f610642021a3febab32f",
"options": {
"enableGlobalFeepayer": true,
"userFeePayer": {
"address": "",
"krn": ""
}
}
}
{
status: 'Submitted',
transactionHash: '0x7dbb6f9c823f1f8bc4a3203486bd79d5979a1c7e23c207ccfe8fdb611bd5cfd8',
options: {
enableGlobalFeepayer: true,
userFeePayer: { krn: '', address: '' }
}
}
class Kip37DeployResponse {
status: Submitted
transactionHash: 0xca97254ab324a5a205538e83b5559c469cdc3f366659f610642021a3febab32f
options: class Kip37FeePayerOptionsResponse {
enableGlobalFeepayer: true
userFeePayer: class Kip37FeePayerOptionsUserFeePayer {
krn:
address:
}
}
}
The transactionHash
in the response can also be used for RPC functions such as klay_getTransactionReceipt.
Getting KIP-37 Contract List
API Request
You can use the Get Contract List API(GET /v2/contract
) of the KIP-37 API to list all deployed contracts, using the following curl
command:
info
You can browse a contract's data using Get Contract Data API(GET /v2/contract/{contract-address-or-alias}
).
curl --location --request GET 'https://kip37-api.klaytnapi.com/v2/contract' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key}
const list = await caver.kas.kip37.getContractList();
Kip37ContractListResponse response = caver.kas.kip37.getContractList();
API Response
Once the contract has been successfully deployed, it will return the following response:
{
"items": [
{
"address": "0x52914186f3a7324ba1f0172b2d33c8e8712cdd9a",
"alias": "my-first-kip37-contract",
"options": {
"enableGlobalFeePayer": true,
"userFeePayer": {
"address": "",
"krn": ""
}
},
"status": "deployed",
"uri": "https://token-cdn-domain/{id}.json"
}
],
"cursor": ""
}
{
items: [
{
address: '0x52914186f3a7324ba1f0172b2d33c8e8712cdd9a',
alias: 'my-first-kip37-contract',
status: 'deployed',
uri: 'https://token-cdn-domain/{id}.json',
options: {
enableGlobalFeePayer: true,
userFeePayer: { krn: '', address: '' }
}
}
],
cursor: ''
}
class Kip37ContractListResponse {
items:[class Kip37Contract {
address:0x52914186f3a7324ba1f0172b2d33c8e8712cdd9a
alias:my-first-kip37-contract
status:deployed
uri:https://token-cdn-domain/{id}.json
options: class Kip37FeePayerOptions {
enableGlobalFeePayer:true
userFeePayer: class Kip37FeePayerOptionsUserFeePayer {
krn:
address:
}
}
}]
}
Minting KIP-37 Tokens
If you deployed a contract, you can now start creating tokens using POST /v2/contract/{contract-address-or-alias}/token
. The path parameter {contract-address-or-alias}
refers to the nickname you have given to the contract during deployment, or the contract address that you can find using Get Contract List API.
API Request
Below is the curl
command to call the Create Token API using the alias used in the previous example, my-first-kip37-contract
.
info
Using the Create Token API calls the function function create(uint256 _id, uint256 _initialSupply, string calldata _uri) external returns (bool);
.
curl --location --request POST 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/token' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key} \
--data-raw '{
"sender": "",
"id": "0x1",
"initialSupply": "0x100",
"uri": "https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json"
}'
const created = await caver.kas.kip37.create(
"my-first-kip37-contract",
"0x1",
"0x100",
"https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json"
);
String alias = "my-first-kip37-contract";
String id = "0x1";
String initialSupply = "0x100";
String uri = "uri": "https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json";
Kip37TransactionStatusResponse response = caver.kas.kip37.create(alias, id, initialSupply, uri);
The required header, and credentials are the same as with Deploy Contract, but the data for location and request must be provided in accordance with the Deploy Token API (POST /v2/contract/{contract-address-or-alias}/token
).
The JSON data required for the Create Token API:
{
"sender": "",
"id": "0x1",
"initialSupply": "0x100",
"uri": "https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json"
}
-
Sender (
sender
): The Kaia account address to create the token. The sender must be authotized as a Minter. If this field is left blank, the token will be created with the deployer's account. You can find the contract deployer address (deployer
) via Get Default Contract Deployer . -
Token ID (
id
): A unique identifier of the token expressed in hexadecimal. It cannot be a duplicate of an existing token ID. But you can reuse the ID of a burned token. -
Initial Supply (
initialSupply
): Initial token supply expressed in hexadecimal. -
Token URI (
uri
): The location of the JSON file containing the token data expressed as URI . Include the URI when minting the token after storing the token data somewhere that can be located with a URI. Please note that the API does not check the validity of the URI link.
info
Kaia account address is expressed in a 20-byte hexadecimal with the prefix "0x" and a total of 42 characters.
API Response
Create Token curl
command gives you the following response:
{
"transactionHash": "0x354aed16b2dbf43b32ab6fdd259c9d3d7b244236870658979a8a2b34fa7b579b",
"status": "Submitted"
}
{
status: 'Submitted',
transactionHash: '0x7b13e0d318aa2283c0e27c3e92996e2c3488c227480d61bff1f5c6148174dd07'
}
class Kip37TransactionStatusResponse {
status: Submitted
transactionHash: 0x354aed16b2dbf43b32ab6fdd259c9d3d7b244236870658979a8a2b34fa7b579b
transactionId: null
}
info
You will notice the status
in the response, that it says "Submitted" instead of "Success" or "Completed". Since all blockchains including Kaia are asynchronous, a response to a request will not be returned immediately. The transaction status cannot be checked right away. To confirm successful transaction, you would have to use the Get Token List API, especially for requests like token deployment, for which requests easily fail due to entering wrong values.
Deploying a contract returns the following response.
Getting Token List
API Request
To confirm that your token has been successfully created, use the Get Token List API GET /v2/contract/{contract-address-or-alias}/token
.
You can browse the list of contract tokens using the curl
command my-first-kip37-contract
.
curl --location --request GET 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/token' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key}
const tokens = await caver.kas.kip37.getTokenList("my-first-kip37-contract");
String alias = "my-first-kip37-contract";
Kip37TokenInfoListResponse response = caver.kas.kip37.getTokenList(alias);
API Response
If your token has been successfully created, you'll get a reponse like this:
{
"items": [
{
"tokenId": "0x1",
"tokenUri": "https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json",
"totalSupply": "0x100"
}
],
"cursor": ""
}
{
items: [
{
tokenId: '0x1',
totalSupply: '0x100',
tokenUri: 'https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json'
}
],
cursor: ''
}
class Kip37TokenInfoListResponse {
items: [class Kip37TokenInfoListResponseItem {
tokenId: 0x1
totalSupply: 0x100
tokenUri: https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json
}]
cursor:
}
Minting Additional Tokens
If the token has been successfully created, you can start minting more of them. Unlike KIP-17, create
refers to the initial creation, while mint
to the additional creation of tokens in KIP-37 API.
API Request
Below is the curl
command for calling Mint Token API using the previous alias my-first-kip37-contract
, and the token id 0x1
.
info
Using Add Token API will call the function mint(uint256 _id, address _to, uint256 _value) external;
(single), function mintBatch(address _to, uint256[] calldata _ids, uint256[] calldata _values)
(batch) of the actual contract.
curl --location --request POST 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/token/mint' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key} \
--data-raw '{
"sender": "",
"to": "0xd9Fe560d3141E78CDd2F617147985e458a529c1E",
"ids": [
"0x1"
],
"amounts": [
"0x10"
]
}'
const minted = await caver.kas.kip37.mint(
"my-first-kip37-contract",
"0xd9Fe560d3141E78CDd2F617147985e458a529c1E",
["0x1"],
["0x10"]
);
String alias = "my-first-kip37-contract";
String id = "0x1";
String amount = "0x10";
String to = "0xd9Fe560d3141E78CDd2F617147985e458a529c1E";
Kip37TransactionStatusResponse response = caver.kas.kip37.mint(alias, to, id, amount);
-
Sender (
sender
): The Kaia account address that mints additional tokens. It needs to be authorized as a Minter. When left blank, the token will be minted from the deployer of the contract. You can find thedeployer
account via Get Default Contract Deployer . -
Recipient (
to
): The Kaia account address of the recipient. The tokens will be minted to the specified address. -
Token ID (
ids
): The list of IDs of the tokens to mint. You can mint additional MT tokens in KIP-37. -
Amount (
amounts
): The list of amount of the tokens to mint expressed in hexadecimal. The elements ofids
andamounts
must always be equal.
API Response
The Mint Token curl
command will return the following response:
{
"status": "Submitted",
"transactionHash": "0x63172503a362566aeed9e64271830ddc090affe7612f99e5f2415caaa379a7f3"
}
{
status: 'Submitted',
transactionHash: '0xd8de974acf6c436644fa049cac7268e7192aa7fe8cf44de80bc4874a2076d83a'
}
class Kip37TransactionStatusResponse {
status: Submitted
transactionHash: 0x63172503a362566aeed9e64271830ddc090affe7612f99e5f2415caaa379a7f3
transactionId: null
}
Getting Token List
API Request
Just as with token creation, use the Get Token List API GET /v2/contract/{contract-address-or-alias}/token
to check the (totalSupply
).
curl --location --request GET 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/token' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key}
const tokens = await caver.kas.kip37.getTokenList("my-first-kip37-contract");
Kip37ContractListResponse response = caver.kas.kip37.getContractList();
API Response
If your token has been successfully created, you'll get a reponse like this:
{
"items": [
{
"tokenId": "0x1",
"tokenUri": "https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json",
"totalSupply": "0x110"
}
],
"cursor": ""
}
{
items: [
{
tokenId: '0x1',
totalSupply: '0x110',
tokenUri: 'https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json'
}
],
cursor: ''
}
class Kip37TokenInfoListResponse {
items: [class Kip37TokenInfoListResponseItem {
tokenId: 0x1
totalSupply: 0x110
tokenUri: https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json
}]
cursor:
}
Transferring KIP-37 Tokens
The endpoint for KIP-37 Send Token API is POST /v2/contract/{contract-address-or-alias}/token/transfer
.
For this tutorial, you should have an account in the KAS Wallet Account Pools.
info
For more information on creating and managing accounts, follow this link.
info
In order to send tokens using the KIP-37 API, the cryptographic key of the sender's account must be registered on KAS Wallet Account Pools. If the Key is not registered on the default Account Pools, you have to put in the KRN of the pool in the x-krn
header directly.
info
The KIP-37 API supports batch
transfers. If you have just one element, use function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
. If you have a batch, use function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
.
API Request
The following curl
command sends one (0x1
) token with the ID 0x1
owned by 0xd9Fe560d3141E78CDd2F617147985e458a529c1E
in the my-first-kip37-contract
to the account (0x74B9bE845D276E6382081995A61a65da91C76328
).
curl --location --request POST 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/token/transfer' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key} \
--data-raw '{
"sender": "0xd9Fe560d3141E78CDd2F617147985e458a529c1E",
"owner": "0xd9Fe560d3141E78CDd2F617147985e458a529c1E",
"to": "0x74B9bE845D276E6382081995A61a65da91C76328",
"ids": [
"0x1"
],
"amounts": [
"0x2"
]
}'
const result = await caver.kas.kip37.transfer(
"my-first-kip37-contract",
"0x0d10a78a15abc40181fd88536f016cf4eaec394e",
"0x0d10a78a15abc40181fd88536f016cf4eaec394e",
"0x74B9bE845D276E6382081995A61a65da91C76328",
["0x1"],
["0x1"]
);
String alias = "my-first-kip37-contract";
String sender = "0xd9Fe560d3141E78CDd2F617147985e458a529c1E";
String owner = "0xd9Fe560d3141E78CDd2F617147985e458a529c1E";
String to = "0x74B9bE845D276E6382081995A61a65da91C76328";
String id = "0x1";
String amount = "0x1";
Kip37TransactionStatusResponse response = caver.kas.kip37.transfer(alias, sender, owner, to, id, amount);
Below is the JSON data required for sending tokens:
-
Sender (
sender
): The Kaia account address that sends the token. Ifsender
andowner
are different, thesender
needs to be authorized to send the token in question. You can authorize a certain address to transfer tokens using the Approve Token Transfer API . -
Owner (
owner
): The Kaia account address that owns the token. -
Recipient (
to
): The recipient's token address. Make sure to enter the it correctly, since a transaction cannot be undone owing to the nature of blockchain. -
Token ID (
ids
): The list of IDs of tokens to send expressed in hexadecimal. You can send MT tokens in KIP-37 API. -
Amount (
amounts
): The list of the number of tokens to send expressed in hexadecimal. The elements ofids
andamounts
must always be equal.
API Response
Executing the Send Token API returns the following response:
{
"transactionHash": "0xe935aa5b7dcd22fc9f3420126d702d23a38ebed8c7eb3f264a930d5377176e18",
"status": "Submitted"
}
{
status: 'Submitted',
transactionHash: '0x567483dc5faecc797278f9067224f805156a761baaad5b31fc5f4083697c14df'
}
class Kip37TransactionStatusResponse {
status: Submitted
transactionHash: 0xe935aa5b7dcd22fc9f3420126d702d23a38ebed8c7eb3f264a930d5377176e18
transactionId: null
}
Getting Token List
API Request
To confirm successful transfer of the token, use the Get Token List by Account API GET /v2/contract/{contract-address-or-alias}/owner/{owner-address}/token
.
curl --location --request GET 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/owner/0x74B9bE845D276E6382081995A61a65da91C76328/token'
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key}
const list = await caver.kas.kip37.getTokenListByOwner(
"my-first-kip37-contract",
"0x74B9bE845D276E6382081995A61a65da91C76328"
);
String alias = "my-first-kip37-contract";
String owner = "0x74B9bE845D276E6382081995A61a65da91C76328";
Kip37TokenListResponse response = caver.kas.kip37.getTokenListByOwner(alias, owner);
API Response
Once the token has been sent successfully, you will have the following result:
{
"items": [
{
"balance": "0x1",
"owner": "0x74b9be845d276e6382081995a61a65da91c76328",
"tokenAddress": "0x52914186f3a7324ba1f0172b2d33c8e8712cdd9a",
"tokenId": "0x1",
"tokenUri": "https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json",
"totalSupply": "0x110",
"transactionHash": "0xe935aa5b7dcd22fc9f3420126d702d23a38ebed8c7eb3f264a930d5377176e18",
"transferFrom": "0xd9fe560d3141e78cdd2f617147985e458a529c1e",
"transferTo": "0x74b9be845d276e6382081995a61a65da91c76328",
"updatedAt": 1627980971
}
],
"cursor": ""
}
{
items: [
{
tokenId: '0x1',
owner: '0x74b9be845d276e6382081995a61a65da91c76328',
tokenAddress: '0x8d8721edf52766af76c6397fb52c70c9cd7dd292',
totalSupply: '0x110',
tokenUri: 'https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json',
replacedTokenUri: undefined,
balance: '0x1',
transactionHash: '0x567483dc5faecc797278f9067224f805156a761baaad5b31fc5f4083697c14df',
transferFrom: '0x0d10a78a15abc40181fd88536f016cf4eaec394e',
transferTo: '0x74b9be845d276e6382081995a61a65da91c76328',
updatedAt: '1633068353'
}
],
cursor: ''
}
class Kip37TokenListResponse {
items: [class Kip37TokenListResponseItem {
tokenId: 0x1
owner: 0x74b9be845d276e6382081995a61a65da91c76328
tokenAddress: 0x52914186f3a7324ba1f0172b2d33c8e8712cdd9a
totalSupply: 0x110
tokenUri: https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json
replacedTokenUri: null
balance: 0x1
transactionHash: 0xe935aa5b7dcd22fc9f3420126d702d23a38ebed8c7eb3f264a930d5377176e18
transferFrom: 0xd9fe560d3141e78cdd2f617147985e458a529c1e
transferTo: 0x74b9be845d276e6382081995a61a65da91c76328
updatedAt: 1627980971
}]
cursor:
}
Burning KIP-37 Token
The endpoint for KIP-37 Burn Token API is DELETE /v2/contract/{contract-address-or-alias}/token
.
info
The KIP-37 API supports burning of multiple tokens at the same time, referred to as a batch
of tokens. If you are burning just one token, call function burn(address _account, uint256 _id, uint256 _value) external;
. To burn multiple tokens call function burnBatch(address _account, uint256[] calldata _ids, uint256[] calldata _values) external;
.
API Request
The following curl
command burns two (0x2
) tokens with the ID (0x1
) owned by 0xd9Fe560d3141E78CDd2F617147985e458a529c1E
in the my-first-kip37-contract
.
curl --location --request DELETE 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/token' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key} \
--data-raw '{
"from": "0xd9Fe560d3141E78CDd2F617147985e458a529c1E",
"ids": [
"0x1"
],
"amounts": [
"0x2"
]
}'
const result = await caver.kas.kip37.burn(
"my-first-kip37-contract",
["0x1"],
["0x2"]
);
String alias = "my-first-kip37-contract";
String from = "0xd9Fe560d3141E78CDd2F617147985e458a529c1E";
String id = "0x1";
String amount = "0x2";
Kip37TransactionStatusResponse response = caver.kas.kip37.burn(alias, id, amount, from);
The JSON data required for burning tokens:
-
From (
from
): The Kaia account address to burn the tokens. -
Token ID (
ids
): List of IDs of the tokens to burn, expressed in hexadecimal. You can burn MT tokens in KIP-37. -
Amount (
amounts
): The amount of tokens to burn, expressed in hexadecimal.ids
andamounts
must always be equal.
API Response
The Burn Token API returns the following result:
{
"transactionHash": "0x1959a49bc76ded2e9705239868043ea0be102c5cc4b17e05248bf9a5e59b6bf1",
"status": "Submitted"
}
{
status: 'Submitted',
transactionHash: '0x0eff1ae7e6887e211a7262b43d0670436ac3dd59422b55614f89c4e930ec19be'
}
class Kip37TransactionStatusResponse {
status: Submitted
transactionHash: 0x1959a49bc76ded2e9705239868043ea0be102c5cc4b17e05248bf9a5e59b6bf1
transactionId: null
}
Getting Token List
API Request
To confirm successful burning of the token, use Get Token List API GET /v2/contract/{contract-address-or-alias}/token
.
curl --location --request GET 'https://kip37-api.klaytnapi.com/v2/contract/my-first-kip37-contract/token' \
--header "x-chain-id: {chain-id}" \
-u {access-key-id}:{secret-access-key}
const list = await caver.kas.kip37.getTokenList("my-first-kip37-contract");
String alias = "my-first-kip37-contract";
Kip37TokenInfoListResponse response = caver.kas.kip37.getTokenList(alias);
API Response
Once the token has been successfully burned, you will be able to see that totalSupply
decreased by 0x2
.
{
"items": [
{
"tokenId": "0x1",
"tokenUri": "https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json",
"totalSupply": "0x10e"
}
],
"cursor": ""
}
{
items: [
{
tokenId: '0x1',
totalSupply: '0x10e',
tokenUri: 'https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json'
}
],
cursor: ''
}
class Kip37TokenInfoListResponse {
items: [class Kip37TokenInfoListResponseItem {
tokenId: 0x1
totalSupply: 0x10e
tokenUri: https://token-cdn-domain/0000000000000000000000000000000000000000000000000000000000000001.json
}]
cursor:
}