How to send an ERC20 token with web3js
Asked Answered
F

5

16

I'm currently using the 0.2x.x version of the Web3 JavaScript API. I deployed my custom ERC20 token by creating smart contract in solidity (on REMIX IDE). I installed the MetaMask and had a test on https://wallet.ethereum.org/ to send some custom ERC token to another my account. It worked well. I want to add the 'send custom ERC20 Token' function in my JavaScript code using Web3js.

Here is my code below.

var http = require('http');
var Web3 = require('web3');
var Tx = require('ethereumjs-tx');

var abi = [{"...."}]; 
var data = '0x00..';
var contract_addr = '0x00..';
var owner = '0x00..';

var web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/")); 
web3.eth.getBlock("latest", (error, result) => {
//console.log('error:', error);
//console.log('results', result);
});

var myContract = web3.eth.contract(abi);
var myContractInstance = myContract.at(address);

eb3.eth.getDefaultAccount = owner;
var defaultAccount = web3.eth.getDefaultAccount;
console.log('DefaultAccount => ', defaultAccount); 

var total = myContractInstance.totalSupply();
var balance = myContractInstance.balanceOf(defaultAccount);

console.log('DefulatAccount total => ',total);
console.log('DefaultAccount balance => ',balance);

var to = '0x00..';
var isAddress = web3.isAddress(to);

console.log('isAddress(to) => ',isAddress);
console.log('balanceOf(to) => ',myContractInstance.balanceOf(to));

I'm working on the 'Ropsten Testnet' and I sent some 'ether' for test using sendRawTransaction(). But what I want to do is just sending my custom ERC20 token. not the ether. How can I send my own token in this script? I have no idea. I tried to use sendTransaction() like below.

var rawTx = {
    from : defaultAccount,
    nonce : nonceHex,
    gasPrice : gasPriceHex,
    gas : gasHex,
    to : to,
    value : 100,
    data : data
};

web3.eth.sendTransaction(rawTx, function(err, transactionHash) {
    if (!err)
        console.log('transactionHash => ',transactionHash);
    else
        console.log(err);
});

I continuously received the error.

Error: Invalid JSON RPC response: ""
at Object.InvalidResponse (/Users/rachel/dev/test/node_modules/web3/lib/web3/errors.js:38:16)
at XMLHttpRequest.request.onreadystatechange (/Users/rachel/dev/test/node_modules/web3/lib/web3/httpprovider.js:119:24)
at XMLHttpRequestEventTarget.dispatchEvent (/Users/rachel/dev/test/node_modules/xhr2/lib/xhr2.js:64:18)
at XMLHttpRequest._setReadyState (/Users/rachel/dev/test/node_modules/xhr2/lib/xhr2.js:354:12)
at XMLHttpRequest._onHttpResponseEnd (/Users/rachel/dev/test/node_modules/xhr2/lib/xhr2.js:509:12)
at IncomingMessage.<anonymous> (/Users/rachel/dev/test/node_modules/xhr2/lib/xhr2.js:469:24)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1056:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)

I really can't understand what is wrong with it. Please let me know some way to deal with this. Thanks!

Foolery answered 10/1, 2018 at 5:38 Comment(0)
W
14

Take EOS token transfering as the example.

Below code need web3 and ethereumjs-tx. If you've not install them, install them with npm install web3 ethereumjs-tx

var Tx = require('ethereumjs-tx');
var Web3 = require('web3')
var web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545/'))

// set token source, destination and amount
var myAddress = "0xaa597b7e8aaffe9f2a187bedb472ef3455957560"
var toAddress = "0xa013927bffe9e879134061b9330a01884a65497c"
var amount = web3.utils.toHex(1e16)

// get transaction count, later will used as nonce
web3.eth.getTransactionCount(myAddress).then(function(v){console.log(v); count = v})  

// set your private key here, we'll sign the transaction below
var privateKey = new Buffer('6d...', 'hex')  

// Get abi array here https://etherscan.io/address/0x86fa049857e0209aa7d9e616f7eb3b3b78ecfdb0#code
var abiArray = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint128"}],"name":"push","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"name_","type":"bytes32"}],"name":"setName","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint128"}],"name":"mint","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"wad","type":"uint128"}],"name":"pull","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint128"}],"name":"burn","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"start","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"},{"name":"guy","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"symbol_","type":"bytes32"}],"payable":false,"type":"constructor"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]
// Here you may get the abicode from a string or a file, here is a string case
// var abiArray = JSON.parse('[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"stop","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint128"}],"name":"push","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"name_","type":"bytes32"}],"name":"setName","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint128"}],"name":"mint","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"stopped","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"wad","type":"uint128"}],"name":"pull","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint128"}],"name":"burn","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"start","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"src","type":"address"},{"name":"guy","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"symbol_","type":"bytes32"}],"payable":false,"type":"constructor"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]', 'utf-8')

var contractAddress = '0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0'
var contract = new web3.eth.Contract(abiArray, contractAddress, {from: myAddress})

var rawTransaction = {"from":myAddress, "gasPrice":web3.utils.toHex(2 * 1e9),"gasLimit":web3.utils.toHex(210000),"to":contractAddress,"value":"0x0","data":contract.methods.transfer(toAddress, amount).encodeABI(),"nonce":web3.utils.toHex(count)} 
var transaction = new Tx(rawTransaction)
transaction.sign(privateKey)

web3.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex'))

// check the balance
contract.methods.balanceOf(myAddress).call().then(function(balance){console.log(balance)})

You also can check the transaction with https://etherscan.io.

After the transaction send, you can check it with https://etherscan.io/address/0xaa597b7e8aaffe9f2a187bedb472ef3455957560#tokentxns, and you'll see the pending transaction as below on the Transactions filed, but you cannot see it in the Token Transfers field.

enter image description here

Wait about 1 minute, you can see the successed on both Transactions filed and the Token Transfers field.

enter image description here enter image description here

Winonawinonah answered 25/4, 2018 at 10:15 Comment(4)
How to send ERC20 token using Web3 API?Winonawinonah
As of July 2018, this post is rather misleading. Kris was referring to the canonical EOS ERC20 token on Ethereum. In the meantime, EOS has launched and they have their own native currency.Diadromous
Here refer to EOS token on Ethereum, not EOS coin.Winonawinonah
hello how to do this in PHP code? any info?Unwisdom
H
2

Error: Invalid JSON RPC response: "" means web3 cant connect to rpc node. Try running one with ::

-for testnet

geth --testnet --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpccorsdomain '*' --rpcapi personal,admin,db,eth,net,web3,miner,shh,txpool,debug --ws --wsaddr 127.0.0.1 --wsport 8546 --wsorigins '*' --wsapi personal,admin,db,eth,net,web3,miner,shh,txpool,debug --maxpeers 25 0 --gasprice 100

-for mainnet

geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --rpccorsdomain '*' --rpcapi personal,admin,db,eth,net,web3,miner,shh,txpool,debug --ws --wsaddr 127.0.0.1 --wsport 8546 --wsorigins '*' --wsapi personal,admin,db,eth,net,web3,miner,shh,txpool,debug --maxpeers 25 0 --gasprice 100

Now in your case (using infura testnet node), get a id from infura.io. It should be like this ::

https://ropsten.infura.io/id
Holism answered 3/7, 2018 at 0:53 Comment(1)
That's right; check your internet connection. I get that error when my internet is offVampirism
I
1

You need to call the transfer method of the ERC20 contract. e.g.:

myContractInstance.methods.transfer(toAddress, amount);

And in your raw transaction object:

  1. You don't need the amount
  2. To address should be to the contract (not the toAddress in the method call)

e.g.:

var rawTx = {
  from : defaultAccount,
  nonce : nonceHex,
  gasPrice : gasPriceHex,
  gas : gasHex,
  to : <contractAddress>,
  data : data

};

Is answered 13/4, 2021 at 23:5 Comment(0)
G
0

Well you can try something like this-:

`myContractInstance.transfer(to,amount, {gas:estimateGas, 
 gasPrice:gasPrice,from:fromAddr, nonce: nonceis}, function(err,txhash)
  {
    console.log("error: "+err);
    console.log("txhash: "+txhash);
  }
`

Here 'to' is the address to whom you want to send tokens
'amount' amount of tokens you want to send
'estimateGas' gas limit you want to put of the transaction execution
'gasPrice' price of each gas unit in terms of wei
'fromAddr' the address from where you want to send these tokens. As the transaction will be signed using this address, this should be the address selected in metamask or passed to infura
'nonceis' nonce for the transaction

Goldston answered 10/1, 2018 at 11:8 Comment(0)
N
0

We can do it with only 'ethers'. In this case, I use backend api with node js.

const fs = require('fs');
const express = require('express');
const router = express.Router();
const { ethers, BigNumber } = require('ethers');
const ethUtil = require('ethereumjs-util');

const BridgeEth = require("../../client/src/components/contract/EthBridge.json");
const BridgeBsc = require("../../client/src/components/contract/BridgeBsc.json");
const addresses = require("../../client/src/components/contract/config.json");
const eth_bridge = addresses.eth_bridge;
const bsc_bridge = addresses.bsc_bridge;
const net_config = require("../../net.config.json");

const ethnet = net_config.eth_url;
const bscnet = net_config.bsc_url;
const eth_provider = new ethers.providers.JsonRpcProvider(ethnet);
const bsc_provider = new ethers.providers.JsonRpcProvider(bscnet);
const eth_contract = new ethers.Contract(eth_bridge, BridgeEth, eth_provider);
const bsc_contract = new ethers.Contract(bsc_bridge, BridgeBsc, bsc_provider);

var privateKey = fs.readFileSync('./secret', 'utf-8');

const adminaccount = {
  publicKey: net_config.admin_public_key,
  privateKey: privateKey
}

console.log(`Admin account is ${adminaccount.publicKey}`);

const adminEthWallet = new ethers.Wallet(adminaccount.privateKey, eth_provider);
const adminBscWallet = new ethers.Wallet(adminaccount.privateKey, bsc_provider);

const signedEthContract = eth_contract.connect(adminEthWallet);
const signedBscContract = bsc_contract.connect(adminBscWallet);

const sig = "0x6162636400000000000000000000000000000000000000000000000000000000";

router.post('/eth2bsc', async (req, res) => {
  var account = req.body.account;
  var amount = req.body.amount;
  var signature = req.body.signature;
  var msg = req.body.hash;

  const isValidAddress = ethUtil.isValidAddress(account);
  const isValidAmount = amount > 0;
  const isValidSign = ethUtil.isHexPrefixed(String(signature));
  const isValidHash = ethUtil.isHexPrefixed(String(msg));

  if (!(isValidAddress && isValidAmount && isValidSign && isValidHash)) {
    return res.status(500).json({ step: 1, message: `Security error! Server received invalid prams!${isValidAddress}, ${amount}, ${isValidSign}, ${isValidHash}` });
  }

  var msgBuffer = '';
  var msgHash = '';
  var signatureBuffer = '';

  try {
    msgBuffer = ethUtil.toBuffer(msg);
    msgHash = ethUtil.hashPersonalMessage(msgBuffer);
    signatureBuffer = ethUtil.toBuffer(signature);
  } catch (e) {
    return res.status(500).json({ step: 1, message: 'Security error! Request with invalid params!' })
  }


  const signatureParams = ethUtil.fromRpcSig(signatureBuffer);
  const publicKey = ethUtil.ecrecover(msgHash, signatureParams.v, signatureParams.r, signatureParams.s);
  const adddressBuffer = ethUtil.publicToAddress(publicKey);
  const address = ethUtil.bufferToHex(adddressBuffer);

  console.log(`recvered address is ${address}`);

  const isMatched = account.toLowerCase() == address.toLowerCase();

  if (!isMatched) {
    return res.status(500).json({ step: 1, message: 'Security error! Transaction caller is not signer!' })
  }

  console.log(`I will burn BSCFloki from ${account}`)
  try {
    var tx = await signedEthContract.burn(account, BigNumber.from(String(amount * Math.pow(10, 18))), 0, sig)
    console.log(tx.hash);
    console.log("First transaction successed(ETHFloki burned)");
  } catch (e) {
    console.log("Transaction to burn ETHFloki faild");
    return res.status(500).json({ step: 1, message: 'Transaction Faild! \nCheck your account and token balance.' })
  }
  console.log(`I will mint BSCFloki to ${account}`)
  try {
    var tx1 = await signedBscContract.mint(account, account, BigNumber.from(String(amount * Math.pow(10, 18))), 0, sig);
    console.log(tx1.hash);
    console.log("Second transaction successed(BSCFloki minted)");
  } catch (e) {
    console.log("Transanction to mint BSCFloki faild");
    return res.status(500).json({ step: 2, message: 'Transaction Faild! \nCheck your account.' })
  }
  return res.send(`Success! \n ${amount} ETHFloki converted to ${amount} BSCFloki in your wallet.`);
});


router.post('/bsc2eth', async (req, res) => {
  var account = req.body.account;
  var amount = req.body.amount;
  var signature = req.body.signature;
  var msg = req.body.hash;

  const isValidAddress = ethUtil.isValidAddress(account);
  const isValidAmount = amount > 0;
  const isValidSign = ethUtil.isHexPrefixed(String(signature));
  const isValidHash = ethUtil.isHexPrefixed(String(msg));

  if (!(isValidAddress && isValidAmount && isValidSign && isValidHash)) {
    return res.status(500).json({ step: 1, message: 'Security error! Server received invalid prams!' });
  }

  var msgBuffer = '';
  var msgHash = '';
  var signatureBuffer = '';

  try {
    msgBuffer = ethUtil.toBuffer(msg);
    msgHash = ethUtil.hashPersonalMessage(msgBuffer);
    signatureBuffer = ethUtil.toBuffer(signature);
  } catch (e) {
    return res.status(500).json({ step: 1, message: 'Security error! Request with invalid params!' })
  }

  const signatureParams = ethUtil.fromRpcSig(signatureBuffer);
  const publicKey = ethUtil.ecrecover(msgHash, signatureParams.v, signatureParams.r, signatureParams.s);
  const adddressBuffer = ethUtil.publicToAddress(publicKey);
  const address = ethUtil.bufferToHex(adddressBuffer);

  console.log(`recvered address is ${address}`);

  const isMatched = account.toLowerCase() == address.toLowerCase();

  if (!isMatched) {
    return res.status(500).json({ step: 0, message: 'Security error! Transaction caller is not signer!' })
  }

  console.log(`I will burn BSCFloki from ${account}`)
  try {
    var tx = await signedBscContract.burn(account, BigNumber.from(String(amount * Math.pow(10, 18))), 0, sig)
    console.log(tx.hash);
    console.log("First transaction successed(BTK burned)");
  } catch (e) {
    console.log("Transaction to burn ETHFloki faild");
    return res.status(500).json({ step: 1, message: 'Transaction Faild! \nCheck your account and token balance.' })
  }
  console.log(`I will mint ETHFloki to ${account}`)
  try {
    var tx1 = await signedEthContract.mint(account, account, BigNumber.from(String(amount * Math.pow(10, 18))), 0, sig);
    console.log(tx1.hash);
    console.log("Second transaction successed(ETHFloki minted)");
  } catch (e) {
    console.log("Transaction to mint ETHFloki faild");
    return res.status(500).json({ step: 2, message: 'Transaction Faild! \nCheck your account.' })
  }
  return res.send(`Success! \n ${amount} BSCFloki converted to ${amount} ETHFloki in your wallet.`);
});

module.exports = router;

This api is sign client's request and send transaction with signed wallet and its private key.

Nimiety answered 2/12, 2021 at 3:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.