-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTestRDC.sol
291 lines (261 loc) · 14.2 KB
/
TestRDC.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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
pragma solidity ^0.4.23;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/RDC.sol";
contract TestRDC {
// set ETH balance for this testing contract to test RDC functionality that requires it
uint256 public initialBalance = 10 ether;
RDC rdc;
/** @dev Test hook to instantiate owned instance of RDC before running tests
@dev This allows for testing of onlyOwner functions in RDC
*/
function beforeAll() public {
rdc = new RDC();
}
/** @dev This is a simple test to ensure that the constructor properly set state variables, including the Owner
@dev Ownership is handled via the Ownable contract inherited from the OpenZeppelin package
@dev This test covers all state variables set by the constructor except for the State enum (enums are not currently supported by the ABI)
*/
function testRandomCoinConstructor() public {
address expected_owner = address(this);
uint256 expected_mpib = 100 szabo;
uint256 expected_mpim = 10;
uint256 expected_ar = 100;
// uint256 expected_er = 100;
// uint256 expected_hw = 50;
uint256 expected_bwt = 10; //5760 * 14; // changed for testing
uint256 expected_mtta = 10;
uint256 expected_mbta = 10 finney;
uint256 expected_crc = 1000;
uint256 expected_crb = 100;
uint256 expected_mri = 15;
bool expected_raf = false;
bool expected_tlm = false;
Assert.equal(expected_owner, rdc.owner(), "Owner should be the deploying contract");
Assert.equal(expected_mpib, rdc.minimumPegInBaseAmount(), "minimumPegInBaseAmount should be equal to 100 szabo");
Assert.equal(expected_mpim, rdc.minimumPegInMultiplier(), "minimumPegInMultiplier should be equal to 10");
Assert.equal(expected_ar, rdc.averageRate(), "averageRate should be equal to 100");
// Assert.equal(expected_er, rdc.expectedRate(), "expectedRate should be equal to 100");
// Assert.equal(expected_hw, rdc.halfWidth(), "halfWidth should be equal to 50");
Assert.equal(expected_bwt, rdc.blockWaitTime(), "blockWaitTime should be equal to 5760 * 14");
Assert.equal(expected_mtta, rdc.minTxToActivate(), "minTxToActivate should be equal to 10");
Assert.equal(expected_mbta, rdc.minBalanceToActivate(), "minBalanceToActivate should be equal to 10 finney");
Assert.equal(expected_crc, rdc.currentRateCeiling(), "currentRateCeiling should be equal to 1000");
Assert.equal(expected_crb, rdc.currentRateBuffer(), "currentRateBuffer should be equal to 100");
Assert.equal(expected_mri, rdc.maxRateIndex(), "maxRateIndex should be equal to 15");
Assert.equal(expected_raf, rdc.rateArrayFull(), "rateArrayFull should be false");
Assert.equal(expected_tlm, rdc.txLockMutex(), "txLockMutex should be false");
}
/** @dev Test that ownership of the RDC contract can be properly transferred to a new owner
@dev This functionality also comes from the Ownable contract in the OpenZeppelin library
@dev This test covers the transferOwnership() function
*/
function testRDCOwnershipTransfer() public {
RDC _xfer_rdc = new RDC();
address expectedOwner = DeployedAddresses.RDC();
// attempt to transfer ownership
_xfer_rdc.transferOwnership(expectedOwner);
// check if we successfully did so
Assert.equal(expectedOwner, _xfer_rdc.owner(), "RandomCoin contract should now own RDCToken instance");
}
/** @dev Test that totalSupply increases after minting some tokens
@dev RDC is Mintable via imports from the OpenZeppelin package
@dev This test covers both the mint() function and the totalSupply() state variable which are key for other functions
*/
function testMintAndTotalSupply() public {
address _add = address(this);
uint firstXfer = 9000;
uint secondXfer = 1000;
uint expected = firstXfer + secondXfer;
rdc.mint(_add, firstXfer);
rdc.mint(_add, secondXfer);
Assert.equal(expected, rdc.totalSupply(), "totalSupply should be 10000");
}
/** @dev This tests that RDC tokens are properly transferable, as this transferability increases their utility
@dev This functionality is inherited from elements of the OpenZeppelin package (ERC20Basic interface, BasicToken contract)
@dev This test covers the transfer() function
*/
function testRDCTransfer() public {
address _add1 = address(this);
address _add2 = DeployedAddresses.RDC();
// mint to _add1, transfer to _add2
rdc.mint(_add1, 1000);
rdc.transfer(_add2, 500);
uint256 _expected = 500;
Assert.equal(_expected, rdc.balanceOf(_add2), "balance of _add2 should be 500");
}
// /** @dev Test that multiple random rates fall within the expected (rescaled) range
// @dev This test covers randomRate() directly, and rescaleRate() indirectly (the latter is always called by the former)
// */
// function testMultipleRandomRate() public {
// uint256 low = 50;
// uint256 high = 150;
// uint256 _cur_rate;
// for (uint i = 0; i < 5; i++) {
// _cur_rate = rdc.randomRate();
// Assert.isAtLeast(_cur_rate, low, "Random rate should be at least 50");
// Assert.isAtMost(_cur_rate, high, "Random rate should be at most 150");
// }
// }
/** @dev Test that multiple random rates fall within the expected ranges
@dev This test covers insecureRandom() which is utilized several times in the randomRate() function
*/
function testMultipleInsecureRandom() public {
uint256[5] memory _highs = [uint(2), uint(1001), uint(250), uint(205), uint(99999910901)];
uint256 _cur_val;
for (uint256 i = 0; i < 5; i++) {
uint256 _high = _highs[i];
_cur_val = rdc.insecureRandom(_high);
Assert.isAtMost(_cur_val, _high, "Random rate should be below upper bound specifed");
}
}
/** @dev Test that an address can properly receive RDC tokens in exchange for ETH
@dev This test is also used to ensure that the contract state can move from Funding to Active when the minBalanceToActivate is sent
@dev (Subsequent tests to peg out would fail if the contract state did not change to Active)
@dev This test covers the pegIn() function directly, and the randomRate() function indirectly (which is also partially tested in the previous test function)
*/
function testPegIn() public {
rdc.pegIn.value(15 finney).gas(300000)(); // actual gas cost is something like 175,000 it appears
Assert.isAtLeast(rdc.balanceOf(address(this)), 1, "pegIn should grant at least 1 RDC");
}
/** @dev Test various functionality related to pegging in multiple times
@dev This tests that averageRate gets updated while pegging in, that it falls within the expected range, and that it changes over time
@dev This also tests that the latestRates array gets properly populated
@dev *** N.B. that it is possible (though very unlikely) to draw the same random number 5 times in a row, so in the (unlikely) event that this test fails, try rerunning it
@dev This test covers pegIn(), updateAverageRate(), and latestRates
*/
function testMultiplePegIn() public {
uint256 _cap = 5;
uint256[5] memory _ARs;
uint256 _sumAR;
// peg in a few times
for (uint8 i; i < _cap; i++) {
rdc.pegIn.value(15 finney).gas(300000)();
uint256 _curAR = rdc.averageRate();
// Assert.isAtLeast(_curAR, 50, "averageRate should be at least 50");
// Assert.isAtMost(_curAR, 150, "averageRate should be at most 150");
_ARs[i] = _curAR;
_sumAR += _curAR;
}
// check that averageRate changed during loop
uint256 _avgAR = _sumAR / _cap;
uint8 _equalsAvg;
for (uint8 j; j < _cap; j++) {
if (_ARs[j] == _avgAR) {
_equalsAvg += 1;
}
}
Assert.notEqual(_equalsAvg, _cap, "averageRate should have changed over multiple pegIn() calls");
// check latestRates after loop
uint256 _expectValueAtIndex = 2;
uint256 _doNotExpectValueAtIndex = 10;
Assert.isAtLeast(rdc.latestRates(_expectValueAtIndex), 1, "A value should have been assigned to index 2 of latestRates");
Assert.equal(rdc.latestRates(_doNotExpectValueAtIndex), 0, "A value should not have been assigned to index 10 of latestRates");
}
/** @dev Test that an account can properly receive ETH in exchange for RDC when pegging out
@dev This test covers the pegOut() function
*/
function testPegOut() public payable {
uint256 _this_eth_bal = this.balance;
uint256 _this_rdc_bal = rdc.balanceOf(address(this));
Assert.isAtLeast(_this_rdc_bal, 100, "this contract should have at least 100 RDCTokens");
rdc.pegOut(_this_rdc_bal / 10);
Assert.isAtLeast(this.balance, _this_eth_bal + 1, "this contract should have received some eth from pegging out");
Assert.equal(rdc.balanceOf(this), _this_rdc_bal - (_this_rdc_bal / 10), "this contract should have lost 1/10th of its RDCTokens");
}
/** @dev Test that the Owner can force an equitable liquidation event
@dev This is essentially a test of startLiquidation(), which is called by equitableLiquidation() and equitableDestruct() (under different circumstances)
@dev This test covers the equitableLiquidation() function directly, and the startLiquidation() and equitableDestruct() functions indirectly
*/
function testEquitableLiquidation() public {
bool result = rdc.equitableLiquidation();
Assert.equal(result, true, "Liquidation should have been triggered");
Assert.notEqual(rdc.liquidationBlockNumber(), 0, "liquidationBlockNumber should have been set");
Assert.notEqual(rdc.availablePayout(), 0, "availablePayout should habe been set");
Assert.equal(address(rdc).balance - rdc.haircut(), rdc.availablePayout(), "availablePayout should have been haircut");
Assert.equal(rdc.mintingFinished(), true, "mintingFinished should have been set to true");
}
/** @dev Test that accounts can cash out their "fair share" of ETH in the RDC contract if the exchange peg breaks
@dev This test covers the equitableCashout() function
*/
function testEquitableCashout() public payable {
uint256 _expected_rdc_bal = 0;
uint256 _this_eth_bal = address(this).balance;
rdc.equitableCashout();
Assert.equal(_expected_rdc_bal, rdc.balanceOf(address(this)), "entire RDC balance of testing contract should have been cashed out");
Assert.isAtLeast(address(this).balance, _this_eth_bal + 1, "the testing contract should have cashed out at least 1 wei worth of ETH");
}
/** @dev The next 10 "tests" simply move the block number forward (to allow testing of resetState()) and can be ignored by the tester
@dev This is done in this fashion as there does not appear to exist any convenient way to do this in Solidity (no equivalent of evm_mine)
*/
function testMoveTimeForward_1of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_2of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_3of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_4of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_5of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_6of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_7of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_8of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_9of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
function testMoveTimeForward_10of10() public {
bool moveTimeForward = true;
Assert.equal(moveTimeForward, true, "Wheeee");
}
/** @dev This tests the contract state can be reset by a new peg-in transaction after the cash-out period has elapsed
@dev This test covers the canChangeStateToFunding() modifier
*/
function testResetViaPegIn() public {
Assert.equal(rdc.mintingFinished(), true, "Minting should be paused in Liquidation state");
rdc.pegIn.value(15 finney).gas(300000)();
Assert.equal(rdc.mintingFinished(), false, "Minting should be allowed again after contract reset");
}
/** @dev This tests that the length-16 array of latest rates can be fetched from the contract
@dev This test covers the getLatestRates() function
*/
function testGetLatestRates() public {
uint256[16] memory _latest = rdc.getLatestRates();
Assert.equal(_latest.length, 16, "Should have fetched a length-16 array");
}
/** @dev This tests that the byte representation flag for the contract state can be fetched
@dev This test covers the getStateBytes() function
*/
function testGetStateBytes() public {
bytes2 _state = rdc.getStateBytes();
bool _match = _state == bytes2(keccak256("Active"));
Assert.equal(_match, true, "stateBytes should be equal to the byte signature for Active");
}
function testNextBlock() public {
uint256 _cur_block = rdc.blockCounter();
rdc.nextBlock();
Assert.equal((_cur_block + 1), rdc.blockCounter(), "blockCounter should have increased by 1");
}
/** @dev fallback function */
function() external payable {}
}