Ethers.js: Listing and transferring ERC20 tokens

Created on 28 May 2018  ยท  23Comments  ยท  Source: ethers-io/ethers.js

Hello,

is it possible to list and transfer ERC20 tokens from an ethers.js wallet?
I didn't find any sample in the documentation ๐Ÿ˜ž

Thank you and keep up the great work ๐Ÿ‘ ,
:panos

discussion documentation

Most helpful comment

Sorry this took so long to get back to.

Yes, that is correct, you can just treat the token like any other contract. I will add a recipe to the cookbook though, for a more permanent example of transferring tokens.

There is no way to get a list of tokens a wallet has, in general. Luckily ERC-20 has a few design decisions to make this easier, although not all tokens adhere to all the specification. Also, events on a pruning node become unreliable after longer periods of time have elapsed, but you can use the Transfer(address, address, uint256) event to find all events, filtered by an address (you would likely want to query for both sent and received tokens).

I will add a recipe for this to the cookbook too, since it is a common task.

All 23 comments

Seems like this is answering how to send tokens.

Now, is there a way to list the tokens that an ethers.js wallet is holding?

Thank you,
:panos

I think you should save the wallet's tokens by yourself, maybe in a database or local files etc.
I think it's difficult to know what tokens does a wallet have.
Maybe you can use the etherscan api: Get a list of "ERC20 - Token Transfer Events" by Address to get all wallet's token transaction and calculate what token the wallet have.

Maybe you can use the etherscan api: Get a list of "ERC20 - Token Transfer Events" by Address to get all wallet's token transaction and calculate what token the wallet have.

That's what I thought as well. But then I thought that this is such a common scenario that maybe the wallet itself supports it..

Thanks for your reply!

Sorry this took so long to get back to.

Yes, that is correct, you can just treat the token like any other contract. I will add a recipe to the cookbook though, for a more permanent example of transferring tokens.

There is no way to get a list of tokens a wallet has, in general. Luckily ERC-20 has a few design decisions to make this easier, although not all tokens adhere to all the specification. Also, events on a pruning node become unreliable after longer periods of time have elapsed, but you can use the Transfer(address, address, uint256) event to find all events, filtered by an address (you would likely want to query for both sent and received tokens).

I will add a recipe for this to the cookbook too, since it is a common task.

Any update on the recipe for transfer ECR20 tokens?

Hello @apollox-sys ,

the following code worked for my node.js service:

function sendToken(req, res, wallet, abi, ico_address) {
  var to = req.query.to;
  var amount = req.query.amount;

  var contract = new ethers.Contract(ico_address, abi, wallet);

  // How many tokens?
  var numberOfDecimals = 18;
  var numberOfTokens = ethers.utils.parseUnits(amount, numberOfDecimals);

  // Send tokens
  contract.transfer(to, numberOfTokens).then(function(transaction) {
    res.send(transaction);
  })
  .catch(function(e){
    res.status(400);
    res.send(e.responseText);
  })
}

Don't simply copy-paste it, since it contains some express library usage ๐Ÿ˜Š

@le4ker this code fails with

Error: sending a transaction require a signer (operation="sendTransaction", version=4.0.4)

Any help around this error?

Sounds like you are not providing a signer to the contract instance. How are you instantiating the contract? Make sure you provide it a Signer (e.g. Wallet or JsonRpcSigner).

@ricmoo hm yes, it seams that you are correct.

const contract = new ethers.Contract(contractAddress, abi);

This is how I construct contract.

I added wallet as 3rd argument and the error changed.

my code

try {
      const valueToSend = ethers.utils.parseUnits(value.toString(), this.numberOfDecimals);
      const transaction = await this.contract.transfer('0x.....', valueToSend);
      console.log(transaction);
    } catch(error) {
      console.log(error);
    }

Error:

TypeError: Cannot read property 'getCode' of undefined
    at Contract.deployed (~/node_modules/ethers/contract.js:344:48)
    at Contract.transfer (~/node_modules/ethers/contract.js:135:26)
    at Ethereum.sendToken (~app/common/ethereum/Ethereum.js:39:42)
    at Ethereum.checkTransaction (~/app/common/ethereum/Ethereum.js:25:10)

How are you instantiating your wallet? My guess is now you need to add a provider to the Wallet. :)

let provider = ethers.getDefaultProvider();
let wallet = new ethers.Wallet(privateKey, provider);
let contract = new ethers.Contract(contractAddress, abi, wallet);

Let me know if that solves it. If so, then I need to add a better error message for when the provider on a Signer is unspecified for deployed. :)

well look

   const provider = ethers.getDefaultProvider();
   const wallet = await ethers.Wallet.fromEncryptedJson(JSON.stringify(encryptedWallet), password);

   const contract = new ethers.Contract(contractAddress, abi, wallet);

this is how I created wallet. What am I doing wrong here :/

Oh! So, you can use:

const provider = ethers.getDefaultProvider();

// You can do this in one step, just splitting it apart and giving it weird names so it is more
// obvious what is happening
let walletWithoutProvider = await ethers.Wallet.fromEncryptedJson(JSON.stringify(encryptedWallet), password);
let walletWithProvider = walletWithoutProvider.connect(provider);

const contract = new ethers.Contract(contractAddress, abi, wallet)

Nice @ricmoo thanks! Should consider creating a series of tutorials regarding ERC20 tokens this would really help you popularize your library :) thanks again

No worries! Feel free to reach out if you have any further issues.

It's in the works. It will be a whole section in the Cook Book in the documentation... :)

// Send tokens contract.transfer(targetAddress, numberOfTokens).then(function(tx) { console.log(tx); });
got error ๏ผš
Error in mounted hook: "TypeError: contract.transfer is not a function"

Heya @motopig! :)

How are you creating the contract instance?

thanks for your reply ๐Ÿ‘
creating contract instance
let privateKey = '0xsdfdfsdfs';
let provider = ethers.getDefaultProvider('rinkeby');
let wallet = new ethers.Wallet(privateKey, provider);
let contractAddress = "0xsswwwfdfdsf";
let contract = new ethers.Contract(contractAddress, abi, wallet);

Where is abi coming from? That's the important part. :)

must use the contract abi which i write in the code let contractAddress = "0xsswwwfdfdsf"; ?

The contract address only specifies the location of the contract on the blockchain, not what the contract ABI is. The Contract class is a meta-class, it will have only the methods which the ABI has specified.

You probably want something like:

let abi = [
  "function transfer(address to, uint amount)"
];

so that the contract "knows" about transfer(address,uint256).

Nice @ricmoo thanks!
i just got wrong conception of abi , problem resolved
thanks again

No problem. Glad I could help. :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jochenonline picture jochenonline  ยท  3Comments

jochenonline picture jochenonline  ยท  3Comments

dave-dm picture dave-dm  ยท  3Comments

PhABC picture PhABC  ยท  3Comments

crazyrabbitLTC picture crazyrabbitLTC  ยท  3Comments