# erc20/v1.ts

    import { ethers } from "ethers";
    import ringABI from "@evo/config/abi/common/abi-ring.json";
    import type { ContractNameType } from "@evo/types";
    import type { CallbackType } from "@evo/utils/ethers/contractHelper";
    import {
      triggerContractByContractName,
      viewContractByContractName,
      triggerContract,
      viewContract,
      getContract,
    } from "@evo/utils/ethers/contractHelper";
    import { LandId } from "@evo/config/constants";
    import { TransactionResponse } from "@ethersproject/providers";

    /**
     * ERC20 Allowance
     * @param provider Ethers provider
     * @param contractName Contract name
     * @param from From, account address
     * @param spender Spender
     * @param callback Callback
     * @returns String amount
     */
    export const erc20Allowance = async (
      landId: LandId,
      provider: ethers.providers.Provider,
      contractName: ContractNameType,
      from: string,
      spender: string,
      callback?: CallbackType
    ): Promise<string> => {
      const results = await viewContractByContractName(
        landId,
        provider,
        contractName,
        "allowance",
        [from, spender],
        callback
      );
      return results.length ? (results[0] as ethers.BigNumber).toHexString() : ethers.utils.hexValue(0);
    };

    /**
     * ERC20 Allowance By Contract Address
     * @param provider Ethers provider
     * @param contractAddress Contract address
     * @param from From
     * @param spender Spender
     * @param callback Callback
     * @returns String amount
     */
    export const erc20AllowanceByContractAddress = async (
      provider: ethers.providers.Provider,
      contractAddress: string,
      from: string,
      spender: string,
      callback?: CallbackType
    ): Promise<string> => {
      const contract = await getContract(provider, contractAddress, ringABI);
      if (contract) {
        const results = await viewContract(contract, "allowance", [from, spender], callback);
        return results.length ? (results[0] as ethers.BigNumber).toHexString() : ethers.utils.hexValue(0);
      } else {
        callback && callback.errorCallback({ error: new Error(`erc20AllowanceByContractAddress failed to get contract.`) });
        return ethers.utils.hexValue(0);
      }
    };

    /**
     * ERC20 Approve
     * @param signer Ethers signer
     * @param contractName Contract name
     * @param spender Spender
     * @param value Value
     * @param callback Callback
     */
    export const erc20Approve = (
      landId: LandId,
      signer: ethers.Signer,
      contractName: ContractNameType,
      spender: string,
      value = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      return triggerContractByContractName(
        landId,
        signer,
        contractName,
        "approve(address,uint256)",
        [spender, value],
        callback
      );
    };

    /**
     * ERC20 Approve By Contract Address
     * @param signer Ethers signer
     * @param contractAddress Contract address
     * @param spender Spender
     * @param value Value
     * @param callback Callback
     */
    export const erc20ApproveByContractAddress = async (
      signer: ethers.Signer,
      contractAddress: string,
      spender: string,
      value = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      const contract = await getContract(signer, contractAddress, ringABI);
      // if (contract) {
      return triggerContract(contract, "approve(address,uint256)", [spender, value], callback);
      // } else {
      //   callback && callback.errorCallback({ error: new Error(`erc20ApproveByContractAddress failed to get contract.`) });
      // }
    };

    /**
     * ERC20 Transfer
     * @param signer Signer
     * @param contractAddress Token contract address
     * @param dst Recipient
     * @param wad Amount
     * @param callback Callback
     * @returns any
     */
    export const erc20TransferByContractAddress = async (
      signer: ethers.Signer,
      contractAddress: string,
      dst: string,
      wad: string,
      callback?: CallbackType
    ): Promise<TransactionResponse> => {
      const contract = await getContract(signer, contractAddress, ringABI);
      // if (contract) {
      return triggerContract(contract, "transfer(address,uint256)", [dst, wad], callback);
      // } else {
      //   callback && callback.errorCallback({ error: new Error(`erc20TransferByContractAddress failed to get contract.`) });
      // }
    };

    /**
     * Get token balance by address
     * @param provider Provider
     * @param tokenAddress ERC20 contract address
     * @param account Address
     * @param callback Callbcak
     * @returns any
     */
    export const erc20BalanceOf = async (
      provider: ethers.providers.Provider,
      tokenAddress: string,
      account: string,
      callback?: CallbackType
    ): Promise<string> => {
      const contract = await getContract(provider, tokenAddress, ringABI);

      const results = await viewContract(contract, "balanceOf(address)", [account], callback);
      return results.length ? (results[0] as ethers.BigNumber).toHexString() : ethers.utils.hexValue(0);
    };

    /**
     * Get token total supply
     * @param provider Provider
     * @param tokenAddress ERC20 contract address
     * @param callback Callback
     * @returns any
     */
    export const erc20TotalSupply = async (
      provider: ethers.providers.Provider,
      tokenAddress: string,
      callback?: CallbackType
    ): Promise<string> => {
      const contract = await getContract(provider, tokenAddress, ringABI);

      const results = await viewContract(contract, "totalSupply", [], callback);
      return results.length ? (results[0] as ethers.BigNumber).toHexString() : ethers.utils.hexValue(0);
    };