This repository contains a solution to Dex Problem 22 from a Solidity challenge, where the goal was to exploit vulnerabilities in a simple decentralized exchange (DEX) contract to manipulate token prices and drain funds.
The problem illustrates the importance of secure price calculation mechanisms in smart contracts, as price manipulation can result in significant losses. Using Echidna, a property-based testing tool, this repository demonstrates how to identify and exploit the vulnerability.
- Objective: Drain all tokens of at least one type from the DEX by manipulating the token prices.
- Setup:
- You start with 10 tokens of
token1
and 10 tokens oftoken2
. - The DEX contract starts with 100 tokens of each type.
- You start with 10 tokens of
- Conditions for success:
- Manipulate the DEX's price calculation to drain all tokens of at least one type.
- Allow the DEX to report a "bad" price for the assets.
The vulnerability lies in the getSwapPrice
function:
function getSwapPrice(address from, address to, uint256 amount) public view returns (uint256) {
return ((amount * IERC20(to).balanceOf(address(this))) / IERC20(from).balanceOf(address(this)));
}
- The price of a token is calculated based on the balance of tokens in the DEX contract.
- By swapping tokens back and forth repeatedly, the balances of
token1
andtoken2
are manipulated, creating drastic price swings. - This allows an attacker to exploit the price discrepancy to drain one of the token reserves entirely.
Exploit the vulnerability to manipulate token prices and drain the reserves of one token.
-
Initial Setup:
- Transfer small amounts of
token1
andtoken2
to the attacker contract.
- Transfer small amounts of
-
Price Manipulation:
- Perform multiple swaps between
token1
andtoken2
. - Each swap manipulates the price by changing the balance of tokens in the DEX.
- Perform multiple swaps between
-
Draining Reserves:
- After sufficient swaps, one token's price becomes significantly undervalued.
- Use the manipulated price to drain the reserves of the undervalued token.
-
Verification:
- Ensure that the total amount of tokens in the attacker's wallet has increased.
- Verify that at least one token's reserve in the DEX is completely drained.
The following Echidna test demonstrates the exploit:
function echidna_manipulate_swap() public returns (bool) {
// Transfer initial tokens to the attacker contract
token1.transfer(address(this), 10 * MUL);
token2.transfer(address(this), 10 * MUL);
uint256 amount = 1 * 10 ** 18; // Swap amount
uint256 attempts = 100; // Number of swaps
uint256 initAmount1 = token1.balanceOf(address(this));
uint256 initAmount2 = token2.balanceOf(address(this));
// Perform swaps to manipulate the price
for (uint256 i = 0; i < attempts; ++i) {
(address from, address to) = _swap_tokens_order(i % 2 == 0);
require(IERC20(from).balanceOf(address(this)) >= amount, 'Not enough balance');
dex.swap(from, to, amount);
}
uint256 finalAmount1 = token1.balanceOf(address(this));
uint256 finalAmount2 = token2.balanceOf(address(this));
// Ensure that no unintended profit was made during the swaps
return finalAmount1 + finalAmount2 <= initAmount1 + initAmount2;
}
- The repeated swaps manipulate the DEX's price calculation due to changes in token balances.
- The vulnerability is exploited to drain tokens from the DEX reserves.
-
Avoid Using Balances for Price Calculation:
- Using token balances directly to calculate prices introduces vulnerabilities.
- Instead, use algorithms like constant product formula (e.g., Uniswap's AMM:
x * y = k
) to ensure price stability.
-
Implement Swap Limits:
- Prevent excessive swaps within a short time frame to reduce price manipulation risks.
-
Test with Property-Based Tools:
- Use tools like Echidna to test for logical vulnerabilities.
- Define invariants to ensure token balances remain consistent under various scenarios.
-
Secure Liquidity Pools:
- Implement mechanisms to prevent attackers from draining reserves by introducing slippage protection.
The Dex Problem 22
challenge highlights the risks of insecure price calculations in decentralized exchanges. By exploiting the dependency on token balances, this repository demonstrates how attackers can manipulate prices and drain reserves.
This solution uses Echidna to identify and exploit the vulnerability, providing a practical demonstration of the importance of secure smart contract design.