From 64d4fd4c65e21b6d2158a045851896d65bdac554 Mon Sep 17 00:00:00 2001 From: Lucas Manuel Date: Wed, 1 Dec 2021 13:58:06 -0500 Subject: [PATCH] feat: Add global pause (SC-4215) (#32) * feat: add global pause * fix: only `acceptNewTerms`, `claim`, `triggerDefault` paused - and get globals from pool * feat: added pause checks and pull funds * fix: added acl for pull funds * fix: update tests * chore: update comments Co-authored-by: Michael De Luca Co-authored-by: JG Carvalho --- contracts/DebtLocker.sol | 162 +++++++++++++++------------ contracts/interfaces/IDebtLocker.sol | 8 ++ contracts/interfaces/Interfaces.sol | 2 + contracts/test/DebtLocker.t.sol | 98 +++++++++------- contracts/test/mocks/Mocks.sol | 7 ++ modules/contract-test-utils | 2 +- modules/liquidations | 2 +- modules/loan | 2 +- modules/maple-proxy-factory | 2 +- 9 files changed, 168 insertions(+), 117 deletions(-) diff --git a/contracts/DebtLocker.sol b/contracts/DebtLocker.sol index ccc3c8f..aefbc3a 100644 --- a/contracts/DebtLocker.sol +++ b/contracts/DebtLocker.sol @@ -15,6 +15,15 @@ import { DebtLockerStorage } from "./DebtLockerStorage.sol"; /// @title DebtLocker interacts with Loans on behalf of PoolV1 contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { + /*****************/ + /*** Modifiers ***/ + /*****************/ + + modifier whenProtocolNotPaused() { + require(!IMapleGlobalsLike(_getGlobals()).protocolPaused(), "DL:PROTOCOL_PAUSED"); + _; + } + /********************************/ /*** Administrative Functions ***/ /********************************/ @@ -41,7 +50,7 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { /*** Pool Delegate Functions ***/ /*******************************/ - function acceptNewTerms(address refinancer_, bytes[] calldata calls_, uint256 amount_) override external { + function acceptNewTerms(address refinancer_, bytes[] calldata calls_, uint256 amount_) external override whenProtocolNotPaused { require(msg.sender == _getPoolDelegate(), "DL:ANT:NOT_PD"); IMapleLoanLike loan_ = IMapleLoanLike(_loan); @@ -60,19 +69,26 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { _principalRemainingAtLastClaim = loan_.principal(); } - function claim() external override returns (uint256[7] memory details_) { + function claim() external override whenProtocolNotPaused returns (uint256[7] memory details_) { require(msg.sender == _pool, "DL:C:NOT_POOL"); return _repossessed ? _handleClaimOfRepossessed() : _handleClaim(); } - function setAllowedSlippage(uint256 allowedSlippage_) external override { + // TODO: Discuss pros/cons of pause on this function + function pullFundsFromLiquidator(address token_, address destination_, uint256 amount_) external override { + require(msg.sender == _getPoolDelegate(), "DL:SA:NOT_PD"); + + Liquidator(_liquidator).pullFunds( token_, destination_, amount_); + } + + function setAllowedSlippage(uint256 allowedSlippage_) external override whenProtocolNotPaused { require(msg.sender == _getPoolDelegate(), "DL:SAS:NOT_PD"); emit AllowedSlippageSet(_allowedSlippage = allowedSlippage_); } - function setAuctioneer(address auctioneer_) external override { + function setAuctioneer(address auctioneer_) external override whenProtocolNotPaused { require(msg.sender == _getPoolDelegate(), "DL:SA:NOT_PD"); emit AuctioneerSet(auctioneer_); @@ -80,13 +96,13 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { Liquidator(_liquidator).setAuctioneer(auctioneer_); } - function setFundsToCapture(uint256 amount_) override external { + function setFundsToCapture(uint256 amount_) override external whenProtocolNotPaused { require(msg.sender == _getPoolDelegate(), "DL:SFTC:NOT_PD"); emit FundsToCaptureSet(_fundsToCapture = amount_); } - function setMinRatio(uint256 minRatio_) external override { + function setMinRatio(uint256 minRatio_) external override whenProtocolNotPaused { require(msg.sender == _getPoolDelegate(), "DL:SMR:NOT_PD"); emit MinRatioSet(_minRatio = minRatio_); @@ -101,9 +117,7 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { emit LiquidationStopped(); } - // TODO: Consider adding pullFunds function, calling liquidator.pullFunds() - - function triggerDefault() external override { + function triggerDefault() external override whenProtocolNotPaused { require(msg.sender == _pool, "DL:TD:NOT_POOL"); require( @@ -136,6 +150,70 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { ); } + /**************************/ + /*** Internal Functions ***/ + /**************************/ + + function _handleClaim() internal returns (uint256[7] memory details_) { + // Get loan state variables needed + uint256 claimableFunds = IMapleLoanLike(_loan).claimableFunds(); + + require(claimableFunds > uint256(0), "DL:HC:NOTHING_TO_CLAIM"); + + // Send funds to pool + IMapleLoanLike(_loan).claimFunds(claimableFunds, _pool); + + uint256 currentPrincipalRemaining = IMapleLoanLike(_loan).principal(); + + // Determine how much of `claimableFunds` is principal + uint256 principalPortion = _principalRemainingAtLastClaim - currentPrincipalRemaining; + + // Update state variables + _principalRemainingAtLastClaim = currentPrincipalRemaining; + + // Set return values + // Note: All fees get deducted and transferred during `loan.fundLoan()` that omits the need to + // return the fees distribution to the pool. + details_[0] = claimableFunds; + details_[1] = claimableFunds - principalPortion; + details_[2] = principalPortion; + + uint256 amountOfFundsToCapture = _fundsToCapture; + + if (amountOfFundsToCapture > uint256(0)) { + details_[0] += amountOfFundsToCapture; + details_[2] += amountOfFundsToCapture; + + _fundsToCapture = uint256(0); + + require(ERC20Helper.transfer(IMapleLoanLike(_loan).fundsAsset(), _pool, amountOfFundsToCapture), "DL:HC:CAPTURE_FAILED"); + } + } + + function _handleClaimOfRepossessed() internal returns (uint256[7] memory details_) { + require(!_isLiquidationActive(), "DL:HCOR:LIQ_NOT_FINISHED"); + + address fundsAsset = IMapleLoanLike(_loan).fundsAsset(); + uint256 principalToCover = _principalRemainingAtLastClaim; // Principal remaining at time of liquidation + uint256 fundsCaptured = _fundsToCapture; + + // Funds recovered from liquidation and any unclaimed previous payment amounts + uint256 recoveredFunds = IERC20Like(fundsAsset).balanceOf(address(this)) - fundsCaptured; + + // If `recoveredFunds` is greater than `principalToCover`, the remaining amount is treated as interest in the context of the pool. + // If `recoveredFunds` is less than `principalToCover`, the difference is registered as a shortfall. + details_[0] = recoveredFunds + fundsCaptured; + details_[1] = recoveredFunds > principalToCover ? recoveredFunds - principalToCover : 0; + details_[2] = fundsCaptured; + details_[5] = recoveredFunds > principalToCover ? principalToCover : recoveredFunds; + details_[6] = principalToCover > recoveredFunds ? principalToCover - recoveredFunds : 0; + + _fundsToCapture = uint256(0); + _repossessed = false; + + require(ERC20Helper.transfer(fundsAsset, _pool, recoveredFunds + fundsCaptured), "DL:HCOR:TRANSFER"); + } + /**********************/ /*** View Functions ***/ /**********************/ @@ -156,7 +234,7 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { return _fundsToCapture; } - function getExpectedAmount(uint256 swapAmount_) external view override returns (uint256 returnAmount_) { + function getExpectedAmount(uint256 swapAmount_) external view override whenProtocolNotPaused returns (uint256 returnAmount_) { address collateralAsset = IMapleLoanLike(_loan).collateralAsset(); address fundsAsset = IMapleLoanLike(_loan).fundsAsset(); @@ -218,70 +296,6 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxied { return IMapleGlobalsLike(_getGlobals()).treasuryFee(); } - /**************************/ - /*** Internal Functions ***/ - /**************************/ - - function _handleClaim() internal returns (uint256[7] memory details_) { - // Get loan state variables needed - uint256 claimableFunds = IMapleLoanLike(_loan).claimableFunds(); - - require(claimableFunds > uint256(0), "DL:HC:NOTHING_TO_CLAIM"); - - // Send funds to pool - IMapleLoanLike(_loan).claimFunds(claimableFunds, _pool); - - uint256 currentPrincipalRemaining = IMapleLoanLike(_loan).principal(); - - // Determine how much of `claimableFunds` is principal - uint256 principalPortion = _principalRemainingAtLastClaim - currentPrincipalRemaining; - - // Update state variables - _principalRemainingAtLastClaim = currentPrincipalRemaining; - - // Set return values - // Note: All fees get deducted and transferred during `loan.fundLoan()` that omits the need to - // return the fees distribution to the pool. - details_[0] = claimableFunds; - details_[1] = claimableFunds - principalPortion; - details_[2] = principalPortion; - - uint256 amountOfFundsToCapture = _fundsToCapture; - - if (amountOfFundsToCapture > uint256(0)) { - details_[0] += amountOfFundsToCapture; - details_[2] += amountOfFundsToCapture; - - _fundsToCapture = uint256(0); - - require(ERC20Helper.transfer(IMapleLoanLike(_loan).fundsAsset(), _pool, amountOfFundsToCapture), "DL:HC:CAPTURE_FAILED"); - } - } - - function _handleClaimOfRepossessed() internal returns (uint256[7] memory details_) { - require(!_isLiquidationActive(), "DL:HCOR:LIQ_NOT_FINISHED"); - - address fundsAsset = IMapleLoanLike(_loan).fundsAsset(); - uint256 principalToCover = _principalRemainingAtLastClaim; // Principal remaining at time of liquidation - uint256 fundsCaptured = _fundsToCapture; - - // Funds recovered from liquidation and any unclaimed previous payment amounts - uint256 recoveredFunds = IERC20Like(fundsAsset).balanceOf(address(this)) - fundsCaptured; - - // If `recoveredFunds` is greater than `principalToCover`, the remaining amount is treated as interest in the context of the pool. - // If `recoveredFunds` is less than `principalToCover`, the difference is registered as a shortfall. - details_[0] = recoveredFunds + fundsCaptured; - details_[1] = recoveredFunds > principalToCover ? recoveredFunds - principalToCover : 0; - details_[2] = fundsCaptured; - details_[5] = recoveredFunds > principalToCover ? principalToCover : recoveredFunds; - details_[6] = principalToCover > recoveredFunds ? principalToCover - recoveredFunds : 0; - - _fundsToCapture = uint256(0); - _repossessed = false; - - require(ERC20Helper.transfer(fundsAsset, _pool, recoveredFunds + fundsCaptured), "DL:HCOR:TRANSFER"); - } - /*******************************/ /*** Internal View Functions ***/ /*******************************/ diff --git a/contracts/interfaces/IDebtLocker.sol b/contracts/interfaces/IDebtLocker.sol index ff3a1f0..6431bc1 100644 --- a/contracts/interfaces/IDebtLocker.sol +++ b/contracts/interfaces/IDebtLocker.sol @@ -72,6 +72,14 @@ interface IDebtLocker is IMapleProxied { */ function mapleTreasury() external view returns (address mapleTreasury_); + /** + * @dev Allows the poolDelegate to pull some funds from liquidator contract + * @param token_ The token address of the funds. + * @param destination_ The destination address of captured funds. + * @param amount_ The amount to pull. + */ + function pullFundsFromLiquidator(address token_, address destination_, uint256 amount_) external; + /** * @dev Returns the annualized establishment fee that will go to the Maple Treasury. */ diff --git a/contracts/interfaces/Interfaces.sol b/contracts/interfaces/Interfaces.sol index 7166ce5..f18c8ea 100644 --- a/contracts/interfaces/Interfaces.sol +++ b/contracts/interfaces/Interfaces.sol @@ -28,6 +28,8 @@ interface IMapleGlobalsLike { function mapleTreasury() external view returns (address mapleTreasury_); + function protocolPaused() external view returns (bool protocolPaused_); + function treasuryFee() external view returns (uint256 treasuryFee_); } diff --git a/contracts/test/DebtLocker.t.sol b/contracts/test/DebtLocker.t.sol index 012a5b8..b1b2b92 100644 --- a/contracts/test/DebtLocker.t.sol +++ b/contracts/test/DebtLocker.t.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.7; -import { TestUtils } from "../../modules/contract-test-utils/contracts/test.sol"; -import { MockERC20 } from "../../modules/erc20/src/test/mocks/MockERC20.sol"; -import { ConstructableMapleLoan } from "../../modules/loan/contracts/test/mocks/Mocks.sol"; -import { Refinancer } from "../../modules/loan/contracts/Refinancer.sol"; +import { TestUtils } from "../../modules/contract-test-utils/contracts/test.sol"; +import { MockERC20 } from "../../modules/erc20/src/test/mocks/MockERC20.sol"; +import { MapleLoan } from "../../modules/loan/contracts/MapleLoan.sol"; +import { MapleLoanFactory } from "../../modules/loan/contracts/MapleLoanFactory.sol"; +import { MapleLoanInitializer } from "../../modules/loan/contracts/MapleLoanInitializer.sol"; +import { Refinancer } from "../../modules/loan/contracts/Refinancer.sol"; import { DebtLocker } from "../DebtLocker.sol"; import { DebtLockerFactory } from "../DebtLockerFactory.sol"; @@ -37,6 +39,8 @@ contract DebtLockerTests is TestUtils { DebtLockerFactory internal dlFactory; Governor internal governor; + MapleLoanFactory internal loanFactory; + MapleLoanInitializer internal loanInitializer; MockERC20 internal collateralAsset; MockERC20 internal fundsAsset; MockGlobals internal globals; @@ -57,6 +61,7 @@ contract DebtLockerTests is TestUtils { globals = new MockGlobals(address(governor)); poolFactory = new MockPoolFactory(address(globals)); dlFactory = new DebtLockerFactory(address(globals)); + loanFactory = new MapleLoanFactory(address(globals)); pool = MockPool(poolFactory.createPool(address(poolDelegate))); @@ -67,27 +72,38 @@ contract DebtLockerTests is TestUtils { globals.setValidLiquidityAsset(address(fundsAsset), true); // Deploying and registering DebtLocker implementation and initializer - address implementation = address(new DebtLocker()); - address initializer = address(new DebtLockerInitializer()); + address debtLockerImplementation = address(new DebtLocker()); + address debtLockerInitializer = address(new DebtLockerInitializer()); + + // Deploying and registering DebtLocker implementation and initializer + address loanImplementation = address(new MapleLoan()); + loanInitializer = new MapleLoanInitializer(); - governor.mapleProxyFactory_registerImplementation(address(dlFactory), 1, implementation, initializer); + governor.mapleProxyFactory_registerImplementation(address(dlFactory), 1, debtLockerImplementation, debtLockerInitializer); governor.mapleProxyFactory_setDefaultVersion(address(dlFactory), 1); + governor.mapleProxyFactory_registerImplementation(address(loanFactory), 1, loanImplementation, address(loanInitializer)); + governor.mapleProxyFactory_setDefaultVersion(address(loanFactory), 1); + globals.setPrice(address(collateralAsset), 10 * 10 ** 8); // 10 USD globals.setPrice(address(fundsAsset), 1 * 10 ** 8); // 1 USD } - function _createLoan(uint256 principalRequested_, uint256 collateralRequired_) internal returns (ConstructableMapleLoan loan_) { + function _createLoan(uint256 principalRequested_, uint256 collateralRequired_) internal returns (MapleLoan loan_) { address[2] memory assets = [address(collateralAsset), address(fundsAsset)]; uint256[3] memory termDetails = [uint256(10 days), uint256(30 days), 6]; uint256[3] memory amounts = [collateralRequired_, principalRequested_, 0]; uint256[4] memory rates = [uint256(0.10e18), uint256(0), uint256(0), uint256(0)]; - loan_ = new ConstructableMapleLoan(address(this), assets, termDetails, amounts, rates); + bytes memory arguments = loanInitializer.encodeArguments(address(this), assets, termDetails, amounts, rates); + bytes32 salt = keccak256(abi.encodePacked("salt")); + + // Create Loan + loan_ = MapleLoan(loanFactory.createInstance(arguments, salt)); } function _fundAndDrawdownLoan(address loan_, address debtLocker_) internal { - ConstructableMapleLoan loan = ConstructableMapleLoan(loan_); + MapleLoan loan = MapleLoan(loan_); uint256 principalRequested = loan.principalRequested(); uint256 collateralRequired = loan.collateralRequired(); @@ -103,7 +119,7 @@ contract DebtLockerTests is TestUtils { loan.drawdownFunds(loan.drawableFunds(), address(1)); // Drawdown to empty funds from loan } - function _createFundAndDrawdownLoan(uint256 principalRequested_, uint256 collateralRequired_) internal returns (ConstructableMapleLoan loan_, DebtLocker debtLocker_) { + function _createFundAndDrawdownLoan(uint256 principalRequested_, uint256 collateralRequired_) internal returns (MapleLoan loan_, DebtLocker debtLocker_) { loan_ = _createLoan(principalRequested_, collateralRequired_); debtLocker_ = DebtLocker(pool.createDebtLocker(address(dlFactory), address(loan_))); @@ -124,7 +140,7 @@ contract DebtLockerTests is TestUtils { principalRequested_ = constrictToRange(principalRequested_, 1_000_000, MAX_TOKEN_AMOUNT); collateralRequired_ = constrictToRange(collateralRequired_, 0, MAX_TOKEN_AMOUNT); - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); /*************************/ /*** Make two payments ***/ @@ -199,7 +215,7 @@ contract DebtLockerTests is TestUtils { } function test_initialize_invalidCollateralAsset() public { - ConstructableMapleLoan loan = _createLoan(1_000_000, 300_000); + MapleLoan loan = _createLoan(1_000_000, 300_000); assertTrue(globals.isValidCollateralAsset(loan.collateralAsset())); @@ -215,7 +231,7 @@ contract DebtLockerTests is TestUtils { } function test_initialize_invalidLiquidityAsset() public { - ConstructableMapleLoan loan = _createLoan(1_000_000, 300_000); + MapleLoan loan = _createLoan(1_000_000, 300_000); assertTrue(globals.isValidLiquidityAsset(loan.fundsAsset())); @@ -239,7 +255,7 @@ contract DebtLockerTests is TestUtils { principalRequested_ = constrictToRange(principalRequested_, 1_000_000, MAX_TOKEN_AMOUNT); collateralRequired_ = constrictToRange(collateralRequired_, 0, principalRequested_ / 12); - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); /**********************/ /*** Make a payment ***/ @@ -336,7 +352,7 @@ contract DebtLockerTests is TestUtils { /*** Create Loan and DebtLocker ***/ /**********************************/ - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired); /*************************************/ /*** Trigger default and liquidate ***/ @@ -418,7 +434,7 @@ contract DebtLockerTests is TestUtils { /*** Create Loan and DebtLocker ***/ /**********************************/ - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired); /*************************************/ /*** Trigger default and liquidate ***/ @@ -492,7 +508,7 @@ contract DebtLockerTests is TestUtils { principalRequested_ = constrictToRange(principalRequested_, 1_000_000, MAX_TOKEN_AMOUNT); collateralRequired_ = constrictToRange(collateralRequired_, 1, principalRequested_ / 10); // Need collateral for liquidator deployment - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); /*************************************/ /*** Trigger default and liquidate ***/ @@ -569,7 +585,7 @@ contract DebtLockerTests is TestUtils { } function test_acl_poolDelegate_setAllowedSlippage() external { - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); DebtLocker debtLocker = DebtLocker(pool.createDebtLocker(address(dlFactory), address(loan))); @@ -582,7 +598,7 @@ contract DebtLockerTests is TestUtils { } function test_acl_poolDelegate_setAuctioneer() external { - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); // Mint collateral into loan so that liquidator gets deployed collateralAsset.mint(address(loan), 1000); @@ -600,7 +616,7 @@ contract DebtLockerTests is TestUtils { } function test_acl_poolDelegate_setFundsToCapture() external { - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); DebtLocker debtLocker = DebtLocker(pool.createDebtLocker(address(dlFactory), address(loan))); @@ -613,7 +629,7 @@ contract DebtLockerTests is TestUtils { } function test_acl_poolDelegate_setMinRatio() external { - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); DebtLocker debtLocker = DebtLocker(pool.createDebtLocker(address(dlFactory), address(loan))); @@ -626,7 +642,7 @@ contract DebtLockerTests is TestUtils { } function test_acl_poolDelegate_upgrade() external { - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); DebtLocker debtLocker = DebtLocker(pool.createDebtLocker(address(dlFactory), address(loan))); @@ -650,7 +666,7 @@ contract DebtLockerTests is TestUtils { } function test_acl_poolDelegate_acceptNewTerms() external { - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); address refinancer = address(new Refinancer()); bytes[] memory data = new bytes[](1); @@ -667,7 +683,7 @@ contract DebtLockerTests is TestUtils { } function test_acl_pool_claim() external { - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); ManipulatableDebtLocker debtLocker = new ManipulatableDebtLocker(address(loan), address(pool), address(dlFactory)); @@ -683,15 +699,17 @@ contract DebtLockerTests is TestUtils { loan.makePayment(total1); - try debtLocker.claim() { assertTrue(false, "Non-pool able to claim"); } catch { } + debtLocker.setPool(address(1)); - debtLocker.setPool(address(this)); + try pool.claim(address(debtLocker)) { assertTrue(false, "Non-pool able to claim"); } catch { } - debtLocker.claim(); + debtLocker.setPool(address(pool)); + + pool.claim(address(debtLocker)); } function test_acl_pool_triggerDefault() external { - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); ManipulatableDebtLocker debtLocker = new ManipulatableDebtLocker(address(loan), address(pool), address(dlFactory)); @@ -699,11 +717,13 @@ contract DebtLockerTests is TestUtils { hevm.warp(loan.nextPaymentDueDate() + loan.gracePeriod() + 1); - try debtLocker.triggerDefault() { assertTrue(false, "Non-pool able to triggerDefault"); } catch { } + debtLocker.setPool(address(1)); - debtLocker.setPool(address(this)); + try pool.triggerDefault(address(debtLocker)) { assertTrue(false, "Non-pool able to triggerDefault"); } catch { } - debtLocker.triggerDefault(); + debtLocker.setPool(address(pool)); + + pool.triggerDefault(address(debtLocker)); } /***********************/ @@ -719,7 +739,7 @@ contract DebtLockerTests is TestUtils { /*** Create Loan and DebtLocker ***/ /**********************************/ - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_); /**********************/ /*** Make a payment ***/ @@ -773,7 +793,7 @@ contract DebtLockerTests is TestUtils { /***************************/ function test_fundsToCaptureForNextClaim() public { - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); // Make a payment amount with interest and principal ( uint256 principal, uint256 interest ) = loan.getNextPaymentBreakdown(); @@ -806,7 +826,7 @@ contract DebtLockerTests is TestUtils { } function test_fundsToCaptureWhileInDefault() public { - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); // Prepare additional amount to be captured fundsAsset.mint(address(debtLocker), 500_000); @@ -847,7 +867,7 @@ contract DebtLockerTests is TestUtils { } function testFail_fundsToCaptureForNextClaim() public { - ( ConstructableMapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); + ( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000); fundsAsset.mint(address(loan), 1_000_000); loan.fundLoan(address(debtLocker), 1_000_000); @@ -884,7 +904,7 @@ contract DebtLockerTests is TestUtils { function test_getGlobals() public { _registerDebtLockerHarnesss(); - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); DebtLockerHarness debtLocker = DebtLockerHarness(pool.createDebtLocker(address(dlFactory), address(loan))); @@ -894,7 +914,7 @@ contract DebtLockerTests is TestUtils { function test_getPoolDelegate() public { _registerDebtLockerHarnesss(); - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); DebtLockerHarness debtLocker = DebtLockerHarness(pool.createDebtLocker(address(dlFactory), address(loan))); @@ -904,7 +924,7 @@ contract DebtLockerTests is TestUtils { function test_isLiquidationActive() public { _registerDebtLockerHarnesss(); - ConstructableMapleLoan loan = _createLoan(1_000_000, 30_000); + MapleLoan loan = _createLoan(1_000_000, 30_000); DebtLockerHarness debtLocker = DebtLockerHarness(pool.createDebtLocker(address(dlFactory), address(loan))); diff --git a/contracts/test/mocks/Mocks.sol b/contracts/test/mocks/Mocks.sol index d8a5361..1555842 100644 --- a/contracts/test/mocks/Mocks.sol +++ b/contracts/test/mocks/Mocks.sol @@ -57,6 +57,7 @@ contract MockLiquidationStrategy { ILiquidatorLike(lender_).liquidatePortion( swapAmount_, + type(uint256).max, abi.encodeWithSelector(this.swap.selector, collateralAsset_, fundsAsset_, swapAmount_, repaymentAmount) ); } @@ -86,6 +87,8 @@ contract MockGlobals { mapping(address => bool) public isValidCollateralAsset; mapping(address => bool) public isValidLiquidityAsset; + + bool public protocolPaused; mapping(address => uint256) assetPrices; @@ -101,6 +104,10 @@ contract MockGlobals { assetPrices[asset_] = price_; } + function setProtocolPause(bool paused_) external { + protocolPaused = paused_; + } + function investorFee() external pure returns (uint256 investorFee_) { return 50; } diff --git a/modules/contract-test-utils b/modules/contract-test-utils index 4d2c7a2..e14deca 160000 --- a/modules/contract-test-utils +++ b/modules/contract-test-utils @@ -1 +1 @@ -Subproject commit 4d2c7a2270d8657f82783fbada252ae24f318601 +Subproject commit e14deca8ad29af516a87186943c02c939dc68407 diff --git a/modules/liquidations b/modules/liquidations index 35c628e..2fffd5d 160000 --- a/modules/liquidations +++ b/modules/liquidations @@ -1 +1 @@ -Subproject commit 35c628e5ab45fbffaab7aef43a030a98b712a94a +Subproject commit 2fffd5d35fb03bd1e19ac2cb5d8f7d6feca853c1 diff --git a/modules/loan b/modules/loan index ef404d4..1c26ce8 160000 --- a/modules/loan +++ b/modules/loan @@ -1 +1 @@ -Subproject commit ef404d4e701a1cf4f98c22e042475ff71daa853c +Subproject commit 1c26ce8228024fad6f75aa03858157693ec67d1c diff --git a/modules/maple-proxy-factory b/modules/maple-proxy-factory index 469f487..ee5f6be 160000 --- a/modules/maple-proxy-factory +++ b/modules/maple-proxy-factory @@ -1 +1 @@ -Subproject commit 469f48778e5f5ce9d2db6a456e1a66597091421d +Subproject commit ee5f6beaf857c1b900cf74bcfdc4250a5189482a