Skip to content

ERC Testing

Antonio Yang edited this page Oct 14, 2021 · 4 revisions

ERC Token tesing scripts

Once you deploy the contract followed by Deploy Guide

It is easy to test the token contract work fine by javascript.

Prepare abi and accounts

Create utils.js with contract abi like this, and provide URL for the blockchain network and also two private key for account with currency.

// utils.js
const Web3 = require("web3");
const HDWalletProvider = require('truffle-hdwallet-provider');
const URL = 'http://localhost:8545';  // network you need
const privateKeys = [
  'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',  // private key
  'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',  // private key
];
const erc20abi = [
    {
        "inputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "totalSupply",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "balanceOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }],
        "name": "transfer",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" }],
        "name": "allowance",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [{ "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }],
        "name": "approve",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "sender", "type": "address" },
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256", "name": "amount", "type": "uint256" }
        ],
        "name": "transferFrom",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "decimals",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "name",
        "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    { "constant": true,
        "inputs": [],
        "name": "symbol",
        "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    }
];

const erc721abi = [
    {
        "inputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "totalSupply",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [{ "internalType": "address", "name": "account", "type": "address" }],
        "name": "balanceOf",
        "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }
        ],
        "name": "transfer",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "_to", "type": "address" },
            { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }
        ],
        "name": "approve",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "sender", "type": "address" },
            { "internalType": "address", "name": "recipient", "type": "address" },
            { "internalType": "uint256", "name": "_tokenId", "type": "uint256" }
        ],
        "name": "transferFrom",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "name",
        "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "symbol",
        "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [{ "name": "_tokenId", "type": "uint256" }],
        "name": "ownerOf",
        "outputs": [{ "name": "_owner", "type": "address" }],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [ { "name": "_tokenId", "type": "uint256" } ],
        "name": "getApproved",
        "outputs": [{ "name": "_owner", "type": "address" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "_operator", "type": "address" },
            { "internalType": "bool", "name": "_approved", "type": "bool" }
        ],
        "name": "setApprovalForAll",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "owner", "type": "address" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "isApprovedForAll",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    }
];
const erc1155abi = [
    {
        "inputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "constructor"
    },
    {
        "constant": true,
        "inputs": [
            { "name": "account", "type": "address" },
            { "name": "token_id", "type": "uint256" }
        ],
        "name": "balanceOf",
        "outputs": [
            { "name": "", "type": "uint256" }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [
            { "internalType": "address[]", "name": "account", "type": "address[]" },
            { "internalType": "uint256[]", "name": "account", "type": "uint256[]" }
        ],
        "name": "balanceOfBatch",
        "outputs": [
            { "name": "", "type": "uint256[]" }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [
            { "internalType": "address", "name": "from", "type": "address" },
            { "internalType": "address", "name": "to", "type": "address" },
            { "internalType": "uint256", "name": "token_id", "type": "uint256" },
            { "internalType": "uint256", "name": "value", "type": "uint256" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "safeTransferFrom",
        "outputs": [],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [
            { "internalType": "address", "name": "from", "type": "address" },
            { "internalType": "address", "name": "to", "type": "address" },
            { "internalType": "uint256[]", "name": "token_id", "type": "uint256[]" },
            { "internalType": "uint256[]", "name": "value", "type": "uint256[]" },
            { "internalType": "bytes", "name": "data", "type": "bytes" }
        ],
        "name": "safeBatchTransferFrom",
        "outputs": [
            { "name": "", "type": "uint256[]" }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "_operator", "type": "address" },
            { "internalType": "bool", "name": "_approved", "type": "bool" }
        ],
        "name": "setApprovalForAll",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            { "internalType": "address", "name": "owner", "type": "address" },
            { "internalType": "address", "name": "operator", "type": "address" }
        ],
        "name": "isApprovedForAll",
        "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    }
];

module.exports = {
  provider: null,
  web3: function () {
    this.provider = new HDWalletProvider(privateKeys, URL, 0, privateKeys.length);
    return new Web3(this.provider);
  },
  erc20abi: erc20abi,
  erc721abi: erc721abi,
  erc1155abi: erc1155abi,
};

Install

Install the dependency of javascript

npm install truffle-hdwallet-provider web3@1.3.3

Testing Scripts

Modify the contract address that you deployed, then run creating following test script, and run by node erc20.js, node erc721.js or node erc1155.js

ERC-20

// erc20.js
const utils = require('./utils');

(async () => {
  const web3 = utils.web3();
  let accounts = await web3.eth.getAccounts();
  console.log(`accounts: ${JSON.stringify(accounts)}`);
  console.log(`${accounts[0]} balance: ${await web3.eth.getBalance(accounts[0])}`);
  console.log(`${accounts[1]} balance: ${await web3.eth.getBalance(accounts[1])}`);

  // TODO modify contract address after deploy
  let contractAddress = "0x17ebaec2e846d0dfff59cd8a6819219517fac610";

  let contract = new web3.eth.Contract(utils.erc20abi, contractAddress);

  let result;
  //////////////////////////////
  // check out token parameters

  // Demo
  result = await contract.methods.name().call();
  console.log(result);
  console.log(`contract.name() = ${result}`);

  // ETD
  result = await contract.methods.symbol().call();
  console.log(`contract.symbol() = ${result}`);

  // 8
  result = await contract.methods.decimals().call();
  console.log(`contract.decimals() = ${result}`);

  // 10000
  result = await contract.methods.totalSupply().call();
  console.log(`contract.totalSupply() = ${result}`);

  //////////////////////////////
  // Transfer and check balance

  // check erc20 balances
  result = await contract.methods.balanceOf(accounts[0]).call();
  console.log(`contract.balanceOf(${accounts[0]}) = ${result}`);
  result = await contract.methods.balanceOf(accounts[1]).call();
  console.log(`contract.balanceOf(${accounts[1]}) = ${result}`);

  let amount = 2;
  let allowance = 3;
  // transfer
  await contract.methods.transfer(accounts[1], amount)
      .send({ from: accounts[0] })
      .on('receipt', function (receipt) {
    console.log(`Transfer ${amount} token from address(${accounts[0]}) to address(${accounts[1]})`);
  });

  // check erc20 balances
  result = await contract.methods.balanceOf(accounts[0]).call();
  console.log(`contract.balanceOf(${accounts[0]}) = ${result}`);
  result = await contract.methods.balanceOf(accounts[1]).call();
  console.log(`contract.balanceOf(${accounts[1]}) = ${result}`);


  //////////////////////////////////////
  // Approve other to transfer allowance

  await contract.methods.approve(accounts[1], allowance)
      .send({ from: accounts[0] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[0]} approve allowance ${allowance} token for address(${accounts[1]})`);
  });

  result = await contract.methods.allowance(accounts[0], accounts[1]).call();
  console.log(`contract.allowance(${accounts[0]},${accounts[1]}) = ${result}`);

  // transfer from
  await contract.methods.transferFrom(accounts[0], accounts[1], amount)
      .send({ from: accounts[1] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[1]} transfer ${amount} token from address(${accounts[0]}) to address(${accounts[1]})`);
  });

  result = await contract.methods.allowance(accounts[0], accounts[1]).call();
  console.log(`contract.allowance(${accounts[0]},${accounts[1]}) = ${result}`);

  result = await contract.methods.balanceOf(accounts[0]).call();
  console.log(`contract.balanceOf(${accounts[0]}) = ${result}`);
  result = await contract.methods.balanceOf(accounts[1]).call();
  console.log(`contract.balanceOf(${accounts[1]}) = ${result}`);

  await utils.provider.engine.stop();
})();

ERC-721

// erc721.js
const utils = require('./utils');

(async () => {
  const web3 = utils.web3();
  let accounts = await web3.eth.getAccounts();
  console.log(`accounts: ${JSON.stringify(accounts)}`);
  console.log(`${accounts[0]} balance: ${await web3.eth.getBalance(accounts[0])}`);
  console.log(`${accounts[1]} balance: ${await web3.eth.getBalance(accounts[1])}`);

  // TODO modify contract address after deploy
  let contractAddress = "0x399ffe5505d47ce4917c5d9feb013b5fc0b4db2d";

  let contract = new web3.eth.Contract(utils.erc721abi, contractAddress);

  let result;
  //////////////////////////////
  // Transfer and check balance
  // check erc20 balances
  result = await contract.methods.balanceOf(accounts[0]).call();
  console.log(`contract.balanceOf(${accounts[0]}) = ${result}`);
  result = await contract.methods.balanceOf(accounts[1]).call();
  console.log(`contract.balanceOf(${accounts[1]}) = ${result}`);

  result = await contract.methods.ownerOf(1).call();
  console.log(`contract.ownerOf(1) = ${result}`);
  result = await contract.methods.ownerOf(2).call();
  console.log(`contract.ownerOf(2) = ${result}`);


  // transfer
  await contract.methods.transfer(accounts[1], 1)
      .send({ from: accounts[0] })
      .on('receipt', function (receipt) {
    console.log(`Transfer token 1 from address(${accounts[0]}) to address(${accounts[1]})`);
  });

  result = await contract.methods.ownerOf(1).call();
  console.log(`contract.ownerOf(1) = ${result}`);
  result = await contract.methods.ownerOf(2).call();
  console.log(`contract.ownerOf(2) = ${result}`);

  result = await contract.methods.balanceOf(accounts[0]).call();
  console.log(`contract.balanceOf(${accounts[0]}) = ${result}`);
  result = await contract.methods.balanceOf(accounts[1]).call();
  console.log(`contract.balanceOf(${accounts[1]}) = ${result}`);

  await contract.methods.approve(accounts[1], 2)
      .send({ from: accounts[0] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[0]} approve token 2 for address(${accounts[1]})`);
  });

  result = await contract.methods.getApproved(2).call();
  console.log(`contract.getApproved(2) = ${result}`);

  await contract.methods.transferFrom(accounts[0], accounts[1], 2)
      .send({ from: accounts[1] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[1]} transfer token 2 from address(${accounts[0]}) to address(${accounts[1]})`);
  });

  result = await contract.methods.ownerOf(2).call();
  console.log(`contract.balanceOf(2) = ${result}`);

  result = await contract.methods.balanceOf(accounts[0]).call();
  console.log(`contract.balanceOf(${accounts[0]}) = ${result}`);
  result = await contract.methods.balanceOf(accounts[1]).call();
  console.log(`contract.balanceOf(${accounts[1]}) = ${result}`);

  await contract.methods.setApprovalForAll(accounts[1], true)
      .send({ from: accounts[0] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[0]} approve address(${accounts[1]})`);
  });

  result = await contract.methods.isApprovedForAll(accounts[0], accounts[1]).call();
  console.log(`contract.isApprovedForAll(${accounts[0]},${accounts[1]}) = ${result}`);

  result = await contract.methods.getApproved(3).call();
  console.log(`contract.getApproved(3) = ${result}`);

  await contract.methods.transferFrom(accounts[0], accounts[1], 3)
      .send({ from: accounts[1] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[1]} transfer token 3 from address(${accounts[0]}) to address(${accounts[1]})`);
  });

  result = await contract.methods.ownerOf(3).call();
  console.log(`contract.balanceOf(2) = ${result}`);

  result = await contract.methods.balanceOf(accounts[0]).call();
  console.log(`contract.balanceOf(${accounts[0]}) = ${result}`);
  result = await contract.methods.balanceOf(accounts[1]).call();
  console.log(`contract.balanceOf(${accounts[1]}) = ${result}`);

  await contract.methods.setApprovalForAll(accounts[1], false)
      .send({ from: accounts[0] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[0]} approve address(${accounts[1]})`);
  });

  result = await contract.methods.isApprovedForAll(accounts[0], accounts[1]).call();
  console.log(`contract.isApprovedForAll(${accounts[0]},${accounts[1]}) = ${result}`);

  await utils.provider.engine.stop();
})();

ERC-1155

// erc1155.js
const utils = require('./utils');

(async () => {
  const web3 = utils.web3();
  let accounts = await web3.eth.getAccounts();
  console.log(`accounts: ${JSON.stringify(accounts)}`);
  console.log(`${accounts[0]} balance: ${await web3.eth.getBalance(accounts[0])}`);
  console.log(`${accounts[1]} balance: ${await web3.eth.getBalance(accounts[1])}`);

  // TODO modify contract address after deploy
  let contractAddress = "0xde906e22fbdfba3bed7fb15aa69278e2ed89659c";

  let contract = new web3.eth.Contract(utils.erc1155abi, contractAddress);

  let result;

  result = await contract.methods.balanceOf(accounts[0], 1).call();
  console.log(`contract.balanceOf(${accounts[0]}, 1) = ${result}`);
  result = await contract.methods.balanceOf(accounts[0], 2).call();
  console.log(`contract.balanceOf(${accounts[0]}, 2) = ${result}`);
  result = await contract.methods.balanceOf(accounts[0], 3).call();
  console.log(`contract.balanceOf(${accounts[0]}, 3) = ${result}`);

  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [1,1]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [1,1]) = ${result}`);
  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [2,2]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [2,2]) = ${result}`);
  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [3,3]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [3,3]) = ${result}`);

  await contract.methods.setApprovalForAll(accounts[1], true)
      .send({ from: accounts[0] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[0]} approve address(${accounts[1]})`);
  });

  result = await contract.methods.isApprovedForAll(accounts[0], accounts[1]).call();
  console.log(`contract.isApprovedForAll(${accounts[0]},${accounts[1]}) = ${result}`);

  await contract.methods.safeTransferFrom(accounts[0], accounts[1], 1, 1, [])
      .send({ from: accounts[1] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[1]} transfer token 1 value 1 from ${accounts[0]} to address(${accounts[1]})`);
  });

  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [1,1]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [1,1]) = ${result}`);
  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [2,2]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [2,2]) = ${result}`);
  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [3,3]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [3,3]) = ${result}`);

  await contract.methods.safeBatchTransferFrom(accounts[0], accounts[1], [2,3], [1,2], [])
      .send({ from: accounts[1] })
      .on('receipt', function (receipt) {
    console.log(`${accounts[1]} transfer token 2 value 1 and token 3 value 2 from ${accounts[0]} to address(${accounts[1]})`);
    // console.log(receipt)
  });

  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [1,1]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [1,1]) = ${result}`);
  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [2,2]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [2,2]) = ${result}`);
  result = await contract.methods.balanceOfBatch([accounts[0], accounts[1]], [3,3]).call();
  console.log(`contract.balanceOfBatch([accounts[0], accounts[1]], [3,3]) = ${result}`);

  await utils.provider.engine.stop();
})();

Expected results

Check the results Following are the examples for running the tokens test scripts

ERC-20

accounts: ["0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993","0x1cCA28600d7491365520B31b466f88647B9839eC"]
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 balance: 8999976899998221840
0x1cCA28600d7491365520B31b466f88647B9839eC balance: 1763999999999999757311
Demo
contract.name() = Demo
contract.symbol() = ETD
contract.decimals() = 8
contract.totalSupply() = 1000
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) = 1000
contract.balanceOf(0x1cCA28600d7491365520B31b466f88647B9839eC) = 0
Transfer 2 token from address(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) to address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) = 998
contract.balanceOf(0x1cCA28600d7491365520B31b466f88647B9839eC) = 2
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 approve allowance 3 token for address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.allowance(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993,0x1cCA28600d7491365520B31b466f88647B9839eC) = 3
0x1cCA28600d7491365520B31b466f88647B9839eC transfer 2 token from address(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) to address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.allowance(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993,0x1cCA28600d7491365520B31b466f88647B9839eC) = 1
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) = 996
contract.balanceOf(0x1cCA28600d7491365520B31b466f88647B9839eC) = 4

ERC-721

accounts: ["0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993","0x1cCA28600d7491365520B31b466f88647B9839eC"]
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 balance: 8999976899998087779
0x1cCA28600d7491365520B31b466f88647B9839eC balance: 1785999999999999741690
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) = 3
contract.balanceOf(0x1cCA28600d7491365520B31b466f88647B9839eC) = 0
contract.ownerOf(1) = 0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993
contract.ownerOf(2) = 0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993
Transfer token 1 from address(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) to address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.ownerOf(1) = 0x1cCA28600d7491365520B31b466f88647B9839eC
contract.ownerOf(2) = 0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) = 2
contract.balanceOf(0x1cCA28600d7491365520B31b466f88647B9839eC) = 1
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 approve token 2 for address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.getApproved(2) = 0x1cCA28600d7491365520B31b466f88647B9839eC
0x1cCA28600d7491365520B31b466f88647B9839eC transfer token 2 from address(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) to address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.balanceOf(2) = 0x1cCA28600d7491365520B31b466f88647B9839eC
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) = 1
contract.balanceOf(0x1cCA28600d7491365520B31b466f88647B9839eC) = 2
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 approve address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.isApprovedForAll(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993,0x1cCA28600d7491365520B31b466f88647B9839eC) = true
contract.getApproved(3) = 0x0000000000000000000000000000000000000000
0x1cCA28600d7491365520B31b466f88647B9839eC transfer token 3 from address(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) to address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.balanceOf(2) = 0x1cCA28600d7491365520B31b466f88647B9839eC
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993) = 0
contract.balanceOf(0x1cCA28600d7491365520B31b466f88647B9839eC) = 3
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 approve address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.isApprovedForAll(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993,0x1cCA28600d7491365520B31b466f88647B9839eC) = false

ERC-1155

accounts: ["0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993","0x1cCA28600d7491365520B31b466f88647B9839eC","0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b"]
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 balance: 4972999999999997532497
0x1cCA28600d7491365520B31b466f88647B9839eC balance: 1999999999999685323
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993, 1) = 1
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993, 2) = 2
contract.balanceOf(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993, 3) = 3
contract.balanceOfBatch([accounts[0], accounts[1]], [1,1]) = 1,0
contract.balanceOfBatch([accounts[0], accounts[1]], [2,2]) = 2,0
contract.balanceOfBatch([accounts[0], accounts[1]], [3,3]) = 3,0
0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 approve address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.isApprovedForAll(0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993,0x1cCA28600d7491365520B31b466f88647B9839eC) = true
0x1cCA28600d7491365520B31b466f88647B9839eC transfer token 1 value 1 from 0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 to address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.balanceOfBatch([accounts[0], accounts[1]], [1,1]) = 0,1
contract.balanceOfBatch([accounts[0], accounts[1]], [2,2]) = 2,0
contract.balanceOfBatch([accounts[0], accounts[1]], [3,3]) = 3,0
0x1cCA28600d7491365520B31b466f88647B9839eC transfer token 2 value 1 and token 3 value 2 from 0x8663DBF0cC68AaF37fC8BA262F2df4c666a41993 to address(0x1cCA28600d7491365520B31b466f88647B9839eC)
contract.balanceOfBatch([accounts[0], accounts[1]], [1,1]) = 0,1
contract.balanceOfBatch([accounts[0], accounts[1]], [2,2]) = 1,1
contract.balanceOfBatch([accounts[0], accounts[1]], [3,3]) = 1,2