Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add acceptNewTerms and rejectNewTerms deadlines to DebtLocker #60

Merged
merged 3 commits into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions contracts/DebtLocker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxiedInternals {
/*** Pool Delegate Functions ***/
/*******************************/

function acceptNewTerms(address refinancer_, bytes[] calldata calls_, uint256 amount_) external override whenProtocolNotPaused {
function acceptNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_, uint256 amount_) external override whenProtocolNotPaused {
require(msg.sender == _getPoolDelegate(), "DL:ANT:NOT_PD");

address loanAddress = _loan;
Expand All @@ -65,7 +65,7 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxiedInternals {
"DL:ANT:TRANSFER_FAILED"
);

IMapleLoanLike(loanAddress).acceptNewTerms(refinancer_, calls_, uint256(0));
IMapleLoanLike(loanAddress).acceptNewTerms(refinancer_, deadline_, calls_, uint256(0));

// NOTE: This must be set after accepting the new terms, which affects the loan principal.
_principalRemainingAtLastClaim = IMapleLoanLike(loanAddress).principal();
Expand All @@ -83,6 +83,12 @@ contract DebtLocker is IDebtLocker, DebtLockerStorage, MapleProxiedInternals {
Liquidator(liquidator_).pullFunds(token_, destination_, amount_);
}

function rejectNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external override {
lucas-manuel marked this conversation as resolved.
Show resolved Hide resolved
require(msg.sender == _getPoolDelegate(), "DL:ANT:NOT_PD");

IMapleLoanLike(_loan).rejectNewTerms(refinancer_, deadline_, calls_);
}

function setAllowedSlippage(uint256 allowedSlippage_) external override whenProtocolNotPaused {
require(msg.sender == _getPoolDelegate(), "DL:SAS:NOT_PD");
require(allowedSlippage_ <= uint256(10_000), "DL:SAS:INVALID_SLIPPAGE");
Expand Down
11 changes: 10 additions & 1 deletion contracts/interfaces/IDebtLocker.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,11 @@ interface IDebtLocker is IMapleProxied {
/**
* @dev Accept the new loan terms and trigger a refinance.
* @param refinancer_ The address of the refinancer contract.
* @param deadline_ The deadline of the new terms proposal.
* @param calls_ The array of encoded data that are to be executed as delegatecalls by the refinancer.
* @param amount_ The amount of `fundsAsset` that is to be sent to the Loan as part of the transaction.
*/
function acceptNewTerms(address refinancer_, bytes[] calldata calls_, uint256 amount_) external;
function acceptNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_, uint256 amount_) external;

/**
* @dev Claims funds to send to Pool. Handles funds from payments and liquidations.
Expand Down Expand Up @@ -84,6 +85,14 @@ interface IDebtLocker is IMapleProxied {
*/
function triggerDefault() external;

/**
* @dev Reject the new loan terms.
* @param refinancer_ The address of the refinancer contract.
* @param deadline_ The deadline of the new terms proposal.
* @param calls_ The array of encoded data that are to be executed as delegatecalls by the refinancer.
*/
function rejectNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external;

/**
* @dev Sets the allowed slippage for auctioneer (used to determine expected amount to be returned in flash loan).
* @param allowedSlippage_ Basis points representation of allowed percent slippage from market price.
Expand Down
4 changes: 3 additions & 1 deletion contracts/interfaces/Interfaces.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface IMapleGlobalsLike {

interface IMapleLoanLike {

function acceptNewTerms(address refinancer_, bytes[] calldata calls_, uint256 amount_) external;
function acceptNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_, uint256 amount_) external;

function claimableFunds() external view returns (uint256 claimableFunds_);

Expand All @@ -54,6 +54,8 @@ interface IMapleLoanLike {

function repossess(address destination_) external returns (uint256 collateralAssetAmount_, uint256 fundsAssetAmount_);

function rejectNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external;

}

interface IPoolLike {
Expand Down
68 changes: 36 additions & 32 deletions contracts/test/DebtLocker.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
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 { MockERC20 } from "../../modules/erc20/contracts/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";
Expand Down Expand Up @@ -146,7 +146,7 @@ contract DebtLockerTests is TestUtils {
/*** Make two payments ***/
/*************************/

( uint256 principal1, uint256 interest1 ) = loan.getNextPaymentBreakdown();
( uint256 principal1, uint256 interest1, , ) = loan.getNextPaymentBreakdown();

uint256 total1 = principal1 + interest1;

Expand All @@ -156,7 +156,7 @@ contract DebtLockerTests is TestUtils {

loan.makePayment(total1);

( uint256 principal2, uint256 interest2 ) = loan.getNextPaymentBreakdown();
( uint256 principal2, uint256 interest2, , ) = loan.getNextPaymentBreakdown();

uint256 total2 = principal2 + interest2;

Expand Down Expand Up @@ -190,7 +190,7 @@ contract DebtLockerTests is TestUtils {
/*** Make last payment ***/
/*************************/

( uint256 principal3, uint256 interest3 ) = loan.getNextPaymentBreakdown();
( uint256 principal3, uint256 interest3, , ) = loan.getNextPaymentBreakdown();

uint256 total3 = principal3 + interest3;

Expand Down Expand Up @@ -261,9 +261,9 @@ contract DebtLockerTests is TestUtils {
/*** Make a payment ***/
/**********************/

( uint256 principal, uint256 interest ) = loan.getNextPaymentBreakdown();
( uint256 principal, uint256 interest, uint256 delegateFee, uint256 treasuryFee ) = loan.getNextPaymentBreakdown();

uint256 total = principal + interest;
uint256 total = principal + interest + delegateFee + treasuryFee;

// Make a payment amount with interest and principal
fundsAsset.mint(address(this), total);
Expand Down Expand Up @@ -703,12 +703,14 @@ contract DebtLockerTests is TestUtils {
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSignature("setEarlyFeeRate(uint256)", 100);

loan.proposeNewTerms(refinancer, data); // address(this) is borrower
uint256 deadline = block.timestamp + 1;

loan.proposeNewTerms(refinancer, deadline, data); // address(this) is borrower

assertEq(loan.earlyFeeRate(), 0);

assertTrue(!notPoolDelegate.try_debtLocker_acceptNewTerms(address(debtLocker), refinancer, data, 0)); // Non-PD can't set
assertTrue( poolDelegate.try_debtLocker_acceptNewTerms(address(debtLocker), refinancer, data, 0)); // PD can set
assertTrue(!notPoolDelegate.try_debtLocker_acceptNewTerms(address(debtLocker), refinancer, deadline, data, 0)); // Non-PD can't set
assertTrue( poolDelegate.try_debtLocker_acceptNewTerms(address(debtLocker), refinancer, deadline, data, 0)); // PD can set

assertEq(loan.earlyFeeRate(), 100);
}
Expand All @@ -720,9 +722,9 @@ contract DebtLockerTests is TestUtils {

_fundAndDrawdownLoan(address(loan), address(debtLocker));

( uint256 principal1, uint256 interest1 ) = loan.getNextPaymentBreakdown();
( uint256 principal1, uint256 interest1, uint256 delegateFee1, uint256 treasuryFee1 ) = loan.getNextPaymentBreakdown();

uint256 total1 = principal1 + interest1;
uint256 total1 = principal1 + interest1 + delegateFee1 + treasuryFee1;

// Make a payment amount with interest and principal
fundsAsset.mint(address(this), total1);
Expand Down Expand Up @@ -774,55 +776,55 @@ contract DebtLockerTests is TestUtils {
/*** Refinance Tests ***/
/***********************/

function test_refinance_withAmountIncrease(uint256 principalRequested_, uint256 collateralRequired_, uint256 principalIncrease_) external {
principalRequested_ = constrictToRange(principalRequested_, 1_000_000, MAX_TOKEN_AMOUNT);
collateralRequired_ = constrictToRange(collateralRequired_, 0, principalRequested_ / 10);
principalIncrease_ = constrictToRange(principalIncrease_, 1, MAX_TOKEN_AMOUNT);
function test_refinance_withAmountIncrease(uint256 principalIncrease_) external {
principalIncrease_ = constrictToRange(principalIncrease_, 1, 1_000_000);

/**********************************/
/*** Create Loan and DebtLocker ***/
/**********************************/

( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(principalRequested_, collateralRequired_);
( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 100_000);

/**********************/
/*** Make a payment ***/
/**********************/

( uint256 principal, uint256 interest ) = loan.getNextPaymentBreakdown();
( uint256 principal, uint256 interest, uint256 delegateFee, uint256 treasuryFee ) = loan.getNextPaymentBreakdown();

uint256 total = principal + interest;
{
uint256 total = principal + interest + delegateFee + treasuryFee;

// Make a payment amount with interest and principal
fundsAsset.mint(address(this), total);
fundsAsset.approve(address(loan), total); // Mock payment amount
// Make a payment amount with interest and principal
fundsAsset.mint(address(this), total);
fundsAsset.approve(address(loan), total); // Mock payment amount

loan.makePayment(total);
loan.makePayment(total);
}

/******************/
/*****************/
/*** Refinance ***/
/****************/
/*****************/

address refinancer = address(new Refinancer());
bytes[] memory data = new bytes[](1);
data[0] = abi.encodeWithSignature("increasePrincipal(uint256)", principalIncrease_);

loan.proposeNewTerms(refinancer, data);
loan.proposeNewTerms(refinancer, block.timestamp, data);

fundsAsset.mint(address(debtLocker), principalIncrease_);

// Should fail due to pending claim
try debtLocker.acceptNewTerms(refinancer, data, principalIncrease_) { fail(); } catch { }
try debtLocker.acceptNewTerms(refinancer, block.timestamp, data, principalIncrease_) { fail(); } catch { }

pool.claim(address(debtLocker));

// Should fail for not pool delegate
try notPoolDelegate.debtLocker_acceptNewTerms(address(debtLocker), refinancer, data, principalIncrease_) { fail(); } catch { }
try notPoolDelegate.debtLocker_acceptNewTerms(address(debtLocker), refinancer, block.timestamp, data, principalIncrease_) { fail(); } catch { }

// Note: More state changes in real loan that are asserted in integration tests
uint256 principalBefore = loan.principal();

poolDelegate.debtLocker_acceptNewTerms(address(debtLocker), refinancer, data, principalIncrease_);
poolDelegate.debtLocker_acceptNewTerms(address(debtLocker), refinancer, block.timestamp, data, principalIncrease_);

uint256 principalAfter = loan.principal();

Expand All @@ -840,8 +842,9 @@ contract DebtLockerTests is TestUtils {
( MapleLoan loan, DebtLocker debtLocker ) = _createFundAndDrawdownLoan(1_000_000, 30_000);

// Make a payment amount with interest and principal
( uint256 principal, uint256 interest ) = loan.getNextPaymentBreakdown();
fundsAsset.mint(address(loan), principal + interest);
( uint256 principal, uint256 interest, uint256 delegateFee, uint256 treasuryFee ) = loan.getNextPaymentBreakdown();

fundsAsset.mint(address(loan), principal + interest + delegateFee + treasuryFee);
loan.makePayment(0);

// Prepare additional amount to be captured in next claim
Expand Down Expand Up @@ -917,8 +920,9 @@ contract DebtLockerTests is TestUtils {
loan.fundLoan(address(debtLocker), 1_000_000);

// Make a payment amount with interest and principal
( uint256 principal, uint256 interest ) = loan.getNextPaymentBreakdown();
fundsAsset.mint(address(loan), principal + interest);
( uint256 principal, uint256 interest, uint256 delegateFee, uint256 treasuryFee ) = loan.getNextPaymentBreakdown();

fundsAsset.mint(address(loan), principal + interest + delegateFee + treasuryFee);
loan.makePayment(principal + interest);

// Erroneously prepare additional amount to be captured in next claim
Expand Down
22 changes: 18 additions & 4 deletions contracts/test/accounts/PoolDelegate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ contract PoolDelegate is ProxyUser {
/*** Direct Functions ***/
/************************/

function debtLocker_acceptNewTerms(address debtLocker_, address refinancer_, bytes[] calldata calls_, uint256 amount_) external {
IDebtLocker(debtLocker_).acceptNewTerms(refinancer_, calls_, amount_);
function debtLocker_acceptNewTerms(address debtLocker_, address refinancer_, uint256 deadline_, bytes[] calldata calls_, uint256 amount_) external {
IDebtLocker(debtLocker_).acceptNewTerms(refinancer_, deadline_, calls_, amount_);
}

function debtLocker_pullFunds(address debtLocker_, address liquidator_, address token_, address destination_, uint256 amount_) external {
IDebtLocker(debtLocker_).pullFundsFromLiquidator(liquidator_, token_, destination_, amount_);
}

function debtLocker_rejectNewTerms(address debtLocker_, address refinancer_, uint256 deadline_, bytes[] calldata calls_) external {
IDebtLocker(debtLocker_).rejectNewTerms(refinancer_, deadline_, calls_);
}

function debtLocker_setAllowedSlippage(address debtLocker_, uint256 allowedSlippage_) external {
IDebtLocker(debtLocker_).setAllowedSlippage(allowedSlippage_);
}
Expand Down Expand Up @@ -50,15 +54,25 @@ contract PoolDelegate is ProxyUser {
function try_debtLocker_acceptNewTerms(
address debtLocker_,
address refinancer_,
uint256 deadline_,
bytes[] calldata calls_,
uint256 amount_
) external returns (bool ok_) {
( ok_, ) = debtLocker_.call(abi.encodeWithSelector(IDebtLocker.acceptNewTerms.selector, refinancer_, calls_, amount_));
( ok_, ) = debtLocker_.call(abi.encodeWithSelector(IDebtLocker.acceptNewTerms.selector, refinancer_, deadline_, calls_, amount_));
}

function try_debtLocker_pullFunds(address debtLocker_, address liquidator_, address token_, address destination_, uint256 amount_) external returns (bool ok_) {
( ok_, ) = debtLocker_.call(abi.encodeWithSelector(IDebtLocker.pullFundsFromLiquidator.selector, liquidator_, token_, destination_, amount_));
}
}

function try_debtLocker_rejectNewTerms(
address debtLocker_,
address refinancer_,
uint256 deadline_,
bytes[] calldata calls_
) external returns (bool ok_) {
( ok_, ) = debtLocker_.call(abi.encodeWithSelector(IDebtLocker.rejectNewTerms.selector, refinancer_, deadline_, calls_));
}

function try_debtLocker_setAllowedSlippage(address debtLocker_, uint256 allowedSlippage_) external returns (bool ok_) {
( ok_, ) = debtLocker_.call(abi.encodeWithSelector(IDebtLocker.setAllowedSlippage.selector, allowedSlippage_));
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/mocks/Mocks.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.7;
import { ILiquidatorLike } from "../../../modules/liquidations/contracts/interfaces/Interfaces.sol";

import { ERC20Helper } from "../../../modules/erc20-helper/src/ERC20Helper.sol";
import { MockERC20 } from "../../../modules/erc20/src/test/mocks/MockERC20.sol";
import { MockERC20 } from "../../../modules/erc20/contracts/test/mocks/MockERC20.sol";

import { IDebtLocker } from "../../interfaces/IDebtLocker.sol";
import { IDebtLockerFactory } from "../../interfaces/IDebtLockerFactory.sol";
Expand Down
2 changes: 1 addition & 1 deletion modules/erc20-helper
Submodule erc20-helper updated 1 files
+31 −7 README.md
2 changes: 1 addition & 1 deletion modules/loan
Submodule loan updated from 21a6d7 to 58cbe5