i get this error whenever i try to test my code with hardhat
Error: call revert exception; VM Exception while processing transaction: reverted with reason string "ERC721: invalid token ID" [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="tokenURI(uint256)", data="0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000184552433732313a20696e76616c696420746f6b656e2049440000000000000000", errorArgs=["ERC721: invalid token ID"], errorName="Error", errorSignature="Error(string)", reason="ERC721: invalid token ID", code=CALL_EXCEPTION, version=abi/5.6.4)
here is my script-test.js code
where could the error be coming from?
and how can i solve it?
const { expect } = require("chai");
describe("NFTMarket", function (){
it("Should create and execute market sale", async function(){
const Market = await ethers.getContractFactory("NFTMarket")
const market = await Market.deploy();
await market.deployed()
const marketAddress = market.address
const NFT = await ethers.getContractFactory("NFT")
const nft = await NFT.deploy(marketAddress)
await nft.deployed()
const nftContractAddress = nft.address
let listingPrice = await market.getListingPrice()
listingPrice = listingPrice.toString()
const auctionPrice = ethers.utils.parseUnits('100', 'ether')
await nft.createToken("https://www.mytokenlocation.com")
await nft.createToken("https://www.mytokenlocation2.com")
await market.createMarketItem(nftContractAddress, 1, auctionPrice, { value:listingPrice })
await market.createMarketItem(nftContractAddress, 2, auctionPrice, { value:listingPrice })
const [_, buyerAddress] = await ethers.getSigners()
await market.connect(buyerAddress).createMarketSale(nftContractAddress, 1, {value: auctionPrice})
let items = await market.fetchMarketItems()
items = await Promise.all(items.map(async i => {
const tokenUri = await nft.tokenURI(i.tokenId)
let item = {
price: i.price.toString(),
tokenId: i.tokenId.toString(),
seller: i.seller,
owner: i.owner,
tokenUri
}
return item
}))
console.log('items: ', items)
});
});
It looks like you haven't minted the NFT yet. try minting first
Related
am trying to save a data from fetch api to my database using mongoose so
the data never come.
could anyone help? and thank you,
this is my code
`
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/Quran')
const SurahSchema = mongoose.Schema({
ayahs:[{
number:Number,
numberInSurah:Number,
text:String
}],
englishName:String,
englishNameTranslation:String,
name:String,
number:Number,
revelationType:String,
});
var surah = mongoose.model('Surah',SurahSchema)
`
`
const API = 'http://api.alquran.cloud/v1/quran/quran-uthmani'
async function getdata(){
const res = await fetch(API)
const data = await res.json()
for (let i = 0; i < data.data.surahs.length; i++) {
const Surah = new surah({
ayahs:[{
number:data.data.surahs[i]['ayahs'].number,
numberInSurah:data.data.surahs[i]['ayahs'].numberInSurah,
text:data.data.surahs[i]['ayahs'].text
}],
englishName:data.data.surahs[i]['englishName'],
englishNameTranslation:data.data.surahs[i]['englishNameTranslation'],
name:data.data.surahs[i]['name'],
number:data.data.surahs[i]['number'],
revelationType:data.data.surahs[i]['revelationType']
})
Surah.save(function (err) {
if (err) return handleError(err);
// saved!
});
}
}
getdata()
`
i tried to search about the problem in google and i did not find anything similar.
Instead of writing such a complicated for loop, you can just use the .insertMany() method on the model
const API = 'http://api.alquran.cloud/v1/quran/quran-uthmani'
async function getdata(){
const res = await fetch(API);
const data = await res.json();
try{
const inserted = await surah.insertMany(data.data.surahs);
}catch(e){
console.log("Some error");
console.log(e);
}
}
getdata()
the following is a complete working snippet
import mongoose from 'mongoose';
import fetch from 'node-fetch';
mongoose.connect('mongodb://localhost:27017/Quran');
const SurahSchema = mongoose.Schema({
ayahs: [
{
number: Number,
numberInSurah: Number,
text: String,
},
],
englishName: String,
englishNameTranslation: String,
name: String,
number: Number,
revelationType: String,
});
const surah = mongoose.model('Surah', SurahSchema);
const API = 'http://api.alquran.cloud/v1/quran/quran-uthmani';
async function getdata() {
const res = await fetch(API);
const data = await res.json();
try {
const inserted = await surah.insertMany(data.data.surahs);
console.log(inserted);
process.exit(0);
} catch (e) {
console.log('Some error');
console.log(e);
process.exit(0);
}
}
getdata();
this inserted 114 documents
PS: you just need to install node-fetch and mongoose
So i tried following the https://discordjs.guide/additional-info/rest-api.html guide before making my own. But I can't get either to work.
Firstly with /cat it crashes and the console returns with:
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at getJSONResponse (BOTLOCATION\index.js:77:14)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Client.<anonymous> (BOTLOCATION\index.js:90:20)
And /urban works but no matter what term I enter it returns with NULL.
Here is the code, its nearly identical from the guides apart from the added SlashCommandBuilder and REST.
const { request } = require('undici');
const clientId = 'CLIENTID_HERE';
const guildId = 'GUILDID_HERE';
const { SlashCommandBuilder } = require('#discordjs/builders');
const { REST } = require('#discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const commands = [
new SlashCommandBuilder().setName('cat').setDescription('Cat thing idk'),
new SlashCommandBuilder().setName('urban').setDescription('Urban Dictionary Thing'),
]
.map(command => command.toJSON());
const rest = new REST({ version: '9' }).setToken("TOKEN_HERE");
rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
//rest.put(Routes.applicationGuildCommands(clientId), { body: commands })
.then(() => console.log('Successfully registered application commands.'))
.catch(console.error);
const trim = (str, max) => (str.length > max ? `${str.slice(0, max - 3)}...` : str);
async function getJSONResponse(body) {
let fullBody = '';
for await (const data of body) {
fullBody += data.toString();
}
return JSON.parse(fullBody);
}
client.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return;
const { commandName } = interaction;
await interaction.deferReply();
if (commandName === 'cat') {
const catResult = await request('https://aws.random.cat/meow');
const { file } = await getJSONResponse(catResult.body);
interaction.reply({ files: [{ attachment: file, name: 'cat.png' }] });
} else if (commandName === 'urban') {
const term = interaction.options.getString('term');
const query = new URLSearchParams({ term });
const dictResult = await request(`https://api.urbandictionary.com/v0/define?${query}`);
const { list } = await getJSONResponse(dictResult.body);
if (!list.length) {
return interaction.editReply(`No results found for **${term}**.`);
}
const [answer] = list;
const embed = new MessageEmbed()
.setColor('#EFFF00')
.setTitle(answer.word)
.setURL(answer.permalink)
.addFields(
{ name: 'Definition', value: trim(answer.definition, 1024) },
{ name: 'Example', value: trim(answer.example, 1024) },
{
name: 'Rating',
value: `${answer.thumbs_up} thumbs up. ${answer.thumbs_down} thumbs down.`,
},
);
interaction.editReply({ embeds: [embed] });
}
});
So for the cat command since there is a deferReply first we need to use editReply since deferReply counts as the first/initial reply.
await interaction.deferReply();
const catResult = await request('https://aws.random.cat/meow').catch((err) => { console.log(err); });;
const { file } = await getJSONResponse(catResult.body).catch((err) => { console.log(err); });
return await interaction.editReply({ files: [{ attachment: file, name: 'cat.png' }] });
I also added a .catch to the end of each await, this was just for testing however I recommend it.
Now with the urban command, the reason it is using null is since you don't have the string option's text. We can check for it by adding an if statement.
await interaction.deferReply();
const term = interaction.options.getString('term');
if (!term) return await interaction.editReply('Please provide a term.'); // We need to add this check to see if the user provided the term option or not.
const query = new URLSearchParams({ term });
const dictResult = await request(`https://api.urbandictionary.com/v0/define?${query}`);
const { list } = await getJSONResponse(dictResult.body);
if (!list.length) {
return interaction.editReply(`No results found for **${term}**.`);
}
const [answer] = list;
const embed = new MessageEmbed()
.setColor('#EFFF00')
.setTitle(answer.word)
.setURL(answer.permalink)
.addFields(
{ name: 'Definition', value: trim(answer.definition, 1024) },
{ name: 'Example', value: trim(answer.example, 1024) },
{
name: 'Rating',
value: `${answer.thumbs_up} thumbs up. ${answer.thumbs_down} thumbs down.`,
},
);
return await interaction.editReply({ embeds: [embed] });
IMPORTANT: When you are building your slash command you are not setting a string option. In the commands array, when creating the second slash command called urban we will add the support for the string option there. (An example using the string option, discord.js guide all command options)
This is how we can do this:
const commands = [
new SlashCommandBuilder().setName('cat')
.setDescription('Cat thing idk'),
new SlashCommandBuilder()
.setName('urban')
.setDescription('Urban Dictionary Thing')
.addStringOption((option) => option.setName('term').setDescription('term')) // We first add the string option then set the name to 'term' which is what the code calls for and then the description.
].map((command) => command.toJSON());
If you would like to make the term input required, add .setRequired(true) which will not allow the command to be ran without entering the term to search.
Once you do that you should be all good! Tested the code and it's working once that's fixed
I everyone, I'm trying to call a function called 'safeMint' on an ERC721 contract deployed on Rinkeby testnet but I'm getting this error:
Error: resolver or addr is not configured for ENS name (argument="name", value="", code=INVALID_ARGUMENT, version=contracts/5.5.0)
This is the code I'm using to call the function
const mintNFT = async () => {
const {ethereum} = window;
if(isMetaMaskInstalled) {
try {
const abi = require('../contracts/Animals.json').abi;
console.log(abi);
const accounts = await ethereum.request({ method: 'eth_accounts' });
setAccount(accounts[0]);
const web3Provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = web3Provider.getSigner();
const contractWrite = new ethers.Contract('0x53Ea14980c8326E93a9F72889171c1e03d4aD6Ce', abi, signer);
let trx = await contractWrite.safeMint(account, props.cidOfJsonInIpfs);
console.log(trx);
} catch(err) {
console.log(err);
}
}
}
I've tried to print the parameters passed but they seem to be right, what am I doing wrong?
I solved it with the following code
const mintNFT = async () => {
const {ethereum} = window;
if(isMetaMaskInstalled) {
try {
const abi = require('../contracts/Animals.json').abi;
console.log(abi);
const accounts = await ethereum.request({ method: 'eth_accounts' });
const web3Provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = web3Provider.getSigner(accounts[0]);
console.log(signer._address)
const contractWrite = new ethers.Contract('0x53Ea14980c8326E93a9F72889171c1e03d4aD6Ce', abi, signer);
let trx = await contractWrite.safeMint(accounts[0], `https://gateway.pinata.cloud/ipfs/${props.cidOfFile}`);
let receipt = await trx.wait();
console.log(receipt);
} catch(err) {
console.log(err);
}
}
What I was missing: I was using setState function to set the 'account' state variable with the first account of metamask, instead, I started using account[0] directly and it worked!
I will accept this as solution in 2 days
Side-Note I connect to DB with the following code:
const mongoose = require('mongoose');
const connectDB = (url) => {
return mongoose.connect(url);
}
Problem Description:
I have two different Collections. Both Operations, findByIdAndUpdate and create must run as an atomic operation. This should be possible with mongoose Transactions.
const registerCustomer = async (req, res) => {
await CustomerRegistrationCode.findByIdAndUpdate(req.body._id, { used: true });
const customer = await Customer.create({firstName: req.body.firstName});
}
What I tried:
const registerCustomer = async (req, res) => {
const session = await mongoose.startSession();
await session.startTransaction();
try {
await CustomerRegistrationCode.findByIdAndUpdate(req.body._id, { used: true }); //updates even though
const customer = await Customer.create({ firstName: req.body.firstName });// this line will throw error
await session.commitTransaction();
session.endSession();
} catch (error) {
console.error('abort transaction');
await session.abortTransaction();
session.endSession();
throw error;
}
}
Problem The CustomerRegistrationCode Collection gets updated even though the Customer.create method throws an error. How can this be solved?
New approach to understand MongoDB Transactions fails, but this is official code from https://mongoosejs.com/docs/transactions.html
const mongoose = require('mongoose');
const debugMongo = async () => {
const db = await mongoose.createConnection("mongodb://localhost:27017/mongotest");
const Customer = db.model('Customer', new mongoose.Schema({ name: String }));
const session = await db.startSession();
session.startTransaction();
await Customer.create([{ name: 'Test' }], { session: session }); //(node:20416) UnhandledPromiseRejectionWarning: MongoServerError: Transaction numbers are only allowed on a replica set member or mongos
let doc = await Customer.findOne({ name: 'Test' });
assert.ok(!doc);
doc = await Customer.findOne({ name: 'Test' }).session(session);
assert.ok(doc);
await session.commitTransaction();
doc = await Customer.findOne({ name: 'Test' });
assert.ok(doc);
session.endSession();
}
debugMongo();
At Customer.create an error gets thrown and i don't know why. Does somebody have an minimal working example?
You are using the transaction in a wrong way, that is why it does not work.
You need to pass the session object to your operations.
const registerCustomer = async (req, res) => {
const session = await mongoose.startSession();
session.startTransaction();
try {
await CustomerRegistrationCode.findByIdAndUpdate(req.body._id, { used: true }, { session });
const customer = await Customer.create({ firstName: req.body.firstName }, { session });
await session.commitTransaction();
} catch (error) {
console.error('abort transaction');
await session.abortTransaction();
} finally {
session.endSession();
}
}
Also, I have refactored your code a bit.
You can read more about transactions here
The original code that scrape the first page of data works but then I created a loop that clicks on a "load more" button and then scrapes the data until there is no more "load more" button. At the end of my run it is not exporting anything. Is my code for exporting to CSV incorrect? Where am I going wrong with this?
const puppeteer = require('puppeteer');
const jsonexport = require('jsonexport');
(async () => {
const browser = await puppeteer.launch({ headless: false }); // default is true
const page = await browser.newPage();
await page.goto('https://www.Website.com/exercises/finder', {
waitUntil: 'domcontentloaded',
});
//load more CSS to be targeted
const LoadMoreButton =
'#js-ex-content > #js-ex-category-body > .ExCategory-results > .ExLoadMore > .bb-flat-btn';
do {
// clicking load more button and waiting 1sec
await page.click(LoadMoreButton);
await page.waitFor(1000);
const loadMore = true;
const rowsCounts = await page.$eval(
'.ExCategory-results > .ExResult-row',
(rows) => rows.length
);
//scraping the data
const exerciseNames = [];
for (let i = 2; i < rowsCounts + 1; i++) {
const exerciseName = await page.$eval(
`.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExHeading > a`,
(el) => el.innerText
);
exerciseNames.push(exerciseName);
}
console.log({exerciseNames});
} while (10000);
const allData = [
{
exercise: exerciseNames,
},
];
// exporting data to CSV
const options = [exercise];
//json export error part
jsonexport(allData, options, function (err, csv) {
if (err) return console.error(err);
console.log(csv);
});
await browser.close();
})().catch((e) => {
console.error(e);
});
Edit:
This is what I have at the moment for the exporting and writing to a CSV file. I'm getting 3 headers but only the exercises are being written and then nothing else. Console.log shows exercises, muscle target group, and equipments being exported though. I'm trying to get it where they are 3 headers (name, equipment, and targeted muscle) and then each row is being filled inside of it. Ex: squat, barbell, legs these would be in one row but each in their own cell.
Current export code:
const allData = [
{
exercise: exerciseNames,
muscleGroup: muscleTargets,
equipment: equipmentTypes,
},
];
var ws = fs.createWriteStream('test1.csv');
csv.write(allData, { headers: true, delimiter: ',' }).pipe(ws);
//json export error part
jsonexport(allData, function (err, csv) {
if (err) return console.error(err);
console.log(csv);
});
Edit 2
This is currently my entire code. It is outputting the allData pre-filled info but no more new data
const puppeteer = require('puppeteer');
const jsonexport = require('jsonexport');
const fs = require('fs');
(async () => {
const browser = await puppeteer.launch({ headless: false }); // default is true
const page = await browser.newPage();
await page.goto('https://www.website.com/exercises/finder', {
waitUntil: 'domcontentloaded',
});
const loadMore = true;
const rowsCounts = await page.$$eval(
'.ExCategory-results > .ExResult-row',
(rows) => rows.length
);
let allData = [];
for (let i = 2; i < rowsCounts + 1; i++) {
const exerciseName = await page.$eval(
`.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExHeading > a`,
(el) => el.innerText
);
const muscleGroupName = await page.$eval(
`.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExResult-muscleTargeted > a`,
(el) => el.innerHTML
);
const equipmentName = await page.$eval(
`.ExCategory-results > .ExResult-row:nth-child(${i}) > .ExResult-cell > .ExResult-equipmentType > a`,
(el) => el.innerHTML
);
let obj = {
exercise: exerciseName,
muscleGroup: muscleGroupName,
equipment: equipmentName,
};
allData.push(obj);
}
console.log(allData);
async function fn() {
const allData = [
{
exercise: 'Rickshaw Carry',
muscleGroup: 'Forearms',
equipment: 'Other',
},
{
exercise: 'Single-Leg Press',
muscleGroup: 'Quadriceps',
equipment: 'Machine',
},
{
exercise: 'Landmine twist',
muscleGroup: 'Forearms',
equipment: 'Other',
},
{
exercise: 'Weighted pull-up',
muscleGroup: 'Forearms',
equipment: 'Other',
},
];
// json export error part
jsonexport(allData, function (err, csv) {
if (err) return console.error(err);
console.log(csv);
fs.writeFileSync('output.csv', csv);
});
}
fn();
await browser.close();
})().catch((e) => {
console.error(e);
});
I see two issues here.
I.) One of them is with the options declaration:
const options = [exercise]; // ❌
You are trying to access the exercise property of allData object without a proper notation. If you really need to extract it inside a new array you can do it by going inside the first element of the allData array using index [0], then using the dot-notation to access the exercise property.
const options = [allData[0].exercise]; // ✅
Note: I suggest to leave the options simply allData[0].exercise (without the wrapping array) as your allData object is already an array, I see no benefit of making the structure deeper.
II.) The second issue is with the usage of jsonexport npm package. I suppose you left allData accidentally in this line:
jsonexport(allData, options, function (err, csv) // ❌
You only need the options here (as according to the docs you can give only one object as the input):
jsonexport(options, function (err, csv) // ✅
Edit
Based on your updated answer your problem can be solved if you restructure a bit your allData object, so the jsonexport will recognize each column and row correctly.
const jsonexport = require('jsonexport')
const fs = require('fs')
async function fn() {
const allData = [
{
exercise: 'Rickshaw Carry',
muscleGroup: 'Forearms',
equipment: 'Other'
},
{
exercise: 'Single-Leg Press',
muscleGroup: 'Quadriceps',
equipment: 'Machine'
},
{
exercise: 'Landmine twist',
muscleGroup: 'Forearms',
equipment: 'Other'
},
{
exercise: 'Weighted pull-up',
muscleGroup: 'Forearms',
equipment: 'Other'
}
]
// json export error part
jsonexport(allData, function (err, csv) {
if (err) return console.error(err)
console.log(csv)
fs.writeFileSync('output.csv', csv)
})
}
fn()
To achieve such structure you should extend allData in each iteration like this:
let allData = []
for (let i = 2; i < rowsCounts; i++) {
const exerciseName = await page.$eval(`...row:nth-child(${i})...`,
el => el.textContent.trim())
const muscleGroupName = await page.$eval(`...row:nth-child(${i})...`,
el => el.textContent.trim())
const equipmentName = await page.$eval(`...row:nth-child(${i})...`,
el => el.textContent.trim())
let obj = {
exercise: exerciseName,
muscleGroup: muscleGroupName,
equipment: equipmentName
}
allData.push(obj)
}
console.log(allData)