How to call Openzeppelin safeTransferFrom() function with Royalty to avoid error, ERC721: owner query for nonexistent token? - blockchain

I am creating a smart contract using Openzeppelin NFT standard and code copied from Tatum, where the safeTransferFrom function looks like this,
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata dataBytes
) public payable virtual override {
uint256 index;
uint256 value; // price 1000 matic
uint256 percentSum;
IERC20 token;
(index, value) = _bytesCheck(dataBytes);
// return error if token id is odd
if (tokenId % 2 == 1) {
//if block time is earlier than 2023 march 1 timestamp
if (block.timestamp < 1677628800) {
revert("You have to wait until 2023 March 1 to mint this token");
}
}
if (_customToken[tokenId] != address(0)) {
token = IERC20(_customToken[tokenId]);
}
if (_cashbackRecipients[tokenId].length > 0) {
for (uint256 i = 0; i < _cashbackValues[tokenId].length; i++) {
uint256 iPercent = (_cashbackValues[tokenId][i] * value) /
10000;
if (iPercent >= _fixedValues[tokenId][i]) {
percentSum += iPercent;
} else {
percentSum += _fixedValues[tokenId][i];
}
}
if (_customToken[tokenId] == address(0)) {
if (percentSum > msg.value) {
payable(from).transfer(msg.value);
revert(
"Value should be greater than or equal to cashback value"
);
}
} else {
if (percentSum > token.allowance(to, address(this))) {
revert(
"Insufficient ERC20 allowance balance for paying for the asset."
);
}
}
for (uint256 i = 0; i < _cashbackRecipients[tokenId].length; i++) {
// transferring cashback to authors
uint256 cbvalue = (_cashbackValues[tokenId][i] * value) / 10000;
if (_customToken[tokenId] == address(0)) {
cbvalue = _cashbackCalculator(
cbvalue,
_fixedValues[tokenId][i]
);
payable(_cashbackRecipients[tokenId][i]).transfer(cbvalue);
} else {
cbvalue = _cashbackCalculator(
cbvalue,
_fixedValues[tokenId][i]
);
token.transferFrom(
to,
_cashbackRecipients[tokenId][i],
cbvalue
);
}
}
if (_customToken[tokenId] != address(0) && msg.value > 0) {
payable(from).transfer(msg.value);
}
if (_customToken[tokenId] == address(0) && msg.value > percentSum) {
payable(from).transfer(msg.value - percentSum);
}
}
_safeTransfer(from, to, tokenId, dataBytes);
string calldata dataString = string(dataBytes);
_appendTokenData(tokenId, dataString);
emit TransferWithProvenance(tokenId, to, dataString[:index], value);
}
It pays royalty using the ERC721 standard. I am calling this function like this,
import { ethers } from "hardhat";
const contractAddressRoyalty = "0x1903344651b356ce3b755458008c0fe74f8cc1c9";
const trans = async () => {
const CannesRoyalty = await ethers.getContractAt(
"Cant",
contractAddressRoyalty
);
const name = await CannesRoyalty.symbol();
// // transfer
const safeTransferFrom = await CantRoyalty[
"safeTransferFrom(address,address,uint256)"
](
"0x888a7E4DAE1d9009694dEdf240F976EC498D7D90",
"0x7542A9d09589B21b5a671e14254318D2016A0A0c",
4,
{
from: "0x888a7E4DAE1d9009694dEdf240F976EC498D7D90",
gasLimit: 2000000,
gasPrice: ethers.utils.parseUnits("10", "gwei"),
value: ethers.utils.parseEther("0"),
}
);
console.log(safeTransferFrom);
console.log(name);
};
trans();
I am getting this error, https://mumbai.polygonscan.com/tx/0xdefbb122ab45bb85c29ffda0a14b61b77564f2748ece65f87067e24b4624cfd5
Message -
Fail with error 'ERC721: owner query for nonexistent token'
But the token is minted. I have also approved. I don't know if I am messing up the input values. I have tried tokenId, 4 and "4". But seems no luck.

It appears the token you're trying to transfer is 'nonexistent'. This usually means that it wasn't minted yet. Can you verify if the tokenId 4 returns anything when you call the public function tokenUri with tokenId 4?

Related

Gas estimation errored with the following message (see below). The transaction execution will likely fail REMIX - Multisignature

I have this contract that when I try to deploy it with Fuji it sends me the gasLimit error and when I do it from Remix it returns the error description Gas estimation errored with the following message (see below). The transaction execution will likely fail. I leave my contract so you can understand it better. Thanks in advance
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
contract MultiSig {
address[] public owners;
uint public transactionCount;
uint public required;
event Confirmation(address indexed sender, uint indexed transactionId);
event Submission(uint indexed transactionId);
event Execution(uint indexed transactionId);
event Deposit(address indexed sender, uint value);
struct Transaction {
address payable destination;
uint value;
bool executed;
bytes data;
}`enter code here`
mapping(uint => Transaction) public transactions;
mapping(uint => mapping(address => bool)) public confirmations;
receive() payable external {
emit Deposit(msg.sender, msg.value);
}
function getOwners() view public returns(address[] memory) {
return owners;
}
function getTransactionIds(bool pending, bool executed) view public returns(uint[] memory) {
uint count = getTransactionCount(pending, executed);
uint[] memory txIds = new uint[](count);
uint runningCount = 0;
for(uint i = 0; i < transactionCount; i++) {
if(pending && !transactions[i].executed ||
executed && transactions[i].executed) {
txIds[runningCount] = i;
runningCount++;
}
}
return txIds;
}
function getTransactionCount(bool pending, bool executed) view public returns(uint) {
uint count = 0;
for(uint i = 0; i < transactionCount; i++) {
if(pending && !transactions[i].executed ||
executed && transactions[i].executed) {
count++;
}
}
return count;
}
function executeTransaction(uint transactionId) public {
require(isConfirmed(transactionId));
emit Execution(transactionId);
Transaction storage _tx = transactions[transactionId];
(bool success, ) = _tx.destination.call{ value: _tx.value }(_tx.data);
require(success, "Failed to execute transaction");
_tx.executed = true;
}
function isConfirmed(uint transactionId) public view returns(bool) {
return getConfirmationsCount(transactionId) >= required;
}
function getConfirmationsCount(uint transactionId) public view returns(uint) {
uint count;
for(uint i = 0; i < owners.length; i++) {
if(confirmations[transactionId][owners[i]]) {
count++;
}
}
return count;
}
function getConfirmations(uint transactionId) public view returns(address[] memory) {
address[] memory confirmed = new address[](getConfirmationsCount(transactionId));
uint runningConfirmed;
for(uint i = 0; i < owners.length; i++) {
if(confirmations[transactionId][owners[i]]) {
confirmed[runningConfirmed] = owners[i];
runningConfirmed++;
}
}
return confirmed;
}
function isOwner(address addr) private view returns(bool) {
for(uint i = 0; i < owners.length; i++) {
if(owners[i] == addr) {
return true;
}
}
return false;
}
function submitTransaction(address payable dest, uint value, bytes memory data) public {
uint id = addTransaction(dest, value, data);
confirmTransaction(id);
emit Submission(id);
}
function confirmTransaction(uint transactionId) public {
require(isOwner(msg.sender));
emit Confirmation(msg.sender, transactionId);
confirmations[transactionId][msg.sender] = true;
if(isConfirmed(transactionId)) {
executeTransaction(transactionId);
}
}
function addTransaction(address payable destination, uint value, bytes memory data) public returns(uint) {
transactions[transactionCount] = Transaction(destination, value, false, data);
transactionCount += 1;
return transactionCount - 1;
}
constructor(address[] memory _owners, uint _confirmations) {
require(_owners.length > 0);
require(_confirmations > 0);
require(_confirmations <= _owners.length);
owners = _owners;
required = _confirmations;
}
}
When it comes to deploy it only deploys locally with Hardhat correctly. But it increases my fees a lot. And the test passes without problems.
deploy.js
const hre = require("hardhat");
async function main() {
const accounts = await ethers.provider.listAccounts();
const MultiSig = await ethers.getContractFactory("MultiSig");
const multiSig = await MultiSig.deploy(accounts, 2);
await multiSig.deployed();
console.log("MultiSig deployed to:", multiSig.address);
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
hardhat.config.js
require('#nomiclabs/hardhat-ethers');
require('#openzeppelin/hardhat-upgrades');
require("#nomiclabs/hardhat-waffle");
require("dotenv").config()
const FUJI_RPC_URL =
process.env.FUJI_RPC_URL
const PRIVATE_KEY =
process.env.PRIVATE_KEY
const SUBNET_RPC_URL =
process.env.SUBNET_RPC_URL
const PRIVATE_KEY_ADMIN =
process.env.PRIVATE_KEY_ADMIN
module.exports = {
solidity: "0.8.15",
paths: {
artifacts: "./src/backend/artifacts",
sources: "./src/backend/contracts",
cache: "./src/backend/cache",
tests: "./src/backend/test"
},
defaultNetwork: 'hardhat',
networks: {
hardhat: {
chainId: 1337 // We set 1337 to make interacting with MetaMask simpler
},
fuji: {
url: FUJI_RPC_URL,
accounts: PRIVATE_KEY !== undefined ? [PRIVATE_KEY] : [],
},
subnet: {
url: SUBNET_RPC_URL,
accounts: PRIVATE_KEY_ADMIN !== undefined ? [PRIVATE_KEY_ADMIN] : [],
},
},
};
try changing the deployment script to
const hre = require("hardhat");
async function main() {
const accounts = await ethers.getSigners();;
const MultiSig = await ethers.getContractFactory("MultiSig");
const multiSig = await MultiSig.deploy(accounts[0].address, 2);
await multiSig.deployed();
console.log("MultiSig deployed to:", multiSig.address);
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});

Transaction fails when I call the play() function from ethers.js

I am using ethers.js to interact with my smart contract deployed on polygon testnet. I try to call a function play() from the smart contract but it always fails with the error: Error: transaction failed [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ]
I have satisfied all the require statements but it still seems to fail. Is there something wrong with my code?
I have also tried using getRandomNumber() function from of chainlink VRF separately and it works there.
My smart contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;
import "./FutNFTTransfer.sol";
import "./VRFConsumer.sol";
contract FutNFTMatch is FutNFTTransfer, VRFConsumer {
uint256 public levelPercentSuitablePosition;
uint256 public levelPercentNoPosition;
mapping(string => string[]) public formationToPositions;
string[] public formations;
string[] public allPositions;
uint256 public lineupFee = 3 ether;
uint256 public matchFee = 1 ether;
// uint256 public lineupFee = 0.001 ether;
address[] public lineupSet;
modifier playersOwned(uint256[11] memory _playerIds) {
for (uint256 i = 0; i < _playerIds.length; i++) {
require(ownerOf(_playerIds[i]) == msg.sender);
}
_;
}
modifier lineUpSet(address _owner) {
require(lineUps[_owner].isValid, "Linup not set");
_;
}
constructor() {
formations.push("4-3-3");
formationToPositions["4-3-3"] = [
"GK",
"LB",
"CB",
"CB",
"RB",
"CMF",
"CMF",
"CMF",
"LWF",
"ST",
"RWF"
];
formations.push("4-3-3 attack");
formationToPositions["4-3-3 attack"] = [
"GK",
"LB",
"CB",
"CB",
"RB",
"CMF",
"AMF",
"CMF",
"RWF",
"ST",
"LWF"
];
allPositions = [
"LWF",
"ST",
"RWF",
"CF",
"AMF",
"CMF",
"DMF",
"LMF",
"RMF",
"RB",
"LB",
"CB",
"GK"
];
}
function setMatchFee(uint256 _fee) public onlyOwner {
matchFee = _fee;
}
function setLineupFee(uint256 _fee) public onlyOwner {
lineupFee = _fee;
}
function getAllFormations() public view returns (string[] memory) {
return formations;
}
function getLineup(address _owner) public view returns (LineUp memory) {
return lineUps[_owner];
}
function addFormation(string memory formation, string[] memory positions)
public
onlyOwner
{
formationToPositions[formation] = positions;
formations.push(formation);
}
function getPositionsFromFormation(string memory formation)
public
view
returns (string[] memory)
{
return formationToPositions[formation];
}
function getAllPositions() public view returns (string[] memory) {
return allPositions;
}
function setLevelPercentSuitablePosition(uint256 _percent)
public
onlyOwner
{
levelPercentSuitablePosition = _percent;
}
function setLevelPercentNoPosition(uint256 _percent) public onlyOwner {
levelPercentNoPosition = _percent;
}
function setLineUp(
uint256[11] memory _playerIds,
string[11] memory _positions,
string memory _formation
) external payable playersOwned(_playerIds) returns (uint256) {
require(msg.value == lineupFee, "Required fee not sent!");
lineUps[msg.sender] = LineUp(_playerIds, _positions, _formation, true);
lineupSet.push(msg.sender);
return _getTeamRating(msg.sender);
}
function _getTeamRating(address _owner)
internal
view
lineUpSet(_owner)
returns (uint256)
{
LineUp memory lineup = lineUps[_owner];
uint256 sum;
uint256 count;
for (uint256 i = 0; i < lineup.playerIds.length; i++) {
sum += _getPlayerLevel(lineup, i);
count++;
}
return sum / count;
}
function _getPlayerLevel(LineUp memory _lineup, uint256 _arrayPosition)
internal
view
returns (uint256)
{
Player memory player = super.getPlayer(
_lineup.playerIds[_arrayPosition]
);
string memory position = _lineup.positions[_arrayPosition];
uint256 level;
if (
keccak256(abi.encodePacked(player.preferredPosition)) ==
keccak256(abi.encodePacked(position))
) {
level = player.level;
} else {
level = _getPlayerLevelForUnpreferredPosition(player, position);
}
return level;
}
function _getPlayerLevelForUnpreferredPosition(
Player memory _player,
string memory _position
) internal view returns (uint256) {
uint256 level = (_player.level * levelPercentNoPosition) / 100;
for (uint256 k = 0; k < _player.suitablePositions.length; k++) {
if (
keccak256(abi.encodePacked(_player.suitablePositions[k])) ==
keccak256(abi.encodePacked(_position))
) {
level = (_player.level * levelPercentSuitablePosition) / 100;
break;
}
}
return level;
}
function getOpponent() public lineUpSet(msg.sender) returns(address) {
require(lineupSet.length > 1, "Players not available!");
getRandomNumber();
randomResult = (randomResult % lineupSet.length) + 1;
address opponent = lineupSet[randomResult - 1];
if(msg.sender == opponent) {
if(randomResult == lineupSet.length) {
opponent = lineupSet[randomResult - 2];
} else {
opponent = lineupSet[randomResult];
}
}
return opponent;
}
function play()
external
payable
lineUpSet(msg.sender)
{
require(msg.value == matchFee, "Required fee not sent!");
address _opponent = getOpponent();
uint256 teamRating = _getTeamRating(msg.sender);
uint256 opponentTeamRating = _getTeamRating(_opponent);
uint256 winProbability = 50;
if (teamRating > opponentTeamRating) {
winProbability = 50 + ((teamRating - opponentTeamRating) * 3);
} else {
winProbability = 50 - ((opponentTeamRating - teamRating) * 3);
}
getRandomNumber();
randomResult = (randomResult % 100) + 1;
address payable winner;
if (randomResult <= winProbability) {
ownerHistory[msg.sender].winCount++;
ownerHistory[_opponent].lossCount++;
winner = payable(msg.sender);
} else {
ownerHistory[msg.sender].lossCount++;
ownerHistory[_opponent].winCount++;
winner = payable(_opponent);
}
(bool sent, ) = winner.call{
value: /*0.0015*/
4.5 ether
}("");
require(sent, "Could not complete transaction!");
}
}
my frontend code:
const provider = new ethers.providers.Web3Provider(
(window as any).ethereum
);
const signer = provider.getSigner();
const matchFee = await this.props.futNFTMatch.matchFee();
const tx = await this.props.futNFTMatch
.connect(signer)
.play({
value: matchFee,
gasLimit: 1000000,
gasPrice: 30000000000,
});
await tx.wait();
Your transaction was reverted due to insufficient gas:
Warning! Error encountered during contract execution [out of gas]
Try removing gas and gasPrice fields from your call or increasing

I get Metamask RPC error when I try to call the play() function in my smart contract

I get this error when I try to call play() function from my smart contract using ethers.js:
MetaMask - RPC Error: Internal JSON-RPC error.
{code: -32603, message: 'Internal JSON-RPC error.', data: {…}}
code: -32603
data:
code: 3
data: "0x4e487b710000000000000000000000000000000000000000000000000000000000000032"
message: "execution reverted"
message: "Internal JSON-RPC error."
my smart contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;
import "./FutNFTTransfer.sol";
import "./VRFConsumer.sol";
contract FutNFTMatch is FutNFTTransfer, VRFConsumer {
uint256 public levelPercentSuitablePosition = 75;
uint256 public levelPercentNoPosition = 50;
mapping(string => string[]) public formationToPositions;
string[] public formations;
string[] public allPositions;
uint256 public lineupFee = 0.2 ether;
uint256 public matchFee = 3 ether;
address[] public lineupSet;
mapping(address => uint256) public ownersToDeposits;
modifier playersOwned(uint256[11] memory _playerIds) {
for (uint256 i = 0; i < _playerIds.length; i++) {
require(ownerOf(_playerIds[i]) == msg.sender, "Players not owned!");
}
_;
}
modifier lineUpSet(address _owner) {
require(lineUps[_owner].isValid, "Linup not set");
_;
}
constructor() {
formations.push("4-3-3");
formationToPositions["4-3-3"] = [
"GK",
"LB",
"CB",
"CB",
"RB",
"CMF",
"CMF",
"CMF",
"LWF",
"ST",
"RWF"
];
formations.push("4-3-3 attack");
formationToPositions["4-3-3 attack"] = [
"GK",
"LB",
"CB",
"CB",
"RB",
"CMF",
"AMF",
"CMF",
"RWF",
"ST",
"LWF"
];
allPositions = [
"LWF",
"ST",
"RWF",
"CF",
"AMF",
"CMF",
"DMF",
"LMF",
"RMF",
"RB",
"LB",
"CB",
"GK"
];
}
function setMatchFee(uint256 _fee) public onlyOwner {
matchFee = _fee;
}
function setLineupFee(uint256 _fee) public onlyOwner {
lineupFee = _fee;
}
function getAllFormations() public view returns (string[] memory) {
return formations;
}
function getLineup(address _owner) public view returns (LineUp memory) {
return lineUps[_owner];
}
function deposit() public payable lineUpSet(msg.sender) {
require(msg.value >= 1 ether, "Not enough funds sent!");
ownersToDeposits[msg.sender] += msg.value;
if (ownersToDeposits[msg.sender] < 2 ether) {
lineupSet.push(msg.sender);
}
}
function _removeFromLineupSet(address _owner) internal {
address[] memory newLineupSet;
uint256 subFromIndex = 0;
for (uint256 i = 0; i < lineupSet.length; i++) {
if (lineupSet[i] != _owner) {
newLineupSet[i - subFromIndex] = lineupSet[i];
} else {
subFromIndex++;
}
}
lineupSet = newLineupSet;
}
function withdrawDeposit(uint256 _price) public payable {
require(
ownersToDeposits[msg.sender] >= _price,
"Enough funds not deposited!"
);
address to = payable(msg.sender);
(bool sent, ) = to.call{value: _price}("");
ownersToDeposits[msg.sender] -= _price;
require(sent, "Could not complete the transaction");
if (ownersToDeposits[msg.sender] < 1 ether) {
_removeFromLineupSet(msg.sender);
}
}
function addFormation(string memory formation, string[] memory positions)
public
onlyOwner
{
formationToPositions[formation] = positions;
formations.push(formation);
}
function getPositionsFromFormation(string memory formation)
public
view
returns (string[] memory)
{
return formationToPositions[formation];
}
function getAllPositions() public view returns (string[] memory) {
return allPositions;
}
function setLevelPercentSuitablePosition(uint256 _percent)
public
onlyOwner
{
levelPercentSuitablePosition = _percent;
}
function setLevelPercentNoPosition(uint256 _percent) public onlyOwner {
levelPercentNoPosition = _percent;
}
function setLineUp(
uint256[11] memory _playerIds,
string[11] memory _positions,
string memory _formation
) external payable playersOwned(_playerIds) returns (uint256) {
require(msg.value == lineupFee, "Required fee not sent!");
lineUps[msg.sender] = LineUp(_playerIds, _positions, _formation, true);
return getTeamRating(msg.sender);
}
function getTeamRating(address _owner)
public
view
lineUpSet(_owner)
returns (uint256)
{
LineUp memory lineup = lineUps[_owner];
uint256 sum;
uint256 count;
for (uint256 i = 0; i < lineup.playerIds.length; i++) {
sum += _getPlayerLevel(lineup, i);
count++;
}
return sum / count;
}
function _getPlayerLevel(LineUp memory _lineup, uint256 _arrayPosition)
internal
view
returns (uint256)
{
Player memory player = super.getPlayer(
_lineup.playerIds[_arrayPosition]
);
string memory position = _lineup.positions[_arrayPosition];
uint256 level;
if (
keccak256(abi.encodePacked(player.preferredPosition)) ==
keccak256(abi.encodePacked(position))
) {
level = player.level;
} else {
level = _getPlayerLevelForUnpreferredPosition(player, position);
}
return level;
}
function _getPlayerLevelForUnpreferredPosition(
Player memory _player,
string memory _position
) internal view returns (uint256) {
uint256 level = (_player.level * levelPercentNoPosition) / 100;
for (uint256 k = 0; k < _player.suitablePositions.length; k++) {
if (
keccak256(abi.encodePacked(_player.suitablePositions[k])) ==
keccak256(abi.encodePacked(_position))
) {
level = (_player.level * levelPercentSuitablePosition) / 100;
break;
}
}
return level;
}
function getOpponent() public lineUpSet(msg.sender) returns (address) {
require(lineupSet.length > 1, "Players not available!");
getRandomNumber();
randomResult = (randomResult % lineupSet.length) + 1;
address opponent = lineupSet[randomResult - 1];
if (msg.sender == opponent) {
if (randomResult == lineupSet.length) {
opponent = lineupSet[randomResult - 2];
} else {
opponent = lineupSet[randomResult];
}
}
return opponent;
}
function play() external payable lineUpSet(msg.sender) {
require(
ownersToDeposits[msg.sender] >= 1 ether,
"Does not have enough funds in deposits!"
);
address _opponent = getOpponent();
uint256 teamRating = getTeamRating(msg.sender);
uint256 opponentTeamRating = getTeamRating(_opponent);
uint256 winProbability = 50;
if (teamRating > opponentTeamRating) {
winProbability = 50 + ((teamRating - opponentTeamRating) * 3);
} else {
winProbability = 50 - ((opponentTeamRating - teamRating) * 3);
}
getRandomNumber();
randomResult = (randomResult % 100) + 1;
if (randomResult <= winProbability) {
ownerHistory[msg.sender].winCount++;
ownerHistory[_opponent].lossCount++;
ownersToDeposits[_opponent] -= 1 ether;
if (ownersToDeposits[_opponent] < 1 ether) {
_removeFromLineupSet(_opponent);
}
ownersToDeposits[msg.sender] += 0.5 ether;
} else {
ownerHistory[msg.sender].lossCount++;
ownerHistory[_opponent].winCount++;
ownersToDeposits[msg.sender] -= 1 ether;
if (ownersToDeposits[msg.sender] < 1 ether) {
_removeFromLineupSet(msg.sender);
}
ownersToDeposits[_opponent] += 0.5 ether;
}
}
}
my ethers.js code:
const provider: ethers.providers.Web3Provider = new ethers.providers.Web3Provider((window as any).ethereum);
const signer = provider.getSigner();
const matchFee = await this.props.futNFTMatch.matchFee();
const tx = await this.props.futNFTMatch.connect(signer).play();
await tx.wait();
I have satisfied all the require statements, but still I get this error. Is something wrong with my code?
Here are all the contracts if you need them: https://github.com/anim7/FutNFT/tree/master/contracts
Try the following suggestion provided by MetaMask.
ensure the network has been added correctly. You can use Chainlist to add custom network/ tokens
ensure you have enough native tokens from that network to pay for gas
ensure you are using the latest version of the app or the extension

"code": -32000, "message": "execution reverted"

Hello I am trying to deploy a contract using remix.ethereum.org after linked the metamask account using mumbai network.
I receive this error while making the transaction for the contract
Gas estimation errored with the following message (see below). The
transaction execution will likely fail. Do you want to force sending?
Internal JSON-RPC error. { "code": -32000, "message": "execution
reverted" }
status false Transaction mined but execution failed
transaction hash 0x7af5f103024420440aa8c2314bd4a136fa3ce20b2cad325c662205308bb96f19
gas 3000000 gas
transaction cost 677934 gas
hash 0x7af5f103024420440aa8c2314bd4a136fa3ce20b2cad325c662205308bb96f19
[
{
"from": "0x0000000000000000000000000000000000001010",
"data": "0x000000000000000000000000000000000000000000000000000605718620be0000000000000000000000000000000000000000000000000006d23f73843bdd2a000000000000000000000000000000000000000000000812986dea162255c6d300000000000000000000000000000000000000000000000006cc3a01fe1b1f2a0000000000000000000000000000000000000000000008129873ef87a87684d3",
"topics": [
"0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63",
"0x0000000000000000000000000000000000000000000000000000000000001010",
"0x0000000000000000000000002af41d8052ad1dfe56af7ce01beb8918985c94e3",
"0x000000000000000000000000be188d6641e8b680743a4815dfa0f6208038960f"
]
}
]
val 0 wei
Anyone has any idea how to solve it ?
That's the contract :
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "contracts/access/Ownable.sol";
contract Appoles is ERC721Enumerable, Ownable {
using Strings for uint256;
string public baseURI;
string public baseExtension = ".json";
uint256 public cost = 0.004 ether;
uint256 public presaleCost = 0.004 ether;
uint256 public maxSupply = 10;
uint256 public maxMintAmount = 2;
bool public paused = false;
mapping(address => bool) public whitelisted;
mapping(address => bool) public presaleWallets;
constructor(
string memory _name,
string memory _symbol,
string memory _initBaseURI
) ERC721(_name, _symbol) {
setBaseURI(_initBaseURI);
mint(msg.sender, 20);
}
// internal
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
// public
function mint(address _to, uint256 _mintAmount) public payable {
uint256 supply = totalSupply();
require(!paused);
require(_mintAmount > 0);
require(_mintAmount <= maxMintAmount);
require(supply + _mintAmount <= maxSupply);
if (msg.sender != owner()) {
if (whitelisted[msg.sender] != true) {
if (presaleWallets[msg.sender] != true) {
//general public
require(msg.value >= cost * _mintAmount);
} else {
//presale
require(msg.value >= presaleCost * _mintAmount);
}
}
}
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(_to, supply + i);
}
}
function walletOfOwner(address _owner)
public
view
returns (uint256[] memory)
{
uint256 ownerTokenCount = balanceOf(_owner);
uint256[] memory tokenIds = new uint256[](ownerTokenCount);
for (uint256 i; i < ownerTokenCount; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}
return tokenIds;
}
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
require(
_exists(tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
string memory currentBaseURI = _baseURI();
return
bytes(currentBaseURI).length > 0
? string(
abi.encodePacked(
currentBaseURI,
tokenId.toString(),
baseExtension
)
)
: "";
}
//only owner
function setCost(uint256 _newCost) public onlyOwner {
cost = _newCost;
}
function setPresaleCost(uint256 _newCost) public onlyOwner {
presaleCost = _newCost;
}
function setmaxMintAmount(uint256 _newmaxMintAmount) public onlyOwner {
maxMintAmount = _newmaxMintAmount;
}
function setBaseURI(string memory _newBaseURI) public onlyOwner {
baseURI = _newBaseURI;
}
function setBaseExtension(string memory _newBaseExtension)
public
onlyOwner
{
baseExtension = _newBaseExtension;
}
function pause(bool _state) public onlyOwner {
paused = _state;
}
function whitelistUser(address _user) public onlyOwner {
whitelisted[_user] = true;
}
function removeWhitelistUser(address _user) public onlyOwner {
whitelisted[_user] = false;
}
function addPresaleUser(address _user) public onlyOwner {
presaleWallets[_user] = true;
}
function add100PresaleUsers(address[100] memory _users) public onlyOwner {
for (uint256 i = 0; i < 2; i++) {
presaleWallets[_users[i]] = true;
}
}
function removePresaleUser(address _user) public onlyOwner {
presaleWallets[_user] = false;
}
function withdraw() public payable onlyOwner {
(bool success, ) = payable(msg.sender).call{
value: address(this).balance
}("");
require(success);
}
}

Internal JSON-RPC error with MetaMask on Polygon Blockchain. `ERC721: transfer caller is not owner nor approved.`

I am making an NFT marketplace. When I deployed my contract on the Mumbai-testnet. The createToken function might work cause it brings up the Metamask for the Gas Fee but after that, the Error occurs something regarding the ONWNERSHIP.
(Error image and text is present below.)
STEPS which I follow
npm hardhat node
npm run dev
Selecting the Creating Page.
Enter all the details.
Click on Create an Asset which calls the createToken function.
then the error occurs.
Here is my NFT contract
contract NFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
address contractAddress;
constructor(address marketplaceAddress) ERC721("Metaverse Tokens", "METT") {
contractAddress = marketplaceAddress;
}
function createToken(string memory tokenURI) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
setApprovalForAll(contractAddress, true);
return newItemId;
}}
Here is my NFTMarket contract
contract NFTMarket is ReentrancyGuard {
using Counters for Counters.Counter;
Counters.Counter private _itemIds;
Counters.Counter private _itemSold;
address payable owner;
uint256 listingPrice = 0.025 ether; // Here ether is denoting the MATIC
constructor() {
owner = payable(msg.sender);
}
struct MarketItem {
uint256 itemId;
address nftContract;
uint256 tokenId;
address payable seller;
address payable owner;
uint256 price;
bool sold;
}
mapping(uint256 => MarketItem) private idToMarketItem;
event MarketItemCreated(
uint256 indexed itemId,
address indexed nftContract,
uint256 indexed tokenId,
address seller,
address owner,
uint256 price,
bool sold
);
function getListingPrice() public view returns (uint256) {
return listingPrice;
}
//Function to create an NFT
function createMarketItem(
address nftContract,
uint256 tokenId,
uint256 price
) public payable nonReentrant {
//Conditions for creating the Item.
require(price > 0, "Price must be at least 1 wei");
require(
msg.value == listingPrice,
"Price must be equal to listing price"
);
_itemIds.increment();
uint256 itemId = _itemIds.current();
idToMarketItem[itemId] = MarketItem(
itemId,
nftContract,
tokenId,
payable(msg.sender),
payable(address(0)), // When new NFT is created its ownership add is set to 0.
price,
false
);
IERC721(nftContract).transferFrom(msg.sender, address(this), tokenId);
//Trigger the Event
emit MarketItemCreated(
itemId,
nftContract,
tokenId,
msg.sender,
address(0),
price,
false
);
}
//Function to Transfer the Ownership
function createMarketSale(address nftContract, uint256 itemId)
public
payable
nonReentrant
{
uint256 price = idToMarketItem[itemId].price;
uint256 tokenId = idToMarketItem[itemId].tokenId;
require(
msg.value == price,
"Please submit the asking value in order to Purchase"
);
//Will transfer the MATIC to the seller address.
idToMarketItem[itemId].seller.transfer(msg.value);
//Will transfer the ownership from the owner of this contract to the Buyer.
IERC721(nftContract).transferFrom(address(this), msg.sender, tokenId);
//Set the local value of the owner to the Buyer(msg.sender).
idToMarketItem[itemId].owner = payable(msg.sender);
//Set this NFT as sold.
idToMarketItem[itemId].sold = true;
_itemSold.increment();
payable(owner).transfer(listingPrice);
}
//Returns number of items unsold
function fetchMarketItems() public view returns (MarketItem[] memory) {
uint256 itemCount = _itemIds.current();
uint256 unsoldItemCount = _itemIds.current() - _itemSold.current();
uint256 currentIndex = 0;
MarketItem[] memory items = new MarketItem[](unsoldItemCount);
for (uint256 i = 0; i < itemCount; i++) {
if (idToMarketItem[i + 1].owner == address(0)) {
uint256 currentId = idToMarketItem[i + 1].itemId;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
//Returns number of Own(Created or Bought) NFTs
function fetchMyNFTs() public view returns (MarketItem[] memory) {
uint256 totalItemCount = _itemIds.current();
uint256 itemCount = 0;
uint256 currentIndex = 0;
for (uint256 i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint256 i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].owner == msg.sender) {
uint256 currentId = idToMarketItem[i + 1].itemId;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}
//Returns the no of NFT created
function fetchItemsCreated() public view returns (MarketItem[] memory) {
uint256 totalItemCount = _itemIds.current();
uint256 itemCount = 0;
uint256 currentIndex = 0;
for (uint256 i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].seller == msg.sender) {
itemCount += 1;
}
}
MarketItem[] memory items = new MarketItem[](itemCount);
for (uint256 i = 0; i < totalItemCount; i++) {
if (idToMarketItem[i + 1].seller == msg.sender) {
uint256 currentId = idToMarketItem[i + 1].itemId;
MarketItem storage currentItem = idToMarketItem[currentId];
items[currentIndex] = currentItem;
currentIndex += 1;
}
}
return items;
}}
I tried changing the RPC in the MetaMask and the configuration files and redeployed it many times with different accounts, but still, nothing changes.
The Error
MetaMask - RPC Error: Internal JSON-RPC error.
data:
code: 3
message: "execution reverted: ERC721: transfer caller is not owner nor approved"
Image of the console
If any other info is required please comment
Link of Blockchain Explorer
Thank You for your efforts.
I got the solution to it(After Searching for 3 days).
SOLUTION=>
There's currently a bug on Mumbai causing deployed addresses to be incorrect. This is causing the constructor of the NFT contract to approve the wrong address for NFT purchases (because it uses the address of the Market deployment for approval) — causing the annoying "execution reverted: ERC721: approve caller is not owner nor approved for all" error.
Try using Mainnet (yes, you'll have to use real money) but it works!
Reference
Here's a workaround deploy script that will make it work on Mumbai. Replace main() in deploy.js with:
const hre = require("hardhat");
async function main() {
const [deployer] = await hre.ethers.getSigners();
console.log(
"Deploying contracts with the account:",
deployer.address
);
let txHash, txReceipt
const NFTMarket = await hre.ethers.getContractFactory("NFTMarket");
const nftMarket = await NFTMarket.deploy();
await nftMarket.deployed();
txHash = nftMarket.deployTransaction.hash;
txReceipt = await ethers.provider.waitForTransaction(txHash);
let nftMarketAddress = txReceipt.contractAddress
console.log("nftMarket deployed to:", nftMarketAddress);
const NFT = await hre.ethers.getContractFactory("NFT");
const nft = await NFT.deploy(nftMarketAddress);
await nft.deployed();
txHash = nft.deployTransaction.hash;
// console.log(`NFT hash: ${txHash}\nWaiting for transaction to be mined...`);
txReceipt = await ethers.provider.waitForTransaction(txHash);
let nftAddress = txReceipt.contractAddress
console.log("nft deployed to:", nftAddress);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
Redeploy the Contracts with this Script, and change the config.js.
I checked your full code and it is working.
You are inheriting from ERC721URIStorage which inherits from ERC721 If you check the transferFrom inside ERC721:
function transferFrom(address from,address to,uint256 tokenId
) public virtual override {
// ***** THIS REQUIRE IS NOT SATISFIED *****
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
you are getting that error, because require statement inside transferFrom is not satisfied.
this is the _isApprovedOrOwner
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
this function is not returning True. in order to get True, this
spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)
should return True. in or operations in order to get True, 3 of conditions must be True.
In my opinion, you are trying to transfer a token that is not yours.
During development, every time you compile your smart contract (using something like hardhat compile..) , you have to copy the new smart contract addresses generated in your command prompt and paste them in the designated location in your source code.