I am engaged on a venture to work together with an ERC721 contract by means of a Node.js backend utilizing ethers.js. The contract permits minting collectible playing cards (NFTs). Right here’s an outline of my setup:
Principal.sol file:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/entry/Ownable.sol";
contract Principal is ERC721, Ownable {
uint256 public nextTokenId;
mapping(uint256 => string) personal _tokenURIs;
constructor() ERC721("PokemonNFT", "PKMN") {
nextTokenId = 1;
}
operate mintCard(uint256 collectionId, handle to, string reminiscence tokenURI) public onlyOwner {
uint256 tokenId = nextTokenId;
_safeMint(to, tokenId);
_setTokenURI(tokenId, tokenURI);
nextTokenId += 1;
}
operate tokenURI(uint256 tokenId) public view digital override returns (string reminiscence) {
require(_exists(tokenId), "ERC721Metadata: URI question for nonexistent token");
return _tokenURIs[tokenId];
}
operate _setTokenURI(uint256 tokenId, string reminiscence _tokenURI) inside {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
}
Node.js Script (index.js):
require('dotenv').config();
const categorical = require('categorical');
const { ethers } = require('ethers');
const app = categorical();
const port = 3000;
// Contract data
const CONTRACT_ADDRESS = 'contract handle';
const ABI = [
{
"inputs": [],
"stateMutability": "nonpayable",
"kind": "constructor"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "collectionId",
"type": "uint256"
},
{
"internalType": "address",
"name": "walletAddress",
"type": "address"
},
{
"internalType": "string",
"name": "tokenURI",
"type": "string"
}
],
"identify": "mintCard",
"outputs": [],
"stateMutability": "nonpayable",
"kind": "operate"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"identify": "tokenURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"kind": "operate"
}
];
// Arrange supplier and signer
const supplier = new ethers.suppliers.JsonRpcProvider('http://127.0.0.1:8545');
const walletPrivateKey = 'walletkey';
const signer = new ethers.Pockets(walletPrivateKey, supplier); // Create signer
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer); // Join contract to signer
// Minting API endpoint
app.get('/mint/:collectionId/:walletAddress/:tokenURI', async (req, res) => {
const { collectionId, walletAddress, tokenURI } = req.params;
strive {
const tx = await contract.mintCard(collectionId, walletAddress, tokenURI);
await tx.wait(); // Look forward to the transaction to be confirmed
res.standing(200).json({ success: true, transactionHash: tx.hash });
} catch (error) {
console.error(error);
res.standing(500).json({ success: false, message: error.message });
}
});
// API endpoint to get token data
app.get('/nft/:tokenId', async (req, res) => {
const tokenId = req.params.tokenId; // Get tokenId from the request parameters
strive {
const tokenURI = await contract.tokenURI(tokenId); // Name tokenURI operate
res.json({ tokenId, tokenURI }); // Reply with tokenId and tokenURI
} catch (error) {
res.standing(400).json({ error: 'Token not discovered' }); // Deal with error if token is just not discovered
}
});
// Begin the server
app.hear(port, () => {
console.log(`Server is working at http://localhost:${port}`);
});
Drawback:
When I attempt to name the /mint endpoint with this URL:
http://localhost:3000/mint/1/0xYourWalletAddressHere/https://metadata-url
I obtain an error saying :
node index.js
Server is working at http://localhost:3000
<ref *1> Error: can not estimate fuel; transaction could fail or could require guide fuel restrict [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (error={"cause":"Error: Transaction reverted: operate selector was not acknowledged and there is not any fallback operate","code":"UNPREDICTABLE_GAS_LIMIT","technique":"estimateGas","transaction":{"from":"Mywalletaddress","maxPriorityFeePerGas":{"kind":"BigNumber","hex":"0x59682f00"},"maxFeePerGas":{"kind":"BigNumber","hex":"0xc1b71080"},"to":"contractaddress","information":"0xf2afa53c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b8d4736382c43a4ea117af8f57ed95823d42c6c0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000003b68747470733a2f2f74636772657075626c69632e636f6d2f6d656469612f62696e6172792f3030302f3530302f3233382f3530303233382e6a70670000000000","kind":2,"accessList":null},"error":{"cause":"processing response error","code":"SERVER_ERROR","physique":"{"jsonrpc":"2.0","id":49,"error":{"code":-32603,"message":"Error: Transaction reverted: operate selector was not acknowledged and there is not any fallback operate","information":{"message":"Error: Transaction reverted: operate selector was not acknowledged and there is not any fallback operate","information":"0x"}}}","error":{"code":-32603,"information":{"message":"Error: Transaction reverted: operate selector was not acknowledged and there is not any fallback operate","information":"0x"}},"requestBody":"{"technique":"eth_estimateGas","params":[{"type":"0x2","maxFeePerGas":"0xc1b71080","maxPriorityFeePerGas":"0x59682f00","from":"walletaddress","to":"contreactaddress","data":"0xf2afa53c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b8d4736382c43a4ea117af8f57ed95823d42c6c0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000003b68747470733a2f2f74636772657075626c69632e636f6d2f6d656469612f62696e6172792f3030302f3530302f3233382f3530303233382e6a70670000000000"}],"id":49,"jsonrpc":"2.0"}","requestMethod":"POST","url":"http://127.0.0.1:8545"}}, tx={"information":"0xf2afa53c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b8d4736382c43a4ea117af8f57ed95823d42c6c0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000003b68747470733a2f2f74636772657075626c69632e636f6d2f6d656469612f62696e6172792f3030302f3530302f3233382f3530303233382e6a70670000000000","to":{},"from":"0x7b8D4736382c43A4eA117AF8F57eD95823d42c6C","kind":2,"maxFeePerGas":{"kind":"BigNumber","hex":"0xc1b71080"},"maxPriorityFeePerGas":{"kind":"BigNumber","hex":"0x59682f00"},"nonce":{},"gasLimit":{},"chainId":{}}, code=UNPREDICTABLE_GAS_LIMIT, model=abstract-signer/5.7.0)
at Logger.makeError (/residence/kali/collectible-card-game-daar/node_modules/@ethersproject/logger/lib/index.js:238:21)
at Logger.throwError (/residence/kali/collectible-card-game-daar/node_modules/@ethersproject/logger/lib/index.js:247:20)
at /residence/kali/collectible-card-game-daar/node_modules/@ethersproject/abstract-signer/lib/index.js:365:47
at course of.processTicksAndRejections (node:inside/course of/task_queues:105:5)
at async Promise.all (index 7) {
cause: 'can not estimate fuel; transaction could fail or could require guide fuel restrict',
code: 'UNPREDICTABLE_GAS_LIMIT',
error: Error: can not estimate fuel; transaction could fail or could require guide fuel restrict [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (cause="Error: Transaction reverted: operate selector was not acknowledged and there is not any fallback operate", technique="estimateGas", transaction={"from":"walletadress","maxPriorityFeePerGas":{"kind":"BigNumber","hex":"0x59682f00"},"maxFeePerGas":{"kind":"BigNumber","hex":"0xc1b71080"},"to":"contractaddress","information":"0xf2afa53c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b8
I even have a deployement script that include this code”└─$
cat 000001-deploy-game.ts
import 'dotenv/config'
import { DeployFunction } from 'hardhat-deploy/sorts'
const deployer: DeployFunction = async hre => {
if (hre.community.config.chainId !== 31337) return
const { deployer } = await hre.getNamedAccounts()
await hre.deployments.deploy('Principal', { from: deployer, log: true })
}
export default deployer
and an artifcat? json script with”
──(kali㉿kali)-[~/collectible-card-game-daar/contracts/deployments/localhost]
└─$ cat Principal.json
{
"handle": "contractaddress",
"abi": [
{
"inputs": [],
"stateMutability": "nonpayable",
"kind": "constructor"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "int256",
"name": "cardCount",
"type": "int256"
}
],
"identify": "createCollection",
"outputs": [],
"stateMutability": "nonpayable",
"kind": "operate"
}
],
"transactionHash": "0xcd0a1ec8b116b46b2f3c16f8148fc567ab98e37d9a438b700574d80136d95c79",
"receipt": {
"to": null,
"from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"contractAddress": "contractaddress",
"transactionIndex": 0,
"gasUsed": "706710",
”
and one other important.json with: ┌──(kali㉿kali)-[~/…/contracts/artifacts/src/Main.sol]
└─$ cat Principal.json
{
"_format": "hh-sol-artifact-1",
"contractName": "Principal",
"sourceName": "src/Principal.sol",
"abi": [
{
"inputs": [],
"stateMutability": "nonpayable",
"kind": "constructor"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "int256",
"name": "cardCount",
"type": "int256"
}
],
"identify": "createCollection",
"outputs": [],
"stateMutability": "nonpayable",
"kind": "operate"
}
],
I am unsure what i am doing flawed i am completely new to this and I need assistance, thanks.