I need to implement in the code below "value" the cost in ETH because in Solidity I require msg.value and in order to be able to lie I have to put a parameter "value" in the code in js, but I don't know how, you can it helps? I also attached the Smart Contract part with mint.
React JS file
async function handleMint() {
if (mintFinish === true) {
setMintFinish(false);
} else {
setMintFinish(true);
}
if (window.ethereum) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(
mintExampleAddress,
mintExampleABI.abi,
signer
);
console.log(signer)
try {
// console.log(contract)
const response = await contract.mint(mint);
console.log(response);
} catch (err) {
console.log(err);
}
}
}
Solidity file
function mint(uint256 _mintAmount) public payable mintCompliance(_mintAmount) {
require(!paused, "The contract is paused!");
require(msg.value >= cost * _mintAmount, "Insufficient funds!");
_mintLoop(msg.sender, _mintAmount);
}
how you are using etherjs and seeing the smart contract code inside the mint function, i suppose that cost is a public variable and can be read from outside the contract, you get the cost and multiply the value by the mint amount parameter, something like this
const cost = await contract.cost();
const response = await contract.mint(mint,{value:cost.mul(mint)});
you have to remember to use bignumbers and that all return values that are numbers will be returned as one, what i'm doing here is getting the cost from the contract and multiply that for mint and pass that to value as the last parameter in the function call
Related
So I have this code:
import { ThirdwebSDK } from "#thirdweb-dev/sdk";
import { ConnectWallet, useAddress } from "#thirdweb-dev/react";
export default function DonationPage() {
let address = useAddress()
async function sendCoins() {
try {
let random = ethers.Wallet.createRandom();
// get a signer from somewhere (createRandom is being used purely for example purposes)
// get an instance of the SDK with the signer already setup
const sdk = ThirdwebSDK.fromSigner(signer || random, "mainnet");
try {
if (selectedCoin == 'eth') {
await sdk.wallet.transfer(CORPORATE_WALLET || "0x", donationAmount);
} else {
// const decimals = await contract.erc20..call()
// const amount = new BigNumber(donationAmount * (10 ** decimals))
const contract = await sdk.getContract(crypto.find((coin) => coin.id == selectedCoin)?.contract_address || '0x');
let balance = await contract.erc20.balance()
let allowance = await contract.erc20.allowance(address || '0x')
// console.log('balance', balance.value)
// console.log('allowance', allowance.value)
if(donationAmount + Number(balance.displayValue) > Number(allowance.displayValue)) {
await contract.erc20.setAllowance(address || '0x', donationAmount + Number(balance.displayValue))
}
await contract.erc20.transferFrom(address || '0x',CORPORATE_WALLET || '0x', donationAmount);
}
} catch (error: any) {
alert(error.message)
}
}
return (<>...</>)
}
So i'm using ConnectWallet button to get address and using TrustWallet for this, and trying to transfer tokens from 'address' to a corporate wallet, with a specified donation amount.
However, I receive this error "Transaction was not mined within 50 blocks, please make sure your transaction was properly sent. Be aware that it might still be mined".
There seems to be no documentation on this online, and ChatGPT won't help either. Does someone know how to fix this?
You can pull up the transaction by its hash on EtherScan and check what the estimation time is for the transaction to be included in a block by a block producer
Because there are no details on the transaction on the question itself, it is not possible to give more specific answer
For transaction troubleshooting, please refer to ethereum.stackexchange.com as diagnosing transaction failures is not really related to programming
Problem/Clarification:
I have a NFT minting DApp that mints with multiple ERC20 tokens.
I'm having an issue with the react code which calls the smart contract minting function multiple times.
When a user mints with their preferred ERC20 token, the react code is structured in a way that a user would see 3 meta-mask popups.
The first metamask popup asks the user to approve the NFT smart contract to access their ERC20 token.
The second metamask popup asks the user to approve the transfer of the ERC20 tokens into the smart contract.
The third and final popup allows the user to go ahead and mint by calling the mintWithERCToken(mintAmount, tokenID) function in the smart contract. This part is problematic because once the ERC20 has been transferred, and then the user decides to cancel/reject the mint, the token would have already been transferred into the smart contract.
All three metamask calls requires the spending of gas.
What is the correct sequence of events? What is the correct way to write the react code?
Could someone help restructure the react code?
React Code
async function mintWithCrypto(tokenId) {
Web3EthContract.setProvider(ethereum);
let web3 = new Web3(ethereum);
//get erc20 contract address
var erc20address = await blockchain.smartContract.methods.getCryptotoken(tokenId).call();
//get token contract information
var currency = new web3.eth.Contract(TOKENABI, erc20address);
//get NFT cost
var mintRate = await blockchain.smartContract.methods.getNFTCost(tokenId).call();
//get mint amount and convert to int
var _mintAmount = Number(mintAmount);
//get total cost of NFTs minted
var totalAmount = mintRate * _mintAmount;
let gasLimit = 285000;
//get total gas
let totalGasLimit = String(gasLimit * _mintAmount);
setFeedback(`Minting your NFT, please hold on...`);
//approve contract address for ERC20 token
currency.methods.approve(CONFIG.CONTRACT_ADDRESS, String(totalAmount)).send({from: blockchain.account, gasLimit: String(totalGasLimit)})
//transfer ERC20 token to smart contract. **Problematic code**
.then(await currency.methods.transfer(CONFIG.CONTRACT_ADDRESS, String(totalAmount)).send({from: blockchain.account},
async function (error, transactionHash) {
// console.log("Transfer Submitted, Hash: ", transactionHash)
let transactionReceipt = null
while (transactionReceipt == null) {
transactionReceipt = await web3.eth.getTransactionReceipt(transactionHash);
await sleep(10000)
}
}))
//mint NFT **Problematic code**
.then(blockchain.smartContract.methods.mintWithERCToken(_mintAmount, tokenId).send({from: blockchain.account, gasLimit: String(totalGasLimit)})
.once("error", (err) => {
if (err.message == "MetaMask Tx Signature: User denied transaction signature.") {
setFeedback("Transaction cancelled.");
} else {
setFeedback("Sorry, something went wrong please try again later.");
}
})
.then((receipt) => {
console.log(receipt);
setFeedback(`Congratulations! You've minted a ${CONFIG.NFT_NAME}.`);
dispatch(fetchData(blockchain.account));
})
)
}
Smart Contract code
function mintWithERCToken(uint256 mintAmount, uint256 tokenID) public payable {
CryptoTokenInfo storage tokens = permittedCrypto[tokenID];
IERC20 paytoken;
paytoken = tokens.paytoken;
uint256 costval;
costval = tokens.costvalue;
uint256 supply = totalSupply();
require(mintAmount > 0, "You need to mint at least 1 NFT");
require(mintAmount <= maxMintAmount, "Max mint amount per session exceeded");
require(supply + mintAmount <= maxSupply, "Max NFT exceeded");
if (msg.sender != owner()) {
//check if the user is whitelisted
if(onlyWhitelisted == true) {
require(isWhitelisted(msg.sender), "Sorry, address is not whitelisted");
}
require(msg.value == costval * mintAmount, "Insufficient funds. Please add more funds to address");
}
for (uint256 i = 1; i <= mintAmount; i++) {
require(paytoken.transferFrom(msg.sender, address(this), costval));
_safeMint(msg.sender, supply + i);
}
}
I wrote a contract in Solidity with the following task in mind:
The user approves the smart contract to transfer a certain amount of tokens from their wallet.
The smart contract uses this amount to transfer to an address given as a parameter. But it also takes 1 token from this amount to transfer to the developer of the contract.
If everything succeeds, the user receives a "Payment successful!" message.
The first step (the approval) was made using React and Web3:
const derc20contract = '0x36850b80ad73fe66216609B9796ed6ceae8BE29F';
const handleClick = async (e) => {
e.preventDefault();
const prtmp = await detectEthereumProvider();
// -------------------- Approve Part ------------------------------//
const web3 = new Web3(prtmp);
const erc20contract = new web3.eth.Contract(
erc20abi,
derc20token,
{ from: '0xFromAddress' }
);
await erc20contract.methods.approve(derc20contract, web3.utils.toHex(3e18)).send();
// ---------------------------------------------------------------//
const contract = new web3.eth.Contract(derc20abi, derc20contract);
const response = await contract.methods.send_usdt(
'0xToAddress',
web3.utils.toHex(3e18)
)
.call({ from: '0xFromAddress'});
console.log(response);
};
Once the approval succeeds the second part of the function resolves. The contract I deployed has a function called send_usdt. Through this function is my smart contract able to transfer the amount approved.
/ SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
interface IERC20 {
function transfer(address _to, uint256 _value) external returns(bool);
function transferFrom(address _from, address _to, uint _amount) external returns (bool);
function allowance(address _owner, address _contract) external returns (uint256);
function balanceOf(address _buyer) external view returns (uint256);
function approve(address _contract, uint tokens) external returns (bool);
}
contract DPortalSubscription {
address private owner;
mapping(address => uint32) subscription_fees;
constructor()
{
owner = msg.sender;
}
function check_balance() external view returns (uint256)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
uint256 balance = usdt.balanceOf(msg.sender);
return balance;
}
function check_sender_address() external view returns (address)
{
return msg.sender;
}
function check_allowance()external returns(uint256)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
uint256 allowance = usdt.allowance(msg.sender, address(this));
return allowance;
}
function send_usdt(address _to, uint256 _amount) external returns (string memory)
{
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
require(_amount > 1, "Purchases must be higher than 1 usdt");
require(usdt.balanceOf(msg.sender) >= _amount, "The buyer doesn't have enough funds");
require(usdt.allowance(msg.sender, address(this)) >= _amount, "Permissions to transfer tokens denied");
require(usdt.transferFrom(msg.sender, _to, _amount-1) == true, "Couldn't transfer tokens to seller");
require(usdt.transferFrom(msg.sender, owner, 1) == true, "Couldn't transfer tokens to support");
return "Payment successful!";
}
}
Once the second part of the function in React resolves, I receive the confirmation "Payment successful!" But the tokens weren't transferred. I keep the same amount in my "From Wallet", "To Wallet" and "Deploy Wallet" as before.
The problem was inside the react snippet. By changing the method call to sell the money could be successfully transferred.
const response = await contract.methods.send_usdt
(
'0xToAddress',
web3.utils.toHex(3e18)
)
.call({ from: '0xFromAddress' });
was changed to:
const response = await contract.methods.send_usdt
(
'0xToAddress',
web3.utils.toHex(3e18),
{ from: '0xFromAddress' }
)
.send();
which worked but raised another question. When I use the previous call method, the function returns "Payment Successful!" and with the sell method I receive an Object.
Since "Payment Successful" isn't true, I was wondering if it could be possible to throw an Exception when someone interacts with my contract using the call method.
Is that possible?
Following #Kuly14's answer and in order to make it clearer, you may want to create the following function instead:
function send_usdt(address _to, uint256 _amount) external returns (string memory) {
// TestToken ( Plasma Bridge ) in Mumbai Network
IERC20 usdt = IERC20(address(0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1));
require(_amount > 1, "Purchases must be higher than 1 usdt");
usdt.transferFrom(msg.sender, owner, 1);
usdt.transferFrom(msg.sender, _to, _amount-1);
return "Payment successful!";
}
Notes:
By just calling the transferFrom method, it will jump its corresponding error if something goes wrong. You do not need to handle them.
I have changed the order in which you transfer the tokens. First, I send them to the owner and then to the desired recipient to avoid fees payments problems, but if you prefer the other way round, it is possible.
I am trying to access an api and I will have to run the api calls several times based on the page numbers I need to iterate, the following is the code which I am using and how can I get the all the response pushed into an array.
as nodeJs is single threaded It is not waiting for the responses from the api.
How can I can tackle this and ensure all the response values are being pushed into an array
Inside the for loop I want the final array which has all the values of the api response. So, I check the total page value and response page Number if that matches which means that will be the last page and I push the array to another function but when I do that it does not have all the values because nodejs does not wait for the api response.
const fs = require('fs');
var pepKey = 'asdfasdfasd';
var pepResponse;
var pepTimecards = [];
pep();
function pep(){
var options = {
headers: {
"content-type": "application/json",
},
agentOptions: {
pfx: fs.readFileSync('./certificate/asdfsdaf.p12'),
passphrase: 'asdasdsda'
}
};
request.get('https://source.asdfasdf.io/api/organisations/asdfasdf/timecard_keys?timecard_type=Flex',options, (err, res, body) => {
if (err) { return console.log(err); }
pepResponse = JSON.parse(body)
pepTimecards = pepResponse.data;
if(pepResponse.pages > 1){
for(let i=2;i<=pepResponse.pages;i++){
var url = 'https://source.`pepme`.io/api/organisations/sdfsadf/timecard_keys?timecard_type=Flex&page='+pageNo;
request.get(url,options, (err, res, body) => {
if (err) { return console.log(err); }
body = JSON.parse(body)
pepTimecards = pepTimecards.concat(body.data)
if(pepResponse.pages == body.page){
console.log(pepResponse.pages)
console.log(body.page +"body page")
console.log(pepTimecards)
}
});
}
}else{
}
});
}
Use the request-promise library which supplies promisified versions of the request library. Then, you can use async/await in your for loop to serialize your operations:
Newer answer to go with the edited code in the OP's question
const fs = require('fs');
const rp = require('request-promise');
const pepKey = 'asdfasdfasd';
pep().then(pepTimecards => {
// the timecard data is valid in here
console.log(pepTimecards);
}).catch(err => {
console.log(err);
});
async function pep() {
let timecards = [];
const options = {
headers: {
"content-type": "application/json",
},
agentOptions: {
pfx: fs.readFileSync('./certificate/asdfsdaf.p12'),
passphrase: 'asdasdsda'
},
json: true,
uri: 'https://source.asdfasdf.io/api/organisations/asdfasdf/timecard_keys?timecard_type=Flex'
};
let pepResponse = await rp(options);
timecards = pepResponse.data;
if (pepResponse.pages > 1) {
for (let i = 2; i <= pepResponse.pages; i++) {
options.uri = 'https://source.`pepme`.io/api/organisations/sdfsadf/timecard_keys?timecard_type=Flex&page='+pageNo;
let body = await rp(url, options);
// add body.data onto the existing array
timecards.push(...body.data);
}
} else {
}
console.log(pepResponse.pages)
console.log(timecards)
return timecards;
}
Prior Answer before OP edited the code in their question:
const rp = require('request-promise');
// I'm assuming this is some sort of method definition on a class, otherwise it needs the function keyword
async pageno(pageNo) {
for (let i=2;i<=pepResponse.pages;i++){
try {
options.uri = 'https://test/timecard_keys?timecard_type=asdas&page='+pageNo;
// let request-promise parse the json for you automatically
options.json = true;
let body = await rp(options);
pepTimecards = pepTimecards.concat(body.data)
if (pepResponse.pages == body.page){
console.log(pepResponse.pages)
console.log(body.page +"body page")
console.log(pepTimecards)
}
} catch(e) {
// decide what to do for error handling
// this will log and rethrow so the caller will get a rejected promise
console.log(e);
throw e;
}
}
// return some value here to be the resolved value of the returned promise
return pepTimecards;
}
In your code, it is not clear where the options, pepTimecards, pepResponse variables are declared. They should probably be declared as local variables here or passed in to the function and/or returned from your function.
Summary of modifications:
Add async to method declaration so we can use await.
Load request-promise library into rp variable
Add options.json = true to the let the request-promise library parse the JSON result for us automatically
Change rp() to just use the options structure (add URL to that)
Add try/catch to catch any errors from the await, log them, then rethrow so pageno() will return a promise that rejects if there is an error (you can customize the behavior when there's an error if desired)
Add a return value so there is meaningful resolved value to the promise (you should not be using side-effect programming as it is now (modifying variables that are not passed in, declared locally or returned).
Things for you still to fix:
Stop using side-effect programming where you modify free variables that aren't passed in, aren't declared locally and aren't returned. This is a bad way to design code. You don't show enough overall context from the calling code or where these other variables are defined to make a concrete recommendation on how it should be done.
Decide what your error handling strategy is if there's an error on one of the requests and implement that strategy and proper handling.
I have the following function in an ERC20 solidity smart contract:
function getSummary() public view returns (string, string, address, uint, uint){
return(
symbol,
name,
creator,
balances[msg.sender],
_totalSupply
);
}
When I call this function in remix I get a non zero balance for the account I'm on in metamask. That value is correct.
But when I call this function in a react next.js app the the balance returns a zero. Here is that code:
const accounts = await web3.eth.getAccounts();
const account = accounts[0];
let tokenContract = new web3.eth.Contract(abi, props.query.address);
let tokenSummary = await tokenContract.methods.getSummary().call();
let balance = await tokenContract.methods.balanceOf(account).call();
console.log(tokenSummary);
When I console.log tokenSummary, the balance is 0. But then if I call balanceOf I get a non-zero value (which is correct). What could be causing this problem ?