Search code examples
solidityhardhat

Solidity HardHat testing NFT transfer


I'd like to test the deployment, minting and transfer of an NFT in hardhat.

Here's my test code:

describe("Receiving NFT", function () {
    it("Should emit a received NFT event", async function () {
      const { bridge, owner, otherAccount } = await loadFixture(deployFixture);
      const { token, owner: tokenContractOwner } = await loadFixture(deployMockNFTFixture);

      await token.connect(otherAccount.address)
      await token.mint(otherAccount.address)
      console.log(await token.balanceOf(otherAccount.address));
      console.log(await token.ownerOf(1));

      console.log("bridge.target: ", bridge.target)
      console.log("owner.address: ", owner.address)

      await token.connect(otherAccount.address)
      await token.transferFrom(otherAccount.address, bridge.target, 1);
      
      console.log(await token.balanceOf(bridge.target));
      console.log(await token.ownerOf(1));

      // console.log(await token.ownerOf(1));
      // await expect() 
      // .to.emit(bridge, "ReceivedNFT");
      // .withArgs(lockedAmount, anyValue);
    })
  })
})

The transferFrom line fails with error: Error: VM Exception while processing transaction: reverted with reason string 'ERC721: caller is not token owner or approved'

I added logs in the code and these are the logs:

1n
otherAccount.address: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8
bridge.target:  0x5FbDB2315678afecb367f032d93F642f64180aa3
owner.address:  0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
msg.sender:  0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266

The msg.sender of when transferFrom is executed is the owner.address of the owner who deployed both the contracts. Even though I use await token.connect(otherAccount.address) to switch the msg.sender to the otherAccount.

How do I execute the transferFrom from the otherAccount ?

I've minted the NFT to the otherAccount and need to transfer it to the bridge contract. Thanks.

EDIT: I've added an approval step:

await token.connect(otherAccount.address)
await token.approve(bridge.target, 1)
await token.transferFrom(otherAccount.address, bridge.target, 1);

However, I still get an error which is: Error: VM Exception while processing transaction: reverted with reason string 'ERC721: approve caller is not token owner or approved for all'

For some reason, the msg.sender is 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, the contract deployer, despite doing token.connect(otherAccount.address)...


Solution

  • I noticed that despite doing a .connect to change the msg.sender to the otherAccount, Hardhat was still showing the msg.sender as the owner.address (the address that deployed both contracts), so as a workaround, I minted the nft from the owner address and approved and transfered from the owner address and the test worked.

    it("Should emit a received NFT event", async function () {
          const { bridge, owner } = await loadFixture(deployFixture);
          const { token } = await loadFixture(deployMockNFTFixture);
    
          // await token.connect(otherAccount.address)
          await token.mint(owner.address)
          console.log(await token.balanceOf(owner.address));
          console.log(await token.ownerOf(1));
    
          console.log("bridge.target: ", bridge.target)
          console.log("owner.address: ", owner.address)
    
          // await token.connect(otherAccount.address)
          await token.approve(bridge.target, 1)
    
          
          console.log(await token.balanceOf(bridge.target));
          console.log(await token.ownerOf(1));
    
          expect(await token.transferFrom(owner.address, bridge.target, 1)) 
          .to.emit(bridge, "ReceivedNFT");
        })