Can we break Behodler?
An exploration into all possible attack vectors of the novel AMM with a focus on whale clout.
Now that Behodler is about to launch a new form of perpetual liquidity mining code named Liquid Queue, it may be prudent to explore the nascent AMM for all possible vulnerabilities before large swathes of new holders arrive, eager to claim their rewards, only to find an AMM vulnerable to attack. To set up the exploration, it’s worth explaining the key mechanics under the hood so that our minds can foment criticisms in the form of attack vectors as our collective internal mental models of Behodler take shape.
This article lays groundwork upfront which may come across as unnecessarily verbose but the principles elucidated here are invoked repeatedly in the article so I’d advise not skipping the theoretical preamble.
Section 1: theoretical groundwork
What Behodler really is
“If you wish to make an apple pie from scratch, you must first invent the universe” — Carl Sagan
Warning: a bit of mathematics ahead
Behodler is an AMM powered by token bonding curves. Each curve takes in an input token and mints Scarcity (SCX). Each curve maintains its own supply schedule for SCX, ignoring the other curves. The amount of Scarcity printed is the logarithm of the current input token balance. The base of the log chosen is 2. So if there is 16 eth then the curve would have printed 4 SCX. If there is 256 eth then the curve would have printed 8 SCX. Now for Ethereum implementation detail reasons, the numbers are scaled but the mechanics are the same. For the sake of explanation, a simple log will do. So how does a fleet of token bonding curves manifest into an AMM? The trick is to take the price of SCX on a given curve and compare it to the current price of SCX on another curve and you can infer relative price.
The reason we choose log is because when you do a bit of simplification, you can show that the relative price between tokens t1 and t2 is T2/T1 where uppercase T represents their total balance in Behodler aka total liquidity.
Behodler 1 used square roots instead of logs but this lead to a situation where the relative marginal price is √T1/√T2. At high levels of liquidity, this doesn’t scale too well. You can prove mathematically that logarithmic curves are suitable for all levels of liquidity but the proof is a little beyond the scope of this article.
On Uniswap, in order to provide liquidity, you supply two tokens to a pair contract and in return mint LP tokens. In Behodler, simply minting SCX along the bonding curve of the token you’re supplying is the act of supplying liquidity. Adding liquidity is therefore unilateral unlike in Uniswap which requires swap ratio balancing. This also means that if you add liquidity and use the SCX you receive to redeem the liquidity of another token, the net result will be identical to performing a direct swap. The purpose of direct token to token swapping is to save you the step of multiple transactions (minting SCX and then immediately redeeming it) and has been optimized for gas consumption.
What all this means is that SCX is both the LP token on Behodler, the medium of exchange and the unit of account. Essentially SCX is the money of the Behodler market. This is different to Uniswap where LP tokens have no bearing on the underlying swap mechanics.
What about the LP fee?
In Uniswap every swap is charged a 0.3% fee which is added to the pool of liquidity. Existing LP holders can therefore redeem more underlying tokens, the more often this fee is exacted. During periods of volatility, LP tokens can grow quite fast in value, even if the underlying token prices don’t change significantly beyond random walk.
To borrow parlance from Nassim Nicholas Taleb, the fee makes Uniswap LP tokens antifragile since they benefit from disorder.
Behodler has an analogous mechanism but as we shall see, it confers antifragility to the entire AMM. This point will be crucial in demonstrating Behodler’s robustness to attack later on.
In theory if you take the total circulating supply of Scarcity, you should be able to redeem 100% of the tokens on Behodler. However, Scarcity has a burn on transfer feature. This is the analogous LP fee. Here, every transfer incurs a 0.5% burn. This has the effect of increasing liquidity in Behodler permanently. The SCX burn fee makes Behodler overcollateralized at all times and this overcollateralization only increases in time. To illustrate, consider the following fictional example:
We have two tokens trading on Behodler, HappyCoin and JollyCoin. The balance of HappyCoin in Behodler is 32 and the balance of JollyCoin is 128. This implies that the Scarcity that has been printed by the HappyCoin bonding curve is 5 and for the JollyCoin bonding curve we expect 7 SCX. This gives a total supply for Scarcity of 12. These contrived numbers are obviously just chosen to give round number results for SCX.
Now suppose there are two SCX pairs on Uniswap for WBTC and ETH. Because of daily price drift, bots occasionally sell on one pair to buy on the other and vice versa to exploit random arbitrage opportunities. Because SCX burns on transfer, each bot trade burns 0.5% of the transferred amount. Suppose that after much trading, an entire unit of SCX is burnt. This means the total supply of SCX is now 11. However, the bonding curves still imply that there should be 12. Suppose we wish to redeem HappyCoin and JollyCoin from Behodler. If we did so, we could send in 7 SCX to the JollyCoin curve. This would indeed redeem all 128 units. We then have (11–7=) 4 SCX remaining. If we redeem all 4 on HappyCoin, we will receive 30 units of HappyCoin. The remaining 2 units are stuck and we’ve used up all of our SCX. We could have reversed this scenario where we redeemed all of HappyCoin first but then we would have ended up with 2 units of JollyCoin.
The only way to get at the stuck coins is to add liquidity to generate SCX and then redeem the stuck tokens. But then we’d have just substituted in one token for another.
This growing pool of unobtainable liquidity in Behodler is known as residual liquidity and as SCX is transferred, the value of residual liquidity grows. The implications for the DEX are that we will gradually move further and further down the bonding curves, implying an increasingly larger value for SCX.
This feature of residual liquidity will be taken advantage of in the upcoming Liquidity Queue: by creating incentives for arbitrage bots to trade SCX on Uniswap, the pace of residual liquidity growth will be quickened. It should be noted then that the reason Behodler is antifragile is that during periods of frenetic trading of SCX on Uniswap (whether it’s being dumped, pumped or just swapped), residual liquidity is on the rise so that after the frenzied trading, the overall value of SCX is higher than before and the AMM permanently has more liquidity than before.
To measure residual liquidity in dollar terms, simply go through the bonding curves and add up the value of SCX implied by their balances and then subtract from this the true total supply. This shortfall is the SCX value of residual liquidity which can be given a dollar value.
For instance if there are 3 tokens listed with balances on Behodler of 4, 8, and 64 then the implied SCX is log_2(4) + log_2(8) + log_2(64) = 2+3+6 = 11 SCX. If there is only 8 SCX in reality then the residual liquidity is 3 SCX. If SCX trades on Uniswap for 10 Dai then the residual liquidity is approximately worth $30.
Section 2: Attack vectors
Now that we have some theoretical muscle to give us clarity on results we see on the blockchain, let’s explore some attack vectors. A critique has surfaced that a whale can withdraw 50% of the liquidity of any bonding curve for relatively cheaply (18 SCX). However for the sake of taking the threat to the extreme, all whales in these scenarios are assumed to be sufficiently large to withdraw the entire balance of any 1 bonding curve, not just 50%. We want to test Behodler in the extreme.
Attack vector: Exponential Whales
Since SCX is minted on a logarithmic scale, one implication is that there’s a very intense early adopter reward for being the first to mint on a bonding curve. To illustrate, consider this dev example of Behodler below.
The first token added to Behodler mints 366 SCX. The second only mints 18. It should be noted that the third mints about 10 as per the image below which shows that the dramatic slippage levels off. This levelling off increases with each token so that slippage declines fairly quickly.
Nonetheless, the first person to add liquidity becomes quite a large whale instantly. These first move whales have a disproportionate effect on their ability to withdraw incredibly large portions of the bonding curves. Before exploring further, it should be noted that there are many strategies in the words to distribute this initial bonanza fairly such as preseeding the bonding curve or having a crowd sale listing. But let’s assume for the sake of this article that one person gets the lion’s share.
The reality of looming whales
The image below shows a snapshot of the top holders of SCX and their balances:
Ignoring smart contracts, the top holders represent some fairly large whale positions. Each of these users would be able to withdraw a very large portion from any of the existing token bonding curves. A growing concern amongst some users is that these large holders move either in a coordinated manner or simply through an external trigger such as a panic and effectively drain the DEX of the vast majority of its liquidity.
This portion of the article will list all of the possible scenarios under which these ‘super whales’ can attack Behodler and what mechanisms exist to protect the AMM.
Scenario 1: Redemption Arc
It should be noted up front that redeeming the vast majority of a bonding curve’s liquidity will result in significant slippage which is why I phrase a mass redemption as an attack rather than just a risk because redeeming all at once is the crypto equivalent of a suicide bombing. To illustrate just how much slippage, consider this screenshot from mainnet Behodler:
If the slippage to redeem all 60 SCX was zero then we’d expect to receive 208x60 = 12480 Dai when redeeming 60. Instead observe the true output:
5058 is only 40% of the non price-impacted value. This demonstrates how extreme a whale redeem hurts the whale.
Finally we could argue that instead of redeeming the entire load of DAI and incurring maximum slippage, a whale only redeems 18 SCX in order to receive half of the DAI. The image below shows the result:
Again, if we take the original price and multiply by 18, we’d get 3744 DAI. Here the slippage of 967 represents a 25% price impact. Making the claim that 18 SCX can redeem any half of any bonding curve, regardless of liquidity added ignores the fact that higher levels of liquidity imply a higher SCX price on the one hand and that arbitrage trading implies that 18 SCX will still hold a similar dollar value across the curves. In other words, this critique is simply another way of saying SCX rises in value as liquidity is added.
So because of extreme slippage, we see that the main impediment to a whale bombing of this magnitude is self interest. Aside from self interest, it is the most unsustainable attack vector. If someone were to redeem on only one bonding curve, the relative price of that particular token would rise significantly, creating arbitrage opportunities for bots and traders everywhere. The effects of the attack would reverse almost instantly, like a transient sun spot only memorable by the slight perturbance in magnetic fields briefly detected. And the end result would be a dead whale.
As if that isn’t enough, Behodler has a max liquidity withdrawal limit per transaction. Currently this is set to 90% but as liquidity grows, there’s no reason that can’t be dropped (through the proper governance channels) to much lower levels. Indeed anything below 50% adds significant resistance to draining. Even 10% is feasible in the future. As such, a whale who can only redeem 10% will have their slight damage undone by bots the following block. In this case, we’re actually protecting the whale from wasting their SCX.
Scenario 2: Carpet Bombing
In this scenario, recognizing the futility of hitting one bonding curve, the whale spreads their attack across as many bonding curves as possible. The question at hand is how many tokens a whale can redeem in one block.
In the following mainnet transaction, I redeemed SCX for Orchid’s OXT token.
The gas usage was 134784. If we take the prevailing block gas limit from Ethstats, we see that we could fit 148 of these transactions into one block, assuming we squeeze out every other person on the Ethereum network (quite the assumption).
Not all tokens are created equal, however. The following transaction is an SCX redemption of PNK.
Here, the gas costs imply only 70 such transactions could fit into one block. So as a convenient midpoint, let’s assume an SCX whale can fit 100 redeems into one block.
Why is it important to all be fit into one block? Because if the attack is conducted over multiple blocks where not all curves are redeemed at once, the price imbalances between blocks will give arbitrage bots opportunities to correct the imbalances. While the whale might be able to muscle out all other traders using gas price auctions in one block, it’s likely that miners of future blocks will simply ignore the whale’s transactions in order to take advantage of the new price imbalances. Transaction ordering and selecting of this nature is becoming an increasingly dominant form of revenue generation for miners.
It should be clear that when Behodler grows to hundreds of tokens, block gas limits eliminate this particular attack vector.
For the sake of argument, let’s assume that we only have 10 tokens and that a whale wants to redeem against all the curves in one block in order to keep relative prices unchanged. Let’s also assume that they have a way of keeping 1inch bots from being able to act on changing relative prices between when the attack starts and when it ends. This is quite a strong assumption as well because bots scan the mempool for pending transactions and evaluate decisions based on the predicted outcomes. But let’s also assume that this whale has a sophisticated way of griefing bots.
So the whale redeems SCX across 10 curves in such a way that relative prices remain unchanged. Now there are no arbitrage opportunities. The idea then is to repeat this attack every block until Behodler is dramatically drained. A new problem emerges: Although the relative prices between curves has remained unchanged, the implied price of Scarcity has fallen on every curve. Since liquidity has left, any liquidity redemption yields less liquidity than in the previous block. This means that an across the board redemption lowers the price of Scarcity on Behodler accross the board.
However, over on Uniswap nothing has changed. So now bots observing Uniswap and Behodler notice that Scarcity can be purchased cheaply on Behodler and dumped on Uniswap. And so the bots begin adding back liquidity to Behodler to exploit the arbitrage opportunity.
It should be noted that since this action causes the price of SCX to converge between the two AMMs, the net effect is a lower price of SCX and less liquidity in Behodler. Well, sort of. Since the arbitrage opportunity created by the whale has lead to SCX transfers to Uniswap, there has been a bit of SCX burning. The deeper the liquidity pool on Uniswap, the more SCX can be minted and sold without affecting the price and hence the more burning.
Recall that SCX burning implies higher residual liquidity in Behodler. Symmetrically over on Uniswap, the increased trading leads to additional LP fees, deepening to pool on Uniswap.
To summarize the net result of a carpet bombing is:
- Reduced SCX concentration by depleting a whale
- Increased resistance to future such attacks by deepening the SCX token pairs on Uniswap because of the LP pool (antifragility)
- Increased residual liquidity on Behodler, leading to permanently higher liquidity.
Recall also that this attack is only possible with a small list of tokens and that Behodler imposes limits on this attack. If anything, a carpet bombing strengthens Behodler.
Scenario 3: Flashloan
The main critique of the logarithmic bonding curve is that it offers disproportionate redemption power to whales. I found this assertion troubling because the bonding curve is symmetric. If you receive a great deal of SCX for relatively little input then when it comes time to redeeming everything on a bonding curve, you’ll receive relatively little for great deal of SCX. Nonetheless, I was intent on testing this theory with empirically. After demonstrating on a testnet that any such attack was in vein, I decided to set about constructing a flashloan attack on Behodler mainnet. If the hypothesis that SCX whales have disproportionate power on Behodler is true then another way of stating this is that large portions of SCX can be “sold” for a higher price on Behodler than on Uniswap.
The flashloan attack would be simple: use Behodler’s flashloan module to mint a large portion of SCX, redeem a token on Behodler and then sell that token for SCX on Uniswap. You should be able to claim a larger portion of SCX on Uniswap than Behodler if the hypothesis is true, revealing the flaw inherent in the system.
Recall the fifth diagram that demonstrates the Dai redeemable by 60 SCX is 5058. If we go to Uniswap and attempt to redeem 60 SCX, we should get less than 5058 Dai if the theory that Behodler favours whales is correct. Since the most liquid SCX pool on Uniswap is the SCX/EYE pair, we should first get a quote in EYE for 60 SCX and then use that to get a quote in DAI. The image below does just that:
Currently not only does Behodler not yield a disproportionate quantity of Dai compared to Uniswap but rather Uniswap yields a much higher value of Dai for 60 SCX.
This makes the premise of the flashloan impossible to test.
Now a counter argument is that when Liquidity Queueing arrives, the liquidity on Behodler will rise such that the SCX whales will gain their super withdrawal powers. But there are three problems with this line of thinking. Firstly, the Liquidity Queue operates by intentionally deepening the SCX pool of liquidity on Uniswap so this disparity is unlikely to disappear. Secondly the slippage on Behodler for large SCX whales who supposedly have enough to redeem an entire curve doesn’t just go away. They’ll always get a raw deal if they try to redeem a large portion. So it’s still not in their interest to suicide bomb Behodler. Thirdly, the Liquidity Queue is going to super charge SCX burning through Uniswap arbitrage opportunities which means residual liquidity is going to rise quickly. There will eventually come a point where all circulating SCX won’t be enough to redeem even 80% of one pool.
We have shown that SCX burning adds an antifragility to Behodler such that over time, the ability to effect a massive withdrawal is neutralized. In the short run, there are safe guards in place such as the max liquidity withdrawal limit. A hypothesis was put forward that SCX whales have a disproportionate ability to drain Behodler, that the top 7 holders own enough SCX to effect a massive drain attack. However, there was no attack vector that was shown to have any permanently negative effect on Behodler. On the contrary, the most devastating attack, the Carpet Bomb, acts like a vaccine against future attacks because of the increasing SCX trading activity and hence the burning it implies.
Finally, we wanted to demonstrate the power of a whale by orchestrating a flash loan attack on Behodler to demonstrate the skewed incentive to own SCX. However the real world data suggests that the logarithmic bonding curves employed by Behodler do not behave sufficiently differently to Uniswap’s constant product swap curves to allow the flash loan to even be feasible.
It should be noted in closing that Uniswap’s constant product curve swap implies logarithmic bonding curves, even if none are present in the code. The derivation can be found here. Not only is Behodler’s choice of logarithmic bonding curve not problematic, it’s not even that unusual.