Written by Yervant Kulbashian and Nat Chin— August 10th, 2018.

TLDR: Vitalik wants a crypto card for mass adoption and we’re building it.

Vitalik Buterin, founder of Ethereum, expresses interest in actual adoption of cryptocurrencies by being able to transact with it in-store.

Mass adoption

The goal of any financial technology company, no matter how big or small, is to make it simpler for you to manage your money. In contrast, for almost a decade, cryptocurrency adoption has been hampered by poor and arcane user interfaces, wrapped around a counter-intuitive and error-prone technology. This is caused, at least in part, by a design naïveté; few companies have yet understood or developed the design language to clearly communicate a new financial ecosystem to a mass audience. In addition, cryptocurrencies have had it rough being a relatively minor contender in a field of well-established and globally-integrated financial institutions. Overcoming both these obstacles simultaneously is certainly a challenge.

Within the crypto web-sphere, there have been a prolific number of cryptocurrencies, across a variety of largely isolated blockchains. This influx of offerings will likely escalate in the next few years. Unlike national currencies, such as the Great British Pound or the Yuan, you can’t rely on a having fixed or stable catalogue of currency symbols to pull from, with perhaps an occasional addition once a decade.

The freedom to create a new token or blockchain out of thin air has resulted in a fragmented ecosystem of incompatible protocols. Multi-token payment channels are part of the growing effort to meet the challenge posed by this landscape. Other efforts include atomic swaps, cross-chain communication, and good-old-fashioned centralized exchanges.

Browsing through CoinMarketCap (as of 10:25pm EST Aug 9, 2018) 41% of listed tokens in the top 100 by Market Capitalization are built on Ethereum. For this reason, we began our work with a focus on Ethereum as it offered the most token coverage in exchange for the lowest effort.

The new payment channel

At STK earlier this year we used payment channels to let members transact with STK tokens in stores, by signing and sending transactions off-chain. The result was similar to a standard payment channel, though modified so that instead of being one-time use, is was repeatedly reusable.

With these standard payment channels, a member needs to create separate channels on the blockchain for each currency he or she wants to use. To pay with STK, ETH, and DAI, you’d need to open three separate channels between your wallet and the recipient’s. The code for each payment channel would be almost identical, aside from the specific token it hold and with which it transacts.

But with the proliferation of new tokens gaining adoption, programming and instantiating a new channel for every token becomes prohibitively expensive. As a result, developed a Multi-token payment channel, to allow a single channel to serve multiple tokens. Such a channel may dynamically add ERC20 tokens even after the channel is running on the blockchain, including tokens that have not yet been invented.

The various tokens in a member’s Multi-token channel are kept distinct. Refunding one token leaves the rest untouched. If you open a Multi-token channel that supports both DAI and STK, you can trigger the contest period of the DAI token at any time, and the STK channel will remain open and continue to accept signed transactions.

Nitty-gritty code

Check out our GitHub repo here: https://github.com/STKtoken/Multi-Token-smart-contracts

The sub-channels for each token are stored in a mapping that connects the address of the token and its data.

mapping (address => MultiLibrary.MultiChannelData) channels;

To review, a payment channel can be in one of three states:

open : when open, the user of the payment channel can continue to transact (pay in stores) and send IOUs. These are both done off-chain

: when open, the user of the payment channel can continue to transact (pay in stores) and send IOUs. These are both done off-chain contest period : this is when the payment channel will no longer accept new IOU’s. The goal of this period is to decide on the final transfer amount that will be sent to each participation

: this is when the payment channel will no longer accept new IOU’s. The goal of this period is to decide on the final transfer amount that will be sent to each participation settled: to funds are set to the participants, the state of the payment channel is to cleared and set to open. It can now resume transactions

To trigger changes between these states, there are a number of functions in the contract:

close() : this function sets the channel to no longer accept new IOUs. It does so by updating state variables to signal that the channel is closed. By calling this function, a participant lays a claim to a certain portion of the tokens stored in the channel, a claim that can be challenged by the other party

: this function sets the channel to no longer accept new IOUs. It does so by updating state variables to signal that the channel is closed. By calling this function, a participant lays a claim to a certain portion of the tokens stored in the channel, a claim that can be challenged by the other party closeWithoutSignature() : if tokens are deposited into the state channel and no IOUs are sent, the user can call this function to refund the tokens from the payment channel

: if tokens are deposited into the state channel and no IOUs are sent, the user can call this function to refund the tokens from the payment channel updateClosedChannel() : if either the member or the recipient wants to challenge (‘contest’) the submitted claim on the tokens when the channel was closed, that person can call this function within in a pre-defined window of time, called the ‘contest period’

: if either the member or the recipient wants to challenge (‘contest’) the submitted claim on the tokens when the channel was closed, that person can call this function within in a pre-defined window of time, called the ‘contest period’ settle() : on settling, the tokens are returned to each party, and the channel resets to allow transactions to continue occurring

: on settling, the tokens are returned to each party, and the channel resets to allow transactions to continue occurring addChannel() : this new function dynamically adds ERC20 tokens to the existing channel

: this new function dynamically adds ERC20 tokens to the existing channel recoverAddressFromHashParameters() : use this function to prove that a given transaction was signed with an authorized signer’s key

You can dynamically add any ERC20 token to your channel by calling the addChannel function. The function checks whether the token has been already added to this channel — if it hasn’t, it creates a reference to the new token, and sets up the data for the new channel.

The addChannel function allows us to add sub-channels for individual tokens within an already running payment channel. Once complete, the member can pay in-store with these additional tokens.

STK

Below is a comparison of gas costs, and how they were significantly improved when we introduced the Multi-token payment channel. Members who pay with any token besides STK pay network fees in STK.

Multi-token channel: adding new tokens

If you transact with another ERC20 token: the user pays fees for initializing a channel (129000 units of gas) and settling the channel, (about 115000 units of gas). In total, the user pays around 244000 units of gas to transact. Assuming a gas cost of 10.1 gwei, the transaction fee is $0.727.

If you transact with STK tokens: STK will pay all operational costs for facilitating payments. Regardless of the number of transactions, the user would pay $0 on top of the STK required for the purchase.

Single-token channel: transacting with additional tokens

If you transact with another ERC20 token: the user pays fees for initializing the channel (600000 units of gas) and settling it (100000 units of gas). In sum, each new payment channel would cost the member about 700000 units of gas. Assuming a gas cost of 10.1 gwei, the transaction fee is $2.08565.

If you transact with STK tokens: just as in the above example, the user pays no fees.

In summary, we have significantly improved the architecture to the benefit of both members and for STACK. It costs about 34.8 % less in gas for a member to transact using a Multi-token payment channel than with a traditional single-token channel.

Returning Lost Tokens

One of the most dangerous traps that results from having a separate channel for each token arises out of the frequent confusion around which address holds which token. When trying to keep track of long strings of numbers and letters, mistakes will happen, even for the most diligent practitioner. One user sent their $136000 into the wrong ZRX contracts. In another example the Golem Contract was found to hold $65000 in unknown cryptocurrencies. These are frequent and unfortunate occurrences. Many victims have addressed their plaints to StackOverflow or Reddit for assistance in getting their funds returned back to them, only to find that the transactions are irreversible.

Using traditional single-token channels, an STK member may create a channel holding STK tokens at 0xf67e5s7d and another channel holding DAI at 0xa538be82 . It is possible that this member, in a rush or a typo, later sends his or her STK tokens to number 0xa538be82 instead of number 0xf67e5s7d . Multiplying this by as many tokens and as many members as we have, it would be difficult to ensure members send the right tokens to the right channels.

And such a transfer is irreversible. 0xa538be82 doesn’t know that it holds any STK and isn’t even aware that STK as a token even exists. This is similar to telling a friend who doesn’t speak your language where a pile of treasure is buried and how to retrieve it. After your death, there is no way for anyone to get the information out of him. In other words, there is no way to extract the DAI out of aforementioned the smart contract.

This problem is solved when using Multi-token payment channels. If a channel has been initialized with STK or DAI tokens, and the member accidentally transfers another ERC20 token such as ZRX into the channel, the money can be returned through thefollowing these steps:

Call the addChannel method with the new token (ZRX) Close and settle the ZRX channel, and the token will be refunded back to where it came from.

By dynamically instantiating tokens we ensure that the contract can recognize any tokens it holds, and since they are explicitly defined as member variables the contract can refund (settle) the tokens back to either party.

Note: This only works for ERC20 tokens. In other words — if you accidentally transfer a non-fungible token (ERC721), such as your Cryptokitty, to our payment channel, we will not be able to get it out and return it to you. Be warned. Watch your Kitty.