Reentrancy attack remains a challenge, and existing defense measures mainly focus on the protocol source code level, which only takes effect before the contract enters the runtime state.
“Runtime protection” is an important supplement to DeFi security, aiming to “protect execution results” and ensure that the protocol’s execution aligns with its intended design.
The design of EVM does not support “runtime protection” because smart contracts cannot access all the contextual information of the runtime state.
Artela explores an EVM+Extension execution layer paradigm to enhance the execution layer and eliminate reentrancy attacks.
- Countdown of the seven Ethereum futures ETF filing companies
- From GameFi to Web3Game, what is the ideal type of encrypted game?
- Civilization Evolution Theory Breaking Free from the Rat Race, From Urban Residents to Digital Nomads.
Artela implements on-chain “runtime protection” extension through Aspect Programming.
We gradually demonstrate how to prevent reentrancy attacks on the Curve contract through Aspect.
Why is reentrancy attack still a challenge despite the existence of risk control measures?
Although reentrancy attack is a well-known issue and many risk control measures have been implemented, security incidents involving such attacks continue to occur in the past two years:
Curve Finance attack (July 2023) – $60 million, Curve suffered a reentrancy attack due to a compilation flaw in its contract programming language Vyper.
Origin Protocol attack (November 2022) – $7 million, stablecoin project Origin Dollar (OUSD) suffered a reentrancy attack.
Siren Protocol attack (September 2021) – $3.5 million, AMM pool suffered a reentrancy attack.
Cream Finance attack (August 2021) – $18.8 million, the attacker exploited a reentrancy vulnerability for a second loan.
Currently, the focus of preventing reentrancy attacks is mainly on the source code level of smart contracts, with measures including integrating OpenZeppelin’s ReentrancyGuard and conducting security audits of contract logic code to avoid predefined security vulnerabilities.
This approach is called a “white-box” solution, aiming to mitigate vulnerabilities at the source code level and minimize logical errors. However, its main challenge lies in the inability to defend against unknown vulnerabilities.
Transforming a contract from source code to actual runtime is a challenging process. Each step may bring unforeseen issues for developers, and the contract source code itself may not cover all potential scenarios comprehensively. In the case of Curve, there may still be discrepancies between the expected design of the protocol and the final execution result due to compiler issues, even if the protocol source code is correct.
Relying solely on the security of the protocol at the source code and compilation level is not enough. Even if the source code appears flawless, vulnerabilities may still unexpectedly arise due to compiler issues.
We need runtime protection
Unlike existing risk control measures that focus on the protocol source code level and take effect before runtime, runtime protection involves protocol developers writing runtime protection rules and operations to handle unforeseen situations at runtime. This helps to assess and respond to runtime execution results in real-time.
Runtime protection is crucial for enhancing DeFi security and serves as an important supplement to existing security measures. By protecting protocols in a “black box” manner, it enhances security by ensuring that the final runtime results are consistent with the expected protocol design, without directly interfering with the execution of contract code.
Challenges in implementing runtime protection
Unfortunately, the EVM design does not support on-chain implementation of runtime protection, as smart contracts cannot access the complete runtime context.
How to overcome this challenge? We believe the following prerequisites are necessary:
A dedicated module that can access all information across smart contracts, including the entire transaction context.
Necessary authorization from smart contracts to enable the module to revert transactions as needed.
Ensuring the functionality of the module takes effect after smart contract execution and before state submission.
The current limitations of the EVM in addressing the above challenges make it difficult to accommodate further innovation. In the paradigm of modular blockchains, the execution layer needs to explore breakthroughs beyond the EVM.
Artela’s approach is EVM + native extension, which achieves going beyond the EVM by building a native WASM extension layer for the EVM.
Introduction to Aspect Programming
We have introduced Aspect Programming, a programming framework that supports the Artela blockchain and enables native extensions on the blockchain.
Aspect is a programmable native extension module used to dynamically integrate custom functionalities into the blockchain at runtime. It serves as a modular supplement to smart contracts, enhancing on-chain functionality.
Aspect has the capability to access system-level APIs of the underlying blockchain layer and add extension logic at various join points in the transaction lifecycle. Smart contracts can bind specified aspects to trigger extension functionalities. When a transaction invokes a smart contract, the transaction is also processed by the associated aspect.
How does Aspect Programming achieve runtime protection?
Aspect can record the execution state of each function call and prevent reentrancy during callback function execution. When a reentrant call occurs during callback function execution, Aspect detects it and immediately reverts the transaction, preventing attackers from exploiting reentrancy vulnerabilities. Through this approach, Aspect effectively eliminates reentrancy attacks and ensures the security and stability of smart contracts.
Key attributes of Aspect for achieving runtime protection:
Triggerable after smart contract execution and before state submission: Aspect modules can be set to activate after smart contract execution but before state submission.
Access to complete transaction context: Aspect can access the complete transaction context, including the entire transaction information (methods, parameters, etc.), call stack (all internal contract calls during execution), state context changes, and events triggered by all transactions.
System call capabilities: Aspect can make system calls and initiate transaction reversals when necessary.
Binding and authorization with smart contracts: Smart contracts can be bound to Aspects and granted permission to participate in transaction processing.
Implementing Aspect for Reentrancy Protection
In this chapter, we discuss how to implement runtime protection for Aspects on the chain.
An actual “contract protection intent” Aspect can be deployed at the join points of “preContractCall” and “postContractCall” to prevent reentrancy attacks.
preContractCall: Triggered before the execution of cross-contract calls
postContractCall: Triggered after the execution of cross-contract calls
For reentrancy protection, our goal is to prevent contract reentrancy before the call ends. Through Aspects, we can achieve this goal by adding specific logic at the join points of the transaction lifecycle.
In the “preContractCall” join point, the Aspect monitors the contract call stack. If there are any duplicate calls in the call stack (which means unexpected reentry occurred in the locked call), the Aspect will roll back the call.
Deploying Curve Contract and Preventing Reentrancy Attacks
We have written a simulated Curve contract and replicated a reentrancy attack to reproduce this process in a more understandable way. The contract code is as follows:
As can be seen, both the add_liquidity and remove_liquidity of the above contract are protected by the same reentry lock called “lock”. This means that if the reentrancy protection works properly, it is not possible to reenter the protected function by changing the lock (for example, calling add_liquidity in remove_liquidity).
Compile the above contract using the vyper compiler 0.2.15, 0.2.16, or 0.3.0 (these versions have known reentrancy protection issues).
Then, we deploy the victim contract mentioned above and attack it using the following contract:
To simulate an actual attack, the attack method of this contract attempts to reenter the add_liquidity function from the remove_liquidity method through its fallback function. If reentry actually occurs, an AddLiquidity event will be recorded before the RemoveLiquidity event in the receipt.
Now let’s use Aspect to protect the attacked contract. Before performing the following operations, please complete the following steps:
1. Deploy Aspect
2. Bind the victim contract to the Aspect
If you are not familiar with operating Aspect, you can first refer to our developer guide for preliminary understanding.
After completing the above operations, let’s try to call the attack method again to check if the operation will be successful.
From the GIF (available in the original article link at the end), we can see that the reentry transaction has been reverted, which means that our Aspect is successfully protecting the victim contract from reentrancy attacks.
The recent attack on Curve once again illustrates that there is no protocol that is 100% secure. Focusing solely on the security of the protocol’s source code and compilation level is not enough. Even if the source code appears flawless, vulnerabilities can still unexpectedly arise due to compiler issues.
In order to enhance the security of DeFi, runtime protection becomes crucial. By protecting the protocol in a “black box” manner and ensuring that its execution aligns with its intended design, runtime reentrancy attacks can be effectively prevented.
We have replicated the Curve contract and fully simulated its recent reentrancy attack, reproducing the entire process in a more understandable way. By using Aspect programming as a new method to achieve runtime protection on-chain, we demonstrate step by step how to protect vulnerable contracts with Aspect. Our goal is to help eliminate reentrancy attacks that DeFi protocols like Curve may suffer from, thereby enhancing the overall security of the entire DeFi ecosystem.
Through Aspect Programming, developers can not only achieve runtime protection on-chain in the security domain, but also enable unprecedented innovative use cases such as intent, JIT, and on-chain automation. In addition, this general framework based on the Cosmos SDK will not only support the Artela blockchain but also support other blockchains in building native extensions based on their own execution layers.