ใช้งาน Wagmi เพื่อเช็คจำนวน Token ของบัญชี

ต่อจากคราวที่เเล้วที่เราได้ทำในการ Project Watch NFT  กันไปเเล้ว  วันนี้เราจะมาทำ การทำ Project Watch Balance กัน

โดยในรอบนี้  เราใช้ในการทำคือ ERC-20  ในการทำ

https://docs.openzeppelin.com/contracts/4.x/api/token/erc20

https://eips.ethereum.org/EIPS/eip-20

เราจะเริ่มจาก เอา Abi ของ ERC-20 มาใส่ใน config ก่อน

[
  {
    "constant": true,
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_spender",
        "type": "address"
      },
      {
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "name": "",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_from",
        "type": "address"
      },
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "name": "",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "name": "",
        "type": "uint8"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "name": "balance",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "name": "",
        "type": "string"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "name": "",
        "type": "bool"
      }
    ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      },
      {
        "name": "_spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "payable": true,
    "stateMutability": "payable",
    "type": "fallback"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  }
]

และ function ที่เราจะเรียกใช้ในการดึงข้อมูลเหรียญต่างๆ

name() → string

จะส่งชื่อเหรียญกลับมา

symbol() → string

จะส่ง symbol ของเหรียญ

decimals() → uint8

จะส่ง decimals ของเหรียญ

ส่วนของการดึง balance เราจะใช้

balanceOf(address account) → uint256

โดย contract address  ของเหรียญ เราจะเลือกมาจาก https://optimistic.etherscan.io/tokens

โดน hook ที่เราจะเขียนจะได้หน้าตาแบบนี้ โดย เราจะรับ contract address เหรียญ ในลักษณะของ Array

ซึ่งในการเรียกค่าครั้งนี่เราจะใช้ useContractReads ในการดึงข้อมูลจาก contract

import { isAddress } from 'ethers'
import { useChainId, useContractReads } from 'wagmi'
import { z } from 'zod'
import Erc20ABI from '../assets/abi/erc20.json'

export const zodAddress = z.custom<`0x${string}`>((value) => {
  if (typeof value !== 'string') {
    return false
  }
  if (!isAddress(value)) {
    return false
  }
  return true
})

const validator = z.object({
  walletAddress: zodAddress,
  contractAddress: zodAddress.array(),
})
const useTokenInfo = (input?: z.input<typeof validator>) => {
  const result = validator.safeParse(input)
  const chainId = useChainId()
  const calls =
    result.success && result.data.contractAddress.length > 0
      ? result.data.contractAddress.map((address) => ({
          abi: Erc20ABI,
          functionName: 'name',
          address: address,
          args: [],
          chainId,
        }))
      : []

  const callsSymbol =
    result.success && result.data.contractAddress.length > 0
      ? result.data.contractAddress.map((address) => ({
          abi: Erc20ABI,
          functionName: 'symbol',
          address: address,
          args: [],
          chainId,
        }))
      : []

  const callsDecimals =
    result.success && result.data.contractAddress.length > 0
      ? result.data.contractAddress.map((address) => ({
          abi: Erc20ABI,
          functionName: 'decimals',
          address: address,
          args: [],
          chainId,
        }))
      : []

  const callsBalance =
    result.success && result.data.contractAddress.length > 0
      ? result.data.contractAddress.map((address) => ({
          abi: Erc20ABI,
          functionName: 'balanceOf',
          address: address,
          args: [result.data.walletAddress],
          chainId,
        }))
      : []

  const { data: names } = useContractReads({
    contracts: calls,
    watch: true,
    enabled: result.success,
  })
  const { data: symbols } = useContractReads({
    contracts: callsSymbol,
    watch: true,
    enabled: result.success,
  })
  const { data: decimals } = useContractReads({
    contracts: callsDecimals,
    watch: true,
    enabled: result.success,
  })
  const { data: balance } = useContractReads({
    contracts: callsBalance,
    watch: true,
    enabled: result.success,
  })

  return {
    names,
    symbols,
    decimals,
    balance,
  }
}

export default useTokenInfo

จากนั้นเราจะลองเรียกใน ส่วนของ ViewTokenInfo มาดูผลลัพธ์กัน

import { useState } from 'react'
import useTokenInfo from '../hooks/useTokensInfo'
import { formatUnits } from 'ethers'

type Address = `0x${string}`

export default function ViewTokenInfo() {
  const [value, setValue] = useState()
  const data = useTokenInfo({
    contractAddress: [
      '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
      '0x7F5c764cBc14f9669B88837ca1490cCa17c31607',
      '0x68f180fcCe6836688e9084f035309E29Bf0A2095',
      '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
    ],
    walletAddress: value as Address,
  })
  return (
    <div>
      <input
        placeholder='enter Address'
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
      {data?.names?.map((item, index) => (
        <div key={index}>
          name: {item.result} <br />
          symbol: {data?.symbols?.[index].result}
          <br />
          decimals: {data?.decimals?.[index].result}
          <br />
          balance:
          {data?.balance &&
            data?.decimals &&
            formatUnits(
              data.balance?.[index].result.toString() || '0',
              data.decimals?.[index].result || '18'
            )}
        </div>
      ))}
    </div>
  )
}

เมื่อได้ค่า  balance ที่เราได้มา  เนื่องจากค่าที่ได้มายังไม่ทำการ formatหน่วย ดังนั้น เราจะเรียกใช้ formatUnits ของ ethers มาทำการ format ค่า balance ที่เราได้ โดย units คือ ค่า decimal ของเเต่ละเหรียญ

เมื่อเราลองเรียกเเล้ว เราจะได้ผลลัพธ์ออกมาแบบนี้

Aa

© 2023, All Rights Reserved, VulturePrime co., ltd.