28

I created a contract instance in hardhat console like so:

const contract_fac = await ethers.getContractFactory("ContractName"); const contract = await contract_fac.attach("CONTRACTADDR..."); 

Contract object has all public/external functions except safeTransferFrom. Why?

When I call it with contract.safeTransferFrom(…) it throws JavaScript Error “safeTransferFrom is not a function”. Is this a bug or do I not understand something? safeTransferFrom function is listed in the ABI.

I use OpenZeppelin (v. 4.2) 721 token template without changes, Ethers.js (v. 5.4.1) and hardhat (v. 2.4.1).

Update: Problem solved. safeTransferFrom is a overloaded function. In ethers, the syntax to call an overloaded contract function is different from the non-overloaded function. Ethers.js doc

Wrong:

contract.safeTransferFrom(addr1, addr2, 1); 

Correct:

contract["safeTransferFrom(address,address,uint256)"](addr1, addr2, 1); 
8
  • Can you share the ABI? And if the contract is deployed on a public network, it's address as well? Commented Jul 7, 2021 at 16:34
  • ABI: pastebin.com/HY8JhzHm I deployed it on local hardhat blockchain. Commented Jul 7, 2021 at 17:13
  • 1
    Ok thanks. The ABI seems fine. Can you also share the JS snippet executing the safeTransferFrom that throws the error? Commented Jul 7, 2021 at 17:57
  • Thanks for the help. Here is a function test script: pastebin.com/UWVSuBrM Commented Jul 8, 2021 at 0:48
  • 1
    @Lightstorm you should add your findings as an answer instead of a question update Commented Feb 12, 2022 at 21:25

3 Answers 3

21

(copying from @Lightstorm's edit for answer clarity)


safeTransferFrom is a overloaded function. In ethers.js, the syntax to call an overloaded contract function is different from the syntax to call a non-overloaded function.

Overloaded functions need to be called by specifying the function signature.

From the ethers.js docs:

// ethers const abi = [ "function getMessage(string) public view returns (string)", "function getMessage() public view returns (string)" ] const contract = new ethers.Contract(address, abi, signer); // for ambiguous functions (two functions with the same // name), the signature must also be specified message = await contract['getMessage(string)']('nice'); 

So for the example in the question:

Wrong:

contract.safeTransferFrom(addr1, addr2, 1);

Correct:

contract["safeTransferFrom(address,address,uint256)"](addr1, addr2, 1);

Sign up to request clarification or add additional context in comments.

1 Comment

await contract.connect(user1)["safeTransferFrom(address,address,uint256,bytes)"](user1Addr, user2Addr, tokenId1, "0x");
3

On hardhat, we face similar issue, due to overloading

Solution:

 // Send NFT to another contract const basicTransferTx = await basicNFTInstance['safeTransferFrom(address,address,uint256)']( owner.address, otherContract.address, 0 // token id ); // syntax is as such due to overloaded function 

keep in mind that it could fail if you have spaces. i.e (address, address, uint256)

1 Comment

@yongknag thank you for mentioning space thing. those little mistakes waste our time a lot
0
contract[""](address_one , address_two ,uint_) 

1 Comment

Remember that Stack Overflow isn't just intended to solve the immediate problem, but also to help future readers find solutions to similar problems, which requires understanding the underlying code. This is especially important for members of our community who are beginners, and not familiar with the syntax. Given that, can you edit your answer to include an explanation of what you're doing and why you believe it is the best approach?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.