Fetch Data Example

This section will guide you through fetching contract state data from the blockchain using a Node RPC provider.

Contracts:

Prerequisites:

  • RPC Node Provider: Alchemy, Infura, or others.

  • NodeJS: version v20.14.0 or v20.15.0.

  • Package Manager: yarn or npm.

Fetch Data Example

Folder Structure:

fetch-data-example
├── package.json
├── src
   ├── abis
      ├── KIPIdentification.json
      └── MockKIPToken.json
   ├── fetchKIPIdentification.ts
   ├── fetchKIPToken.ts
   └── main.ts
└── tsconfig.json

Let's get started:

  1. Create a project folder:

mkdir fetch-data-example && cd fetch-data-example
  1. Create package.json and install dependencies:

  • Create package.json

  touch package.json && open package.json
  • Add the following content to package.json:

  {
    "name": "fetch-data-example",
    "version": "1.0.0"
  }
  • Install dependencies:

  yarn add @types/node dotenv ethers typescript
  # or
  npm install --save-dev @types/node dotenv ethers typescript
  1. Create tsconfig.json:

  • Create the file:

  touch tsconfig.json && open tsconfig.json
  • Add the following content to tsconfig.json:

  {
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "resolveJsonModule": true
  },
  "include": ["src"]
}
  1. Create .env file:

  • Create the file:

  touch .env && open .env
  • Add the following content to .env:

  // Provide your Node RPC URL that created in another section
  RPC_URL=<YOUR_RPC_URL>
  1. Create src and abis folders:

mkdir -p src/abis && cd src/abis
  1. Create ABI files for the smart contracts:

  • KIPIdentification Contract ABI:

  // make sure your current directory is "./src/abis"
  touch KIPIdentification.json && open KIPIdentification.json
  • Add the ABI content to KIPIdentification.json:

  [{"inputs":[{"internalType":"contract IKIPManagement","name":"management","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AdminRequire","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[],"name":"MinterRequire","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"idType","type":"uint256"}],"name":"KIPIdentity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"KIPManagement","outputs":[{"internalType":"contract IKIPManagement","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"idTypes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"idType","type":"uint256"},{"internalType":"string","name":"tokenURI","type":"string"}],"name":"issueId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"management","type":"address"}],"name":"setManagement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenURI","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]
  • Mock KIPToken Contract ABI:

  // make sure your current directory is "./src/abis"
  touch MockKIPToken.json && open MockKIPToken.json
  • Add the ABI content to MockKIPToken.json:

  [{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
  1. Create scripts to interact with the contracts:

  • Fetch data from KIPIdentification contract:

  cd ..
  # Ensure you are in the "src" directory before running a following command
  touch fetchKIPIdentification.ts && open fetchKIPIdentification.ts
  • Add the code to interact with the KIPIdentification contract into fetchKIPIdentification.ts:

  import { AddressLike, ethers } from "ethers";
  import ABI from "./abis/KIPIdentification.json";
  import * as dotenv from "dotenv";
  dotenv.config();

  //  Change CONTRACT_ADDRESS to match your contract if needed
  const CONTRACT_ADDRESS = "0x3cDfD20F5AA27335bE4A68d0e1B1085A65418b09";
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL as string);
  const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, provider);

  export const getOwner = async (
    tokenId: bigint | string
  ): Promise<AddressLike> => {
    return await contract.ownerOf(tokenId);
  };

  export const getTokenURI = async (
    tokenId: bigint | string
  ): Promise<string> => {
    return await contract.tokenURI(tokenId);
  };
  • Fetch data from the mock KIPToken contract:

  touch fetchKIPToken.ts && open fetchKIPToken.ts
  • Add the code to interact with the mock KIPToken contract into fetchKIPToken.ts:

  import { AddressLike, ethers } from "ethers";
  import ABI from "./abis/MockKIPToken.json";
  import * as dotenv from "dotenv";
  dotenv.config();

  //  Change CONTRACT_ADDRESS to match your contract if needed
  const CONTRACT_ADDRESS = "0x4b565A132347064Ca7F1eDC9489a00b3E68431dd";
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL as string);
  const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, provider);

  export const getBalance = async (account: AddressLike): Promise<BigInt> => {
    return await contract.balanceOf(account);
  };

  export const getAllowance = async (
    owner: AddressLike,
    spender: AddressLike
  ) => {
    return await contract.allowance(owner, spender);
  };
  1. Create main.ts to test the setup:

  • Create the file:

touch main.ts && open main.ts
  • Add the code into main.ts:

  import { getOwner, getTokenURI } from "./fetchKIPIdentification";
  import { getAllowance, getBalance } from "./fetchKIPToken";

  async function main() {
    const tokenId = BigInt(1);
    const owner = await getOwner(tokenId);
    console.log(`Owner of tokenId = ${tokenId}: ${owner}`);
    const tokenURI = await getTokenURI(tokenId);
    console.log(`TokenURI of tokenId = ${tokenId}: ${tokenURI}`);

    //  Change `account` and `spender` addresses for your case
    const account = "0x31003C2D5685c7D28D7174c3255307Eb9a0f3015";
    const balance = await getBalance(account);
    console.log(`Balance of ${account}: ${balance}`);
    const spender = "0x87a7A0223D6F96B3DECaAf3666d5c550b36fEfEe";
    const allowance = await getAllowance(account, spender);
    console.log(
      `Spender ${spender} is allowed to spend: ${allowance} on the ${account} behalf`
    );
  }

  main()
    .then(() => process.exit(0))
    .catch((error) => {
    console.error(error);
    process.exit(1);
  });
  1. Run the test:

  cd ..
  # Ensure your current directory is "fetch-data-example"
  npx ts-node src/main.ts
  • After running, you should see output similar to the following:

  (base)   fetch-data-example npx ts-node src/main.ts

    Owner of tokenId = 1: 0x31003C2D5685c7D28D7174c3255307Eb9a0f3015
    TokenURI of tokenId = 1: ipfs://QmZcH4YvBVVRJtdn4RdbaqgspFU8gH6P9vomDpBVpAL3u4/4375
    Balance of 0x31003C2D5685c7D28D7174c3255307Eb9a0f3015: 100880000000000000000420
    Spender 0x87a7A0223D6F96B3DECaAf3666d5c550b36fEfEe is allowed to spend: 0 on the 0x31003C2D5685c7D28D7174c3255307Eb9a0f3015 behalf

  (base)   fetch-data-example

Last updated