A Simple ERC20 Exchange Wallet

Making a custodial wallet for ERC20 tokens is not as easy as you may think

Mark Mathis
Coinmonks
Published in
4 min readNov 17, 2018

--

Update

I am a technical advisor to an awesome project — xera.tech. We are building the next generation in exchanges and I would encourage you to check it out if you can!

Disclaimer

Please be wise and do not put the code in this article into production without first doing due diligence and making sure that it meets your security requirements. This article is written for entertainment and educational purposes only and does not constitute advice for your organization’s security or custodial decisions.

The Problem

Ethereum wallets can be a bit tricky to manage on an exchange since every Ethereum address has its own wallet. It’s not like Bitcoin or Cardano even, where you can generate sub-accounts below the main address and reflect the balance and manage it with that single wallet address. This presents a problem in the typical flow of an exchange where a user will generate a deposit address to send their funds to. In Ethereum, if we generate an account for the user to send their funds to, we also need to maintain the private key of that account on the exchange. This is a custody nightmare and not maintainable.

Also Read: The Best Cryptocurrency Hardware Wallets

What We Want

What we would like to do is have a custodial wallet on our exchange that we have a single private key to and generate multiple public deposit addresses for the customers to deposit to.

Our Solution

One way to solve this is to create a smart contract that creates and owns other smart contracts. This is super high level, but what we essentially do is this

  • Deploy a Smart Contract that is owned by our custodial Ethereum account with the ability to create child wallets and return a list of them
  • Have the child wallets be owned by the custodial Ethereum account and not by the parent smart contract(which is default)

This will allow the custodial account to manage all the funds sent to this wallet. This is a similar approach that big custodial providers such as BitGo use.

Mega Wallet!!!

Our MegaWallet code is below and you can see our methods to create a wallet and list the wallets owned.

If you notice, we are able to store any ERC20 token in the created ERC20Wallet — so long as it conforms to the OpenZeppelin DetailedERC20 type.

ERC20Wallet wallet = new ERC20Wallet(DetailedERC20(_token), owner);

This is powerful and dangerous in that you could store ALL of your ERC20 tokens on the exchange in a single wallet. You should not do this, but you should create multiple hot and cold wallets to maintain a good balance between liquidity and safety.

ERC20Wallet

This is the child wallet that we will generate and send the public address to the user for deposit.

Note that we pass in the token address and the owner address. We pass in the token address so that we can transfer that particular token when we want to sweep all of the deposit accounts. We pass in the owner address so that we can own this wallet from our custodial account and set the destination for the sweep.

Tests

We setup some expectations in the tests below. We need an external account whose private key we know so we used the truffle-hd-wallet-privkey library to simulate an exchange user sending funds to our generated wallet address. We also had to create a dummy ERC20 coin to be used to test our wallet functions with aptly named GenericERC20. The test itself should be self-explanatory but feel free to ask me if you have any questions about its intent.

Try it out

Environment and Repo

You will need to install the following

# Clone the wallet repository
git clone git@github.com:cipherzzz/erc20-megawallet.git
# Install the dependencies
npm install

Project Setup

Copy the .env.example to a new file named .env

Add the mnemonic phrase from the ganache app to your .env

Add a public and private key from any ganache account other than the first to your .env file(I used the 6th one down). Just click on the key icon and you will see the public and private keys.

You will also want to make sure that the post listed in your truffle.js matches the port your ganache server is running on. Normally it’s either 7545 or 8545 .

Run It

Now you are ready for the fruits of your labor — to see if all of this is going to work. Pay attention to the output of the tests and study them to see what is going on under the covers.

# Compile the contracts
truffle compile
# Migrate/Deploy them to the network(Ganache in this case)
truffle migrate
# Run the tests
truffle test

Summary

There is a lot going on in this article with some higher order concepts that my not be apparent at first. I encourage you to dig into the tests and ask me if you have any questions. This was a challenging problem and hopefully it has given you some inspiration to use smart contracts in solving your own problems in the future. The repository for this project is here for your reference.

Disclaimer

Please be wise and do not put the code in this article into production without first doing due diligence and making sure that it meets your security requirements. This article is written for entertainment and educational purposes only and does not constitute advice for your organization’s security or custodial decisions.

Get Best Software Deals Directly In Your Inbox

--

--