The incident in question, courtesy of @RektHQ
TLDR: Ethereum relies on smart contracts sending chains of messages to one another. This brings complexity and sometimes chaos. Radix’s Transaction Manifest interacts with each component in turn, providing a simple, atomic, and composable way of guaranteeing token movements.
Furucombo is a dApp on Ethereum that allows its users to combine multiple actions together in a single transaction, through an easy to use interface.
For example, users can arbitrage a price difference between two DEXs (although in the image below the user would lose money!).
Furucombo exists because it’s not possible to call two or more contracts directly on Ethereum. Instead, you have to first deploy a custom smart contract that specifies what actions to take, and you then call that smart contract to execute those multiple actions. Ethereum also makes use of what are called “proxy” contracts. These act as a gateway, routing actions to other contracts depending on what needs doing.
This is useful if a developer needs to deploy a new contract, as the proxy can be updated to route to the new contract.
Looking at the diagram above, you can see that Ethereum transactions are made up of long chains of messages sent from contract to contract.
When a contract sends an instruction downstream on behalf of an entity upstream, this is called a “delegate-call”.
On Feb 27 2021, a hacker set up their own custom contract which instructed Furucombo to send a complex stack of “delegate-calls” to other contracts downstream.
One such delegate-call included the hacker’s own contract address, which Furucombo forwarded to an Aave Proxy. The Aave Proxy accepted the hacker’s address, and now routes messages from Furucombo to the hacker’s malicious contract.
With the Aave proxy pointing to the hacker’s contract, the hacker could now instruct Furucombo to use all its accumulated “approvals” across other ERC20 smart contracts (e.g. stETH, USDC, and Dai), and transfer those funds to the hacker. This drained $14m in total.
So why could this hack never happen on Radix’s upcoming Babylon mainnet? Instead of chains of calls between contracts, transactions on Radix are composed using what’s called the transaction manifest. We’re going to dive into this in a bit more depth than in previous Rekt Retweets.
The first thing to note is that the transaction manifest describes all the asset movements that must happen between smart contracts that are part of that transaction.
So for the example arbitrage between two DEXs below, the transaction calls each component in turn with assets that “physically” move between the components, ultimately resulting in swapping between the two DEXs for a profit (or if not, then the transaction fails).
Compare this to Ethereum, where a transaction interacts only with the first smart contract, which sends messages downstream, and downstream again. This results in highly complex execution stacks and potential for error and exploitation. On Radix, as the transaction interacts with each component, components don’t even need to talk to each other to compose them together - the transaction itself can do it directly!
This makes developing on Radix far more simple, as the transaction manifest speaks directly in a language of asset movement, and Radix Engine provides guarantees on how assets behave.
Contrast this to a Solidity developer who has to account for a thousand and one ways in which their smart contract might interact with a complex stack of other third party contracts, invisible to the transaction that the user submits.
This also makes Radix components far more composable, as components are developed against standardized asset movements, just like a box of lego bricks is composable because the pins and holes are standardized.
If the attack were attempted on Radix:
1. You would never need Furucombo on Radix, as the transaction manifest can compose with an unlimited number of components directly. There is no stack of calls from one contract to another for a hacker to exploit.
2. As tokens are natively understood by the platform, and live in vaults inside components, there’s no more “approving” contracts to spend your tokens. “Draining” someone’s wallet using a hijacked approval just isn’t a thing on Radix.
For a deep dive into the technicals of the Transaction Manifest, check out the relevant docs here: https://docs.radixdlt.com/main/scrypto/transaction-manifest/intro.html
For the last in the Rekt Retweet series:
Rekt Retweet #8: Why the $90m Mirror Protocol hack could NEVER happen on Radix