If you think that ERC20 tokens are something new and terrible, think again. Our world is already full of tokens:
Of course, the more tokens we have, the harder it is to manage all of them. But eventually, everything will always be compared to the most stable token (as it is today for USD or EUR).
As far as you probably know, in order to transfer common ERC20 tokens, token owners must have Ether on their balances. This introduces quite a big inconvenience for users: in addition to the tokens they want, they also need to get Ether somewhere. Imagine spending dollars and then being asked to also hand over some Hryvnias.
Managing two crypto assets instead of one creates more problems both for users (they have to manage two assets instead of one) and application owners (as each little complication drastically drops the number of users).
The need of Ether to transfer tokens is not just about how Ethereum was made. To keep any decentralized network (today’s blockchains) running smoothly, it requires support and that doesn’t come free. The payment usually comes in the form of some kind of currency fee or computing power. If everyone made transactions without paying network fees, the network would be spammed with millions of transactions and, eventually, reach its peak capacity.
In Ethereum, you must pay fee in Ether for any network state change, thus rewarding miners for including your transaction into the block. Fees in Ether are paid for each transaction, including transferring Ether, deploying smart contracts and executing smart contract functions.
ERC20 typical transaction fee distribution
Taking into account that current Ethereum is made of nearly 90% different ICOs and transactions that utilize ERC20 tokens, an inconvenience about holding Ether makes those projects highly narrowed only to those users who are experienced enough in terms of Ethereum, and not useable at all for the masses.
If you have ever learned about the technical part of Ethereum, you’ve probably noticed web3. Web3 tends to be something more than just a JavaScript library for Ethereum. It’s about the way you interact with a decentralized network such as Ethereum.
In the ideal decentralized web3 world, every individual has their private key (secret), which they use to interact with the network on their behalf. No one can ever transact on the network on someone’s behalf if they don’t know their private key. In terms of Ethereum and other crypto-platforms, your wallet (Metamask, Exodus, Trezor, etc) holds this private key for you and thus only you are able to do transactions on behalf of your account (public address) on this network.
The public address, or your account’s address is generated by hashing the private key. It is impossible to know the private key from the public address, which is one of the great properties of the hashing function. This means that you are safe to share your public address. To prove that you own the private key, you can simply put your digital signature on any requested data.
In Ethereum, when you are about to do a transaction, say, send some Ether or tokens, you have to sign the transaction data and submit both the data and corresponding signature to the network. As only the private key owner can make a valid signature, it is guaranteed that no one else will be able to forge the signature nor change the signed data and transact on the network on behalf of your public address.
There is a problem with Ether-free transfers. In Ethereum, by design, the transaction fee is subtracted from the account which makes the signature. Theoretically, we can set this fee to 0, by setting the gas price to 0. But practically, today, the transaction fee is the only motivation for miners to include your transaction into the next block, so you have to set it to a reasonable amount. Or, alternatively, you have to contact the top miners directly and ask them to always include your transaction into their blocks (which is not even an option).
However, think about it this way: we always have to pay transaction fees in Ether. However, does it really matter who pays this fee? For instance, we can write such a smart contract that will perform certain actions, no matter which account made the transaction. Moreover, we can utilize public key cryptography in the smart contract itself, which opens wide possibilities for asset management.
By having an ability to cryptographically prove that you are an account (address) owner, let’s design an ERC20-compatible token smart contract, which will allow the transfer of someone’s tokens by having their valid signature on the transfer data (arguments of transfer function). In this scenario, the Token Sender doesn’t need Ether, as the transaction will be published by the Transaction Publisher. However, we still need some confirmation from the Token Sender about their intent to send tokens, so we have to prompt the Token Sender for their signature, which is a free operation.
Here’s how this works:
How can we transfer tokens without Ether in theory, using the transferViaSignature function
Great, we’ve just made the Token Sender happy! Now, they don’t need to go to an exchange and buy Ether. However, this design doesn’t include the following problems:
We can simply fix the first problem by motivating Transaction Publishers in some way. Transaction Publishers can ask for some kind of fee in order to compensate for spent Ether. Taking into account that in many cases the Token Sender only has one type of token, so it’s rational to give the reward to the Transaction Publisher in that token so as to not need Ether .
Rewards distribution while transferring tokens with transferViaSignature
To make the signature unique and solve problem #2, the Token Sender also has to sign some sort of “signature identifier” in addition to the transfer function parameters. The Smart contract code then can store the signature identifier and check whether the same signature has already been used. Alternatively, we can remember used signatures and not allow the use of the same signature twice.
To give the Token Sender more control over when and how the signature can be used and solve problem #3, we can introduce one more parameter which the Token Sender has to sign, a deadline. This parameter will be validated by a smart contract and guarantee that the signature expires at some point in the future.
And finally, to solve problem #4, when a transaction can be mined by another Transaction Publisher, we also have to include the Transaction Publisher’s address to the Token Sender’s signature. Or, more elegantly, let’s call it fee recipient. No matter who has submitted the transaction, the transaction fee goes to the given address.
Regarding points #2 and #3 (the signature identifier and deadline), this is a design which we have implemented at DreamTeam, but there are a couple of other options available about which data to sign and validate. For example, in the ERC865 proposal, which originally inspired me to do our own implementation, there’s no deadline, and instead of a signature identifier an unsigned integer nonce is used.
I’ve also seen some implementations where people use nonce for signatures in the way Ethereum uses nonce for transactions: each following transaction (via signature) requires a higher nonce set than the previous one. While such implementation saves some gas (starting from the second transaction via signature), it requires a more strict workflow and dApp maintenance, because of two reasons:
1. In the case the Token Sender makes multiple signatures at once, the application must ensure that the Transaction Publisher submits transactions to the network in sequential order, ensuring that the nonce conflict doesn’t happen.
2. Without the relatively cheap deadline parameter, there’s no other option for the Token Sender to expire the signature other than to manually do a transaction on the network spending even more Ether (to mark nonce in the signature as used).
So far, we have been discussing simple token transfers via signature. But the ERC20 standard also features two more functions: approve and transferFrom. These functions can be implemented by analogy, paying a small fee in tokens to the Transaction Publisher. In the case of transferFrom, it makes sense to take the fee directly from the allowed amount, as, almost, the only use case is when this function is used “by the signature” is for token withdrawals to a personal account.
Now, let’s talk about something more complicated: signature standards.
At the time of writing this article, there isn’t a single signature standard established by the community, and this is a problem. In order to verify signatures on a smart contract, we need to, for sure, know the algorithm of how the signature was created. Currently, as far as I know, there are at least 4 different signature standards supported by different clients (wallets):
Let me show you a quick example. When using the most widely adopted eth.personal.sign, in a pop-up of your wallet, you are presented with some unreadable gibberish, which is very bad from a UX point of view:
Still, you can hope that this dApp doesn’t do anything bad
Even though this gibberish could be a readable HEX string, it is still not obvious to users what they are putting their signature on. The SignTypedData signature standard solves this and makes the signature pop-up more readable for users while maintaining the same level of security:
Readable data that you sign
While the best available option from the options above is obviously to go with SignTypedData, it is not widely adopted yet, and still, is a subject to potential (UX) improvements. However, as you may have noticed from the screenshot, the amount to transfer and the fee is displayed in decimals, which is a signature standard limitation. Our token has 6 decimals. Imagine how much more difficult it would be for users to check the amount in the case of 18 decimals.
In our DREAM token (DreamTeam Token), we managed to implement all existing standards, at the time of development (and writing this article). We did a separate function in a smart contract that performs a signature validation, along with validating signature expiration timestamp. You are free to look over our implementation ideas and discuss what can be added or improved.
Some statistics on gas consumption using transfers via the signature standard:
As you can see, transferring tokens via a signature consumes around 2 times more gas than simply transferring tokens with Ether. Nevertheless, enabling such great features in token smart contracts is worth it.
To launch a successful application today, you have to make its user interface as easy and straightforward as possible. Modern corporations and startups spend millions on designing easy to use interfaces and perfecting the user experience. When it comes to Ethereum applications that use standard ERC20 tokens, UX can drastically go bad and make the application unprofitable, all because of the need to pay fees in Ether.
The proposed solution in this article eliminates the need for users to pay fees in Ether while maintaining the same level of security. In a combination with a well-designed application, it can eliminate the need for users to care about the underlying Ethereum platform altogether.
While the proposed solution requires writing ERC20-compatible token smart contracts that support some actions via signature, one can adopt the solution to existing ERC20 tokens, by utilizing a similar strategy as multi-signature wallets do: to deploy a dedicated (tiny) smart contract for each account that won’t hold Ether. In general, the only difference here would be the initial deployment cost for each new account.
Thank you for reading! Follow me on Medium for more interesting stories about cryptoplatforms, programming and useful things!
Follow-Up(s)