27

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);
Jasperan
  • 2,154
  • 1
  • 16
  • 40
Lightstorm
  • 379
  • 4
  • 5
  • Can you share the ABI? And if the contract is deployed on a public network, it's address as well? – Petr Hejda Jul 07 '21 at 16:34
  • ABI: https://pastebin.com/HY8JhzHm I deployed it on local hardhat blockchain. – Lightstorm Jul 07 '21 at 17:13
  • 1
    Ok thanks. The ABI seems fine. Can you also share the JS snippet executing the `safeTransferFrom` that throws the error? – Petr Hejda Jul 07 '21 at 17:57
  • Thanks for the help. Here is a function test script: https://pastebin.com/UWVSuBrM – Lightstorm Jul 08 '21 at 00:48
  • @PetrHejda Thank you. The problem is solved. I updated the post :) – Lightstorm Jul 08 '21 at 18:41
  • If needing to connect to a signer object, syntax is as follows: `await instance.connect(secondUser)['safeTransferFrom(address,address,uint256)'](owner.address, secondUser.address, 2);` – nolanjacobson Oct 29 '21 at 10:40
  • 1
    @Lightstorm you should add your findings as an answer instead of a question update – Jasperan Feb 12 '22 at 21:25
  • To elaborate further, the reason why it is an overloaded function is because when you look at https://docs.openzeppelin.com/contracts/4.x/api/token/erc721#ERC721 there are two safeTransferFrom functions. Hence, a different way of calling it via ethers.js – jmsandiegoo Feb 20 '22 at 08:38

3 Answers3

19

(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);

thatguyintech
  • 501
  • 3
  • 14
  • 1
    await contract.connect(user1)["safeTransferFrom(address,address,uint256,bytes)"](user1Addr, user2Addr, tokenId1, "0x"); – Russo Jul 06 '22 at 12:27
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)

Pang
  • 9,564
  • 146
  • 81
  • 122
chia yongkang
  • 786
  • 10
  • 20
0
contract[""](address_one , address_two ,uint_)
alsayadi
  • 17
  • 1
  • 4
  • 2
    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? – Jeremy Caney Apr 16 '22 at 00:40