0

I'm trying to retrieve the token IDs of a minting operation in my front-end.

I was trying to use the Transfer event of my ER721A contract

    {
      "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"
    },

Here is my minting function call, the idea is to get the tokenID just afeter the minting is complete to display it a modal.

async function mint() {
      try {
        const contract = web3Context.contract;
        const transaction = await contract.mint(count, {
          value: ethers.utils.parseEther((Number(price) * count).toString()),
        });
        toast.promise(transaction.wait(), {
          pending: "Minting in progress ⛏️",
          success: "NFT Minted 👌",
          error: "Transaction rejected 🚫",
        });
        await transaction.wait();
        contract.on("Transfer", (tokenId) => {
          console.log(tokenId);
        });
      } catch (e: any) {
        console.log(e);
        toast.error("Transaction rejected 🚫");
      }
  }

The minting is going well, but nothing is logged into the console, like if the contract.on method was not triggered.

Any idea ? Thanks

2 Answers 2

1

I believe the reason is that contract.on starts when the transaction is already mined. You can try writing contract.on before making the transaction, and a contract.off after you get your event.

However, there's a better way that doesn't include making a listener. You can pick up the event from the receipt of the transaction:

const receipt = await transaction.wait();
console.log(receipt.logs)

This should show all events from the transaction, then you can filter for your Transfer -> tokenId, like this:

const transferEventId = ethers.utils.id("Transfer(address,address,uint256)")

for (let i=0; i<receipt.logs.length; i++) {
    if (receipt.logs[i].address.toLowerCase() == contract.address.toLowerCase()) {
        if (receipt.logs[i].topics[0] == transferEventId) {
            const tokenId = BigNumber.from(receipt.logs[i].topics[3]).toString()
            console.log(tokenId)
        }
    }
}
4
  • Thanks. I do get the events as an array of objects, each containing hashes & block number. How should I filter that afterwards ?
    – Matos2802
    Dec 21, 2022 at 17:01
  • @Matos2802 I've edited the answer to show how :)
    – 0xSanson
    Dec 21, 2022 at 18:48
  • Ok thanks. Did you see my reply bellow too ? It's working the way I wanted, with way less code. What do you think ?
    – Matos2802
    Dec 22, 2022 at 7:41
  • @Matos2802 If it works it works. You're giving some load to your RPC node provider though. Also maybe using contract.once is better than contract.on in your case (docs.ethers.org/v5/api/contract/contract/#Contract-once) so you're freeing some resources at the end.
    – 0xSanson
    Dec 22, 2022 at 11:38
0

I found the solution. Code was almost good, just positionning the event listener before the await transaction.wait(); and giving to the callback params all the event params (not only tokenId) worked as excepted.

  contract.on("Transfer", (form, to, tokenId) => {
          console.log(tokenId);
        });
        await transaction.wait();

Result, for tokenId #15 is BigNumber {_hex: '0x0f', _isBigNumber: true}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.