Anima Reputation SBT System Overview

This guide explains how to interact with the Anima Reputation Soulbound Token (SBT) system using Tact functions to retrieve token metadata and query specific attributes.

Smart Contract Interaction

The Anima SBT smart contract allows you to retrieve metadata associated with a user's token, which contains information such as the reputation level and the last verification timestamp. Below are the key functions for interacting with the contract:

1. get_nft_address_by_owner_and_anima_collection(owner: Address, anima_collection: String)

This function retrieves the SBT contract address associated with a specific address and collection. For the main Anima Reputation collection, use the provided collection ID.

get fun get_nft_address_by_owner_and_anima_collection(owner: Address, anima_collection: String): Address
  • Input:

  • Ton address (Address)

  • Collection ID (String)

  • Output: Token contract address (Address) linked to the user's account for the specified collection.

Main Reputation Collection

The main collection ID for the Anima Reputation system is:

#0x2170459f9ebc370517e9fd1abfcf476586c10aa80121c185d406f695ef6f2d6c# 

If a project wants to create a custom NFT collection with a unique visual for their users, they need to contact Anima for setup. Custom collections can use their own distinct collection ID.

2. get_nft_uri()

This function retrieves the metadata URL associated with a specific token ID. It has to be called on the contract from the get_nft_address_by_owner_and_anima_collection(owner: Address, anima_collection: String) call

get fun get_nft_uri(): String 
  • Input: None
  • Output: Metadata URL (string) containing the SBT's attributes and other data.

Querying the Metadata

To retrieve the metadata for a specific user in the main collection, you have to call these 2 methods one by one :

get fun get_nft_address_by_owner_and_anima_collection(owner: Address, anima_collection: String): Address

And then call on the fetched address

get fun get_nft_uri(): String 

This will return the URL of the metadata JSON file for the SBT associated with the provided user address in the specified collection.

Example of Metadata Structure

The metadata returned is in JSON format and includes various attributes related to the user's reputation.

{
  "name": "Anima Reputation",
  "image": "https://example.com/image.png",
  "attributes": [
    {
      "value": 1,
      "trait_type": "Reputation Level"
    },
    {
      "value": 1709223352,
      "trait_type": "Last Verification"
    }
  ],
  "external_url": "https://dapp.anima.io"
}

Key Metadata Fields:

  • name: The name of the reputation level (e.g., "Reputation Level #1").
  • image: URL of the image representing the reputation.
  • attributes:
  • Reputation Level: Numeric value representing the user's current reputation level.
  • Last Verification: Timestamp of the user's last verification event.
  • external_url: Link to the Anima Reputation SBT service.

Smart Contract Address

The Anima Reputation SBT smart contract is now deployed at the address:

  • EQB2kfkkkZC8KjQb3TctkRKpuZ3WLyRCEj_LHXMvR8tTxgbu

Example: Querying Metadata in JavaScript with ton.js

Below is an example of how to query the metadata from the Anima Reputation SBT smart contract using ton.js, followed by fetching the metadata JSON via an HTTP call.

Step 1: Set Up ton.js

First, install the required dependencies if you haven't done so:

npm install @ton/ton @orbs-network/ton-access node-fetch

Step 2: Query the Smart Contract

Here's a JavaScript code example to retrieve the metadata URL and then fetch the metadata using fetch:

const { TonClient, Address, TupleBuilder } = require('@ton/ton');
const { getHttpEndpoint } = require('@orbs-network/ton-access');
const fetch = require('node-fetch');

async function main() {
    try {
      console.log('Connecting to TON');
      const endpoint = await getHttpEndpoint({ network: 'mainnet' });
      console.log(`Connected to endpoint: ${endpoint}`);
      const client = new TonClient({ endpoint });
  
      // Collection contract address
      const collectionAddress = Address.parse('EQSoulboundCollectionAddress');
      console.log(`Using collection: ${collectionAddress.toString()}`);
  
      // User's wallet address
      const userAddress = Address.parse('EQUserWalletAddress');
      console.log(`User address: ${userAddress.toString()}`);
      
      // Anima collection identifier
      const animaCollection = 'anima_collection';
      console.log(`Anima collection: ${animaCollection}`);
  
      // Step 1: Get the Soulbound NFT address
      console.log('\nStep 1: Getting Soulbound NFT address...');
      
      // Create a TupleBuilder and add parameters
      const builder = new TupleBuilder();
      builder.writeAddress(userAddress);
      builder.writeString(animaCollection);
      
      const result = await client.runMethod(
        collectionAddress,
        'get_nft_address_by_owner_and_anima_collection',
        builder.build()
      );
      
      const soulboundAddress = result.stack.readAddress();
      console.log(`✅ Soulbound NFT Address: ${soulboundAddress.toString()}`);
  
      // Step 2: Get the NFT URI directly from the Soulbound NFT
      console.log('\nStep 2: Getting NFT URI from Soulbound NFT...');
      
      // Create an empty TupleBuilder for the URI call
      const uriBuilder = new TupleBuilder();
      
      try {
        // Call get_nft_uri 
        const uriResult = await client.runMethod(
          soulboundAddress,
          'get_nft_uri',
          uriBuilder.build()
        );
        
        const uri = uriResult.stack.readString();
        console.log(`✅ NFT URI: ${uri}`);
  
        // Step 3: Fetch the metadata JSON from the URL
        const response = await fetch(uri);
        const metadata = await response.json();
  
        // Step 4: Log the fetched metadata
        console.log('Fetched Metadata:', metadata);
        
      } catch (error) {
        console.error('\n❌ Error getting NFT URI:');
        console.error('Message:', error.message);
      }
    } catch (error) {
      console.error('\n❌ Error occurred:');
      console.error('Message:', error.message);
      console.error('Stack:', error.stack);
    }
  }
  
  // Run the main function
  console.log('TON Soulbound NFT Metadata Fetcher Starting...\n');
  main().then(() => {
    console.log('\nProcess complete!');
  }).catch(err => {
    console.error('\nUnhandled error:', err);
  });

Explanation:

  1. Set up the provider: Connect to the Ton network using a provider from ton access
  2. Smart contract interaction:
  • Call get_nft_address_by_owner_and_anima_collection with the user's address and the anima_collection to retrieve the SBT contract address for the user.
  • Call get_nft_uri to get the metadata URL for that SBT contract address.
  1. Fetch metadata: Once you have the metadata URL, use fetch to retrieve and parse the metadata JSON file.
  2. Log the metadata: The fetched JSON data will include attributes like the reputation level and last verification timestamp.

How It Works: Step-by-Step

  1. Retrieve the Token ID: Call the get_nft_address_by_owner_and_anima_collection function with the user's address and the anima_collection to retrieve the SBT contract address associated with their account for that collection.

  2. Fetch Metadata: Once you have the SBT contract address, use the get_nft_uri function to get the metadata URL, which contains all the relevant information about the user's reputation and verification status.

  3. Query Attributes: Parse the JSON metadata file returned from the URL to extract attributes such as the user's current reputation level and the timestamp of their last verification.

Summary:

This example demonstrates how to use ton.js to query the Anima SBT smart contract for metadata and then fetch the metadata using an HTTP request. You can easily customize the code to fit your use case, such as querying different blockchain networks or using custom NFT collections.