From fdbc486e2377b601d8d6425624a8b90086fa7f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Fingen?= Date: Fri, 3 May 2024 15:51:11 +0100 Subject: [PATCH] feat: Remove combined action withdratETHGainToTrove --- contracts/src/BorrowerOperations.sol | 16 - .../src/Interfaces/IBorrowerOperations.sol | 2 - contracts/src/Interfaces/IStabilityPool.sol | 7 - contracts/src/StabilityPool.sol | 41 - contracts/src/test/TestContracts/BaseTest.sol | 6 - ...rowerOperationsOnBehalfTroveManagament.sol | 95 - .../src/test/interestRateAggregate.t.sol | 120 - contracts/src/test/interestRateBasic.t.sol | 64 - contracts/test/AccessControlTest.js | 17 - contracts/test/StabilityPoolTest.js | 705 ---- .../StabilityPool_SPWithdrawalToCDPTest.js | 3577 ----------------- 11 files changed, 4650 deletions(-) delete mode 100644 contracts/test/StabilityPool_SPWithdrawalToCDPTest.js diff --git a/contracts/src/BorrowerOperations.sol b/contracts/src/BorrowerOperations.sol index 54c9afdd..e497dcd6 100644 --- a/contracts/src/BorrowerOperations.sol +++ b/contracts/src/BorrowerOperations.sol @@ -239,18 +239,6 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe assert(troveManager.getTroveEntireColl(_troveId) > oldColl); } - // Send ETH as collateral to a trove. Called by only the Stability Pool. - function moveETHGainToTrove(address _sender, uint256 _troveId, uint256 _ETHAmount) external override { - ContractsCacheTMAPBT memory contractsCache = ContractsCacheTMAPBT(troveManager, activePool, boldToken); - _requireTroveIsActive(contractsCache.troveManager, _troveId); - // TODO: Use oldColl and assert in fuzzing, remove before deployment - uint256 oldColl = troveManager.getTroveEntireColl(_troveId); - _requireCallerIsStabilityPool(); - // TODO: check owner? - _adjustTrove(_sender, _troveId, _ETHAmount, true, 0, false, 0, contractsCache); - assert(troveManager.getTroveEntireColl(_troveId) > oldColl); - } - // Withdraw ETH collateral from a trove function withdrawColl(uint256 _troveId, uint256 _collWithdrawal) external override { ContractsCacheTMAPBT memory contractsCache = ContractsCacheTMAPBT(troveManager, activePool, boldToken); @@ -797,10 +785,6 @@ contract BorrowerOperations is LiquityBase, Ownable, CheckContract, IBorrowerOpe ); } - function _requireCallerIsStabilityPool() internal view { - require(msg.sender == stabilityPoolAddress, "BorrowerOps: Caller is not Stability Pool"); - } - function _requireSufficientBoldBalance(IBoldToken _boldToken, address _borrower, uint256 _debtRepayment) internal view diff --git a/contracts/src/Interfaces/IBorrowerOperations.sol b/contracts/src/Interfaces/IBorrowerOperations.sol index 7609d7ae..da051d09 100644 --- a/contracts/src/Interfaces/IBorrowerOperations.sol +++ b/contracts/src/Interfaces/IBorrowerOperations.sol @@ -37,8 +37,6 @@ interface IBorrowerOperations is ILiquityBase { function addColl(uint256 _troveId, uint256 _ETHAmount) external; - function moveETHGainToTrove(address _sender, uint256 _troveId, uint256 _ETHAmount) external; - function withdrawColl(uint256 _troveId, uint256 _amount) external; function withdrawBold(uint256 _troveId, uint256 _maxFee, uint256 _amount) external; diff --git a/contracts/src/Interfaces/IStabilityPool.sol b/contracts/src/Interfaces/IStabilityPool.sol index 0f5c9d5b..9be68bbd 100644 --- a/contracts/src/Interfaces/IStabilityPool.sol +++ b/contracts/src/Interfaces/IStabilityPool.sol @@ -63,13 +63,6 @@ interface IStabilityPool is ILiquityBase { */ function withdrawFromSP(uint256 _amount) external; - /* withdrawETHGainToTrove(): - * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove - * - Leaves their compounded deposit in the Stability Pool - * - Takes new snapshots of accumulators P and S - */ - function withdrawETHGainToTrove(uint256 _troveId) external; - /* * Initial checks: * - Caller is TroveManager diff --git a/contracts/src/StabilityPool.sol b/contracts/src/StabilityPool.sol index 579a386d..07bb63f2 100644 --- a/contracts/src/StabilityPool.sol +++ b/contracts/src/StabilityPool.sol @@ -334,38 +334,6 @@ contract StabilityPool is LiquityBase, Ownable, CheckContract, IStabilityPool { _sendETHGainToDepositor(depositorETHGain); } - /* withdrawETHGainToTrove(): - * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove - * - Leaves their compounded deposit in the Stability Pool - * - Takes new snapshots of accumulators P and S - */ - function withdrawETHGainToTrove(uint256 _troveId) external override { - uint256 initialDeposit = deposits[msg.sender].initialValue; - _requireUserHasDeposit(initialDeposit); - _requireTroveIsOpen(_troveId); - _requireUserHasETHGain(msg.sender); - - uint256 depositorETHGain = getDepositorETHGain(msg.sender); - - uint256 compoundedBoldDeposit = getCompoundedBoldDeposit(msg.sender); - uint256 boldLoss = initialDeposit - compoundedBoldDeposit; // Needed only for event log - - _updateDepositAndSnapshots(msg.sender, compoundedBoldDeposit); - - /* Emit events before transferring ETH gain to Trove. - This lets the event log make more sense (i.e. so it appears that first the ETH gain is withdrawn - and then it is deposited into the Trove, not the other way around). */ - emit ETHGainWithdrawn(msg.sender, depositorETHGain, boldLoss); - emit UserDepositChanged(msg.sender, compoundedBoldDeposit); - - uint256 newETHBalance = ETHBalance - depositorETHGain; - ETHBalance = newETHBalance; - emit StabilityPoolETHBalanceUpdated(newETHBalance); - emit EtherSent(msg.sender, depositorETHGain); - - borrowerOperations.moveETHGainToTrove(msg.sender, _troveId, depositorETHGain); - } - // --- Liquidation functions --- /* @@ -695,15 +663,6 @@ contract StabilityPool is LiquityBase, Ownable, CheckContract, IStabilityPool { require(_amount > 0, "StabilityPool: Amount must be non-zero"); } - function _requireTroveIsOpen(uint256 _troveId) internal view { - require(troveManager.checkTroveIsOpen(_troveId), "StabilityPool: trove must be active to withdraw ETHGain to"); - } - - function _requireUserHasETHGain(address _depositor) internal view { - uint256 ETHGain = getDepositorETHGain(_depositor); - require(ETHGain > 0, "StabilityPool: caller must have non-zero ETH Gain"); - } - function _requireValidKickbackRate(uint256 _kickbackRate) internal pure { require(_kickbackRate <= DECIMAL_PRECISION, "StabilityPool: Kickback rate must be in range [0,1]"); } diff --git a/contracts/src/test/TestContracts/BaseTest.sol b/contracts/src/test/TestContracts/BaseTest.sol index 26ba8a76..91ccefad 100644 --- a/contracts/src/test/TestContracts/BaseTest.sol +++ b/contracts/src/test/TestContracts/BaseTest.sol @@ -223,12 +223,6 @@ contract BaseTest is Test { vm.stopPrank(); } - function withdrawETHGainToTrove(address _from, uint256 _troveId) public { - vm.startPrank(_from); - stabilityPool.withdrawETHGainToTrove(_troveId); - vm.stopPrank(); - } - function batchLiquidateTroves(address _from, uint256[] memory _trovesList) public { vm.startPrank(_from); console.log(_trovesList[0], "trove 0 to liq"); diff --git a/contracts/src/test/borrowerOperationsOnBehalfTroveManagament.sol b/contracts/src/test/borrowerOperationsOnBehalfTroveManagament.sol index ab493d25..0d980b12 100644 --- a/contracts/src/test/borrowerOperationsOnBehalfTroveManagament.sol +++ b/contracts/src/test/borrowerOperationsOnBehalfTroveManagament.sol @@ -342,99 +342,4 @@ contract BorrowerOperationsOnBehalfTroveManagamentTest is DevTestSetup { assertEq(boldToken.balanceOf(A), AInitialBoldBalance + 10e18, "Wrong owner balance"); assertEq(boldToken.balanceOf(B), BInitialBoldBalance, "Wrong manager balance"); } - - // TODO: withdrawETHGainToTrove - - function testWithdrawETHGainToTroveWithAddManager() public { - uint256 ATroveId = openTroveNoHints100pctMaxFee(A, 100 ether, 10000e18, 1e17); - - // Set add manager - vm.startPrank(A); - borrowerOperations.setAddManager(ATroveId, B); - // A provides to SP - stabilityPool.provideToSP(10000e18); - vm.stopPrank(); - - // B provides to SP - deal(address(boldToken), B, 10000e18); - vm.startPrank(B); - stabilityPool.provideToSP(10000e18); - vm.stopPrank(); - - // C opens trove, price drops and gets liquidated - uint256 CTroveId = openTroveNoHints100pctMaxFee(C, 100 ether, 14000e18, 1e17); - priceFeed.setPrice(priceFeed.getPrice() * 3 / 4); - troveManager.liquidate(CTroveId); - - // Owner can withdraw ETH gain to trove - vm.startPrank(A); - uint256 AInitialGain = stabilityPool.getDepositorETHGain(A); - - stabilityPool.withdrawETHGainToTrove(ATroveId); - vm.stopPrank(); - - assertEq(troveManager.getTroveColl(ATroveId), 100 ether + AInitialGain, "Wrong trove coll"); - assertEq(stabilityPool.getDepositorETHGain(A), 0, "Wrong owner SP ETH balance"); - - // Manager can withdraw ETH gain to trove - vm.startPrank(B); - uint256 BInitialGain = stabilityPool.getDepositorETHGain(B); - - stabilityPool.withdrawETHGainToTrove(ATroveId); - vm.stopPrank(); - - assertEq(troveManager.getTroveColl(ATroveId), 100 ether + AInitialGain + BInitialGain, "Wrong trove coll"); - assertEq(stabilityPool.getDepositorETHGain(B), 0, "Wrong manager balance"); - } - - function testWithdrawETHGainToTroveWithoutAddManager() public { - uint256 ATroveId = openTroveNoHints100pctMaxFee(A, 100 ether, 10000e18, 1e17); - - // A provides to SP - vm.startPrank(A); - stabilityPool.provideToSP(10000e18); - vm.stopPrank(); - - // B provides to SP - deal(address(boldToken), B, 10000e18); - vm.startPrank(B); - stabilityPool.provideToSP(10000e18); - vm.stopPrank(); - - // C opens trove, price drops and gets liquidated - uint256 CTroveId = openTroveNoHints100pctMaxFee(C, 100 ether, 14000e18, 1e17); - priceFeed.setPrice(priceFeed.getPrice() * 3 / 4); - troveManager.liquidate(CTroveId); - - // Owner can withdraw ETH gain to trove - vm.startPrank(A); - uint256 AInitialGain = stabilityPool.getDepositorETHGain(A); - - stabilityPool.withdrawETHGainToTrove(ATroveId); - vm.stopPrank(); - - assertEq(troveManager.getTroveColl(ATroveId), 100 ether + AInitialGain, "Wrong trove coll"); - assertEq(stabilityPool.getDepositorETHGain(A), 0, "Wrong owner SP ETH balance"); - - // Others can’t withdraw ETH gain to trove - vm.startPrank(B); - uint256 BInitialGain = stabilityPool.getDepositorETHGain(B); - - vm.expectRevert("TroveManager: sender is not trove owner nor manager"); - stabilityPool.withdrawETHGainToTrove(ATroveId); - vm.stopPrank(); - - // Set remove manager - still won’t work - vm.startPrank(A); - borrowerOperations.setRemoveManager(ATroveId, B); - vm.stopPrank(); - - vm.startPrank(B); - vm.expectRevert("TroveManager: sender is not trove owner nor manager"); - stabilityPool.withdrawETHGainToTrove(ATroveId); - vm.stopPrank(); - - assertEq(troveManager.getTroveColl(ATroveId), 100 ether + AInitialGain, "Wrong trove coll"); - assertEq(stabilityPool.getDepositorETHGain(B), BInitialGain, "Wrong manager SP ETH balance"); - } } diff --git a/contracts/src/test/interestRateAggregate.t.sol b/contracts/src/test/interestRateAggregate.t.sol index b3a613e9..6e995701 100644 --- a/contracts/src/test/interestRateAggregate.t.sol +++ b/contracts/src/test/interestRateAggregate.t.sol @@ -1763,126 +1763,6 @@ contract InterestRateAggregate is DevTestSetup { // TODO: more thorough invariant test - // --- withdrawETHGainToTrove --- - - function testWithdrawETHGainToTroveIncreasesAggRecordedDebtByAggInterest() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // fast-forward time so interest accrues - vm.warp(block.timestamp + 1 days); - - uint256 aggRecordedDebt_1 = activePool.aggRecordedDebt(); - assertGt(aggRecordedDebt_1, 0); - uint256 pendingAggInterest = activePool.calcPendingAggInterest(); - assertGt(pendingAggInterest, 0); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - assertEq(activePool.aggRecordedDebt(), aggRecordedDebt_1 + pendingAggInterest); - } - - function testWithdrawETHGainToTroveReducesPendingAggInterestTo0() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // fast-forward time so interest accrues - vm.warp(block.timestamp + 1 days); - - // check there's pending agg. interest - assertGt(activePool.calcPendingAggInterest(), 0); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - // Check pending agg. interest reduced to 0 - assertEq(activePool.calcPendingAggInterest(), 0); - } - - function testWithdrawETHGainToTroveMintsInterestToRouter() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // fast-forward time so interest accrues - vm.warp(block.timestamp + 1 days); - - // Get I-router balance - uint256 boldBalRouter_1 = boldToken.balanceOf(address(mockInterestRouter)); - assertEq(boldBalRouter_1, 0); - - uint256 pendingAggInterest = activePool.calcPendingAggInterest(); - assertGt(pendingAggInterest, 0); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - // Check I-router Bold bal has increased as expected from SP deposit - uint256 boldBalRouter_2 = boldToken.balanceOf(address(mockInterestRouter)); - assertEq(boldBalRouter_2, pendingAggInterest); - } - - function testWithdrawETHGainToTroveUpdatesLastAggUpdateTimeToNow() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // fast-forward time so interest accrues - vm.warp(block.timestamp + 1 days); - - assertGt(activePool.lastAggUpdateTime(), 0); - assertLt(activePool.lastAggUpdateTime(), block.timestamp); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - // Check last agg update time increased to now - assertEq(activePool.lastAggUpdateTime(), block.timestamp); - } - - function testWithdrawETHGainToTroveChangesAggWeightedDebtSumCorrectly() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // fast-forward time - vm.warp(block.timestamp + 1 days); - - // Get weighted sum before - uint256 weightedDebtSum_1 = activePool.aggWeightedDebtSum(); - assertGt(weightedDebtSum_1, 0); - - uint256 oldRecordedWeightedDebt = troveManager.getTroveWeightedRecordedDebt(ATroveId); - assertGt(oldRecordedWeightedDebt, 0); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - // Expect recorded weighted debt to have increased due to accrued Trove interest being applied - uint256 newRecordedWeightedDebt = troveManager.getTroveWeightedRecordedDebt(ATroveId); - assertGt(newRecordedWeightedDebt, oldRecordedWeightedDebt); - - // Expect weighted sum decreases by the old and increases by the new individual weighted Trove debt. - assertEq(activePool.aggWeightedDebtSum(), weightedDebtSum_1 - oldRecordedWeightedDebt + newRecordedWeightedDebt); - } - - function testWithdrawETHGainToTroveChangesRecordedDebtSumCorrectly() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // fast-forward time - vm.warp(block.timestamp + 1 days); - - // Get recorded sum before - uint256 recordedDebt_1 = activePool.getRecordedDebtSum(); - assertGt(recordedDebt_1, 0); - - uint256 oldTroveRecordedDebt = troveManager.getTroveDebt(ATroveId); - assertGt(oldTroveRecordedDebt, 0); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - // Expect recorded debt to have increased due to accrued Trove interest being applied - uint256 newTroveRecordedDebt = troveManager.getTroveDebt(ATroveId); - assertGt(newTroveRecordedDebt, oldTroveRecordedDebt); - - // Get recorded sum after, check no change - assertEq(activePool.getRecordedDebtSum(), recordedDebt_1 - oldTroveRecordedDebt + newTroveRecordedDebt); - } - // --- batchLiquidateTroves (Normal Mode, offset) --- function testBatchLiquidateTrovesPureOffsetChangesAggRecordedInterestCorrectly() public { diff --git a/contracts/src/test/interestRateBasic.t.sol b/contracts/src/test/interestRateBasic.t.sol index 5eac83f7..66189bdf 100644 --- a/contracts/src/test/interestRateBasic.t.sol +++ b/contracts/src/test/interestRateBasic.t.sol @@ -714,70 +714,6 @@ contract InterestRateBasic is DevTestSetup { vm.stopPrank(); } - // --- withdrawETHGainToTrove tests --- - - function testWithdrawETHGainToTroveSetsTroveLastDebtUpdateTimeToNow() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // Fast-forward time - vm.warp(block.timestamp + 1 days); - - assertLt(troveManager.getTroveLastDebtUpdateTime(ATroveId), block.timestamp); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - assertEq(troveManager.getTroveLastDebtUpdateTime(ATroveId), block.timestamp); - } - - function testWithdrawETHGainToTroveReducesTroveAccruedInterestTo0() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // Fast-forward time - vm.warp(block.timestamp + 1 days); - - assertGt(troveManager.calcTroveAccruedInterest(ATroveId), 0); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - assertEq(troveManager.calcTroveAccruedInterest(ATroveId), 0); - } - - function testWithdrawETHGainToTroveDoesntChangeEntireTroveDebt() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // Fast-forward time - vm.warp(block.timestamp + 90 days); - - (uint256 entireTroveDebt_1,,,,) = troveManager.getEntireDebtAndColl(ATroveId); - assertGt(entireTroveDebt_1, 0); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - (uint256 entireTroveDebt_2,,,,) = troveManager.getEntireDebtAndColl(ATroveId); - - assertEq(entireTroveDebt_2, entireTroveDebt_1); - } - - function testWithdrawETHGainToTroveIncreasesRecordedTroveDebtByAccruedInterest() public { - (uint256 ATroveId,,) = _setupForWithdrawETHGainToTrove(); - - // Fast-forward time - vm.warp(block.timestamp + 90 days + 1); - - uint256 recordedTroveDebt_1 = troveManager.getTroveDebt(ATroveId); - uint256 accruedTroveInterest = troveManager.calcTroveAccruedInterest(ATroveId); - - // A withdraws ETH gain to Trove - withdrawETHGainToTrove(A, ATroveId); - - uint256 recordedTroveDebt_2 = troveManager.getTroveDebt(ATroveId); - - assertEq(recordedTroveDebt_2, recordedTroveDebt_1 + accruedTroveInterest); - } - // --- redemptions --- function testRedemptionSetsTroveLastDebtUpdateTimeToNow() public { diff --git a/contracts/test/AccessControlTest.js b/contracts/test/AccessControlTest.js index 71957915..da261a70 100644 --- a/contracts/test/AccessControlTest.js +++ b/contracts/test/AccessControlTest.js @@ -60,23 +60,6 @@ contract( borrowerOperations = contracts.borrowerOperations; }); - describe("BorrowerOperations", async (accounts) => { - it("moveETHGainToTrove(): reverts when called by an account that is not StabilityPool", async () => { - // Attempt call from alice - try { - const tx1 = await borrowerOperations.moveETHGainToTrove( - bob, - th.addressToTroveId(bob), - 1, - { from: bob }, - ); - } catch (err) { - assert.include(err.message, "revert"); - // assert.include(err.message, "BorrowerOps: Caller is not Stability Pool") - } - }); - }); - describe("TroveManager", async (accounts) => { // getAndApplyRedistributionGains it("getAndApplyRedistributionGains(): reverts when called by an account that is not BorrowerOperations", async () => { diff --git a/contracts/test/StabilityPoolTest.js b/contracts/test/StabilityPoolTest.js index 3062ae3f..5ee0d1e0 100644 --- a/contracts/test/StabilityPoolTest.js +++ b/contracts/test/StabilityPoolTest.js @@ -1548,18 +1548,6 @@ contract("StabilityPool", async (accounts) => { // Check ETH in pool does not change const ETHinSP_1 = (await stabilityPool.getETHBalance()).toString(); assert.equal(ETHinSP_Before, ETHinSP_1); - - // Third deposit - await stabilityPool.provideToSP(dec(10000, 18), { - from: alice, - }); - assert.equal(await stabilityPool.getDepositorETHGain(alice), 0); - - // Alice attempts third withdrawal (this time, from SP to Trove) - const txPromise_A = stabilityPool.withdrawETHGainToTrove(aliceTroveId, { - from: alice, - }); - await th.assertRevert(txPromise_A); }); it("withdrawFromSP(): it correctly updates the user's Bold and ETH snapshots of entitled reward per unit staked", async () => { @@ -2989,699 +2977,6 @@ contract("StabilityPool", async (accounts) => { }); await th.assertRevert(withdrawalPromise_C, expectedRevertMessage); }); - - // --- withdrawETHGainToTrove --- - - it("withdrawETHGainToTrove(): reverts when user has no active deposit", async () => { - await openTrove({ - extraBoldAmount: toBN(dec(100000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - - const { troveId: aliceTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(10000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: alice }, - }); - const { troveId: bobTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(10000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: bob }, - }); - - await stabilityPool.provideToSP(dec(10000, 18), { - from: alice, - }); - - const alice_initialDeposit = ( - await stabilityPool.deposits(alice) - ).toString(); - const bob_initialDeposit = ( - await stabilityPool.deposits(bob) - ).toString(); - - assert.equal(alice_initialDeposit, dec(10000, 18)); - assert.equal(bob_initialDeposit, "0"); - - // Defaulter opens a trove, price drops, defaulter gets liquidated - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - await priceFeed.setPrice(dec(105, 18)); - assert.isFalse(await th.checkRecoveryMode(contracts)); - await troveManager.liquidate(defaulter_1_TroveId); - assert.isFalse(await sortedTroves.contains(defaulter_1_TroveId)); - - const txAlice = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { - from: alice, - }); - assert.isTrue(txAlice.receipt.status); - - const txPromise_B = stabilityPool.withdrawETHGainToTrove(bobTroveId, { - from: bob, - }); - await th.assertRevert(txPromise_B); - }); - - it("withdrawETHGainToTrove(): Applies BoldLoss to user's deposit, and redirects ETH reward to user's Trove", async () => { - // --- SETUP --- - // Whale deposits 185000 Bold in StabilityPool - await openTrove({ - extraBoldAmount: toBN(dec(1000000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - await stabilityPool.provideToSP(dec(185000, 18), { - from: whale, - }); - - // Defaulter opens trove - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // --- TEST --- - - // Alice makes deposit #1: 15000 Bold - const { troveId: aliceTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(15000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: alice }, - }); - await stabilityPool.provideToSP(dec(15000, 18), { - from: alice, - }); - - // check Alice's Trove recorded ETH Before: - const aliceTrove_Before = await troveManager.Troves(aliceTroveId); - const aliceTrove_ETH_Before = aliceTrove_Before[1]; - assert.isTrue(aliceTrove_ETH_Before.gt(toBN("0"))); - - // price drops: defaulter's Trove falls below MCR, alice and whale Trove remain active - await priceFeed.setPrice(dec(105, 18)); - - // Defaulter's Trove is closed - const liquidationTx_1 = await troveManager.liquidate(defaulter_1_TroveId, { - from: owner, - }); - const [liquidatedDebt, liquidatedColl] = th.getEmittedLiquidationValues(liquidationTx_1); - - const ETHGain_A = await stabilityPool.getDepositorETHGain(alice); - const compoundedDeposit_A = await stabilityPool.getCompoundedBoldDeposit( - alice, - ); - - // Alice should receive rewards proportional to her deposit as share of total deposits - const expectedETHGain_A = liquidatedColl - .mul(toBN(dec(15000, 18))) - .div(toBN(dec(200000, 18))); - const expectedBoldLoss_A = liquidatedDebt - .mul(toBN(dec(15000, 18))) - .div(toBN(dec(200000, 18))); - const expectedCompoundedDeposit_A = toBN(dec(15000, 18)).sub( - expectedBoldLoss_A, - ); - - assert.isAtMost( - th.getDifference(expectedCompoundedDeposit_A, compoundedDeposit_A), - 100000, - ); - - // Alice sends her ETH Gains to her Trove - await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - - // check Alice's BoldLoss has been applied to her deposit expectedCompoundedDeposit_A - const alice_deposit_afterDefault = await stabilityPool.deposits(alice); - assert.isAtMost( - th.getDifference( - alice_deposit_afterDefault, - expectedCompoundedDeposit_A, - ), - 100000, - ); - - // check alice's Trove recorded ETH has increased by the expected reward amount - const aliceTrove_After = await troveManager.Troves(aliceTroveId); - const aliceTrove_ETH_After = aliceTrove_After[1]; - - const Trove_ETH_Increase = aliceTrove_ETH_After - .sub(aliceTrove_ETH_Before) - .toString(); - - assert.equal(Trove_ETH_Increase, ETHGain_A); - }); - - it("withdrawETHGainToTrove(): reverts if it would leave trove with ICR < MCR", async () => { - // --- SETUP --- - // Whale deposits 1850 Bold in StabilityPool - await openTrove({ - extraBoldAmount: toBN(dec(1000000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - await stabilityPool.provideToSP(dec(185000, 18), { - from: whale, - }); - - // defaulter opened - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // --- TEST --- - - // Alice makes deposit #1: 15000 Bold - const { troveId: aliceTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(15000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: alice }, - }); - await stabilityPool.provideToSP(dec(15000, 18), { - from: alice, - }); - - // check alice's Trove recorded ETH Before: - const aliceTrove_Before = await troveManager.Troves(aliceTroveId); - const aliceTrove_ETH_Before = aliceTrove_Before[1]; - assert.isTrue(aliceTrove_ETH_Before.gt(toBN("0"))); - - // price drops: defaulter's Trove falls below MCR - await priceFeed.setPrice(dec(10, 18)); - - // defaulter's Trove is closed. - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - // Alice attempts to her ETH Gains to her Trove - await assertRevert( - stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }), - "BorrowerOps: An operation that would result in ICR < MCR is not permitted", - ); - }); - - it("withdrawETHGainToTrove(): Subsequent deposit and withdrawal attempt from same account, with no intermediate liquidations, withdraws zero ETH", async () => { - // --- SETUP --- - // Whale deposits 1850 Bold in StabilityPool - await openTrove({ - extraBoldAmount: toBN(dec(1000000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - await stabilityPool.provideToSP(dec(185000, 18), { - from: whale, - }); - - // defaulter opened - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // --- TEST --- - - // Alice makes deposit #1: 15000 Bold - const { troveId: aliceTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(15000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: alice }, - }); - await stabilityPool.provideToSP(dec(15000, 18), { - from: alice, - }); - - // check alice's Trove recorded ETH Before: - const aliceTrove_Before = await troveManager.Troves(aliceTroveId); - const aliceTrove_ETH_Before = aliceTrove_Before[1]; - assert.isTrue(aliceTrove_ETH_Before.gt(toBN("0"))); - - // price drops: defaulter's Trove falls below MCR - await priceFeed.setPrice(dec(105, 18)); - - // defaulter's Trove is closed. - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - // price bounces back - await priceFeed.setPrice(dec(200, 18)); - - // Alice sends her ETH Gains to her Trove - await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - - assert.equal(await stabilityPool.getDepositorETHGain(alice), 0); - - const ETHinSP_Before = (await stabilityPool.getETHBalance()).toString(); - - // Alice attempts second withdrawal from SP to Trove - reverts, due to 0 ETH Gain - const txPromise_A = stabilityPool.withdrawETHGainToTrove(aliceTroveId, { - from: alice, - }); - await th.assertRevert(txPromise_A); - - // Check ETH in pool does not change - const ETHinSP_1 = (await stabilityPool.getETHBalance()).toString(); - assert.equal(ETHinSP_Before, ETHinSP_1); - - await priceFeed.setPrice(dec(200, 18)); - - // Alice attempts third withdrawal (this time, from SP to her own account) - await stabilityPool.withdrawFromSP(dec(15000, 18), { from: alice }); - - // Check ETH in pool does not change - const ETHinSP_2 = (await stabilityPool.getETHBalance()).toString(); - assert.equal(ETHinSP_Before, ETHinSP_2); - }); - - it("withdrawETHGainToTrove(): decreases StabilityPool ETH and increases activePool ETH", async () => { - // --- SETUP --- - // Whale deposits 185000 Bold in StabilityPool - await openTrove({ - extraBoldAmount: toBN(dec(1000000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - await stabilityPool.provideToSP(dec(185000, 18), { - from: whale, - }); - - // defaulter opened - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // --- TEST --- - - // Alice makes deposit #1: 15000 Bold - const { troveId: aliceTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(15000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: alice }, - }); - await stabilityPool.provideToSP(dec(15000, 18), { - from: alice, - }); - - // price drops: defaulter's Trove falls below MCR - await priceFeed.setPrice(dec(100, 18)); - - // defaulter's Trove is closed. - const liquidationTx = await troveManager.liquidate(defaulter_1_TroveId); - const [liquidatedDebt, liquidatedColl, gasComp] = th.getEmittedLiquidationValues(liquidationTx); - - // Expect alice to be entitled to 15000/200000 of the liquidated coll - const aliceExpectedETHGain = liquidatedColl - .mul(toBN(dec(15000, 18))) - .div(toBN(dec(200000, 18))); - const aliceETHGain = await stabilityPool.getDepositorETHGain(alice); - assert.isTrue(aliceExpectedETHGain.eq(aliceETHGain)); - - // price bounces back - await priceFeed.setPrice(dec(200, 18)); - - // check activePool and StabilityPool Ether before retrieval: - const active_ETH_Before = await activePool.getETHBalance(); - const stability_ETH_Before = await stabilityPool.getETHBalance(); - - // Alice retrieves redirects ETH gain to her Trove - await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - - const active_ETH_After = await activePool.getETHBalance(); - const stability_ETH_After = await stabilityPool.getETHBalance(); - - const active_ETH_Difference = active_ETH_After.sub(active_ETH_Before); // AP ETH should increase - const stability_ETH_Difference = stability_ETH_Before.sub(stability_ETH_After); // SP ETH should decrease - - // check Pool ETH values change by Alice's ETHGain, i.e 0.075 ETH - assert.isAtMost( - th.getDifference(active_ETH_Difference, aliceETHGain), - 10000, - ); - assert.isAtMost( - th.getDifference(stability_ETH_Difference, aliceETHGain), - 10000, - ); - }); - - it("withdrawETHGainToTrove(): All depositors are able to withdraw their ETH gain from the SP to their Trove", async () => { - // Whale opens trove - await openTrove({ - extraBoldAmount: toBN(dec(100000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - - // Defaulter opens trove - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // 6 Accounts open troves and provide to SP - const depositors = [alice, bob, carol, dennis, erin, flyn]; - for (account of depositors) { - await openTrove({ - extraBoldAmount: toBN(dec(10000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: account }, - }); - await stabilityPool.provideToSP(dec(10000, 18), { - from: account, - }); - } - - await priceFeed.setPrice(dec(105, 18)); - await troveManager.liquidate(defaulter_1_TroveId); - - // price bounces back - await priceFeed.setPrice(dec(200, 18)); - - // All depositors attempt to withdraw - const tx1 = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(alice), { - from: alice, - }); - assert.isTrue(tx1.receipt.status); - const tx2 = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(bob), { - from: bob, - }); - assert.isTrue(tx1.receipt.status); - const tx3 = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(carol), { - from: carol, - }); - assert.isTrue(tx1.receipt.status); - const tx4 = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(dennis), { - from: dennis, - }); - assert.isTrue(tx1.receipt.status); - const tx5 = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(erin), { - from: erin, - }); - assert.isTrue(tx1.receipt.status); - const tx6 = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(flyn), { - from: flyn, - }); - assert.isTrue(tx1.receipt.status); - }); - - it("withdrawETHGainToTrove(): All depositors withdraw, each withdraw their correct ETH gain", async () => { - // Whale opens trove - await openTrove({ - extraBoldAmount: toBN(dec(100000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - - // defaulter opened - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // 6 Accounts open troves and provide to SP - const depositors = [alice, bob, carol, dennis, erin, flyn]; - for (account of depositors) { - await openTrove({ - extraBoldAmount: toBN(dec(10000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: account }, - }); - await stabilityPool.provideToSP(dec(10000, 18), { - from: account, - }); - } - const collBefore = (await troveManager.Troves(th.addressToTroveId(alice)))[1]; // all troves have same coll before - - await priceFeed.setPrice(dec(105, 18)); - const liquidationTx = await troveManager.liquidate(defaulter_1_TroveId); - const [, liquidatedColl] = th.getEmittedLiquidationValues(liquidationTx); - - /* All depositors attempt to withdraw their ETH gain to their Trove. Each depositor - receives (liquidatedColl/ 6). - - Thus, expected new collateral for each depositor with 1 Ether in their trove originally, is - (1 + liquidatedColl/6) - */ - - const expectedCollGain = liquidatedColl.div(toBN("6")); - - await priceFeed.setPrice(dec(200, 18)); - - await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(alice), { from: alice }); - const aliceCollAfter = (await troveManager.Troves(th.addressToTroveId(alice)))[1]; - assert.isAtMost( - th.getDifference(aliceCollAfter.sub(collBefore), expectedCollGain), - 10000, - ); - - await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(bob), { from: bob }); - const bobCollAfter = (await troveManager.Troves(th.addressToTroveId(bob)))[1]; - assert.isAtMost( - th.getDifference(bobCollAfter.sub(collBefore), expectedCollGain), - 10000, - ); - - await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(carol), { from: carol }); - const carolCollAfter = (await troveManager.Troves(th.addressToTroveId(carol)))[1]; - assert.isAtMost( - th.getDifference(carolCollAfter.sub(collBefore), expectedCollGain), - 10000, - ); - - await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(dennis), { - from: dennis, - }); - const dennisCollAfter = (await troveManager.Troves(th.addressToTroveId(dennis)))[1]; - assert.isAtMost( - th.getDifference(dennisCollAfter.sub(collBefore), expectedCollGain), - 10000, - ); - - await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(erin), { from: erin }); - const erinCollAfter = (await troveManager.Troves(th.addressToTroveId(erin)))[1]; - assert.isAtMost( - th.getDifference(erinCollAfter.sub(collBefore), expectedCollGain), - 10000, - ); - - await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(flyn), { from: flyn }); - const flynCollAfter = (await troveManager.Troves(th.addressToTroveId(flyn)))[1]; - assert.isAtMost( - th.getDifference(flynCollAfter.sub(collBefore), expectedCollGain), - 10000, - ); - }); - - it("withdrawETHGainToTrove(): caller can withdraw full deposit and ETH gain to their trove during Recovery Mode", async () => { - // --- SETUP --- - - // Defaulter opens - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // A, B, C open troves - const { troveId: aliceTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(10000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: alice }, - }); - const { troveId: bobTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(20000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: bob }, - }); - const { troveId: carolTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(30000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: carol }, - }); - - // A, B, C provides 10000, 5000, 3000 Bold to SP - await stabilityPool.provideToSP(dec(10000, 18), { - from: alice, - }); - await stabilityPool.provideToSP(dec(5000, 18), { from: bob }); - await stabilityPool.provideToSP(dec(3000, 18), { - from: carol, - }); - - assert.isFalse(await th.checkRecoveryMode(contracts)); - - // Price drops to 105, - await priceFeed.setPrice(dec(105, 18)); - const price = await priceFeed.getPrice(); - - assert.isTrue(await th.checkRecoveryMode(contracts)); - - // Check defaulter 1 has ICR: 100% < ICR < 110%. - assert.isTrue( - await th.ICRbetween100and110(defaulter_1_TroveId, troveManager, price), - ); - - const alice_Collateral_Before = (await troveManager.Troves(aliceTroveId))[1]; - const bob_Collateral_Before = (await troveManager.Troves(bobTroveId))[1]; - const carol_Collateral_Before = (await troveManager.Troves(carolTroveId))[1]; - - // Liquidate defaulter 1 - assert.isTrue(await sortedTroves.contains(defaulter_1_TroveId)); - await troveManager.liquidate(defaulter_1_TroveId); - assert.isFalse(await sortedTroves.contains(defaulter_1_TroveId)); - - const alice_ETHGain_Before = await stabilityPool.getDepositorETHGain( - alice, - ); - const bob_ETHGain_Before = await stabilityPool.getDepositorETHGain(bob); - const carol_ETHGain_Before = await stabilityPool.getDepositorETHGain( - carol, - ); - - // A, B, C withdraw their full ETH gain from the Stability Pool to their trove - await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Check collateral of troves A, B, C has increased by the value of their ETH gain from liquidations, respectively - const alice_expectedCollateral = alice_Collateral_Before - .add(alice_ETHGain_Before) - .toString(); - const bob_expectedColalteral = bob_Collateral_Before - .add(bob_ETHGain_Before) - .toString(); - const carol_expectedCollateral = carol_Collateral_Before - .add(carol_ETHGain_Before) - .toString(); - - const alice_Collateral_After = (await troveManager.Troves(aliceTroveId))[1]; - const bob_Collateral_After = (await troveManager.Troves(bobTroveId))[1]; - const carol_Collateral_After = (await troveManager.Troves(carolTroveId))[1]; - - assert.equal(alice_expectedCollateral, alice_Collateral_After); - assert.equal(bob_expectedColalteral, bob_Collateral_After); - assert.equal(carol_expectedCollateral, carol_Collateral_After); - - // Check ETH in SP has reduced to zero - const ETHinSP_After = (await stabilityPool.getETHBalance()).toString(); - assert.isAtMost(th.getDifference(ETHinSP_After, "0"), 100000); - }); - - it("withdrawETHGainToTrove(): reverts if user has no trove", async () => { - await openTrove({ - extraBoldAmount: toBN(dec(10000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - - // A, B, C open troves - await openTrove({ - extraBoldAmount: toBN(dec(10000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: alice }, - }); - await openTrove({ - extraBoldAmount: toBN(dec(20000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: bob }, - }); - await openTrove({ - extraBoldAmount: toBN(dec(30000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: carol }, - }); - - // Defaulter opens - const { troveId: defaulter_1_TroveId } = await openTrove({ - ICR: toBN(dec(2, 18)), - extraParams: { from: defaulter_1 }, - }); - - // A transfers Bold to D - await boldToken.transfer(dennis, dec(10000, 18), { from: alice }); - - // D deposits to Stability Pool - await stabilityPool.provideToSP(dec(10000, 18), { - from: dennis, - }); - - // Price drops - await priceFeed.setPrice(dec(105, 18)); - - // Liquidate defaulter 1 - await troveManager.liquidate(defaulter_1_TroveId); - assert.isFalse(await sortedTroves.contains(defaulter_1_TroveId)); - - await priceFeed.setPrice(dec(200, 18)); - - // D attempts to withdraw his ETH gain to Trove - await th.assertRevert( - stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(dennis), { from: dennis }), - "caller must have an active trove to withdraw ETHGain to", - ); - }); - - it("withdrawETHGainToTrove(): reverts when depositor has no ETH gain", async () => { - await openTrove({ - extraBoldAmount: toBN(dec(100000, 18)), - ICR: toBN(dec(10, 18)), - extraParams: { from: whale }, - }); - - // Whale transfers Bold to A, B - await boldToken.transfer(A, dec(10000, 18), { from: whale }); - await boldToken.transfer(B, dec(20000, 18), { from: whale }); - - // C, D open troves - const { troveId: CTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(3000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: C }, - }); - const { troveId: DTroveId } = await openTrove({ - extraBoldAmount: toBN(dec(4000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: D }, - }); - - // A, B, C, D provide to SP - await stabilityPool.provideToSP(dec(10, 18), { from: A }); - await stabilityPool.provideToSP(dec(20, 18), { from: B }); - await stabilityPool.provideToSP(dec(30, 18), { from: C }); - await stabilityPool.provideToSP(dec(40, 18), { from: D }); - - // fastforward time, and E makes a deposit - await time.increase(timeValues.SECONDS_IN_ONE_HOUR); - await openTrove({ - extraBoldAmount: toBN(dec(3000, 18)), - ICR: toBN(dec(2, 18)), - extraParams: { from: E }, - }); - await stabilityPool.provideToSP(dec(3000, 18), { from: E }); - - // Confirm A, B, C have zero ETH gain - assert.equal(await stabilityPool.getDepositorETHGain(A), "0"); - assert.equal(await stabilityPool.getDepositorETHGain(B), "0"); - assert.equal(await stabilityPool.getDepositorETHGain(C), "0"); - - // Check withdrawETHGainToTrove reverts for A, B, C - const txPromise_A = stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(A), { - from: A, - }); - const txPromise_B = stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(B), { - from: B, - }); - const txPromise_C = stabilityPool.withdrawETHGainToTrove(CTroveId, { - from: C, - }); - const txPromise_D = stabilityPool.withdrawETHGainToTrove(DTroveId, { - from: D, - }); - - await th.assertRevert(txPromise_A); - await th.assertRevert(txPromise_B); - await th.assertRevert(txPromise_C); - await th.assertRevert(txPromise_D); - }); }); }); diff --git a/contracts/test/StabilityPool_SPWithdrawalToCDPTest.js b/contracts/test/StabilityPool_SPWithdrawalToCDPTest.js deleted file mode 100644 index 9b5a4563..00000000 --- a/contracts/test/StabilityPool_SPWithdrawalToCDPTest.js +++ /dev/null @@ -1,3577 +0,0 @@ -const testHelpers = require("../utils/testHelpers.js"); -const { createDeployAndFundFixture } = require("../utils/testFixtures.js"); -const TroveManagerTester = artifacts.require("./TroveManagerTester.sol"); - -const { dec, toBN } = testHelpers.TestHelper; -const th = testHelpers.TestHelper; - -contract("StabilityPool - Withdrawal of stability deposit - Reward calculations", async (accounts) => { - const fundedAccounts = accounts.slice(0, 22); - - const [ - owner, - defaulter_1, - defaulter_2, - defaulter_3, - defaulter_4, - defaulter_5, - defaulter_6, - whale, - // whale_2, - alice, - bob, - carol, - dennis, - erin, - flyn, - graham, - harriet, - A, - B, - C, - D, - E, - F, - ] = fundedAccounts; - - const [bountyAddress, lpRewardsAddress, multisig] = accounts.slice(997, 1000); - - let contracts; - - let priceFeed; - let boldToken; - let troveManager; - let stabilityPool; - - let gasPriceInWei; - - const ZERO_ADDRESS = th.ZERO_ADDRESS; - - const getOpenTroveBoldAmount = async (totalDebt) => th.getOpenTroveBoldAmount(contracts, totalDebt); - - const deployFixture = createDeployAndFundFixture({ - accounts: fundedAccounts, - mocks: { TroveManager: TroveManagerTester }, - }); - - describe("Stability Pool Withdrawal", async () => { - before(async () => { - gasPriceInWei = await web3.eth.getGasPrice(); - }); - - beforeEach(async () => { - const result = await deployFixture(); - contracts = result.contracts; - priceFeed = contracts.priceFeedTestnet; - boldToken = contracts.boldToken; - troveManager = contracts.troveManager; - stabilityPool = contracts.stabilityPool; - }); - - // --- Compounding tests --- - - // --- withdrawETHGainToTrove() --- - - // --- Identical deposits, identical liquidation amounts--- - it("withdrawETHGainToTrove(): Depositors with equal initial deposit withdraw correct compounded deposit and ETH Gain after one liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulter opens trove with 200% ICR and 10k Bold net debt - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - // Check depositors' compounded deposit is 6666.66 Bold and ETH Gain is 33.16 ETH - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "6666666666666666666666"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "6666666666666666666666"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "6666666666666666666666"), - 10000, - ); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "33166666666666666667"), 10000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "33166666666666666667"), 10000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "33166666666666666667"), 10000); - }); - - it("withdrawETHGainToTrove(): Depositors with equal initial deposit withdraw correct compounded deposit and ETH Gain after two identical liquidations", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Two defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Check depositors' compounded deposit is 3333.33 Bold and ETH Gain is 66.33 ETH - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "3333333333333333333333"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "3333333333333333333333"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "3333333333333333333333"), - 10000, - ); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "66333333333333333333"), 10000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "66333333333333333333"), 10000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "66333333333333333333"), 10000); - }); - - it("withdrawETHGainToTrove(): Depositors with equal initial deposit withdraw correct compounded deposit and ETH Gain after three identical liquidations", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Three defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - // Check depositors' compounded deposit is 0 Bold and ETH Gain is 99.5 ETH - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "0"), 10000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "0"), 10000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "0"), 10000); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(99500, 15)), 10000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(99500, 15)), 10000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(99500, 15)), 10000); - }); - - // --- Identical deposits, increasing liquidation amounts --- - it("withdrawETHGainToTrove(): Depositors with equal initial deposit withdraw correct compounded deposit and ETH Gain after two liquidations of increasing Bold", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(5000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: "50000000000000000000" }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(7000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: "70000000000000000000" }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Check depositors' compounded deposit - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "6000000000000000000000"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "6000000000000000000000"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "6000000000000000000000"), - 10000, - ); - - // (0.5 + 0.7) * 99.5 / 3 - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(398, 17)), 10000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(398, 17)), 10000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(398, 17)), 10000); - }); - - it("withdrawETHGainToTrove(): Depositors with equal initial deposit withdraw correct compounded deposit and ETH Gain after three liquidations of increasing Bold", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(5000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: "50000000000000000000" }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(6000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: "60000000000000000000" }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(7000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: "70000000000000000000" }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Three defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - // Check depositors' compounded deposit - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "4000000000000000000000"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "4000000000000000000000"), - 10000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "4000000000000000000000"), - 10000, - ); - - // (0.5 + 0.6 + 0.7) * 99.5 / 3 - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(597, 17)), 10000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(597, 17)), 10000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(597, 17)), 10000); - }); - - // --- Increasing deposits, identical liquidation amounts --- - it("withdrawETHGainToTrove(): Depositors with varying deposits withdraw correct compounded deposit and ETH Gain after two identical liquidations", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k, 20k, 30k Bold to A, B and C respectively who then deposit it to the SP - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - await boldToken.transfer(bob, dec(20000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(20000, 18), { from: bob }); - await boldToken.transfer(carol, dec(30000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(30000, 18), { from: carol }); - - // 2 Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Three defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Depositors attempt to withdraw everything - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "6666666666666666666666"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "13333333333333333333333"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "20000000000000000000000"), - 100000, - ); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "33166666666666666667"), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "66333333333333333333"), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(995, 17)), 100000); - }); - - it("withdrawETHGainToTrove(): Depositors with varying deposits withdraw correct compounded deposit and ETH Gain after three identical liquidations", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k, 20k, 30k Bold to A, B and C respectively who then deposit it to the SP - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - await boldToken.transfer(bob, dec(20000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(20000, 18), { from: bob }); - await boldToken.transfer(carol, dec(30000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(30000, 18), { from: carol }); - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Three defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - // Depositors attempt to withdraw everything - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "5000000000000000000000"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "10000000000000000000000"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "15000000000000000000000"), - 100000, - ); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "49750000000000000000"), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "149250000000000000000"), 100000); - }); - - // --- Varied deposits and varied liquidation amount --- - it("withdrawETHGainToTrove(): Depositors with varying deposits withdraw correct compounded deposit and ETH Gain after three varying liquidations", async () => { - // Whale opens Trove with 1m ETH - await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(1000000, 18)), - whale, - whale, - 0, - { from: whale, value: dec(1000000, "ether") }, - ); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - /* Depositors provide:- - Alice: 2000 Bold - Bob: 456000 Bold - Carol: 13100 Bold */ - // Whale transfers Bold to A, B and C respectively who then deposit it to the SP - await boldToken.transfer(alice, dec(2000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(2000, 18), { from: alice }); - await boldToken.transfer(bob, dec(456000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(456000, 18), { from: bob }); - await boldToken.transfer(carol, dec(13100, 18), { from: whale }); - await stabilityPool.provideToSP(dec(13100, 18), { from: carol }); - - /* Defaulters open troves - - Defaulter 1: 207000 Bold & 2160 ETH - Defaulter 2: 5000 Bold & 50 ETH - Defaulter 3: 46700 Bold & 500 ETH - */ - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("207000000000000000000000"), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(2160, 18) }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(5, 21)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(50, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("46700000000000000000000"), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(500, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Three defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - // Depositors attempt to withdraw everything - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - // () - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "901719380174061000000"), - 100000000000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "205592018679686000000000"), - 10000000000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "5906261940140100000000"), - 10000000000, - ); - - // 2710 * 0.995 * {2000, 456000, 13100}/4711 - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "11447463383570366500"), 10000000000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "2610021651454043834000"), 10000000000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "74980885162385912900"), 10000000000); - }); - - // --- Deposit enters at t > 0 - - it("withdrawETHGainToTrove(): A, B, C Deposit -> 2 liquidations -> D deposits -> 1 liquidation. All deposits and liquidations = 100 Bold. A, B, C, D withdraw correct Bold deposit and ETH Gain", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // First two defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Whale transfers 10k to Dennis who then provides to SP - await boldToken.transfer(dennis, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: dennis }); - - // Third defaulter liquidated - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "1666666666666666666666"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "1666666666666666666666"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "1666666666666666666666"), - 100000, - ); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), "5000000000000000000000"), - 100000, - ); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "82916666666666666667"), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "82916666666666666667"), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "82916666666666666667"), 100000); - - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "49750000000000000000"), 100000); - }); - - it("withdrawETHGainToTrove(): A, B, C Deposit -> 2 liquidations -> D deposits -> 2 liquidations. All deposits and liquidations = 100 Bold. A, B, C, D withdraw correct Bold deposit and ETH Gain", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // First two defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Dennis opens a trove and provides to SP - await boldToken.transfer(dennis, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: dennis }); - - // Third and fourth defaulters liquidated - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), "0"), 100000); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, dec(995, 17)), 100000); - }); - - it("withdrawETHGainToTrove(): A, B, C Deposit -> 2 liquidations -> D deposits -> 2 liquidations. Various deposit and liquidation vals. A, B, C, D withdraw correct Bold deposit and ETH Gain", async () => { - // Whale opens Trove with 1m ETH - await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(1000000, 18)), - whale, - whale, - 0, - { from: whale, value: dec(1000000, "ether") }, - ); - - // A, B, C, D open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - /* Depositors open troves and make SP deposit: - Alice: 60000 Bold - Bob: 20000 Bold - Carol: 15000 Bold - */ - // Whale transfers Bold to A, B and C respectively who then deposit it to the SP - await boldToken.transfer(alice, dec(60000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(60000, 18), { from: alice }); - await boldToken.transfer(bob, dec(20000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(20000, 18), { from: bob }); - await boldToken.transfer(carol, dec(15000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(15000, 18), { from: carol }); - - /* Defaulters open troves: - Defaulter 1: 10000 Bold, 100 ETH - Defaulter 2: 25000 Bold, 250 ETH - Defaulter 3: 5000 Bold, 50 ETH - Defaulter 4: 40000 Bold, 400 ETH - */ - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(25000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: "250000000000000000000" }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(5000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: "50000000000000000000" }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(40000, 18)), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: dec(400, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // First two defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Dennis provides 25000 Bold - await boldToken.transfer(dennis, dec(25000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(25000, 18), { from: dennis }); - - // Last two defaulters liquidated - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - - // Each depositor withdraws as much as possible - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "17832817337461300000000"), - 100000000000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "5944272445820430000000"), - 100000000000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "4458204334365320000000"), - 100000000000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), "11764705882352900000000"), - 100000000000, - ); - - // 3.5*0.995 * {60000,20000,15000,0} / 95000 + 450*0.995 * {60000/950*{60000,20000,15000},25000} / (120000-35000) - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "419563467492260055900"), 100000000000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "139854489164086692700"), 100000000000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "104890866873065014000"), 100000000000); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "131691176470588233700"), 100000000000); - }); - - // --- Depositor leaves --- - - it("withdrawETHGainToTrove(): A, B, C, D deposit -> 2 liquidations -> D withdraws -> 2 liquidations. All deposits and liquidations = 100 Bold. A, B, C, D withdraw correct Bold deposit and ETH Gain", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and C who then deposit it to the SP - const depositors = [alice, bob, carol, dennis]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // First two defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Dennis withdraws his deposit and ETH gain - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - await priceFeed.setPrice(dec(100, 18)); - - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), "5000000000000000000000"), - 100000, - ); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "49750000000000000000"), 100000); - - // Two more defaulters are liquidated - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "0"), 1000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "0"), 1000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "0"), 1000); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(995, 17)), 100000); - }); - - it("withdrawETHGainToTrove(): A, B, C, D deposit -> 2 liquidations -> D withdraws -> 2 liquidations. Various deposit and liquidation vals. A, B, C, D withdraw correct Bold deposit and ETH Gain", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - /* Initial deposits: - Alice: 20000 Bold - Bob: 25000 Bold - Carol: 12500 Bold - Dennis: 40000 Bold - */ - // Whale transfers Bold to A, B,C and D respectively who then deposit it to the SP - await boldToken.transfer(alice, dec(20000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(20000, 18), { from: alice }); - await boldToken.transfer(bob, dec(25000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(25000, 18), { from: bob }); - await boldToken.transfer(carol, dec(12500, 18), { from: whale }); - await stabilityPool.provideToSP(dec(12500, 18), { from: carol }); - await boldToken.transfer(dennis, dec(40000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(40000, 18), { from: dennis }); - - /* Defaulters open troves: - Defaulter 1: 10000 Bold - Defaulter 2: 20000 Bold - Defaulter 3: 30000 Bold - Defaulter 4: 5000 Bold - */ - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(20000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(200, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(30000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(300, "ether") }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(5000, 18)), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: "50000000000000000000" }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // First two defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Dennis withdraws his deposit and ETH gain - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txD = await stabilityPool.withdrawFromSP(dec(40000, 18), { from: dennis }); - await priceFeed.setPrice(dec(100, 18)); - - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - assert.isAtMost( - th.getDifference((await boldToken.balanceOf(dennis)).toString(), "27692307692307700000000"), - 100000000000, - ); - // 300*0.995 * 40000/97500 - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "122461538461538466100"), 100000000000); - - // Two more defaulters are liquidated - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "1672240802675590000000"), - 10000000000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "2090301003344480000000"), - 100000000000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "1045150501672240000000"), - 100000000000, - ); - - // 300*0.995 * {20000,25000,12500}/97500 + 350*0.995 * {20000,25000,12500}/57500 - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "182361204013377919900"), 100000000000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "227951505016722411000"), 100000000000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "113975752508361205500"), 100000000000); - }); - - // --- One deposit enters at t > 0, and another leaves later --- - it("withdrawETHGainToTrove(): A, B, D deposit -> 2 liquidations -> C makes deposit -> 1 liquidation -> D withdraws -> 1 liquidation. All deposits: 100 Bold. Liquidations: 100,100,100,50. A, B, C, D withdraw correct Bold deposit and ETH Gain", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B and D who then deposit it to the SP - const depositors = [alice, bob, dennis]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulters open troves - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(5000, 18)), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: "50000000000000000000" }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // First two defaulters liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Carol makes deposit - await boldToken.transfer(carol, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: carol }); - - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - // Dennis withdraws his deposit and ETH gain - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txD = await stabilityPool.withdrawFromSP(dec(10000, 18), { from: dennis }); - await priceFeed.setPrice(dec(100, 18)); - - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - assert.isAtMost( - th.getDifference((await boldToken.balanceOf(dennis)).toString(), "1666666666666666666666"), - 100000, - ); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "82916666666666666667"), 100000); - - await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "666666666666666666666"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "666666666666666666666"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "2000000000000000000000"), - 100000, - ); - - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, "92866666666666666667"), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "92866666666666666667"), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "79600000000000000000"), 100000); - }); - - // --- Tests for full offset - Pool empties to 0 --- - - // A, B deposit 10000 - // L1 cancels 20000, 200 - // C, D deposit 10000 - // L2 cancels 10000,100 - - // A, B withdraw 0Bold & 100e - // C, D withdraw 5000Bold & 500e - it("withdrawETHGainToTrove(): Depositor withdraws correct compounded deposit after liquidation empties the pool", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B who then deposit it to the SP - const depositors = [alice, bob]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // 2 Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(20000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(200, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter 1 liquidated. 20000 Bold fully offset with pool. - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - // Carol, Dennis each deposit 10000 Bold - const depositors_2 = [carol, dennis]; - for (const account of depositors_2) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulter 2 liquidated. 10000 Bold offset - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // await th.openTroveWrapper(contracts, th._100pct, dec(1, 18), account, account, { from: erin, value: dec(2, 'ether') }) - // await stabilityPool.provideToSP(dec(1, 18), { from: erin }) - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - - // Expect Alice And Bob's compounded deposit to be 0 Bold - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "0"), 10000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "0"), 10000); - - // Expect Alice and Bob's ETH Gain to be 100 ETH - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 100000); - - // Expect Carol And Dennis' compounded deposit to be 50 Bold - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "5000000000000000000000"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), "5000000000000000000000"), - 100000, - ); - - // Expect Carol and and Dennis ETH Gain to be 50 ETH - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "49750000000000000000"), 100000); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "49750000000000000000"), 100000); - }); - - // A, B deposit 10000 - // L1 cancels 10000, 1 - // L2 10000, 200 empties Pool - // C, D deposit 10000 - // L3 cancels 10000, 1 - // L2 20000, 200 empties Pool - it("withdrawETHGainToTrove(): Pool-emptying liquidation increases epoch by one, resets scaleFactor to 0, and resets P to 1e18", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B who then deposit it to the SP - const depositors = [alice, bob]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // 4 Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - const epoch_0 = (await stabilityPool.currentEpoch()).toString(); - const scale_0 = (await stabilityPool.currentScale()).toString(); - const P_0 = (await stabilityPool.P()).toString(); - - assert.equal(epoch_0, "0"); - assert.equal(scale_0, "0"); - assert.equal(P_0, dec(1, 18)); - - // Defaulter 1 liquidated. 10--0 Bold fully offset, Pool remains non-zero - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - // Check epoch, scale and sum - const epoch_1 = (await stabilityPool.currentEpoch()).toString(); - const scale_1 = (await stabilityPool.currentScale()).toString(); - const P_1 = (await stabilityPool.P()).toString(); - - assert.equal(epoch_1, "0"); - assert.equal(scale_1, "0"); - assert.isAtMost(th.getDifference(P_1, dec(5, 17)), 1000); - - // Defaulter 2 liquidated. 1--00 Bold, empties pool - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Check epoch, scale and sum - const epoch_2 = (await stabilityPool.currentEpoch()).toString(); - const scale_2 = (await stabilityPool.currentScale()).toString(); - const P_2 = (await stabilityPool.P()).toString(); - - assert.equal(epoch_2, "1"); - assert.equal(scale_2, "0"); - assert.equal(P_2, dec(1, 18)); - - // Carol, Dennis each deposit 10000 Bold - const depositors_2 = [carol, dennis]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulter 3 liquidated. 10000 Bold fully offset, Pool remains non-zero - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - // Check epoch, scale and sum - const epoch_3 = (await stabilityPool.currentEpoch()).toString(); - const scale_3 = (await stabilityPool.currentScale()).toString(); - const P_3 = (await stabilityPool.P()).toString(); - - assert.equal(epoch_3, "1"); - assert.equal(scale_3, "0"); - assert.isAtMost(th.getDifference(P_3, dec(5, 17)), 1000); - - // Defaulter 4 liquidated. 10000 Bold, empties pool - await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - - // Check epoch, scale and sum - const epoch_4 = (await stabilityPool.currentEpoch()).toString(); - const scale_4 = (await stabilityPool.currentScale()).toString(); - const P_4 = (await stabilityPool.P()).toString(); - - assert.equal(epoch_4, "2"); - assert.equal(scale_4, "0"); - assert.equal(P_4, dec(1, 18)); - }); - - // A, B deposit 10000 - // L1 cancels 20000, 200 - // C, D, E deposit 10000, 20000, 30000 - // L2 cancels 10000,100 - - // A, B withdraw 0 Bold & 100e - // C, D withdraw 5000 Bold & 50e - it("withdrawETHGainToTrove(): Depositors withdraw correct compounded deposit after liquidation empties the pool", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D, E open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - const erinTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: erin, value: dec(10000, "ether") }, - ); - - // Whale transfers 10k Bold to A, B who then deposit it to the SP - const depositors = [alice, bob]; - for (const account of depositors) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // 2 Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(20000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(200, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - - // price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter 1 liquidated. 20000 Bold fully offset with pool. - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - // Carol, Dennis, Erin each deposit 10000, 20000, 30000 Bold respectively - await boldToken.transfer(carol, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: carol }); - - await boldToken.transfer(dennis, dec(20000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(20000, 18), { from: dennis }); - - await boldToken.transfer(erin, dec(30000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(30000, 18), { from: erin }); - - // Defaulter 2 liquidated. 10000 Bold offset - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - const txE = await stabilityPool.withdrawETHGainToTrove(erinTroveId, { from: erin }); - - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - const erin_ETHWithdrawn = th.getEventArgByName(txE, "ETHGainWithdrawn", "_ETH").toString(); - - // Expect Alice And Bob's compounded deposit to be 0 Bold - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "0"), 10000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "0"), 10000); - - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "8333333333333333333333"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), "16666666666666666666666"), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(erin)).toString(), "25000000000000000000000"), - 100000, - ); - - // Expect Alice and Bob's ETH Gain to be 1 ETH - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 100000); - - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "16583333333333333333"), 100000); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "33166666666666666667"), 100000); - assert.isAtMost(th.getDifference(erin_ETHWithdrawn, "49750000000000000000"), 100000); - }); - - // A deposits 10000 - // L1, L2, L3 liquidated with 10000 Bold each - // A withdraws all - // Expect A to withdraw 0 deposit and ether only from reward L1 - it("withdrawETHGainToTrove(): single deposit fully offset. After subsequent liquidations, depositor withdraws 0 deposit and *only* the ETH Gain from one liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - - // Defaulter 1,2,3 withdraw 10000 Bold - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - - // price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter 1, 2 and 3 liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), 0), 100000); - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(995, 17)), 100000); - }); - - // --- Serial full offsets --- - - // A,B deposit 10000 Bold - // L1 cancels 20000 Bold, 2E - // B,C deposits 10000 Bold - // L2 cancels 20000 Bold, 2E - // E,F deposit 10000 Bold - // L3 cancels 20000, 200E - // G,H deposits 10000 - // L4 cancels 20000, 200E - - // Expect all depositors withdraw 0 Bold and 100 ETH - - it("withdrawETHGainToTrove(): Depositor withdraws correct compounded deposit after liquidation empties the pool", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // A, B, C, D, E, F, G, H open troves - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - const erinTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: erin, value: dec(10000, "ether") }, - ); - const flynTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: flyn, value: dec(10000, "ether") }, - ); - const harrietTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: harriet, value: dec(10000, "ether") }, - ); - const grahamTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: graham, value: dec(10000, "ether") }, - ); - - // 4 Defaulters open trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(20000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(200, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(20000, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(200, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(20000, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(200, "ether") }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(20000, 18)), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: dec(200, "ether") }, - ); - - // price drops by 50%: defaulter ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Alice, Bob each deposit 10k Bold - const depositors_1 = [alice, bob]; - for (const account of depositors_1) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulter 1 liquidated. 20k Bold fully offset with pool. - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - // Carol, Dennis each deposit 10000 Bold - const depositors_2 = [carol, dennis]; - for (const account of depositors_2) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulter 2 liquidated. 10000 Bold offset - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - // Erin, Flyn each deposit 10000 Bold - const depositors_3 = [erin, flyn]; - for (const account of depositors_3) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulter 3 liquidated. 10000 Bold offset - await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - - // Graham, Harriet each deposit 10000 Bold - const depositors_4 = [graham, harriet]; - for (const account of depositors_4) { - await boldToken.transfer(account, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: account }); - } - - // Defaulter 4 liquidated. 10k Bold offset - await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - const txE = await stabilityPool.withdrawETHGainToTrove(erinTroveId, { from: erin }); - const txF = await stabilityPool.withdrawETHGainToTrove(flynTroveId, { from: flyn }); - const txG = await stabilityPool.withdrawETHGainToTrove(grahamTroveId, { from: graham }); - const txH = await stabilityPool.withdrawETHGainToTrove(harrietTroveId, { from: harriet }); - - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - const erin_ETHWithdrawn = th.getEventArgByName(txE, "ETHGainWithdrawn", "_ETH").toString(); - const flyn_ETHWithdrawn = th.getEventArgByName(txF, "ETHGainWithdrawn", "_ETH").toString(); - const graham_ETHWithdrawn = th.getEventArgByName(txG, "ETHGainWithdrawn", "_ETH").toString(); - const harriet_ETHWithdrawn = th.getEventArgByName(txH, "ETHGainWithdrawn", "_ETH").toString(); - - // Expect all deposits to be 0 Bold - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(alice)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(erin)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(flyn)).toString(), "0"), 100000); - assert.isAtMost(th.getDifference((await stabilityPool.getCompoundedBoldDeposit(graham)).toString(), "0"), 100000); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(harriet)).toString(), "0"), - 100000, - ); - - /* Expect all ETH gains to be 100 ETH: Since each liquidation of empties the pool, depositors - should only earn ETH from the single liquidation that cancelled with their deposit */ - assert.isAtMost(th.getDifference(alice_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(erin_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(flyn_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(graham_ETHWithdrawn, dec(995, 17)), 100000); - assert.isAtMost(th.getDifference(harriet_ETHWithdrawn, dec(995, 17)), 100000); - - const finalEpoch = (await stabilityPool.currentEpoch()).toString(); - assert.equal(finalEpoch, 4); - }); - - // --- Scale factor tests --- - - // A deposits 10000 - // L1 brings P close to boundary, i.e. 9e-9: liquidate 9999.99991 - // A withdraws all - // B deposits 10000 - // L2 of 9900 Bold, should bring P slightly past boundary i.e. 1e-9 -> 1e-10 - - // expect d(B) = d0(B)/100 - // expect correct ETH gain, i.e. all of the reward - // - // TODO: Changes since v1 have introduced very slight precision error in this test. Potentially due to slightly different rounding - // in helper functon getOpenTroveBoldAmount due to now-zero borrow fees. Double-check this when we write new SP arithmetic tests and fix the "P" issue. - it.skip("withdrawETHGainToTrove(): deposit spans one scale factor change: Single depositor withdraws correct compounded deposit and ETH Gain after one liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - - // Defaulter 1 withdraws 'almost' 10000 Bold: 9999.99991 Bold - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999999910000000000000"), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - - assert.equal(await stabilityPool.currentScale(), "0"); - - // Defaulter 2 withdraws 9900 Bold - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(9900, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(60, "ether") }, - ); - - // price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter 1 liquidated. Value of P reduced to 9e9. - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - th.logBN("P", await stabilityPool.P()); // 8999999999, i.e. 1 wei less than expected - assert.equal((await stabilityPool.P()).toString(), dec(9, 9)); - - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txA = await stabilityPool.withdrawFromSP(dec(10000, 18), { from: alice }); - await priceFeed.setPrice(dec(100, 18)); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = await th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - - await boldToken.transfer(bob, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: bob }); - - // Defaulter 2 liquidated. 9900 Bold liquidated. P altered by a factor of 1-(9900/10000) = 0.01. Scale changed. - await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - - assert.equal(await stabilityPool.currentScale(), "1"); - - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const bob_ETHWithdrawn = await th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - - // Expect Bob to retain 1% of initial deposit (100 Bold) and all the liquidated ETH (60 ether) - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), "100000000000000000000"), - 100000, - ); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "59700000000000000000"), 100000); - }); - - // A deposits 10000 - // L1 brings P close to boundary, i.e. 9e-9: liquidate 9999.99991 Bold - // A withdraws all - // B, C, D deposit 10000, 20000, 30000 - // L2 of 59400, should bring P slightly past boundary i.e. 1e-9 -> 1e-10 - - // expect d(B) = d0(B)/100 - // expect correct ETH gain, i.e. all of the reward - // - // TODO: Changes since v1 have introduced very slight precision error in this test. Potentially due to slightly different rounding - // in helper functon getOpenTroveBoldAmount due to now-zero borrow fees. Double-check this when we write new SP arithmetic tests and fix the "P" issue. - it.skip("withdrawETHGainToTrove(): Several deposits of varying amounts span one scale factor change. Depositors withdraw correct compounded deposit and ETH Gain after one liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - - // Defaulter 1 withdraws 'almost' 10k Bold. - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999999910000000000000"), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - - // Defaulter 2 withdraws 59400 Bold - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("59400000000000000000000"), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(330, "ether") }, - ); - - // price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter 1 liquidated. Value of P reduced to 9e9 - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - th.logBN("P", await stabilityPool.P()); // P = 8999999999, i.e. 1 wei less than expected - assert.equal((await stabilityPool.P()).toString(), dec(9, 9)); - - assert.equal(await stabilityPool.currentScale(), "0"); - - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txA = await stabilityPool.withdrawFromSP(dec(10000, 18), { from: alice }); - await priceFeed.setPrice(dec(100, 18)); - - // B, C, D deposit to Stability Pool - await boldToken.transfer(bob, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: bob }); - - await boldToken.transfer(carol, dec(20000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(20000, 18), { from: carol }); - - await boldToken.transfer(dennis, dec(30000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(30000, 18), { from: dennis }); - - // 54000 Bold liquidated. P altered by a factor of 1-(59400/60000) = 0.01. Scale changed. - const txL2 = await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - assert.isTrue(txL2.receipt.status); - - assert.equal(await stabilityPool.currentScale(), "1"); - - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - - /* Expect depositors to retain 1% of their initial deposit, and an ETH gain - in proportion to their initial deposit: - - Bob: 1000 Bold, 55 Ether - Carol: 2000 Bold, 110 Ether - Dennis: 3000 Bold, 165 Ether - - Total: 6000 Bold, 300 Ether - */ - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), dec(100, 18)), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), dec(200, 18)), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), dec(300, 18)), - 100000, - ); - - const bob_ETHWithdrawn = await th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = await th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = await th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, "54725000000000000000"), 100000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, "109450000000000000000"), 100000); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, "164175000000000000000"), 100000); - }); - - // Deposit's ETH reward spans one scale change - deposit reduced by correct amount - - // A make deposit 10000 Bold - // L1 brings P to 1e-5*P. L1: 9999.9000000000000000 Bold - // A withdraws - // B makes deposit 10000 Bold - // L2 decreases P again by 1e-5, over the scale boundary: 9999.9000000000000000 (near to the 10000 Bold total deposits) - // B withdraws - // expect d(B) = d0(B) * 1e-5 - // expect B gets entire ETH gain from L2 - // - // TODO: Changes since v1 have introduced very slight precision error in this test. Potentially due to slightly different rounding - // in helper functon getOpenTroveBoldAmount due to now-zero borrow fees. Double-check this when we write new SP arithmetic tests and fix the "P" issue. - it.skip("withdrawETHGainToTrove(): deposit spans one scale factor change: Single depositor withdraws correct compounded deposit and ETH Gain after one liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - - // Defaulter 1 and default 2 each withdraw 9999.999999999 Bold - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(99999, 17)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(99999, 17)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - - // price drops by 50%: defaulter 1 ICR falls to 100% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter 1 liquidated. Value of P updated to to 1e13 - const txL1 = await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - assert.isTrue(txL1.receipt.status); - th.logBN("P", await stabilityPool.P()); // P = 0.000009999999999999 i.e. 1 wei less than expected - assert.equal(await stabilityPool.P(), dec(1, 13)); // P decreases. P = 1e(18-5) = 1e13 - assert.equal(await stabilityPool.currentScale(), "0"); - - // Alice withdraws - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txA = await stabilityPool.withdrawFromSP(dec(10000, 18), { from: alice }); - await priceFeed.setPrice(dec(100, 18)); - - // Bob deposits 10k Bold - await boldToken.transfer(bob, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: bob }); - - // Defaulter 2 liquidated - const txL2 = await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - assert.isTrue(txL2.receipt.status); - assert.equal(await stabilityPool.P(), dec(1, 17)); // Scale changes and P changes. P = 1e(13-5+9) = 1e17 - assert.equal(await stabilityPool.currentScale(), "1"); - - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const bob_ETHWithdrawn = await th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - - // Bob should withdraw 1e-5 of initial deposit: 0.1 Bold and the full ETH gain of 100 ether - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), dec(1, 17)), - 100000, - ); - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 100000000000); - }); - - // A make deposit 10000 Bold - // L1 brings P to 1e-5*P. L1: 9999.9000000000000000 Bold - // A withdraws - // B,C D make deposit 10000, 20000, 30000 - // L2 decreases P again by 1e-5, over boundary. L2: 59999.4000000000000000 (near to the 60000 Bold total deposits) - // B withdraws - // expect d(B) = d0(B) * 1e-5 - // expect B gets entire ETH gain from L2 - // - // TODO: Changes since v1 have introduced very slight precision error in this test. Potentially due to slightly different rounding - // in helper functon getOpenTroveBoldAmount due to now-zero borrow fees. Double-check this when we write new SP arithmetic tests and fix the "P" issue. - it.skip("withdrawETHGainToTrove(): Several deposits of varying amounts span one scale factor change. Depositors withdraws correct compounded deposit and ETH Gain after one liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - - // Defaulter 1 and default 2 withdraw up to debt of 9999.9 Bold and 59999.4 Bold - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999900000000000000000"), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("59999400000000000000000"), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(600, "ether") }, - ); - - // price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - // Defaulter 1 liquidated. P updated to 1e13 - const txL1 = await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - th.logBN("P", await stabilityPool.P()); // P: 0.000009999999999999, 1 wei less than expected - assert.equal(await stabilityPool.P(), dec(1, 13)); // P decreases. P = 1e(18-5) = 1e13 - assert.equal(await stabilityPool.currentScale(), "0"); - - // Alice withdraws - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txA = await stabilityPool.withdrawFromSP(dec(100, 18), { from: alice }); - await priceFeed.setPrice(dec(100, 18)); - - // B, C, D deposit 10000, 20000, 30000 Bold - await boldToken.transfer(bob, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: bob }); - - await boldToken.transfer(carol, dec(20000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(20000, 18), { from: carol }); - - await boldToken.transfer(dennis, dec(30000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(30000, 18), { from: dennis }); - - // Defaulter 2 liquidated - const txL2 = await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - assert.isTrue(txL2.receipt.status); - assert.equal(await stabilityPool.P(), dec(1, 17)); // P decreases. P = 1e(13-5+9) = 1e17 - assert.equal(await stabilityPool.currentScale(), "1"); - - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const bob_ETHWithdrawn = await th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const carol_ETHWithdrawn = await th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - const dennis_ETHWithdrawn = await th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - - // {B, C, D} should have a compounded deposit of {0.1, 0.2, 0.3} Bold - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(bob)).toString(), dec(1, 17)), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(carol)).toString(), dec(2, 17)), - 100000, - ); - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), dec(3, 17)), - 100000, - ); - - assert.isAtMost(th.getDifference(bob_ETHWithdrawn, dec(995, 17)), 10000000000); - assert.isAtMost(th.getDifference(carol_ETHWithdrawn, dec(1990, 17)), 100000000000); - assert.isAtMost(th.getDifference(dennis_ETHWithdrawn, dec(2985, 17)), 100000000000); - }); - - // A make deposit 10000 Bold - // L1 brings P to (~1e-10)*P. L1: 9999.9999999000000000 Bold - // Expect A to withdraw 0 deposit - it("withdrawETHGainToTrove(): Deposit that decreases to less than 1e-9 of it's original value is reduced to 0", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - // Defaulters 1 withdraws 9999.9999999 Bold - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999999999900000000000"), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - - // Price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - - // Defaulter 1 liquidated. P -> (~1e-10)*P - const txL1 = await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - assert.isTrue(txL1.receipt.status); - - const aliceDeposit = (await stabilityPool.getCompoundedBoldDeposit(alice)).toString(); - // console.log(`alice deposit: ${aliceDeposit}`) - assert.equal(aliceDeposit, 0); - }); - - // --- Serial scale changes --- - - /* A make deposit 10000 Bold - L1 brings P to 0.0001P. L1: 9999.900000000000000000 Bold, 1 ETH - B makes deposit 9999.9, brings SP to 10k - L2 decreases P by(~1e-5)P. L2: 9999.900000000000000000 Bold, 1 ETH - C makes deposit 9999.9, brings SP to 10k - L3 decreases P by(~1e-5)P. L3: 9999.900000000000000000 Bold, 1 ETH - D makes deposit 9999.9, brings SP to 10k - L4 decreases P by(~1e-5)P. L4: 9999.900000000000000000 Bold, 1 ETH - expect A, B, C, D each withdraw ~100 Ether - */ - // - // TODO: Changes since v1 have introduced very slight precision error in this test. Potentially due to slightly different rounding - // in helper functon getOpenTroveBoldAmount due to now-zero borrow fees. Double-check this when we write new SP arithmetic tests and fix the "P" issue. - it.skip("withdrawETHGainToTrove(): Several deposits of 10000 Bold span one scale factor change. Depositors withdraws correct compounded deposit and ETH Gain after one liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - const aliceTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: alice, value: dec(10000, "ether") }, - ); - const bobTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: bob, value: dec(10000, "ether") }, - ); - const carolTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: carol, value: dec(10000, "ether") }, - ); - const dennisTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: dennis, value: dec(10000, "ether") }, - ); - - // Defaulters 1-4 each withdraw 9999.9 Bold - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999900000000000000000"), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(100, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999900000000000000000"), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(100, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999900000000000000000"), - defaulter_3, - defaulter_3, - 0, - 0, - { from: defaulter_3, value: dec(100, "ether") }, - ); - const defaulter_4_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount("9999900000000000000000"), - defaulter_4, - defaulter_4, - 0, - { from: defaulter_4, value: dec(100, "ether") }, - ); - - // price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - await boldToken.transfer(alice, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: alice }); - - // Defaulter 1 liquidated. P decreases to 1e13 - const txL1 = await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - assert.isTrue(txL1.receipt.status); - th.logBN("P", await stabilityPool.P()); // P = 0.000009999999999999, 1 wei less than expected - assert.equal(await stabilityPool.P(), dec(1, 13)); // P decreases to 1e(18-5) = 1e13 - assert.equal(await stabilityPool.currentScale(), "0"); - - // B deposits 9999.9 Bold - await boldToken.transfer(bob, dec(99999, 17), { from: whale }); - await stabilityPool.provideToSP(dec(99999, 17), { from: bob }); - - // Defaulter 2 liquidated - const txL2 = await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - assert.isTrue(txL2.receipt.status); - assert.equal(await stabilityPool.P(), dec(1, 17)); // Scale changes and P changes to 1e(13-5+9) = 1e17 - assert.equal(await stabilityPool.currentScale(), "1"); - - // C deposits 9999.9 Bold - await boldToken.transfer(carol, dec(99999, 17), { from: whale }); - await stabilityPool.provideToSP(dec(99999, 17), { from: carol }); - - // Defaulter 3 liquidated - const txL3 = await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - assert.isTrue(txL3.receipt.status); - assert.equal(await stabilityPool.P(), dec(1, 12)); // P decreases to 1e(17-5) = 1e12 - assert.equal(await stabilityPool.currentScale(), "1"); - - // D deposits 9999.9 Bold - await boldToken.transfer(dennis, dec(99999, 17), { from: whale }); - await stabilityPool.provideToSP(dec(99999, 17), { from: dennis }); - - // Defaulter 4 liquidated - const txL4 = await troveManager.liquidate(defaulter_4_TroveId, { from: owner }); - assert.isTrue(txL4.receipt.status); - assert.equal(await stabilityPool.P(), dec(1, 16)); // Scale changes and P changes to 1e(12-5+9) = 1e16 - assert.equal(await stabilityPool.currentScale(), "2"); - - const txA = await stabilityPool.withdrawETHGainToTrove(aliceTroveId, { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(bobTroveId, { from: bob }); - const txC = await stabilityPool.withdrawETHGainToTrove(carolTroveId, { from: carol }); - const txD = await stabilityPool.withdrawETHGainToTrove(dennisTroveId, { from: dennis }); - - const alice_ETHWithdrawn = await th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH").toString(); - const bob_ETHWithdrawn = await th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH").toString(); - const carol_ETHWithdrawn = await th.getEventArgByName(txC, "ETHGainWithdrawn", "_ETH").toString(); - const dennis_ETHWithdrawn = await th.getEventArgByName(txD, "ETHGainWithdrawn", "_ETH").toString(); - - // A, B, C should retain 0 - their deposits have been completely used up - assert.equal(await stabilityPool.getCompoundedBoldDeposit(alice), "0"); - assert.equal(await stabilityPool.getCompoundedBoldDeposit(alice), "0"); - assert.equal(await stabilityPool.getCompoundedBoldDeposit(alice), "0"); - // D should retain around 0.9999 Bold, since his deposit of 9999.9 was reduced by a factor of 1e-5 - assert.isAtMost( - th.getDifference((await stabilityPool.getCompoundedBoldDeposit(dennis)).toString(), dec(99999, 12)), - 100000, - ); - - // 99.5 ETH is offset at each L, 0.5 goes to gas comp - // Each depositor gets ETH rewards of around 99.5 ETH. 1e17 error tolerance - assert.isTrue(toBN(alice_ETHWithdrawn).sub(toBN(dec(995, 17))).abs().lte(toBN(dec(1, 17)))); - assert.isTrue(toBN(bob_ETHWithdrawn).sub(toBN(dec(995, 17))).abs().lte(toBN(dec(1, 17)))); - assert.isTrue(toBN(carol_ETHWithdrawn).sub(toBN(dec(995, 17))).abs().lte(toBN(dec(1, 17)))); - assert.isTrue(toBN(dennis_ETHWithdrawn).sub(toBN(dec(995, 17))).abs().lte(toBN(dec(1, 17)))); - }); - - it("withdrawETHGainToTrove(): 2 depositors can withdraw after each receiving half of a pool-emptying liquidation", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - const ATroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: A, value: dec(10000, "ether") }, - ); - const BTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: B, value: dec(10000, "ether") }, - ); - const CTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: C, value: dec(10000, "ether") }, - ); - const DTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: D, value: dec(10000, "ether") }, - ); - const ETroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: E, value: dec(10000, "ether") }, - ); - const FTroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(10000, 18)), - ZERO_ADDRESS, - ZERO_ADDRESS, - 0, - { from: F, value: dec(10000, "ether") }, - ); - - // Defaulters 1-3 each withdraw 24100, 24300, 24500 Bold (inc gas comp) - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(24100, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(200, "ether") }, - ); - const defaulter_2_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(24300, 18)), - defaulter_2, - defaulter_2, - 0, - { from: defaulter_2, value: dec(200, "ether") }, - ); - const defaulter_3_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(24500, 18)), - defaulter_3, - defaulter_3, - 0, - { from: defaulter_3, value: dec(200, "ether") }, - ); - - // price drops by 50% - await priceFeed.setPrice(dec(100, 18)); - - // A, B provide 10k Bold - await boldToken.transfer(A, dec(10000, 18), { from: whale }); - await boldToken.transfer(B, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: A }); - await stabilityPool.provideToSP(dec(10000, 18), { from: B }); - - // Defaulter 1 liquidated. SP emptied - const txL1 = await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - assert.isTrue(txL1.receipt.status); - - // Check compounded deposits - const A_deposit = await stabilityPool.getCompoundedBoldDeposit(A); - const B_deposit = await stabilityPool.getCompoundedBoldDeposit(B); - // console.log(`A_deposit: ${A_deposit}`) - // console.log(`B_deposit: ${B_deposit}`) - assert.equal(A_deposit, "0"); - assert.equal(B_deposit, "0"); - - // Check SP tracker is zero - const BoldinSP_1 = await stabilityPool.getTotalBoldDeposits(); - // console.log(`BoldinSP_1: ${BoldinSP_1}`) - assert.equal(BoldinSP_1, "0"); - - // Check SP Bold balance is zero - const SPBoldBalance_1 = await boldToken.balanceOf(stabilityPool.address); - // console.log(`SPBoldBalance_1: ${SPBoldBalance_1}`) - assert.equal(SPBoldBalance_1, "0"); - - // Attempt withdrawals - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txA = await stabilityPool.withdrawETHGainToTrove(ATroveId, { from: A }); - const txB = await stabilityPool.withdrawETHGainToTrove(BTroveId, { from: B }); - await priceFeed.setPrice(dec(100, 18)); - - assert.isTrue(txA.receipt.status); - assert.isTrue(txB.receipt.status); - - // ========== - - // C, D provide 10k Bold - await boldToken.transfer(C, dec(10000, 18), { from: whale }); - await boldToken.transfer(D, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: C }); - await stabilityPool.provideToSP(dec(10000, 18), { from: D }); - - // Defaulter 2 liquidated. SP emptied - const txL2 = await troveManager.liquidate(defaulter_2_TroveId, { from: owner }); - assert.isTrue(txL2.receipt.status); - - // Check compounded deposits - const C_deposit = await stabilityPool.getCompoundedBoldDeposit(C); - const D_deposit = await stabilityPool.getCompoundedBoldDeposit(D); - // console.log(`A_deposit: ${C_deposit}`) - // console.log(`B_deposit: ${D_deposit}`) - assert.equal(C_deposit, "0"); - assert.equal(D_deposit, "0"); - - // Check SP tracker is zero - const BoldinSP_2 = await stabilityPool.getTotalBoldDeposits(); - // console.log(`BoldinSP_2: ${BoldinSP_2}`) - assert.equal(BoldinSP_2, "0"); - - // Check SP Bold balance is zero - const SPBoldBalance_2 = await boldToken.balanceOf(stabilityPool.address); - // console.log(`SPBoldBalance_2: ${SPBoldBalance_2}`) - assert.equal(SPBoldBalance_2, "0"); - - // Attempt withdrawals - // Increasing the price for a moment to avoid pending liquidations to block withdrawal - await priceFeed.setPrice(dec(200, 18)); - const txC = await stabilityPool.withdrawETHGainToTrove(CTroveId, { from: C }); - const txD = await stabilityPool.withdrawETHGainToTrove(DTroveId, { from: D }); - await priceFeed.setPrice(dec(100, 18)); - - assert.isTrue(txC.receipt.status); - assert.isTrue(txD.receipt.status); - - // ============ - - // E, F provide 10k Bold - await boldToken.transfer(E, dec(10000, 18), { from: whale }); - await boldToken.transfer(F, dec(10000, 18), { from: whale }); - await stabilityPool.provideToSP(dec(10000, 18), { from: E }); - await stabilityPool.provideToSP(dec(10000, 18), { from: F }); - - // Defaulter 3 liquidated. SP emptied - const txL3 = await troveManager.liquidate(defaulter_3_TroveId, { from: owner }); - assert.isTrue(txL3.receipt.status); - - // Check compounded deposits - const E_deposit = await stabilityPool.getCompoundedBoldDeposit(E); - const F_deposit = await stabilityPool.getCompoundedBoldDeposit(F); - // console.log(`E_deposit: ${E_deposit}`) - // console.log(`F_deposit: ${F_deposit}`) - assert.equal(E_deposit, "0"); - assert.equal(F_deposit, "0"); - - // Check SP tracker is zero - const BoldinSP_3 = await stabilityPool.getTotalBoldDeposits(); - assert.equal(BoldinSP_3, "0"); - - // Check SP Bold balance is zero - const SPBoldBalance_3 = await boldToken.balanceOf(stabilityPool.address); - // console.log(`SPBoldBalance_3: ${SPBoldBalance_3}`) - assert.equal(SPBoldBalance_3, "0"); - - // Attempt withdrawals - const txE = await stabilityPool.withdrawETHGainToTrove(ETroveId, { from: E }); - const txF = await stabilityPool.withdrawETHGainToTrove(FTroveId, { from: F }); - assert.isTrue(txE.receipt.status); - assert.isTrue(txF.receipt.status); - }); - - // --- Extreme values, confirm no overflows --- - - it("withdrawETHGainToTrove(): Large liquidated coll/debt, deposits and ETH price", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // ETH:USD price is $2 billion per ETH - await priceFeed.setPrice(dec(2, 27)); - - const depositors = [alice, bob]; - for (const account of depositors) { - await th.openTroveWrapper(contracts, th._100pct, dec(1, 36), account, account, 0, { - from: account, - value: dec(2, 27), - }); - await stabilityPool.provideToSP(dec(1, 36), { from: account }); - } - - // Defaulter opens trove with 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(1, 36)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: dec(1, 27) }, - ); - - // ETH:USD price drops to $1 billion per ETH - await priceFeed.setPrice(dec(1, 27)); - - // Defaulter liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - const txA = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(alice), { from: alice }); - const txB = await stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(bob), { from: bob }); - - // Grab the ETH gain from the emitted event in the tx log - const alice_ETHWithdrawn = th.getEventArgByName(txA, "ETHGainWithdrawn", "_ETH"); - const bob_ETHWithdrawn = th.getEventArgByName(txB, "ETHGainWithdrawn", "_ETH"); - - // Check Bold balances - const aliceBoldBalance = await stabilityPool.getCompoundedBoldDeposit(alice); - const aliceExpectedBoldBalance = web3.utils.toBN(dec(5, 35)); - const aliceBoldBalDiff = aliceBoldBalance.sub(aliceExpectedBoldBalance).abs(); - - assert.isTrue(aliceBoldBalDiff.lte(toBN(dec(1, 18)))); // error tolerance of 1e18 - - const bobBoldBalance = await stabilityPool.getCompoundedBoldDeposit(bob); - const bobExpectedBoldBalance = toBN(dec(5, 35)); - const bobBoldBalDiff = bobBoldBalance.sub(bobExpectedBoldBalance).abs(); - - assert.isTrue(bobBoldBalDiff.lte(toBN(dec(1, 18)))); - - // Check ETH gains - const aliceExpectedETHGain = toBN(dec(4975, 23)); - const aliceETHDiff = aliceExpectedETHGain.sub(toBN(alice_ETHWithdrawn)); - - assert.isTrue(aliceETHDiff.lte(toBN(dec(1, 18)))); - - const bobExpectedETHGain = toBN(dec(4975, 23)); - const bobETHDiff = bobExpectedETHGain.sub(toBN(bob_ETHWithdrawn)); - - assert.isTrue(bobETHDiff.lte(toBN(dec(1, 18)))); - }); - - // TODO: Changes since v1 have made the error margin in this test i.e. aliceBoldBalanceDiff increase 100x (but still low relative to the huge values used in test). - // Potentially due to slightly different rounding in helper getOpenTroveBoldAmount due to now-zero borrow fees. - // Double-check this when we write new SP arithmetic tests and fix the "P" issue. - it.skip("withdrawETHGainToTrove(): Small liquidated coll/debt, large deposits and ETH price", async () => { - // Whale opens Trove with 100k ETH - await th.openTroveWrapper(contracts, th._100pct, await getOpenTroveBoldAmount(dec(100000, 18)), whale, whale, 0, { - from: whale, - value: dec(100000, "ether"), - }); - - // ETH:USD price is $2 billion per ETH - await priceFeed.setPrice(dec(2, 27)); - const price = await priceFeed.getPrice(); - - const depositors = [alice, bob]; - for (const account of depositors) { - await th.openTroveWrapper(contracts, th._100pct, dec(1, 38), account, account, { - from: account, - value: dec(2, 29), - }); - await stabilityPool.provideToSP(dec(1, 38), { from: account }); - } - - // Defaulter opens trove with 50e-7 ETH and 5000 Bold. 200% ICR - const defaulter_1_TroveId = await th.openTroveWrapper( - contracts, - th._100pct, - await getOpenTroveBoldAmount(dec(5000, 18)), - defaulter_1, - defaulter_1, - 0, - { from: defaulter_1, value: "5000000000000" }, - ); - - // ETH:USD price drops to $1 billion per ETH - await priceFeed.setPrice(dec(1, 27)); - - // Defaulter liquidated - await troveManager.liquidate(defaulter_1_TroveId, { from: owner }); - - const txAPromise = stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(alice), { from: alice }); - const txBPromise = stabilityPool.withdrawETHGainToTrove(th.addressToTroveId(bob), { from: bob }); - - // Expect ETH gain per depositor of ~1e11 wei to be rounded to 0 by the ETHGainedPerUnitStaked calculation (e / D), where D is ~1e36. - await th.assertRevert(txAPromise, "StabilityPool: caller must have non-zero ETH Gain"); - await th.assertRevert(txBPromise, "StabilityPool: caller must have non-zero ETH Gain"); - - const aliceBoldBalance = await stabilityPool.getCompoundedBoldDeposit(alice); - // const aliceBoldBalance = await boldToken.balanceOf(alice) - const aliceExpectedBoldBalance = toBN("99999999999999997500000000000000000000"); - const aliceBoldBalDiff = aliceBoldBalance.sub(aliceExpectedBoldBalance).abs(); - - th.logBN("aliceBoldBalDiff", aliceBoldBalDiff); // 100x bigger than expected - - assert.isTrue(aliceBoldBalDiff.lte(toBN(dec(1, 18)))); - - const bobBoldBalance = await stabilityPool.getCompoundedBoldDeposit(bob); - const bobExpectedBoldBalance = toBN("99999999999999997500000000000000000000"); - const bobBoldBalDiff = bobBoldBalance.sub(bobExpectedBoldBalance).abs(); - - assert.isTrue(bobBoldBalDiff.lte(toBN("100000000000000000000"))); - }); - }); -}); - -contract("Reset chain state", async (accounts) => {});