-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathCoreSaltyFeed.t.sol
259 lines (208 loc) · 11.9 KB
/
CoreSaltyFeed.t.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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// SPDX-License-Identifier: BUSL 1.1
pragma solidity =0.8.22;
import "../../dev/Deployment.sol";
import "../CoreSaltyFeed.sol";
contract TestCoreSaltyFeed is Deployment
{
CoreSaltyFeed public saltyFeed;
constructor()
{
initializeContracts();
saltyFeed = new CoreSaltyFeed( pools, exchangeConfig );
grantAccessAlice();
grantAccessBob();
grantAccessCharlie();
grantAccessDeployer();
grantAccessDefault();
vm.startPrank(DEPLOYER);
wbtc.approve( address(pools), type(uint256).max );
weth.approve( address(pools), type(uint256).max );
usds.approve( address(pools), type(uint256).max );
wbtc.approve( address(collateralAndLiquidity), type(uint256).max );
weth.approve( address(collateralAndLiquidity), type(uint256).max );
usds.approve( address(collateralAndLiquidity), type(uint256).max );
vm.stopPrank();
vm.prank( address(collateralAndLiquidity) );
usds.mintTo(DEPLOYER, 1000000000 ether);
finalizeBootstrap();
vm.prank(address(daoVestingWallet));
salt.transfer(DEPLOYER, 1000000 ether);
}
// Assumes no initial liquidity
function setPriceInPoolsWBTC( uint256 price ) public
{
vm.startPrank(DEPLOYER);
collateralAndLiquidity.depositLiquidityAndIncreaseShare( wbtc, usds, 1000 * 10**8, price * 1000, 0, block.timestamp, false );
vm.stopPrank();
}
// Assumes no initial liquidity
function setPriceInPoolsWETH( uint256 price ) public
{
vm.startPrank(DEPLOYER);
collateralAndLiquidity.depositLiquidityAndIncreaseShare( weth, usds, 1000 ether, price * 1000, 0, block.timestamp, false );
vm.stopPrank();
}
// A unit test that verifies the correct operation of getPriceBTC and getPriceETH functions when the reserves of WBTC/WETH and USDS are above the DUST limit. The test should set the reserves to known values and check that both functions return the expected price. Additionally, this test should cover scenarios where the pool reserves fluctuate or are updated in real-time.
function testCorrectOperationOfGetPriceBTCAndETHWithSufficientReserves() public
{
uint256 wbtcPrice = 50000 ether; // WBTC price in terms of USDS
uint256 wethPrice = 3000 ether; // WETH price in terms of USDS
// Set prices in the pools
this.setPriceInPoolsWBTC(wbtcPrice);
this.setPriceInPoolsWETH(wethPrice);
// Prices should match those set in the pools
assertEq(saltyFeed.getPriceBTC(), wbtcPrice, "Incorrect WBTC price returned");
assertEq(saltyFeed.getPriceETH(), wethPrice, "Incorrect WETH price returned");
// // Remove all liquidity before changing price
// vm.startPrank( DEPLOYER );
// pools.removeLiquidity( wbtc, usds, pools.getUserLiquidity(DEPLOYER, wbtc, usds), 0, 0, block.timestamp );
// pools.removeLiquidity( weth, usds, pools.getUserLiquidity(DEPLOYER, weth, usds), 0, 0, block.timestamp );
// vm.stopPrank();
//
// // Change reserves to simulate real-time update
// uint256 newWbtcPrice = 55000 ether;
// uint256 newWethPrice = 3200 ether;
//
// this.setPriceInPoolsWBTC(newWbtcPrice);
// this.setPriceInPoolsWETH(newWethPrice);
//
// // Prices should reflect new reserves
// assertEq(saltyFeed.getPriceBTC(), newWbtcPrice, "Incorrect WBTC price returned after reserves update");
// assertEq(saltyFeed.getPriceETH(), newWethPrice, "Incorrect WETH price returned after reserves update");
}
// A unit test that confirms that getPriceBTC and getPriceETH functions return zero when the reserves of WBTC/WETH or USDS are equal to or below the DUST limit, regardless of the other's reserves.
function testGetPriceReturnsZeroWithDustReserves() public
{
// Prices should be zero due to DUST limit
assertEq(saltyFeed.getPriceBTC(), 0, "Price for WBTC should be zero when reserves are DUST");
assertEq(saltyFeed.getPriceETH(), 0, "Price for WETH should be zero when reserves are DUST");
// // Set prices in the pools with dust reserve
// this.setPriceInPoolsWBTC(1 ether);
// this.setPriceInPoolsWETH(1 ether);
//
// // Remove all liquidity except for DUST amount
// vm.startPrank( DEPLOYER );
// pools.removeLiquidity( wbtc, usds, pools.getUserLiquidity(DEPLOYER, wbtc, usds) - PoolUtils.DUST + 1, 0, 0, block.timestamp );
// pools.removeLiquidity( weth, usds, pools.getUserLiquidity(DEPLOYER, weth, usds) - PoolUtils.DUST + 1, 0, 0, block.timestamp );
// vm.stopPrank();
//
// // Prices should be zero due to DUST limit
// assertEq(saltyFeed.getPriceBTC(), 0, "Price for WBTC should be zero when reserves are DUST");
// assertEq(saltyFeed.getPriceETH(), 0, "Price for WETH should be zero when reserves are DUST");
}
// A unit test that checks if the contract behaves as expected when the WBTC, WETH, or USDS token contract addresses are invalid or manipulated. This could include scenarios where the token contracts do not implement the expected ERC20 interface, or when the token contracts behave maliciously.
function testInvalidTokens() public
{
exchangeConfig = new ExchangeConfig( ISalt(address(0x1)), IERC20(address(0x1)), IERC20(address(0x1)), IERC20(address(0x1)), IUSDS(address(0x2)), managedTeamWallet);
saltyFeed = new CoreSaltyFeed(pools, exchangeConfig );
// Prices should match those set in the pools
assertEq(saltyFeed.getPriceBTC(), 0, "Incorrect WBTC price returned");
assertEq(saltyFeed.getPriceETH(), 0, "Incorrect WETH price returned");
}
// A unit test that verifies the correct initialization of the pools, WBTC, WETH, and USDS contract addresses in the CoreSaltyFeed constructor.
function testCorrectInitializationOfContractAddresses() public
{
assertEq(address(saltyFeed.pools()), address(pools), "Pools address not correctly initialized");
assertEq(address(saltyFeed.wbtc()), address(wbtc), "WBTC address not correctly initialized");
assertEq(address(saltyFeed.weth()), address(weth), "WETH address not correctly initialized");
assertEq(address(saltyFeed.usds()), address(usds), "USDS address not correctly initialized");
}
// A unit test that validates that getPriceBTC function does not revert in case of zero reserves for WBTC and USDS.
function testGetPriceBTCDoesNotRevertWithZeroReserves() public
{
// Call getPriceBTC, should not revert and should return 0
assertEq(saltyFeed.getPriceBTC(), 0, "Price for WBTC should be zero when reserves are zero");
}
// A unit test that validates that getPriceETH function does not revert in case of zero reserves for WETH and USDS.
function testGetPriceETHDoesNotRevertWithZeroReserves() public
{
// Call getPriceETH, should not revert and should return 0
assertEq(saltyFeed.getPriceETH(), 0, "Price for WETH should be zero when reserves are zero");
}
// A unit test to verify the getPriceBTC functions return a non-zero value when reserves of WBTC/WETH are just above the DUST limit and USDS reserves are substantially high.
function testLargeUSDSReservesBTC() public
{
uint256 btcPrice = 30000 ether; // BTC price in terms of USDS
vm.startPrank(DEPLOYER);
collateralAndLiquidity.depositLiquidityAndIncreaseShare( wbtc, usds, PoolUtils.DUST + 1, btcPrice * (PoolUtils.DUST + 1), 0, block.timestamp, false );
vm.stopPrank();
// Prices should match those set in the pools
assertEq(saltyFeed.getPriceBTC(), btcPrice * 10**8, "Incorrect WBTC price returned");
}
// A unit test to verify the getPriceETH functions return a non-zero value when reserves of WBTC/WETH are just above the DUST limit and USDS reserves are substantially high.
function testLargeUSDSReservesETH() public
{
uint256 ethPrice = 3000 ether; // ETH price in terms of USDS
vm.startPrank(DEPLOYER);
collateralAndLiquidity.depositLiquidityAndIncreaseShare( weth, usds, PoolUtils.DUST + 1, ethPrice * (PoolUtils.DUST + 1), 0, block.timestamp, false );
vm.stopPrank();
// Prices should match those set in the pools
assertEq(saltyFeed.getPriceETH(), ethPrice * 10**18, "Incorrect WETH price returned");
}
// A unit test that checks whether getPriceBTC and getPriceETH functions can handle a division by zero error.
function testDivisionByZero() public
{
// Prices should be zero due to DUST limit
assertEq(saltyFeed.getPriceBTC(), 0, "Price for WBTC should be zero when reserves are less than DUST");
assertEq(saltyFeed.getPriceETH(), 0, "Price for WETH should be zero when reserves are less than DUST");
// // Set prices in the pools with dust reserve
// this.setPriceInPoolsWBTC(1 ether);
// this.setPriceInPoolsWETH(1 ether);
//
// // Remove all liquidity except for 1, which is less than DUST
// vm.startPrank( DEPLOYER );
// pools.removeLiquidity( wbtc, usds, pools.getUserLiquidity(DEPLOYER, wbtc, usds) - 1, 0, 0, block.timestamp );
// pools.removeLiquidity( weth, usds, pools.getUserLiquidity(DEPLOYER, weth, usds) - 1, 0, 0, block.timestamp );
// vm.stopPrank();
//
// // Prices should be zero due to DUST limit
// assertEq(saltyFeed.getPriceBTC(), 0, "Price for WBTC should be zero when reserves are less than DUST");
// assertEq(saltyFeed.getPriceETH(), 0, "Price for WETH should be zero when reserves are less than DUST");
}
// A unit test to confirm that getPriceBTC and getPriceETH function returns are consistent if reserves do not change.
function testGetPriceConsistency() public
{
// Set known reserves in pools
uint256 wbtcPrice = 40000 ether; // WBTC price in terms of USDS
uint256 wethPrice = 2000 ether; // WETH price in terms of USDS
this.setPriceInPoolsWBTC(wbtcPrice);
this.setPriceInPoolsWETH(wethPrice);
uint256 initialPriceBTC = saltyFeed.getPriceBTC();
uint256 initialPriceETH = saltyFeed.getPriceETH();
assertEq(initialPriceBTC, wbtcPrice, "Price BTC changed over time without reserve changes");
assertEq(initialPriceETH, wethPrice, "Price ETH changed over time without reserve changes");
// Simulate passing of time without changing reserves
vm.warp(block.timestamp + 60 * 60 * 24);
// Prices should be consistant over time if reserves do not change
assertEq(initialPriceBTC, saltyFeed.getPriceBTC(), "Price BTC changed over time without reserve changes");
assertEq(initialPriceETH, saltyFeed.getPriceETH(), "Price ETH changed over time without reserve changes");
}
//
// // A unit test that verifies if the getPriceBTC and getPriceETH functions handle accurately when reserves of WBTC/WETH or USDS are excessively small.
// function testGetPriceWithExcessivelySmallReserves() public
// {
// // Set prices in the pools with very small reserve
// this.setPriceInPoolsWBTC(1);
// this.setPriceInPoolsWETH(1);
//
// // Remove all liquidity except for 1, which is less than DUST
// vm.startPrank( DEPLOYER );
// pools.removeLiquidity( wbtc, usds, pools.getUserLiquidity(DEPLOYER, wbtc, usds) - 1, 0, 0, block.timestamp );
// pools.removeLiquidity( weth, usds, pools.getUserLiquidity(DEPLOYER, weth, usds) - 1, 0, 0, block.timestamp );
// vm.stopPrank();
//
// // Prices should be zero due to small reserves
// assertEq(saltyFeed.getPriceBTC(), 0, "Price for WBTC should be zero when reserves are too small");
// assertEq(saltyFeed.getPriceETH(), 0, "Price for WETH should be zero when reserves are too small");
//
// // Remove all liquidity
// vm.startPrank( DEPLOYER );
// pools.removeLiquidity( wbtc, usds, pools.getUserLiquidity(DEPLOYER, wbtc, usds), 0, 0, block.timestamp );
// pools.removeLiquidity( weth, usds, pools.getUserLiquidity(DEPLOYER, weth, usds), 0, 0, block.timestamp );
// vm.stopPrank();
//
// // Prices should still be zero
// assertEq(saltyFeed.getPriceBTC(), 0, "Price for WBTC should still be zero after removing liquidity");
// assertEq(saltyFeed.getPriceETH(), 0, "Price for WETH should still be zero after removing liquidity");
// }
}