11

I've read some docs, run parity in docker container, and being able to connect and get token balance of an account

const Web3 = require('web3'),
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545'));
const contract = new web3.eth.Contract(JSON.parse(config.contract.abi), config.contract.address, { from: '0x...', gas: 100000 });

contract.methods.balanceOf('0x...').call()
    .then(console.log)
    .catch(console.error);

What I don't understand is how to initiate transfer of the tokens?

According to docs it should be something like this:

contract.methods.transfer('0x...', web3.utils.toWei(0.001)).send()
    .then(console.log)
    .catch(console.error);

I've tried with callbacks, promises, tried listening to events, but in any case my script is getting stuck and doesn't exit or produce any output

I'm expecting an error: unauthorized in this case and then I'd figure out how to pass my private key or unlock an account (not really sure). Couldn't find anywhere complete example.

Everything I found on stackexchange looks similar to

contract.transfer.sendTransaction('0x...', amount, { from: ..., gas: 100000 })

and doesn't work for me at all, complains about undefined methods: transfer and then sendTransaction if I use contract.methods.transfer

So what's the proper way of doing that?

4 Answers 4

9

Almost all of the docs out there refer to the 0.20 branch of web3.js which is the current stable branch. The version with promises as above is the 1.0.0-beta branch, which as of a few days ago npm installs by default.

As for sample code, the following code, almost identical to yours, is working correctly for me from the node console against my own ERC20 token running with testrpc locally.

The main point of difference I think is only the amount transferred. The toWei() method is not really applicable to ERC20 tokens and may confuse things.

Also, if you are on mainnet, it's going to take a while for the send() to get mined and the promise won't resolve until then. You may need to set the gasPrice option on the contract to a few GWei. On reflection, this is definitely an issue. (The call() methods are processed locally so there's no waiting and no gas cost.)

But then, if it's not asking you to unlock an account, I don't know... It may be well worth setting up testrpc locally (testrpc -d is useful) and deploying an ERC20 contract locally to check everything out without the added complications of paying for gas etc.

Anyway, perhaps this sample is useful to you or to others.

> const Web3 = require('web3');
undefined
> const web3 = new Web3('http://localhost:8545');
undefined
> web3.version
'1.0.0-beta.11'
> fs = require('fs');
<blah>
> const abi = fs.readFileSync('erc20_abi.json', 'utf-8');
undefined
> const contract = new web3.eth.Contract(JSON.parse(abi), '0xafb7b8a4d90c2df4ce640338029d54a55bedcfc4', { from: '0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1', gas: 100000});
undefined
> contract.methods.balanceOf('0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1').call().then(console.log).catch(console.error);
Promise {...}
> 99997
> contract.methods.transfer('0xffcf8fdee72ac11b5c542428b35eef5769c409f0', 1).send().then(console.log).catch(console.error);
Promise {...}
> { transactionHash: '0xf2d621ba5029a086e212d87fab83be31c3fa41fe47198c378f55c252e5b25d5b',
  transactionIndex: 0,
  blockHash: '0x0e806bf3e88f9335ee9be903303a2393c940ab22f4a73c7e28ca8d9a212ffa4e',
  blockNumber: 429,
  gasUsed: 35206,
  cumulativeGasUsed: 35206,
  contractAddress: null,
  events: 
   { Transfer: 
      { logIndex: 0,
        transactionIndex: 0,
        transactionHash: '0xf2d621ba5029a086e212d87fab83be31c3fa41fe47198c378f55c252e5b25d5b',
        blockHash: '0x0e806bf3e88f9335ee9be903303a2393c940ab22f4a73c7e28ca8d9a212ffa4e',
        blockNumber: 429,
        address: '0xAFB7b8A4d90C2Df4ce640338029d54A55BEDcfC4',
        type: 'mined',
        id: 'log_bfd297b0',
        returnValues: [Object],
        event: 'Transfer',
        signature: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
        raw: [Object] } } }
> contract.methods.balanceOf('0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1').call().then(console.log).catch(console.error);
Promise {...}
> 99996
2
  • This is great, so I'm on the right track. However I still can't see from your example how do you authenticate/unlock an account. I'm aware that toWei is not for tokens, but works great with the one I'm testing on.
    – user16150
    Commented Jul 27, 2017 at 21:23
  • To be fair, that wasn't your original question... Accounts are unlocked with web3.eth.personal.unlockAccount(account, password, unlocktime) which they haven't got round to documenting yet. I don't know how this with a Ledger Nano S, say, probably through the GUI first. I'll look into it at the weekend and update the answer with anything useful. Commented Jul 28, 2017 at 6:04
8

web3 1.0 API change.

let myContract = new web3.eth.Contract(abi, contractAddress);
let data = myContract.methods.transfer(toAddress, value).encodeABI();
let rawTx = {
    "nonce": web3.utils.toHex(nonce),
    "gasPrice": "0x3b9aca00",
    "gasLimit": web3.utils.toHex(gasLimit),
    "to": contractAddress,
    "value": "0x00",
    "data": data,
}
const tx = new Tx(rawTx)
tx.sign(privateKey)
let serializedTx = "0x" + tx.serialize().toString('hex');
web3.eth.sendSignedTransaction(serializedTx).on('transactionHash', function (txHash) {

}).on('receipt', function (receipt) {
    console.log("receipt:" + receipt);
}).on('confirmation', function (confirmationNumber, receipt) {
    //console.log("confirmationNumber:" + confirmationNumber + " receipt:" + receipt);
}).on('error', function (error) {

});

you can see this: Transferring ERC20 tokens from account using web3 over Ropsten

1
  • 2
    To complement your answer, transaction can also be signed with the web3 instance like this: let signedTx = web3.eth.accounts.signTransaction(rawTx, privateKey) and then web3.eth.sendSignedTransaction(signedTx.rawTransaction)
    – Gus
    Commented Jun 12, 2018 at 17:32
3

For anyone else having difficulty, this is fully working code with web3 1.0.0-beta.51

The other solutions on this page did not work for me.

The "contractAddress" is the master token contract - the one owned by the team who runs the project. In my example it's HST, and their contract address is https://etherscan.io/token/0x554c20b7c486beee439277b4540a434566dc4c02

const Web3 = require('web3')
const Tx = require('ethereumjs-tx')

const Web3js = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/v3/YOUR_PROJECT_ID'))

let tokenAddress = '0x554c20b7c486beee439277b4540a434566dc4c02' // HST contract address
let toAddress = '' // where to send it
let fromAddress = '' // your wallet
let privateKey = Buffer.from('PRIVATE_KEY', 'hex')

let contractABI = [
  // transfer
  {
    'constant': false,
    'inputs': [
      {
        'name': '_to',
        'type': 'address'
      },
      {
        'name': '_value',
        'type': 'uint256'
      }
    ],
    'name': 'transfer',
    'outputs': [
      {
        'name': '',
        'type': 'bool'
      }
    ],
    'type': 'function'
  }
]

let contract = new Web3js.eth.Contract(contractABI, tokenAddress, {from: fromAddress})

// 1e18 === 1 HST
let amount = Web3js.utils.toHex(1e18)

Web3js.eth.getTransactionCount(fromAddress)
  .then((count) => {
    let rawTransaction = {
      'from': fromAddress,
      'gasPrice': Web3js.utils.toHex(20 * 1e9),
      'gasLimit': Web3js.utils.toHex(210000),
      'to': tokenAddress,
      'value': 0x0,
      'data': contract.methods.transfer(toAddress, amount).encodeABI(),
      'nonce': Web3js.utils.toHex(count)
    }
    let transaction = new Tx(rawTransaction)
    transaction.sign(privateKey)
    Web3js.eth.sendSignedTransaction('0x' + transaction.serialize().toString('hex'))
      .on('transactionHash', console.log)
  })
0

For transferring refer the code below: (replace privateKey with from which account token is going to deduct.

let data = myContract.methods.transfer(dest, amt).encodeABI();
let txObj = {
    gas: config.gas,
    gasPrice: config.gasPrice,
    "to": config.tusdContract,
    "value": "0x00",
    "data": data,
}
web3.eth.accounts.signTransaction(txObj, privateKey, (err, signedTx) => {
if (err) {
    return callback(err);
} else {
    console.log(signedTx);
    return web3.eth.sendSignedTransaction(signedTx.rawTransaction, (err, res) => {
    if (err) {
        console.log(err)
    } else {
        console.log(res);
    }
  });
}
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.