Skip to content

Instantly share code, notes, and snippets.

@HildisviniOttar
Last active September 16, 2021 00:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HildisviniOttar/d3cf0da2242731f60416c77fc986d79c to your computer and use it in GitHub Desktop.
Save HildisviniOttar/d3cf0da2242731f60416c77fc986d79c to your computer and use it in GitHub Desktop.

Repeated bond fine past zero creates arb opportunities

When an active validator steals from their Yggdrasil vault, they are immediately fined 1.5x the amount stolen, down to zero.

When Ygg assets are stolen, THORChain deducts the asset stolen from internal accounting to adjust the pool ratio.

A Yggdrasil can be "topped up" by the user, which is not recognised by any thorchain accounting.

A rogue validator with active bond can repeatedly top-up, steal, top-up, steal past when their bond is zero, and thorchain keeps adjusting pool asset ratio down to zero (even though no funds are stolen). This creates a fake arbritrage opportunity.

Attack

An operator buys 300,000 RUNE ($2.4m) and bonds in to become an Active validator.

Their Yggdrasil wallet is topped up to around 25% of bond amount: ~$600k. Of this, around $30k BNB. Maybe $100-200k of other BNB assets, but let's focus on BNB for now.

First, the node operator steals all of their Yggdrasil funds to get ~$600k worth of assets back. They are instantly fined ~112k RUNE.

The node operator then executes a script that transfers the entire amount of BNB back into their Yggdrasil ($30k), and out again repeatedly. A round trip takes (at best) 600ms.

Thorchain ignores the tx in, and repeatedly fines the node operator $45k for the tx out until their bond reaches zero. The node operator continues the attack.

Once bond reaches zero, each time the node operator sends out of their Yggdrasil again, manager_slasher_v63.go will slash bond zero, but also deduct asset amount stolen from pool:

runeValue := pool.AssetValueInRune(slashAmount).MulUint64(3).QuoUint64(2)  // A high number that gets higher each time
if runeValue.GT(na.Bond) {
	runeValue = na.Bond      //Eventually zero
}
pool.BalanceAsset = common.SafeSub(pool.BalanceAsset, slashAmount)  //Subtracts $30k worth of BNB
pool.BalanceRune = pool.BalanceRune.Add(runeValue)   //Stays the same 
na.Bond = common.SafeSub(na.Bond, runeValue)  // Stays zero

Eventually the pool ratio shows 1 BNB to All of the RUNE (assuming no other Arbs have hit it in the mean time).

The attacker profits by swapping 1 BNB for All of the RUNE. Then swaps all of the rune for ETH.

Economics (does this work?!)

Yes but it's slightly risky due to arbs! Damn arbs!!

Assuming no arbs for a moment:

Current BNB pool is $8m. At $8 RUNE and $400 BNB, that would be a ratio of 20k:1M.

That takes 266 round trips of $30k to "drain". At 600ms each, that's just under 3 minutes. Call the attack duration 3 minutes if we're good.

If we "drain" the BNB pool, it actually becomes over-solvent (real funds exceed what it thinks it has).

Eventually it thinks it has 1 BNB and 1M RUNE. We can do some very easy arbs from BNB to steal 1M RUNE (huge slips, but ...).

With BNB alone, you could steal up to 1M RUNE. That's 3x more than your initial BOND you lost.

Could be higher if also hit all the BNB token pools like BUSD at the same time.

However with Arbs, they will quickly eat into profits, so perhaps this attack is not feasible in real life.

Update: Actually perhaps this attack is possible for a well resourced attacker, who has $8m worth of BNB or BUSD available and does it in a single 300ms out tx and instantly arbs at the moment the pool ratio is adjusted, then the next RUNE block later (After receiving 1M RUNE), swaps it all for BUSD. Bam - 5 second hack.

@HildisviniOttar
Copy link
Author

Fix is to auto-ban when bond reaches zero, stopping further observations of fake theft. If a validator is stupid enough to repeat-fine themselves this is still a thorchain accounting problem (over solvent), but this merge request removes the ability to create profitable arb opportunities:
https://gitlab.com/thorchain/thornode/-/merge_requests/1870

@HildisviniOttar
Copy link
Author

0.67 active - releasing to public

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment