TLDR: Ethereum relies on messages, callbacks, and complex execution stacks requiring re-entrancy. This enables exploits if there is even one mistake in the ordering of logic. On Radix, re-entrancy is disabled by default, and so this hack could never happen on Radix.
Rari Capital’s Fuse is a fork of Compound on Ethereum. Fuse allows anyone to create their own lending and borrowing “pools” using any combination of ERC20 tokens. Both lending and borrowing is fully collateralized.
In the following hypothetical Fuse Pool, a user deposits 4,000 USDC to borrow 1 ETH. If they want their 4,000 USDC back, they must return $4,000 worth of tokens, plus interest.
As part of this process, the Rari Fuse Pool smart contract records that it has lent the ETH, preventing the USDC collateral from being withdrawn. But this did not follow the recommended “check-effect-interaction“ pattern, as the ETH is sent before the borrow record is updated.
On May 1 2022, a hacker was able to steal ~$80m worth of tokens from a variety of Fuse pools. For one example pool, they started by borrowing a 150m USDC flash loan from Balancer, and deposited that in the Fuse Pool’s account.
To learn more about what a flash loan is: https://www.radixdlt.com/post/what-is-a-flash-loan
Next, that 150m USDC was used as collateral to borrow 1,977 ETH from the Fuse Pool.
But before the Fuse Pool smart contract was able to update its internal borrow record (the effect), the hacker’s contract performed a re-entrant call to the Fuse Pool contract to withdraw the 150m USDC, and pay back the Balancer Flash Loan, allowing them to keep the 1,977 ETH.
So why couldn’t this hack have happened on Radix’s upcoming Babylon release?
First, let’s understand how transactions (tx) differ between Ethereum and Radix.
On Ethereum: (1) Transactions can only call a single smart contract function, which sends messages downstream to other contracts which sometimes “callback” to the original contract. This results in complex execution stacks for which re-entrancy is a vital enabling feature.
(2) With all these interactions, Solidity smart contract developers always have to worry about their contract interacting with potentially malicious code in other smart contracts.
On Radix: (1) Users define all asset movements across all components in the tx manifest. If one step doesn’t execute, the tx fails safely. This lessens reliance on contracts messaging or calling back to one another, eliminating the need for re-entrancy.
(2) Resources (such as tokens) are “physically” sent between components in temporary containers called “buckets” that must empty by the end of the tx, or the tx fails. Scrypto developers no longer have to think about untrustworthy code in other components - as their code interacts with the bucket. And when receiving a token from a bucket, users and components can select where to deposit the tokens from, improving composability as deposits don’t have to specify a particular account.
With all this in place, this means that in Radix, re-entrancy is disabled by default, Scrypto developers can write simpler, clearer applications to achieve equivalent functionality without re-entrancy!
Here is “Rari” on Radix. All the resource movements are specified in the transaction manifest. The resources physically move between components. And Radix Engine combined with buckets guarantees correct resolution of all the resources in the tx.
For the attempted hack, the hacker obtains a flash loan of 150m USDC, deposits it in “Rari”, and obtains a loan of 1,977 ETH. They then attempt to use their component to re-enter the “Rari” component mid-execution, in order to withdraw the newly deposited 150m USDC before the Borrow Record is updated.
However, it can’t, as re-entrancy is disabled! The hack is thwarted, even with sloppy code by the developer.
Also, notice how the transaction has a “receive repayment burden” as part of step 1? That’s a temporary NFT that the “Balancer” component requires the transaction to include when giving out a flash loan. If the transaction can’t resolve the burden, then it fails.
If you’d like to learn more about Radix Engine and how it makes DeFi and your tokens on Radix far more secure, visit developers.radixdlt.com
For the last tweet thread in this series, check out Rekt Retweet #5: Why the $30m Spartan Protocol hack could NEVER happen on Radix