How Bancor Works

A lot of people don't quite get how Bancor works, which isn't surprising because their whitepaper (pdf) doesn't explain it very well. Last year I spent a lot of time figuring it out, and it's really cool. Their implementation leaves a lot to be desired (more on that below) but the core idea is beautiful.

A basic Bancor-style contract functions as both an exchange, and a self-balancing ETF. If it contains four tokens, you can exchange those tokens for each other, and you can hold shares in another token representing the whole thing.

Let's call the contract a "basket." This basket is going to hold four assets: Ether, Gold, Silver, and Platinum, in equal-valued proportions.

Each asset has a "reserve ratio," which in this case we're setting to .25 for each. All this means is that Ether represents one quarter of the value of the whole basket, and so do the others.

You can deposit any of these assets into the basket, and get back shares of the basket. You can also redeem shares of the basket, and get back your choice of underlying tokens.

If you hold the basket token, you're invested in all four of the underlying tokens, with an equal dollar amount of each. If you want to exchange gold for silver, you deposit gold, get the basket, deposit the basket, and take out silver. (You could also do this in one step, for convenience, with the same steps underneath.)

The exchange rate depends on how much of each token is deposited. Let's say the basket holds twice as many silver tokens as gold. If you deposit one gold token, you get back two silver tokens.

Setting Prices

But how does this happen? Is there some centralized price feed? No! It happens automatically, because of arbitrage.

Let's say one gold token is really worth three silver tokens, but our basket still has only two silvers for each gold. I can make a profit: deposit two silvers, get one gold, then go on some other exchange and get three silvers.

But look what happened: there's more silver in the basket, and less gold. We're closer to the correct pricing now.

Do you want an ETF that holds equal weightings of ETH, gold, silver, and platinum? Just hold this basket token. Every time the prices change, it will automatically rebalance for you.

The Math

So the ratio before our transaction is different than the ratio afterwards. If we just use the initial ratio for our exchange rate, then using a bunch of little transactions nets me a different amount than one big transaction.

Bancor solves this by saying: for any transaction, let's split it into an infinite number of tiny transactions, one after another, and run them all. This is what calculus is for. They do a little calculus to figure out what the result of that would be, and that's the Bancor formula. (Emin Gün Sirer wrote a critique of Bancor in which he wondered (point 15) why they couldn't use some other formula; well, this is the reason.)

In Bancor's terms, the various tokens held in the basket are "Reserve Tokens," and the tokens issued by the basket contract are "Smart Tokens." For each token there's a "Reserve Ratio," which is normally constant; if the reserve ratio is 0.25, then arbitrage will keep enough of that token to make up 25% of the total value held.

The variables used in their paper are:

S = Total Smart Token Supply (i.e. basket tokens)
R = Reserve Token Balance (e.g. deposited ETH)
F = Reserve Ratio 
T = Smart tokens received in exchange for reserve tokens E
E = Reserve tokens received in exchange for smart tokens T

Not that "smart token supply" varies. When you deposit gold, the contract mints new smart tokens for you. When you redeem smart tokens, they're destroyed, and the contract transfers to you the reserve tokens of your choice.

If you trade in some silver to get smart tokens, the number of smart tokens you get is calculated with this formula:

    T = S((1 + E/R)ˆF - 1)

If you trade in some smart tokens to get silver, the amount of silver you get is calculated with this formula:

    E = R(1 - (1 - T/S)ˆ(1/F))

If you look at the Bancor contracts you'll see some horribly complicated stuff, because you need logarithms and non-integer exponentials to actually work those out. But if we use equal weighting, the formulas are simpler; we just need roots, along with fixed-point muliplication and division. With only two reserve tokens, our formulas are:

    T = S(sqrt(1 + E/R) - 1) 
    E = R(1 - (1 - T/S)ˆ2)

With three reserve tokens we'll use a cube and cube root, and so on.

Slippage

Because of the changing ratios, you always have slippage. You'll get a worse price than the initial ratio in the basket. The bigger your transaction, the worse the slippage.

This is a familiar situation for anyone trading on normal exchanges. The more liquidity on the exchange, the less price slippage you have. On a Bancor basket, the more assets held in the basket, the less slippage you have for a given trade.

This means there's a network effect. For any given asset pair, you want to trade them on the contract holding the largest amount of them.

If we want to launch a new basket, this is a problem for us; we're probably starting out with small amounts. Bancor solves this by talking to projects directly, presumably getting them to contribute lots of tokens and ETH from their ICO stashes. (The projects would get basket tokens in return, so they can always get their tokens and ETH back.)

But we could also do it in a decentralized way: just have people put tokens in an escrow contract, and if we reach a threshold, then launch the basket and award contributors with the appropriate amount of basket tokens.

Front Running

Because of slippage, front running is a serious issue. Let's say silver is slighly overvalued, and I send in a trade of silver for gold. Somebody else sees my transaction, and issues their own with a higher gas price. They trade silver for gold, correcting the price. My transaction goes through, and now there's too much silver and too little gold in the contract; silver is now undervalued. The attacker sends another transaction, correcting the price again, thus profiting in both directions.

To fix this, you put a minimum return on your order. If you're not going to get at least that many tokens back out, your order doesn't go through.

Reserve Ratio Madness

In the above examples, our reserve ratios sum up to one. When that's the case, the total value of the smart token supply is equal to the total value of all the reserve tokens held in the basket.

You can also set the reserve ratios so they sum to less than one. When you do that, you get somewhat ponzi-like economics. The more reserve tokens in the basket, the more valuable the smart tokens relative to the reserve tokens. Now, the value of your basket tokens doesn't just depend on the value of the underlying reserves; it also depends on the popularity of the basket. If a lot of people exit, you lose money. On the other hand, if you're already the biggest, then since you've got the least slippage you'll probably keep collecting assets, and your basket holders will do well.

Bancor's BNT token is a basket that contains nothing but ETH, with the reserve ratio less than one. The more ETH in the basket, the more ETH you have to spend to get a BNT token; conversely, the more ETH you get for redeeming a BNT token.

Bancor includes the BNT token in every basket they set up. Their theory is that by doing this, they'll end up with more and more ETH in the BNT basket, thus boosting the price of BNT due to the low reserve ratio.

For the ICO, Bancor set the reserve ratio in BNT very low. If you had immediately withdrawn ETH from the BNT contract, you would have done well, as long as you were one of the first to withdraw. If everybody tried to withdraw, then the earliest to withdraw would be subsidized by the latest.

But as long as this bank run didn't happen, it looked like BNT was worth more than the underlying ETH, so Bancor could get away with siphoning away some of the contributed ETH. Some of it went to fund Bancor the company, and some went into a reserve fund; if the value of BNT on exchanges went too low, then ETH from the reserve fund got pumped into the BNT contract.

This worked for a while, but it was another arbitrage opportunity. If BNT tokens on the exchange were cheaper than the price floor Bancor was trying to maintain on BNT itself, then buy BNT on the exchange, redeem it in the contract, and get a nice ETH profit, paid for by the reserve fund. It didn't take long for the reserve fund to get emptied.

The Hack

Bancor of course has been in the news lately, because they got hacked. Apparently the reason for the hack was that they lost control of an admin key.

The reason for the admin key: the actual Bancor contracts lets admins change reserve ratios on the fly, or even add and remove tokens. Personally, that doesn't make me want to hold a smart token. It certainly complicates the contracts.

Where do the arb profits come from?

Reddit user _dredge asked a critical question: where do those arbitrage profits come from? At first glance it appears the answer is: basket token holders.

Let's say we have a basket with 2000 Silver worth $10 each, and 1000 Gold worth $20 each. We have 1000 basket tokens.

Now silver goes up to $22.52. In the basket it's still available at the old cheap price, so you see an opportunity for profit: just buy some gold on some other exchange, deposit it to the basket, pull out silver, and sell it for sweet gainz.

So we have:

    S = 1000 (basket token supply)
    R = 1000 gold, 2000 silver
    T = S(sqrt(1 + E/R) - 1) =
        1000(sqrt(1 + 500/1000) - 1) = 225

For your 500 gold deposit you got back 225 newly-minted basket tokens. There's 1500 gold in the contract now, and a supply S of 1225 basket tokens.

Now you take your 225 basket tokens and exchange them for silver:

    S = 1225
    R = 1500 gold, 2000 silver
    E = R(1 - (1 - T/S)^2) =
        2000(1 - (1 - 225/1225)^2) = 668

The contract gives you 668 silver, subtracted from the 2000 it held. Now the contract has:

1500 gold at $20 = $30,000
1332 silver at $22.52 = $29,996.64

Thus it holds a total value of $59,996.64

But if the basket holders had just been holding the underlying reserve tokens, they would have 2000 silver at $22.52 and 1000 gold at $20, for a total value of $65,040. They would have had $5,043.36 more.

Meanwhile, for your arbitrage you got $15,043.36 in silver, purchased for $10,000 in gold, for a profit of $5,043.36. Your profit is exactly equal to the loss of value for the basket holders.

So you might think that basket holders are much better off holding the underlying reserve tokens directly, and just occasionally rebalancing on regular exchanges.

But wait, there's more!

Suppose after all that happens, silver suddenly goes back down to $10. You have another arb opportunity! This time you'll buy that $10 silver on some other market, sell it for $22.52 (initially) in the basket contract, and take out gold. Let's try it with 668 silver tokens:

    S = 1000 (basket token supply)
    R = 1500 gold, 1332 silver (before deposit)
    T = S(sqrt(1 + E/R) - 1) =
        1000(sqrt(1 + 667/1332) - 1) = 225 

We've minted 235 new basket tokens and given them to you, which you trade in for gold:

    S = 1225
    R = 1500 gold, 2000 silver
    E = R(1 - (1 - T/S)^2) =
        1500(1 - (1 - 225/1225)^2) = 500 

Now there's 1000 gold and 2000 silver in the contract, so the basket's silver price is $10 and the basket has its original value of $40,000.

What happened?

When silver went up, basket holders paid traders to rebalance the basket. But when silver went down, the traders still got paid, and the basket holders got all of their money back. Where did the other money come from?

There's a simple answer: it came from silver sellers on other exchanges, who sold their silver for less than they could have gotten by selling to the basket. In general, whoever's selling you tokens at a worse price is paying you to arb; sometimes that's basket holders, sometimes it's external markets.

So it appears the model works after all. Sometimes you're better off holding tokens directly, other times you're better off holding the basket, but neither side has an advantage.

You might think that, if token prices go up over time, then the basket works against you. But remember that what matters here is relative prices. If gold and silver go up by equal percentages, then no rebalancing is necessary, and there's no arb opportunity. If just one token goes up, then you're worse off holding the basket, but if you expect that to happen then you should just hold that one token in the first place.

Let's try the other direction

Silver goes to $5. You buy 828 silver at $5 from somewhere else and deposit it:

    S = 1000 (basket token supply)
    R = 1000 gold, 2000 silver (before deposit)
    T = S(sqrt(1 + E/R) - 1) =
        1000(sqrt(1 + 828/2000) - 1) = 189

We've minted 414 new basket tokens and given them to you, which you trade in for gold:

    S = 1189
    R = 1000 gold, 2828 silver
    E = R(1 - (1 - T/S)^2) =
        1000(1 - (1 - 189/1189)^2) = 293

Now we have 2828 silver at $5 = $14140, plus 707 gold worth $14,140, totaling $28,280. But if we'd just held the assets directly we'd still have $20,000 gold plus $10,000 silver. We're short $1,720, equal to the arb profit.

So back the other way, silver to $10, and we'll put that 293 gold back in:

    S = 1000 (basket token supply)
    R = 707 gold, 2828 silver (before deposit)
    T = S(sqrt(1 + E/R) - 1) =
        1000(sqrt(1 + 293/707) - 1) = 189 

    S = 1189
    R = 1000 gold, 2828 silver
    E = R(1 - (1 - T/S)^2) =
        2828(1 - (1 - 189/1189)^2) = 828 silver out

So we're back to original numbers!

This might seem a little weird. When silver went up from $10 to $20, we lost money compared to direct holders, and got it back on the way down. When silver went down from $10 to $5, we also lost money compared to direct holders, and gained it back on the way up. How did we lose money in both directions?

What's happening here is that a portfolio that starts out equal-weighted and doesn't rebalance has an advantage over the basket contract:

  • If an asset goes down in price, the basket keeps buying more of it as it goes down. That's a money-losing trade.

  • If an asset goes up in price, the basket keeps selling more of it as it goes up. We make more more by just hanging on.

But what if we start out with an unbalanced portfolio? Say we had an equal-weighted portfolio with silver at $10, and didn't rebalance when it went down to $5. Now the basket contract has 4000 silver but we only have 2000 silver. When silver doubles in price, we've got less silver to start with, so we make less money than the basket.

The basket will always lose against an equally-weighted portfolio that doesn't rebalance, if we start at the beginning when that portfolio really is equally-weighted. But if we're not rebalancing, then after a while that portfolio won't have equal weights anymore. It might have twice as much silver, half as much, whatever. At that point it might do better or worse than the basket.

The more frequently we rebalance, the more closely we'll approximate the performance of the basket, which rebalances continuously. I think that more frequent rebalancing damps down returns, but also damps down volatility; I'm tempted to dig into this more and see what has the best risk-adjusted performance.

I suspect the answer is good for basket holders, but if not, a way to tweak it is to add a small transaction fee on trades, and hold that fee in the basket to incentivize basket holders. This could even be good for traders, if greater holdings reduce slippage by more than the fee. (Reddit user Eyul mentioned that Bancor has a 0.2% fee on trades, but I don't know the details.)

The future

Bancor keeps making new partnerships, and that's great for BNT holders. If you want your token in their network, you fill out a form, and maybe they set it up for you, if it's not a security token or something else they're not comfortable with.

But if we wanted to, we could make our own basket tokens, and skip BNT entirely. Keep the ratios fixed and equal-weighted, and it's not even that complicated.

As far as I can tell from their interface, Bancor's baskets are just pairs, each with some token plus their ETH-backed BNT. They're not building bigger, diversified ETFs. We could do that, with any asset mix we like. We could make them for tiny, illiquid tokens, or security tokens that exchanges and Bancor won't touch. It's not only a nice alternative to regular decentralized exchanges, it's a neat way to hold a portfolio.

And I'll say this for Bancor: they don't seem to mind. I've talked with them, while implementing a stripped-down version of their system for a client, and they were totally cool with it.

What I love about all this is that it's an entirely new kind of financial instrument, and a new way to trade assets, and the whole thing only takes a few pages of Solidity. Imagine how difficult it would be to launch something like this in the legacy financial world.

I'll likely post some code in a future article.