Polygon transaction working just fine on Mumbai but not on Mainnet - node.js

Hello I'm trying to mint an NFT using Polygon and it works just fine on Mumbai but as soon as i switch over to the mainnet the transaction doesn't go through instead of going through in 5 seconds on mumbai. Even though im using the exact same contract just deployed on the mainnet instead of Mumbai and the code is the same too. All im doing is switching the contract address and rpc url but for some reason it just doesn't work on the Polygon mainnet below is the code im using.
// Init contract
const contractABI = require('../../contract-abi.json');
const contractAddress = config.mintingContractAddress;
const contract = await new this.web3.eth.Contract(contractABI, contractAddress);
// Mint NFT
const nft = contract.methods.mintNFT(user.walletAddress, metadataUploadURL, user.paymentAddress).encodeABI();
// Get gas pricing
const priorityFees = await axios.get('https://gasstation-mainnet.matic.network');
const estBaseGas = await this.web3.eth.estimateGas({
data: nft,
to: contractAddress,
});
console.log('USING GAS: ' + estBaseGas);
// Sign NFT minting transaction
const totalGas = estBaseGas + priorityFees.data.standard;
console.log('TOTALGAS: ', Math.round(totalGas).toString());
const transaction = await this.web3.eth.accounts.signTransaction(
{
from: user.walletAddress,
to: contractAddress,
nonce: await this.web3.eth.getTransactionCount(user.walletAddress, 'pending'), // Get count of all transactions sent to the contract from this address including pending ones
data: nft,
// maxPriorityFee: priorityFees.data.average, Not supported on Polygon MATIC yet
gas: Math.round(totalGas).toString(),
gasPrice: await this.web3.eth.getGasPrice(),
},
wallet.privateKey,
);
this.logger.silly('Finished signing NFT transaction');
// Send the transaction that we signed
const mintT = await this.web3.eth.sendSignedTransaction(transaction.rawTransaction);
this.logger.silly('Sent transaction');
console.log(mintT);
Also tried this for signing
// Get gas pricing
const priorityFees = await axios.get('https://gasstation-mainnet.matic.network');
const estBaseGas = await this.web3.eth.estimateGas({
data: nft,
to: contractAddress,
});
console.log('USING GAS: ' + estBaseGas);
// Sign NFT minting transaction
const totalGas = estBaseGas + priorityFees.data.standard;
console.log('TOTALGAS: ', Math.round(totalGas).toString());
console.log('P', priorityFees.data.standard);
const gp = this.web3.utils.toWei(priorityFees.data.standard.toString(), 'Gwei').toString();
console.log('GP', gp);
const transaction = await this.web3.eth.accounts.signTransaction(
{
from: user.walletAddress,
to: contractAddress,
nonce: await this.web3.eth.getTransactionCount(user.walletAddress, 'pending'), // Get count of all transactions sent to the contract from this address including pending ones
data: nft,
// maxPriorityFee: priorityFees.data.average, Not supported on Polygon MATIC yet
gas: '1000000',
gasPrice: gp,
},
wallet.privateKey,
);
Mempool explorer for transaction that takes forever and nearly instant one.
Forever:
Instant:
One on mainnet that used 30 gwei of gas:
Does anybody know why this is happening?
Also yes i do know that the fast one does have 2 extra gwei in gas but even setting it to that manually it still takes forever and according to https://polygonscan.com/gastracker even with one gwei it should be processed within 30 seconds. Even when using 50 Gwei it seems to take hours to process or maybe it's being dropped? The transactions don't even seem to be getting to the contract they are just stuck somewhere in the chain.
contract address: 0xa915E82285e6F82eD10b0579511F48fD716a2043
contract source code:
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
event MintedNFT(address recipent,string tokenURI,address artist, uint256 tokenID);
mapping(uint256 => address) private artists; // Used to store token ids => artist addresses
// mapping(uint256 => uint256) private royalties; // tokenId => royaltyPercentage
// mapping(uint256 => address) private nftMintInitators; // Used to store token ids => sender addresses
// mapping(uint256 => bool) private royaltiesSet;
constructor(string memory name_, string memory symbol_)
ERC721(name_, symbol_) {
}
// // Support for https://eips.ethereum.org/EIPS/eip-2981
// /// #notice Called with the sale price to determine how much royalty
// // is owed and to whom.
// /// #param _tokenId - the NFT asset queried for royalty information
// /// #param _salePrice - the sale price of the NFT asset specified by _tokenId
// /// #return receiver - address of who should be sent the royalty payment
// /// #return royaltyAmount - the royalty payment amount for _salePrice
// function royaltyInfo(
// uint256 _tokenId,
// uint256 _salePrice
// ) external view returns (
// address receiver,
// uint256 royaltyAmount
// ) {
// return (
// artists[_tokenId],
// _salePrice * royalties[_tokenId] // Take percentage
// );
// }
// function updateRoyaltyPercentage(
// uint256 royaltyPercentage, // In decimal like 0.5 or 0.25 (Send 0.0 for no royalties)
// uint256 tokenID
// ) public {
// if (msg.sender == nftMintInitators[tokenID] && royaltiesSet[tokenID] == false) {
// royalties[tokenID] = royaltyPercentage;
// royaltiesSet[tokenID] = true;
// }
// }
function mintNFT(address recipient,
string memory tokenURI,
address artist // Address for the artist not using _msgSender() because this transaction is sent by the users NFT holding account
)
public
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
artists[newItemId] = artist;
// nftMintInitators[newItemId] = msg.sender;
// royaltiesSet[newItemId] = false;
emit MintedNFT(recipient,tokenURI,artist,newItemId);
return newItemId;
}
}

You can test with simple code just to mint one NFT. Adding gasPrice and gasLimit parameters directly into minting function could help
const hre = require("hardhat");
async function main() {
const NFT = await hre.ethers.getContractFactory("NFTNAME");
const WALLET_ADDRESS = "0xxxxxxxxxxxxxx"
const CONTRACT_ADDRESS = "0xa915E82285e6F82eD10b0579511F48fD716a2043"
const contract = NFT.attach(CONTRACT_ADDRESS);
mintedNFT = await contract.mintNFT(WALLET_ADDRESS,{ gasLimit: 285000, gasPrice: ethers.utils.parseUnits('30', 'gwei')});
console.log("NFT minted:", mintedNFT);
}
main().then(() => process.exit(0)).catch(error => {
console.error(error);
process.exit(1);
});

Related

Why are all ethersjs & web3js calls to BSC network failing?

All calls using "wss://bsc-ws-node.nariox.org:443" and other RPC/WSS endpoints have been failing throughout this week. It just hangs and doesn’t return anything.
This is happening in BSC network, but is okay in Polygon network.
On BSC network it happens with both Ethers.js and Web3.js libraries.
Below is a sample implementation using ethers.js
Note that this has been tested from a NodeJS server on an AWS server located in London. Then subsequently it was tested on a Moralis server based in Singapore, but obtained the same results (hanging & no return).
code:
const ethers = require('ethers');
console.log(`ethers version: ${ ethers.version }`);//5.4.4
const Web3 = require('web3');
const _ = require('lodash');
const dotenv = require("dotenv");
dotenv.config();
//const add = “ wss://ws-matic-mainnet.chainstacklabs.com/”; //“https://polygon-rpc.com”; //polygon // swing 1
const add = "wss://bsc-ws-node.nariox.org:443"; //bsc
console.log(`add: ${ add }`);
const mnemonic_3 = process.env.YOUR_MNEMONIC_3 //''; //privatekey GANTI // add own private key to test
const provider = new ethers.providers.WebSocketProvider( add );
const wallet_3 = new ethers.Wallet(mnemonic_3);
const account_3 = wallet_3.connect(provider);
let awaits = async () => {
console.log(`account: ${ await account_3.getAddress() }`);
console.log(`wallet: ${ await wallet_3.getAddress() }`);
//console.log(`account: ${ await account_3.provider.getSigner().getAddress() }`);
console.log(`signer: ${ account_3 == (await account_3.provider.getSigner()) }`);
console.log(`signer: ${ wallet_3 == (await account_3.provider.getSigner()) }`);
//console.log(`provider: ${ await account_3.provider.getAddress() }`); // not a function
// A Human-Readable ABI; for interacting with the contract, we
// must include any fragment we wish to use
const abi = [
// Read-Only Functions
"function balanceOf(address owner) view returns (uint256)",
"function decimals() view returns (uint8)",
"function symbol() view returns (string)",
// Authenticated Functions
"function transfer(address to, uint amount) returns (bool)",
// Events
"event Transfer(address indexed from, address indexed to, uint amount)"
];
// This can be an address or an ENS name
//const address = "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270"; // matic - polygon // swing 2
const address = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"; // bnb - bsc
// Read-Only; By connecting to a Provider, allows:
// - Any constant function
// - Querying Filters
// - Populating Unsigned Transactions for non-constant methods
// - Estimating Gas for non-constant (as an anonymous sender)
// - Static Calling non-constant methods (as anonymous sender)
const erc20 = new ethers.Contract(address, abi, provider);
console.log(`decimals: ${ await erc20.decimals() }`);
// Read-Write; By connecting to a Signer, allows:
// - Everything from Read-Only (except as Signer, not anonymous)
// - Sending transactions for non-constant functions
const erc20_rw = new ethers.Contract(address, abi, account_3)
console.log(`decimals: ${ await erc20_rw.decimals() }`);
}
awaits();
I changed provider to Chainstack, works great now.
Steps to sign up are outlined here

Transfer NFT using Token.createTransferInstruction

We have a transaction that transfers SOL & an NFT from the wallet's owner to our wallet.
The transaction contains simple instructions:
Token.createAssociatedTokenAccountInstruction
Conditionnal, depending on the destination (our wallet)
Token.createTransferInstruction
Transfers from the owner's token account to our token account.
SystemProgram.transfer
SOL transfer.
Here is the transfer code (spl-token v0.1.8)
let createTransferInstructions = async function (mint, from, to, cluster) {
let connection = new Connection(cluster, "confirmed")
const mintPublicKey = new PublicKey(mint);
const ownerPublicKey = new PublicKey(from);
const destPublicKey = new PublicKey(to);
// GET SOURCE ASSOCIATED ACCOUNT
const associatedSourceTokenAddr = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
mintPublicKey,
ownerPublicKey
);
// GET DESTINATION ASSOCIATED ACCOUNT
const associatedDestinationTokenAddr = await Token.getAssociatedTokenAddress(
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
mintPublicKey,
destPublicKey
);
const receiverAccount = await connection.getAccountInfo(associatedDestinationTokenAddr);
const instructions = [];
if (receiverAccount === null)
instructions.push(
Token.createAssociatedTokenAccountInstruction(
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
mintPublicKey,
associatedDestinationTokenAddr,
destPublicKey,
ownerPublicKey
)
)
instructions.push(
Token.createTransferInstruction(
TOKEN_PROGRAM_ID,
associatedSourceTokenAddr,
associatedDestinationTokenAddr,
ownerPublicKey,
[],
1
)
);
return instructions;
}
Here is the transaction code:
var transaction = new this.solana.Transaction({
feePayer: new this.solana.PublicKey(from),
recentBlockhash: await blockhashObj.blockhash
});
for (let transferInstruction of transferInstructions) {
transaction.add(transferInstruction);
}
transaction.add(this.solana.SystemProgram.transfer({
fromPubkey: new this.solana.PublicKey(this.provider.publicKey),
toPubkey: new this.solana.PublicKey(farm.address),
lamports: 10000000
}));
The owners have to validate the transaction with their wallets (phantom, solflare etc..)
And everything works great, for most NFTs.
Some NFT owners are complaining about not being able to validate the transaction on the wallet, an error message indicates that the transaction can't be confirmed.
However, the NFT can be transferred successfully using the wallet's interface, can be listed on marketplaces etc. Even when the NFT is transferred to another wallet, the transaction above works perfectly.
I'm wondering if this has anything to do with the associated token account?
If so, what is the solution?

Failed To Transfer BEP20 Smart Contract Token

I am writing an API to transfer my custom bep20 contract token from the owner's account to another account. For example, I have 10,000 units of my token in my wallet and i want to transfer any specified amount to another account using web3js inside the node server. here is what I have done so far and is not working properly. am having Failed as the response and also Error: Transaction has been reverted by the EVM:
Here is my token transferring function in node:
async transferToken(pkey, tokenContractAddress , toAddress , amount , chainId, callback) {
//import account by private key
let account = this.web3.eth.accounts.privateKeyToAccount(pkey);
let wallet = this.web3.eth.accounts.wallet.add(account);
// ABI to transfer ERC20 Token
let abi = ABI_CONFIG;
// calculate ERC20 token amount
let tokenAmount = this.web3.utils.toWei(amount.toString(), 'ether')
// Get ERC20 Token contract instance
let contract = new this.web3.eth.Contract(abi, tokenContractAddress, {from: wallet.address});
const data = await contract.methods.transfer(toAddress, tokenAmount).encodeABI();
// The gas price is determined by the last few blocks median gas price.
const gasPrice = await this.web3.eth.getGasPrice();
const gasLimit = 90000;
// Build a new transaction object.
const rawTransaction = {
'from': wallet.address,
'nonce': this.web3.utils.toHex(this.web3.eth.getTransactionCount(wallet.address)),
'gasPrice': this.web3.utils.toHex(gasPrice),
'gasLimit': this.web3.utils.toHex(gasLimit),
'to': tokenContractAddress,
'value': 0,
'data': data,
'chainId': chainId
};
const res = await contract.methods.transfer(toAddress, tokenAmount).send({
from: wallet.address,
gas: 30400
});
console.log(res);
// Get Name
let name = await contract.methods.name().call();
// Get Symbol
let symbol = await contract.methods.symbol().call();
/* send to hyperledger */
const map = {
"action_type" : "SEND_TOKEN",
"from_wallet_address" : wallet.address,
"to_wallet_address" : toAddress,
"amount" : this.web3.utils.toWei(amount.toString(), 'ether'),
"tx_hash" : res.transactionHash,
"gasLimit" : 21000,
"gasPrice" : gasPrice,
"fee" : gasPrice * 21000,
"token_smart_contract" : tokenContractAddress,
"token_name" : name,
"token_symbol" : symbol,
"status" : "SUCCESS"
}
callback({data: res, map});
}
There is not enough gas to complete the operation as most of the 30400 was used by the transaction. I think you must increase your gas limit from 30400 to 100000 for example.

Call a smart contract function using INFURA

I can not understand how I can prepare the transaction, sign it and then send it using INFURA. I expect to get something wrong with the NodeJS code I posted. Can anyone kindly help me solve this problem?
Note: I am able to send the transaction on my smart contract, but the EVM reverts the execution.
Part of the Smart Contract (Solidity) (the function that I want to call):
function testFunction() public pure returns (string memory) {
return "testSuccess";
}
The function used in NodeJS:
const printRequestTransaction = async (gcodeHash) => {
log(`Preparing a transaction to register that the gcode has been sent`.yellow);
// With every new transaction send using a specific wallet address, it needed to increase a nonce which is tied to the sender wallet
let nonce = await web3.eth.getTransactionCount(web3.eth.defaultAccount);
// Fetch the current transaction gas prices from https://ethgasstation.info/
let gasPrices = await getCurrentGasPrices();
// Build a new transaction object and sign it locally
let details = {
"to": process.env.SMART_CONTRACT_ADDRESS,
//"value": web3.utils.toHex(web3.utils.toWei(amountToSend.toString(), 'ether')),
"gas": 210000,
"gasPrice": gasPrices.low * 1000000000, // converts the gwei price to wei
"nonce": nonce,
//"data": gcodeHash,
"function": "testFunction",
"chainId": 3 // EIP 155 chainId - mainnet: 1, ropsten: 3, rinkeby: 4 (https://ethereum.stackexchange.com/questions/17051/how-to-select-a-network-id-or-is-there-a-list-of-network-ids/17101#17101)
};
const transaction = new EthereumTx(details);
// This is where the transaction is authorized on Local PC behalf. The private key is what unlocks Local PC wallet.
transaction.sign(Buffer.from(process.env.WALLET_PRIVATE_KEY, 'hex'));
// Compress the transaction info down into a transportable object
const serializedTransaction = transaction.serialize();
// The Web3 library is able to automatically determine the "from" address based on Local PC private key
// Submit the raw transaction details to the provider configured above (INFURA)
const transactionHash = await web3.eth.sendSignedTransaction('0x' + serializedTransaction.toString('hex')).then(function (receipt) {
log(`result of the invokation: ${receipt})`.red);
return receipt.transactionHash;
}).catch((err) => {
log(`error occurred: ${err})`.red);
});
//const transactionHash = "exampleHash";
_transactionHash = transactionHash;
// Now it is known the transaction ID, so let's build the public Etherscan url where the transaction details can be viewed.
const url = `https://ropsten.etherscan.io/tx/${transactionHash}`;
log(url.cyan);
log(`Note: please allow for 30 seconds before transaction appears on Etherscan`.yellow)
};
Output:
error occurred: Error: Transaction has been reverted by the EVM:
{
"blockHash": "0x6205c1b8ce2fde3693e85843dce684ff11472e9df01fd850bc99e5771b3262d5",
"blockNumber": 5024524,
"contractAddress": null,
"cumulativeGasUsed": "0x50170f",
"from": "0x8882528C7104e146E0500203C353C09922575385",
"gasUsed": "0x5236",
"logs": [],
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"status": "0x0",
"to": "0x1732089F6F6EeFA942871707c5AE1909B60774EB",
"transactionHash": "0xf748c9a6bdb19e776db4d8a9802d2bf5f8b588158da387029529249aca00a499",
"transactionIndex": 1
})
I would like to pay particular attention to the let details = {...}; object for which I am not very sure it is correct, I have a little confusion about this.

Ethereum sending with web3.js is not working today (the result is fail)

This is my web3.js function to send the ETH.
It works perfectly last month. But today It is not working well.
It took more than 1~5 min and then return the fail.
Some times it sent but It also takes very long time to complete the transaction.
Please help me with this problem.
This is my current codes.
var web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/GfgWbe8c2O82N18RRSuJ'));
// Who holds the token now?
var myAddress = address;
// This file is just JSON stolen from the contract page on etherscan.io under "Contract ABI"
return await web3.eth.getBalance(myAddress);
}
const sendETHCoin = async (from_addr, to_addr, amount, private_key, fee) => {
var content = fs.readFileSync(base_path + 'abiDefinitions/ethAbiContract.json');
content = JSON.parse(content);
///////////////////////////////////
// connect to Infura node
var web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/GfgWbe8c2O82N18RRSuJ'));
// the address that will send the test transaction
const addressFrom = from_addr;
const privKey = private_key;
// the destination address
const addressTo = to_addr;
var gasPrice = "0x02540BE400";
var gasLimit = "0x250CA";
if(fee == ''){
fee = parseInt(gasPrice, 16) * parseInt(gasLimit, 16);
}else{
gasPrice = parseInt(parseInt(fee)/parseInt(gasLimit, 16))+1;
if(gasPrice < 1){
gasPrice = 1;
}
gasPrice = "0x"+gasPrice.toString(16);
}
//gasPrice = "0x03540BE400";
var txCount = await web3.eth.getTransactionCount(addressFrom);
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(25000),
gasPrice: web3.utils.toHex(10e9), // 10 Gwei
to: addressTo,
from: addressFrom,
value: web3.utils.toHex(web3.utils.toWei(amount, 'wei'))
}
// Signs the given transaction data and sends it. Abstracts some of the details
// of buffering and serializing the transaction for web3.
const privateKey = new Buffer(privKey, 'hex')
const transaction = new Tx(txData)
transaction.sign(privateKey)
const serializedTx = transaction.serialize().toString('hex')
try {
return await web3.eth.sendSignedTransaction('0x' + serializedTx)
}catch(err) {
console.log(err.message);
return err.message;
}
//////////////////////////////
}
I hope someone could help me.
Best Regards.
TianYang
you can check in etherscan why the transaction fails. if the transaction worked last month, probably the problem is in the gas price. last week the gas prices were too high (safe low was 50 gwei) and I see that you are sending with 10gwei, this is most probably the reason why your transactions fail. Try increasing the gas price and see if it works again

Resources