-
Notifications
You must be signed in to change notification settings - Fork 60
Open
Description
Hello, I was rewriting my contract and came across with this issue.
useNft seems to be requesting a uri method which isn't present in ERC721 storage and this results in an error.
Reproduction
Here's the contract code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "hardhat/console.sol";
contract MyNFT is ERC721, Ownable, ERC721URIStorage {
event Mint(uint256 id);
event Claim(uint256 id);
uint256 public constant MAX_TOKENS = 50;
uint256 private constant PRICE = 50000000000000000;
using SafeMath for uint256;
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721("MyNFT", "MNFT") {}
function _burn(uint256 tokenId)
internal
override(ERC721, ERC721URIStorage)
{
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
// Mint an NFT and add URI to it
function mint(string memory tokenURI_) public onlyOwner returns (uint256) {
_tokenIds.increment();
uint256 tokenId = _tokenIds.current();
_safeMint(msg.sender, tokenId);
require(tokenId <= MAX_TOKENS, "Sold out!");
console.log(tokenId);
_setTokenURI(tokenId, tokenURI_);
return tokenId;
}
// Claim and mint NFT
function claim(uint256 id) external payable {
require(msg.value == PRICE, "Claiming an NFT costs 0.05 ETH");
require(id <= MAX_TOKENS, "Cannot claim non-existent token");
// Transfer to seller
safeTransferFrom(address(this), msg.sender, id);
emit Claim(id);
}
// withdraw bobux
function withdraw() public onlyOwner {
uint256 balance = address(this).balance;
payable(msg.sender).transfer(balance);
}
function transferTo(address acc, uint256 id) public onlyOwner {
safeTransferFrom(msg.sender, acc, id);
}
}Dapp code:
import React, { useEffect } from 'react'
import { Contract, utils } from 'ethers'
import { useOnboard } from 'use-onboard'
import { useNft, NftProvider } from 'use-nft'
const contractAddress = 'COPY_ADDRESS_FROM_HARDHAT_DEPLOY_SCRIPT'
function NFT() {
const { loading, error, nft } = useNft(contractAddress, '1')
console.log(nft)
// nft.loading is true during load.
if (loading) return <>Loading…</>
// nft.error is an Error instance in case of error.
if (error || !nft) return <>{error.message}</>
// You can now display the NFT metadata.
return (
<section>
<h1>{nft.name}</h1>
<img src={nft.image} alt="" />
<p>{nft.description}</p>
<p>Owner: {nft.owner}</p>
<p>Metadata URL: {nft.metadataUrl}</p>
</section>
)
}
const App = () => {
const { selectWallet, address, isWalletSelected, disconnectWallet, balance, provider } = useOnboard({
options: {
networkId: 1337,
networkName: 'localhost'
}
})
return (
<div>
{
<button
onClick={async () => {
if (isWalletSelected) disconnectWallet()
else await selectWallet()
}}
>
{isWalletSelected ? 'Disconnect' : 'Connect'}
</button>
}
<p>Address: {address}</p>
<p>Balance: {balance} ETH</p>
{isWalletSelected && provider && (
<NftProvider
fetcher={[
'ethers',
{
ethers: { Contract },
provider
}
]}
>
<NFT />
</NftProvider>
)}
</div>
)
}
export default AppThe error I see:
eth_call
Contract call: MyNFT#<unrecognized-selector>
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
To: 0x2e13f7644014f6e934e314f0371585845de7b986
Error: Transaction reverted: function selector was not recognized and there's no fallback function
Workaround
I came up with this function to fetch NFTs:
async function fetchNFTs(provider: Web3Provider, address: string) {
const signer = provider.getSigner()
const account = await signer.getAddress()
const contract = new Contract(contractAddress, abi, provider)
const balance = await contract.balanceOf(account)
console.log(balance.toNumber())
const data = []
for (let i = 0; i < balance.toNumber(); ++i) {
let tokenURI = await contract.tokenURI(1)
data.push(tokenURI)
}
return data
}Metadata
Metadata
Assignees
Labels
No labels