Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions oracles/compund-uni-exploit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## Compound Uni Trap

## Running the Examples
```
forge test
```

## Results
```
Ran 1 test for test/CompoundUniTrapTest.t.sol:CompoundUniTrapTest
[PASS] testContinuousMonitoring() (gas: 154422)
Logs:
Setting for block number: 19290918
Setting for block number: 19290919
Setting for block number: 19290920
Setting for block number: 19290921
Setting for block number: 19290922
Setting for block number: 19290923
Setting for block number: 19290924
Setting for block number: 19290925
Setting for block number: 19290926
Setting for block number: 19290927
Block Number: 19290918
Price from chainlink: 9474361440000000000
Price from uniswap: 8340000000000000000
Difference is: 1134361440000000000
Deviation is: 11
Block Number: 19290919
Price from chainlink: 9713000000000000000
Price from uniswap: 8340000000000000000
Difference is: 1373000000000000000
Deviation is: 14
Block Number: 19290920
Price from chainlink: 9713000000000000000
Price from uniswap: 8340000000000000000
Difference is: 1373000000000000000
Deviation is: 14
Block Number: 19290921
Price from chainlink: 10158692020000000000
Price from uniswap: 8340000000000000000
Difference is: 1818692020000000000
Deviation is: 17
Price deviation detected at block: 19290921

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 11.70s (15.68ms CPU time)
```

6 changes: 6 additions & 0 deletions oracles/compund-uni-exploit/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
93 changes: 93 additions & 0 deletions oracles/compund-uni-exploit/src/CompoundUniTrap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {IERC20} from "forge-std/interfaces/IERC20.sol";
import {Test, console} from "forge-std/Test.sol";

interface IUniswapAnchoredView {
function getUnderlyingPrice(address cToken) external view returns (uint256);
}

interface AggregatorV3Interface {
function decimals() external view returns (uint8);

function description() external view returns (string memory);

function version() external view returns (uint256);

function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);

function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}

contract CompoundUniTrap {
struct PriceDataPoint {
uint256 chainlinkPrice;
uint256 uniswapPrice;
}

AggregatorV3Interface public dataFeed = AggregatorV3Interface(0x553303d460EE0afB37EdFf9bE42922D8FF63220e);
IUniswapAnchoredView public uniswapView = IUniswapAnchoredView(0x50ce56A3239671Ab62f185704Caedf626352741e);
uint256 public deviationThreshold = 14;

function getPricefromChainlink() public view returns (int) {
// prettier-ignore
(
/* uint80 roundID */,
int answer,
/*uint startedAt*/,
/*uint timeStamp*/,
/*uint80 answeredInRound*/
) = dataFeed.latestRoundData();
return answer;
}


function collect() public view returns (PriceDataPoint memory) {
int256 chainlinkPrice = getPricefromChainlink();
uint256 adjustedChainlinkPrice = uint256(chainlinkPrice) * 10 ** 10;

address tokenAddress = 0x35A18000230DA775CAc24873d00Ff85BccdeD550;
uint256 uniswapPrice = uniswapView.getUnderlyingPrice(tokenAddress);

console.log("Price from chainlink: ", adjustedChainlinkPrice);
console.log("Price from uniswap: ", uniswapPrice);

PriceDataPoint memory newPoint = PriceDataPoint({
chainlinkPrice: adjustedChainlinkPrice,
uniswapPrice: uniswapPrice
});

return newPoint;
}


function isValid(PriceDataPoint[] calldata dataPoints) public view returns (bool) {
PriceDataPoint memory currentPrice = dataPoints[0];
uint256 chainlinkPrice = currentPrice.chainlinkPrice;
uint256 uniswapPrice = currentPrice.uniswapPrice;

// Calculate the price difference
uint256 priceDiff = (chainlinkPrice > uniswapPrice) ? chainlinkPrice - uniswapPrice : uniswapPrice - chainlinkPrice;

console.log("Difference is: ",priceDiff);

// Calculate the percentage difference
uint256 priceDeviation = (priceDiff * 100) / chainlinkPrice;

console.log("Deviation is: ",priceDeviation);
// Check if the deviation exceeds the threshold

if (priceDeviation > deviationThreshold) {
return false;
}

return true;
}

}
42 changes: 42 additions & 0 deletions oracles/compund-uni-exploit/test/CompoundUniTrapTest.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pragma solidity ^0.8.13;

import {Test, console} from "forge-std/Test.sol";
import {CompoundUniTrap} from "../src/CompoundUniTrap.sol";

contract CompoundUniTrapTest is Test {
CompoundUniTrap public compoundUniTrap;
uint256 public currentBlockNumber = 19290918;

//The attack takes place at block 19290921

//Defi Lab source
//https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2024-02/CompoundUni_exp.sol
//https://etherscan.io/tx/0xaee0f8d1235584a3212f233b655f87b89f22f1d4890782447c4ef742b37af58d

uint256[10] public forks;

function setUp() public {
compoundUniTrap = new CompoundUniTrap();

for (uint256 i = 0; i < 10; i++) {
console.log("Setting for block number: ",currentBlockNumber + i);
forks[i] = vm.createSelectFork(vm.rpcUrl("https://mainnet.infura.io/v3/39b2abffe10e4659a12074ce9a344bae"), currentBlockNumber + i);
}
}

function testContinuousMonitoring() public {
for (uint256 i = 0; i < 10; i++) {
console.log("Block Number:",currentBlockNumber + forks[i]);
CompoundUniTrap.PriceDataPoint[] memory prices = new CompoundUniTrap.PriceDataPoint[](1);
vm.selectFork(forks[i]);

prices[0] = compoundUniTrap.collect();

bool valid = compoundUniTrap.isValid(prices);
if (!valid) {
console.log("Price deviation detected at block: ", currentBlockNumber + i);
break;
}
}
}
}