Sending ERC-20 tokens fails. Transaction succeeds, but no tokens are sent - node.js

When I run the following code, it accurately gets the token balance for both addresses and the transaction even goes through (I can see it on the testnet), although no tokens are sent.
I've tried a variety of things including replacing the signed transaction piece with this:
await contract.methods.transfer(toAddress, 100000).send({
from: fromAddress
});
but that fails with an unknown account error.
My Code for sending tokens:
const Web3 = require("web3");
const { hdkey } = require("ethereumjs-wallet");
const bip39 = require("bip39");
const token = require("./token.json");
const mnemonic = "12 word phrase";
const provider = "https://apis.ankr.com/.../binance/full/test";
(async() => {
try {
const seed = await bip39.mnemonicToSeed(mnemonic);
const root = hdkey.fromMasterSeed(seed);
const web3 = new Web3(provider);
const addrNode = root.derivePath(`m/44'/60'/0'/0/0`);
const wallet = addrNode.getWallet();
// #0 in the hdwallet, the owner of the tokens
const fromAddress = wallet.getAddressString();
// #1 in the hdwallet, already has a token balance
const toAddress = "0x...";
const contract = new web3.eth.Contract(token.abi, token.contract_address);
let fromAddressBalance = await contract.methods.balanceOf(fromAddress).call();
let toAddressBalance = await contract.methods.balanceOf(toAddress).call();
console.log(`Pre Transaction: Sender: ${fromAddressBalance} TOKENS / Wallet: ${toAddressBalance} TOKENS`);
// token has 3 decimal places, this is 100.000
const encodedABI = contract.methods.transfer(toAddress, 100000).encodeABI();
const tx = {
from: fromAddress,
to: toAddress,
gas: 2000000,
value: 0x0,
data: encodedABI
};
const signed = await web3.eth.accounts.signTransaction(tx, wallet.privateKey.toString("hex"));
const trans = await web3.eth.sendSignedTransaction(signed.rawTransaction);
fromAddressBalance = await contract.methods.balanceOf(fromAddress).call();
toAddressBalance = await contract.methods.balanceOf(toAddress).call();
console.log(`Post Transaction: Sender: ${fromAddressBalance} TOKENS / Wallet: ${toAddressBalance} TOKENS`);
} catch (err) {
console.error(err.stack);
}
process.exit();
})();

There were a few things wrong that once fixed resolved my issue. I haven't gone back through and tested which did it, or if all were required, but wanted to leave this for future explorers.
I was creating a wallet with ethereum-js-wallet, and then using it with web3. You have to let web3 know about the wallet.
const account = web3.eth.accounts.privateKeyToAccount(privateKey);
web3.eth.accounts.wallet.create();
web3.eth.accounts.wallet.add(account);
Private key addresses need to start with 0x.
Source: https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#privatekeytoaccount
const privateKey = `0x${wallet.privateKey.toString("hex")}`;
This ended up not mattering, and not being the correct way to transfer, but it's still a good note that I was sending a signed transaction to a 3rd party, NOT to the contract, the correct way to send the transaction would have been
const tx = {
from: fromAddress,
to: token.contract_address,
gas: 2000000,
value: 0x0,
data: encodedABI
};
Ultimately, I needed to take advantage of the contract's transfer method vs signing/sending a transaction
const result = await contract.methods.transfer(toAddress, 100).send({
from: fromAddress,
gas: 2000000
});

Related

UniswapV2 swapExactETHForTokens method fails with error status 'UniswapV2: TRANSFER_FAILED'

I am using web3.js library and I am trying to buy a token by calling swapExactETHForTokens method from
UniswapV2Router02 smart contract, but I don't know why my transaction fails. I approved WETH for this transaction, but still get an error with the following status:
Fail with error 'UniswapV2: TRANSFER_FAILED'
My code:
const swapTokens = async () => {
const PRIVATE_KEY = 'my private key goes here';
web3.eth.accounts.wallet.add(PRIVATE_KEY);
const myAccount = web3.eth.accounts.wallet[0].address;
const WETHAddress = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const swapRouterAddress = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D';
const routerContract = new web3.eth.Contract(
UNISWAP_V2_ROUTER_ABI,
swapRouterAddress,
);
const tokenToBuyAddress = '0x0913dDAE242839f8995c0375493f9a1A3Bddc977';
const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
const block = await web3.eth.getBlock('latest');
const gasLimit = Math.round(block.gasLimit / block.transactions.length);
const amountToBuy = 0.01;
const result = await routerContract.methods
.swapExactETHForTokens(
web3.utils.toHex(0),
[WETHAddress, tokenToBuyAddress],
myAccount,
deadline,
)
.send({
from: myAccount,
gasLimit,
value: web3.utils.toWei(`${amountToBuy}`, 'ether'),
});
console.log('result: ', result);
}
swapTokens();
Transaction details on etherscan: https://etherscan.io/tx/0x4c6f507ed95b2889bdb929a34dbbe0114db168c2462ce21778eeed9dc4a894eb
Smart contract of token which I am trying to buy: https://etherscan.io/address/0x0913dDAE242839f8995c0375493f9a1A3Bddc977#code
Your transaction ran out of gas. Increase your gas limit

How to send already minted NFT using alchemy

I have minted some NFTs on opensea. These are on Polygon Mumbai network. Now I want to transfer these to token to other addresses using alchemy web3. Here is the code I am using.
Note: This is supposed to run in nodejs restful API, so there is no wallet available that why I am manually signing the transaction.
async function main() {
require('dotenv').config();
const { API_URL,API_URL_TEST, PRIVATE_KEY } = process.env;
const { createAlchemyWeb3 } = require("#alch/alchemy-web3");
const web3 = createAlchemyWeb3(API_URL_TEST);
const myAddress = '*************************'
const nonce = await web3.eth.getTransactionCount(myAddress, 'latest');
const transaction = { //I believe transaction object is not correct, and I dont know what to put here
'asset': {
'tokenId': '******************************',//NFT token id in opensea
},
'gas': 53000,
'to': '***********************', //metamask address of the user which I want to send the NFT
'quantity': 1,
'nonce': nonce,
}
const signedTx = await web3.eth.accounts.signTransaction(transaction, PRIVATE_KEY);
web3.eth.sendSignedTransaction(signedTx.rawTransaction, function(error, hash) {
if (!error) {
console.log("🎉 The hash of your transaction is: ", hash, "\n Check Alchemy's Mempool to view the status of your transaction!");
} else {
console.log("âť—Something went wrong while submitting your transaction:", error)
}
});
}
main();
Assumed that you have Metamask installed in your browser, and that the NFT smart contract follows ERC721 Standard
const { API_URL,API_URL_TEST, PRIVATE_KEY } = process.env;
const { createAlchemyWeb3 } = require("#alch/alchemy-web3");
const {abi} = YOUR_CONTRACT_ABI
const contract_address = CONTRACT ADDRESS
require('dotenv').config();
async function main() {
const web3 = createAlchemyWeb3(API_URL_TEST);
web3.eth.getAccounts().then(accounts => {
const account = account[0]
const nameContract = web3.eth.Contract(abi, contract_address);
nameContract.methods.transfer(account, ADDRESS_OF_WALLET_YOU_WANT_TO_SEND_TO, TOKEN_ID).send();
})
.catch(e => console.log(e));
}
main();
Had the same problem, because there is no example on transferring NFT token.
There is a well explained 3-parts-example on ethereum website to mint an NFT.
In the first part, step 10, it explains how to write a contract and also mentions the existing methods in the contract object extended:
After our import statements, we have our custom NFT smart contract, which is surprisingly short — it only contains a counter, a constructor, and single function! This is thanks to our inherited OpenZeppelin contracts, which implement most of the methods we need to create an NFT, such as ownerOf which returns the owner of the NFT, and transferFrom, which transfers ownership of the NFT from one account to another.
So, with these informations, I made an NFT transfer transaction between two addresses with my metamask mobile app. Then I searched the JSON of this transaction through etherscan API.
In this way, I was able to transfer tokens to other addresses using alchemy web3 with this script:
require("dotenv").config()
const API_URL = process.env.API_URL; //the alchemy app url
const PUBLIC_KEY = process.env.PUBLIC_KEY; //my metamask public key
const PRIVATE_KEY = process.env.PRIVATE_KEY;//my metamask private key
const {createAlchemyWeb3} = require("#alch/alchemy-web3")
const web3 = createAlchemyWeb3(API_URL)
const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json")//this is the contract created from ethereum example site
const contractAddress = "" // put here the contract address
const nftContract = new web3.eth.Contract(contract.abi, contractAddress)
/**
*
* #param tokenID the token id we want to exchange
* #param to the metamask address will own the NFT
* #returns {Promise<void>}
*/
async function exchange(tokenID, to) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest');
//the transaction
const tx = {
'from': PUBLIC_KEY,
'to': contractAddress,
'nonce': nonce,
'gas': 500000,
'input': nftContract.methods.safeTransferFrom(PUBLIC_KEY, to, tokenID).encodeABI() //I could use also transferFrom
};
const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY)
signPromise
.then((signedTx) => {
web3.eth.sendSignedTransaction(
signedTx.rawTransaction,
function (err, hash) {
if (!err) {
console.log(
"The hash of your transaction is: ",
hash,
"\nCheck Alchemy's Mempool to view the status of your transaction!"
)
} else {
console.log(
"Something went wrong when submitting your transaction:",
err
)
}
}
)
})
.catch((err) => {
console.log(" Promise failed:", err)
})
}
I Had the same problem. I need to transfer NFT in node.js back-end.
I use network provider to use Moralis NetworkWeb3Connector.
here's my repository for example:
https://github.com/HanJaeJoon/Web3API/blob/2e30e89e38b7b1f947f4977a0fe613c882099fbc/views/index.ejs#L259-L275
await Moralis.start({
serverUrl,
appId,
masterKey,
});
await Moralis.enableWeb3({
// rinkeby
chainId: 0x4,
privateKey: process.env.PRIVATE_KEY,
provider: 'network',
speedyNodeApiKey: process.env.MORALIS_SPEEDY_NODE_API_KEY,
});
const options = {
type,
receiver,
contractAddress,
tokenId,
amount: 1,
};
try {
await Moralis.transfer(options);
} catch (error) {
console.log(error);
}
you can get speed node api key in
Moralis dashboad > Networks > Eth Rinkeby(in my case) > Settings
screenshot

Rinkeby Uniswap swapExactETHForTokens - Fail with error 'UniswapV2Router: EXPIRED'

Ideally, I need example of correct transaction format in web3 or ethers,
Where it can swap WETH for ERC20 or ERC20 for WETH using UniswapV2Router on Rinkeby,
I think, I'm having wrong transaction format, maybe it's because of gasPrice or gasLimit, but I don't understand where it happens, So I tried with the increased gasPrice(100 Gwei) and gasLimit(8,000,000) but it's still failing, I also decreased the "amountOutMin" to 1,
Transaction deadline is 20 minutes but it's failiing in a few seconds
Swap 1 Ether for UNI (WETH and ETH balances are more than 5 on sender's address)
transaction deadline: 20 minute
UNI address: 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
UniswapV2Router: 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Another small question, when you swap ETH for ERC20 does it takes WETH or ETH from senders balance?
const swap = async () => {
try{
const chainId = ChainId.RINKEBY
const tokenAddress = "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"
const uni = await Fetcher.fetchTokenData(chainId, tokenAddress)
const weth = WETH[chainId]
const pair = await Fetcher.fetchPairData(uni, weth)
const route = new Route([pair], weth)
const trade = new Trade(route, new TokenAmount(weth, '100000000000000000'), TradeType.EXACT_INPUT)
console.log('1 WETH for', route.midPrice.toSignificant(6), ' UNI')
console.log('1 UNI for', route.midPrice.invert().toSignificant(6), ' WETH')
console.log('Trade price 1 WETH for ', trade.executionPrice.toSignificant(6), ' UNI')
const accounts = await web3.eth.getAccounts()
const account = accounts[0]
const slippageTolerance = new Percent('20', '100')
const path = [weth.address, uni.address ]
const to = account
// function toHex(currencyAmount) {
// return `0x${currencyAmount.raw.toString(16)}`
// }
// const amountOutMin = toHex(trade.minimumAmountOut(slippageTolerance))
// const value = toHex(trade.inputAmount)
const uniswap = await new web3.eth.Contract(abi, "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")
const now = moment().unix()
const DEADLINE = now + 60 *20
console.log('Sending...')
let txn = await uniswap.methods.swapExactETHForTokens( 1, path, to, DEADLINE ).send( {
from: account,
gasLimit: 8000000,
gasPrice: web3.utils.toWei('100', 'Gwei'),
value: web3.utils.toWei('1', 'Ether')
})
console.log(`Txn: https://rinkeby.etherscan.io/tx/${txn.transactionHash}`)
}catch(e){
console.log(e)
}
}
module.exports = swap
Transaction results on rinkeby etherscan:
Console:
"Error: Transaction has been reverted by the EVM "
Here is an example of swapping ETH to UNI. I am using ethJS.
const WETH_ADDRESS = "0xc778417e063141139fce010982780140aa0cd5ab";
const UNI_ADDRESS = "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984";
const path = [WETH_ADDRESS, UNI_ADDRESS];
const ethAmount = ethers.utils.parseEther("0.1");
const nowInSeconds = Math.floor(Date.now() / 1000)
const expiryDate = nowInSeconds + 900;
const txn = await uniswapV2Contract.swapExactETHForTokens(
0,
path,
user.address,
expiryDate,
{
gasLimit: 1000000,
gasPrice: ethers.utils.parseUnits("10", "gwei"),
value: ethAmount
}
)
const res = await txn.wait();
When you call the method swapExactETHForTokens, it would be taking ETH and not WETH. If you would like to swap with WETH, you should call swapExactTokensForTokens.

ERC20 Token transfer with Web3JS on Infura Ropsten Testnet - Transaction has been reverted by the EVM

So, after one day of searching and many purple links I cannot do anything else but to ask a question about the topic asked a dozen times, yet somehow each issue is unique to its own.
Info:
Node v12.16.1
Ropsten Testnet via Infura API
"web3": "1.2.6"
"ethereumjs-tx": "2.1.2"
ERC20 token example , changed Token name and decimals to 8 and pragma solidity ^0.5.2;
Important note: Smart contract is compiled and deployed via Remix (using 0.5.3 compiler), transfer() method tested successfully via Metamask.
This code produces this bug: - Transaction has been reverted by the EVM
const Web3 = require("web3");
const compiled = require("./compile");
const Tx = require("ethereumjs-tx").Transaction;
const contractAddress = "0x27...";
const address = "0x02...";
const privateKey = "A475...";
const bufferedPrivKey = Buffer.from(privateKey, "hex");
const rpcUrl = "https://ropsten.infura.io/v3/{INFURA_API_KEY}";
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl));
const call = async () => {
try {
const abi = compiled.abi; //copied from remix
const contract = await new web3.eth.Contract(abi, contractAddress, {
from: address
});
const gasPrice = await web3.eth.getGasPrice();
const nonce = await web3.eth.getTransactionCount(address);
const data = await contract.methods.transfer("0x2B0...", 1000).encodeABI();
const rawTx = {
from: address,
gasPrice: web3.utils.toHex(gasPrice),
gas: web3.utils.toHex(100000),
data: data,
nonce: web3.utils.toHex(nonce),
value: 0x00,
chainId: 0x03 //ropsten i guess?
};
const tx = new Tx(rawTx, { chain: "ropsten" });
tx.sign(bufferedPrivKey);
const serializedTx = tx.serialize();
await web3.eth.sendSignedTransaction("0x" + serializedTx.toString("hex"));
} catch (err) {
console.log(err);
console.log(err.stack);
}
};
call();
Fun facts:
I was having the same issue when i tried to deploy smart contract via web3.eth.sendSignedTransaction()
Following the rabbit hole I've found potential solution to lower web3 version to 1.0.0-beta.34 and when I did, I had gas issues - transfer transaction took ages and eventually I ran out of gas. Most of the issues were:
intrinsic gas too low
or
Transaction ran out of gas. Please provide more gas

Sending a transaction results in "invalid sender"

I'm attempting to call a function on my smart contract (Ropsten) using web3 via an Infura node. I've created a test account in Metmask and have exported the account address and private key. The details look correct, however I am getting the error {"code":-32000,"message":"invalid sender"}. I'm guessing this is a problem with the signing of the transaction?
Here's my code
const Web3 = require('web3');
const Tx = require('ethereumjs-tx').Transaction;
const fs = require('fs');
const pk = Buffer.from('PRIVATE KEY FROM METAMASK', 'hex')
const sourceAccount = 'ACCOUNT ADDRESS FROM METAMASK'
const web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/v3/API_KEY"));
const consumerAddress = '0xc36577aa0171f649be6bd7205148ed83c07198ee';
web3.eth.defaultAccount = sourceAccount;
//Get Consumer contract instance
const consumerAbi = JSON.parse(fs.readFileSync('rental-contract-abi.json', 'utf8'));
let consumerContract = new web3.eth.Contract(consumerAbi, consumerAddress);
const myData = consumerContract.methods.checkDate("e716efba3b404da98e28faaa2939c0fd","2019-06-04","AU-NSW").encodeABI();
web3.eth.getTransactionCount(sourceAccount, (err, txCount) => {
// Build the transaction
const txObject = {
nonce: web3.utils.toHex(txCount),
to: consumerAddress,
from: sourceAccount,
chainId: 3,
value: web3.utils.toHex(web3.utils.toWei('0', 'ether')),
gasLimit: web3.utils.toHex(2100000),
gasPrice: web3.utils.toHex(web3.utils.toWei('6', 'gwei')),
data: myData
}
// Sign the transaction
const tx = new Tx(txObject);
tx.sign(pk);
const feeCost = tx.getUpfrontCost()
console.log('Total Amount of ETH needed:' + web3.utils.fromWei(feeCost.toString(), 'ether'))
console.log('---Serialized TX----')
console.log(tx.serialize().toString('hex'))
console.log('--------------------')
const serializedTx = tx.serialize();
const raw = '0x' + serializedTx.toString('hex');
// Broadcast the transaction
const transaction = web3.eth.sendSignedTransaction(raw, (err, tx) => {
console.log(tx);
console.log(err);
});
});
You need to add network information while signing the transaction. Refer to latest web3 docs. Change signing transaction code to :
const tx = new Tx(txObject,{'chain':'ropsten'});

Resources