August 24, 2021: Hacking TriCrypto π§βπ»π΅οΈ
Practical demonstration of Curve v2 Pool mechanics
Even non-coders in Curve community should check out the most recent Curve Brownie Tutorial. The video explores how the TriCrypto pool functions under extreme attempts to hack it. In the process, it makes it a bit easier to understand the mechanics of how the pool behaves.
Itβs a good video, and thatβs not just my biased opinion!
If youβre like me and hate watching videos, even videos with hosts so uncannily handsome they must be a deepfake, hereβs a written redux:
The video searches for an attack vector against TriCrypto by brute force. This helps to show how the pool actually functions in real world circumstances, which is useful because itβs easier to understand experimentally than theoretically. You may not easily comprehend this:
Yet itβs not so tough in practice. The pool likes to be balanced. This may not be immediately obvious because the pool contains volatile assets:
But itβs really simple to multiply by the price of these assets and divide by decimals to see that the pool is usually in a state of balance at any given time.
We can see that USDT, WBTC, and WETH all contain nearly the exact same value of assets at the moment, about $146MM apiece.
The functioning of the pool depends on the capability of the pool to calculate the effective price of these assets. TriCrypto does not rely on an external oracle, instead the fancy math shown in the white paper to deduce the current price. The current balanced state of the pool is according to the internal βprice oracleβ, which is the poolβs expectation of the current price based on the pool activity.
Enter the distinction between the price_oracle and the price_scale. The price scale can be thought of the actual conditions of the pool. As activity happens in the pool, it pushes in the direction of the oracle price, but lags slightly (as an exponential moving average). We can see the same script as above, but computed using the price_scale instead of the price_oracle, shows a slight imbalance.
At the moment, the scale price of ETH and BTC is a bit higher than the oracle price, so these assets are slightly overweighted. We would expect these to push downwards towards the oracle price as long as profits permit. Within the code, the pool is basically capturing profit where it can. It will spend up to half of this profit moving liquidity around to realize the current price. Moving liquidity costs money, but the contract can calculate how much.
To illustrate this effect, we examine the effect of nuking the pool. Since weβre working with an exponential moving average, one transaction wonβt move the price a lot. But we can manipulate the poolβs price by running several transactions in one direction. In the case of the video, we show the effect of depositing $1MM worth of Tether 200 times in a row.
How it started:
How itβs going:
We moved the price of Bitcoin from $46.4K to $52.9K, and all it took was $200 million dollars!
If you look at the before and after balances, you can see the effect in action. At the outset, each asset had about $95MM. Once the pool got flooded with Tether, TriCrypto assumed Bitcoin and Ethereum were the scarce asset, so their price shot up accordingly. We also observe the scale price lagging the oracle price as it pushes in this direction.
We also observe TriCrypto doesnβt take any action to capture profit at this point. The initial balance of BTC ($95,499,776 / $46,410.86 = 2,057.7 BTC) is the same as the balance after the nuke ($108,850,466 / $52,899.02 = 2,057.7 BTC) β the poolβs added to its balance of BTC and ETH only by increasing the oracle price.
At the reverse of the nuke, after $1MM is withdrawn 200 times in a row. The price of BTC and ETH are still drifting upwards ever so slightly, presumably the oracle prices still have upward pressure in adjusting to the prior shock before the downward pressure kicks in, so the final price ends up about level but slightly up. The final balance ($114,003,316 / $55,403.19 = 2057.7 BTC) shows the exact same balance at the end.
Knowing that we can manipulate the price with a lot of money, is it possible to drive up the price and get a quick arbitrage opportunity? We test this out by running both possible directions. The first direction is a lemon:
We drive up the price of the pool, convert a million Tether to 151 ETH, run it back through Sushi, and we lose $516K. Not a surprise, since we made ETH expensive. What about in reverse?
Well, unsurprisingly, the other direction works better. When we get $1MM Tether worth of ETH at Sushi itβs now cheaper, so we get 307 ETH to play with, and converting it to Tether in TriCrypto gets us $1MM.
Easy profit? Well, it cost us $200MM in the first place to nuke the pool to this state. Our bosses wonβt be too happy if we spent $200MM to make a million. We try to get our money back out after the fact, but we canβt get it back so easily. When we un-nuke the pool by withdrawing $1MM at a time, we find that at the end of the day weβve actually lost money.
Maybe this is just a function of the symmetry β we unnuked and nuked exactly 100 times apiece. Perhaps if we adjust the amounts and values of our nukes, we could find a scenario that captures this advantage for ourselves.
Here we create a script to test this possibility. We provide an integrative test, which will vary parameters until it finds a failing condition.
We assert that the pool cannot be arbitraged in this manner, then we vary the parameters and fail the test if we find a set of parameters that successfully make money on the trades. Itβs notably slow to run this, of course since thereβs hundreds of trials apiece.
Having varied these parameters in several ways, Iβve yet to stumble upon a successful strategy. If I had, you can be sure Iβd be arb-ing my way to a rare-looking NFT of a rock, instead of posting my Lβs here.
To be clear, there are arb strategies with TriCrypto that work, and other bots or lightning fast traders appear to have hopped right on it. Through the normal course of people interacting with the pool, thereβs occasional imbalances that can appear, and opportunities to take profit are short-lived. The arb strategy thatβs not working here is the attempt to manipulate the price, arb, and get your money back in one closed circuit loop.
Weβd be interested in hearing your ideas for how to break TriCrypto! Now that you understand TriCrypto a bit better, see if you can brainstorm a way to crack it. If you figure a clever strategy and it doesnβt work, we can feature it in a future newsletter. Or run it yourself with the code here: https://github.com/curvefi/brownie-tutorial/tree/main/lesson-18-applications-ii
Or if you share a strategy and it works, we can both retire and enjoy looking at our rock collection!


For more info, check our live market data atΒ https://curvemarketcap.com/Β or our subscribe to our daily newsletter atΒ https://curve.substack.com/. Nothing in our newsletter can be construed as financial advice. Author is a Curve maximalist and has a stake in TriCrypto2.