Skip to content

Commit

Permalink
rebase w/ one failing test
Browse files Browse the repository at this point in the history
  • Loading branch information
0xgregthedev committed Nov 2, 2023
1 parent 97e6932 commit 687ef2e
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 43 deletions.
5 changes: 4 additions & 1 deletion src/LoanManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,10 @@ contract LoanManager is Ownable, ERC721, PausableNonReentrant {
loan = applyRefinanceConsiderationToLoan(loan, considerationPayment, carryPayment, pricingData);

_transferSpentItems(considerationPayment, lender, loan.issuer);
_transferSpentItems(carryPayment, lender, loan.originator);

if (carryPayment.length > 0) {
_transferSpentItems(carryPayment, loan.issuer, loan.custodian);
}

loan.issuer = lender;
loan.originator = address(0);
Expand Down
2 changes: 1 addition & 1 deletion test/StarPortTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ contract StarPortTest is BaseOrderTest {
}

function getRefinanceCaveat(LoanManager.Loan memory loan, bytes memory pricingData, address fulfiller)
external
public
returns (LoanManager.Loan memory)
{
(SpentItem[] memory considerationPayment, SpentItem[] memory carryPayment,) =
Expand Down
138 changes: 99 additions & 39 deletions test/integration-testing/TestCaveats.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import "starport-test/StarPortTest.sol";
import {DeepEq} from "starport-test/utils/DeepEq.sol";
import {MockCall} from "starport-test/utils/MockCall.sol";
import "forge-std/Test.sol";
import {StarPortLib, Actions} from "starport-core/lib/StarPortLib.sol";
import {StarPortLib, Actions, AdditionalTransfer} from "starport-core/lib/StarPortLib.sol";
import "forge-std/console.sol";

//Informational Finding:
//If you sign a caveat and submit the caveat as the borrower or lender, then it will not be invalidated
//Can the borrower refinance there own loan in this setup?
//With the current implementations, I think finding a valid refinance may be difficult

contract IntegrationTestCaveats is StarPortTest, DeepEq, MockCall {
event LogLoan(LoanManager.Loan loan);

function testOriginateWCaveats() public {
LoanManager.Loan memory loan = generateDefaultLoanTerms();

Expand All @@ -27,7 +29,7 @@ contract IntegrationTestCaveats is StarPortTest, DeepEq, MockCall {
_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.prank(loan.borrower);
LM.originate(new ConduitTransfer[](0), _emptyCaveat(), lenderCaveat, loan);
LM.originate(new AdditionalTransfer[](0), _emptyCaveat(), lenderCaveat, loan);
}

function testOriginateWCaveatsInvalidSalt() public {
Expand All @@ -45,24 +47,52 @@ contract IntegrationTestCaveats is StarPortTest, DeepEq, MockCall {
_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.startPrank(loan.issuer);
LM.originate(new ConduitTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);
LM.originate(new AdditionalTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);

vm.expectRevert(StarPortLib.InvalidSalt.selector);
LM.originate(new ConduitTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);
LM.originate(new AdditionalTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);
}

function testOriginateWCaveatsInvalidSaltManual() public {
vm.prank(lender.addr);
LM.invalidateCaveatSalt(msg.sig);
LoanManager.Loan memory loan = generateDefaultLoanTerms();

CaveatEnforcer.CaveatWithApproval memory borrowerCaveat = getBorrowerSignedCaveat({
details: BorrowerEnforcer.Details({loan: loan}),
signer: borrower,
salt: bytes32(0),
enforcer: address(borrowerEnforcer)
});
_setApprovalsForSpentItems(borrower.addr, loan.collateral);

_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.prank(borrower.addr);
LM.invalidateCaveatSalt(0);

vm.expectRevert(StarPortLib.InvalidSalt.selector);
newLoanWithDefaultTerms();
vm.prank(lender.addr);
LM.originate(new AdditionalTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);
}

function testOriginateWCaveatsIncrementedNonce() public {
vm.prank(lender.addr);
LoanManager.Loan memory loan = generateDefaultLoanTerms();

CaveatEnforcer.CaveatWithApproval memory borrowerCaveat = getBorrowerSignedCaveat({
details: BorrowerEnforcer.Details({loan: loan}),
signer: borrower,
salt: bytes32(0),
enforcer: address(borrowerEnforcer)
});
_setApprovalsForSpentItems(borrower.addr, loan.collateral);

_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.prank(borrower.addr);
LM.incrementCaveatNonce();

vm.expectRevert(LoanManager.InvalidCaveatSigner.selector);
newLoanWithDefaultTerms();
vm.prank(lender.addr);
LM.originate(new AdditionalTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);
}

function testOriginateWBorrowerApproval() public {
Expand All @@ -82,7 +112,7 @@ contract IntegrationTestCaveats is StarPortTest, DeepEq, MockCall {
vm.prank(loan.borrower);
LM.setOriginateApproval(address(0x5), LoanManager.ApprovalType.BORROWER);
vm.prank(address(0x5));
LM.originate(new ConduitTransfer[](0), _emptyCaveat(), lenderCaveat, loan);
LM.originate(new AdditionalTransfer[](0), _emptyCaveat(), lenderCaveat, loan);
}

function testOriginateWLenderApproval() public {
Expand All @@ -100,7 +130,7 @@ contract IntegrationTestCaveats is StarPortTest, DeepEq, MockCall {
vm.prank(lender.addr);
LM.setOriginateApproval(address(0x5), LoanManager.ApprovalType.LENDER);
vm.prank(address(0x5));
LM.originate(new ConduitTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);
LM.originate(new AdditionalTransfer[](0), borrowerCaveat, _emptyCaveat(), loan);
}

function testOriginateUnapprovedFulfiller() public {
Expand All @@ -124,75 +154,105 @@ contract IntegrationTestCaveats is StarPortTest, DeepEq, MockCall {
_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.prank(address(0x5));
LM.originate(new ConduitTransfer[](0), borrowerCaveat, lenderCaveat, loan);
LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan);
}

//Test Refinance with caveats
function testRefinanceWCaveats() public {
function testRefinanceWCaveatsInvalidSalt() public {
LoanManager.Loan memory loan = newLoanWithDefaultTerms();

CaveatEnforcer.CaveatWithApproval memory lenderCaveat = getLenderSignedCaveat({
details: LenderEnforcer.Details({loan: loan}),
signer: lender,
salt: bytes32(0),
enforcer: address(lenderEnforcer)
LenderEnforcer.Details memory details = LenderEnforcer.Details({
loan: LM.applyRefinanceConsiderationToLoan(loan, loan.debt, new SpentItem[](0), defaultPricingData)
});

_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.prank(loan.borrower);
mockIsValidRefinanceCall(loan.terms.pricing, new SpentItem[](0), new SpentItem[](0), new ConduitTransfer[](0));
LM.refinance(lender.addr, lenderCaveat, loan, "");
}

function testRefinanceWCaveatsInvalidSalt() public {
LoanManager.Loan memory loan = newLoanWithDefaultTerms();
loan.collateral[0] = _getERC20SpentItem(erc20s[0], 1000);
details.loan.issuer = lender.addr;
details.loan.originator = address(0);
details.loan.start = 0;

CaveatEnforcer.CaveatWithApproval memory lenderCaveat = getLenderSignedCaveat({
details: LenderEnforcer.Details({loan: loan}),
details: details,
signer: borrower,
salt: bytes32(msg.sig),
enforcer: address(borrowerEnforcer)
});

_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.warp(block.timestamp + 1);
mockIsValidRefinanceCall(loan.terms.pricing, loan.debt, new SpentItem[](0), new AdditionalTransfer[](0));
vm.expectRevert(StarPortLib.InvalidSalt.selector);
LM.refinance(lender.addr, lenderCaveat, loan, "");
}

function testRefinanceAsLender() public {
LoanManager.Loan memory loan = newLoanWithDefaultTerms();

address newLender = address(0x5);
allocateTokensAndApprovals(newLender, type(uint128).max);
_setApprovalsForSpentItems(newLender, loan.debt);

vm.warp(block.timestamp + 1);
vm.prank(newLender);
mockIsValidRefinanceCall(loan.terms.pricing, loan.debt, new SpentItem[](0), new AdditionalTransfer[](0));
LM.refinance(newLender, _emptyCaveat(), loan, defaultPricingData);
}

function testRefinanceWLenderApproval() public {
LoanManager.Loan memory loan = generateDefaultLoanTerms();
LoanManager.Loan memory loan = newLoanWithDefaultTerms();

_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.prank(lender.addr);
LM.setOriginateApproval(borrower.addr, LoanManager.ApprovalType.LENDER);

vm.warp(block.timestamp + 1);
vm.prank(borrower.addr);
mockIsValidRefinanceCall(loan.terms.pricing, new SpentItem[](0), new SpentItem[](0), new ConduitTransfer[](0));
LM.refinance(lender.addr, _emptyCaveat(), loan, "");
mockIsValidRefinanceCall(loan.terms.pricing, loan.debt, new SpentItem[](0), new AdditionalTransfer[](0));
LM.refinance(lender.addr, _emptyCaveat(), loan, defaultPricingData);
}

function testRefinanceUnapprovedFulfiller() public {
LoanManager.Loan memory loan = newLoanWithDefaultTerms();
LenderEnforcer.Details memory details = LenderEnforcer.Details({
loan: LM.applyRefinanceConsiderationToLoan(loan, loan.debt, new SpentItem[](0), defaultPricingData)
});

details.loan.issuer = lender.addr;
details.loan.originator = address(0);
details.loan.start = 0;

CaveatEnforcer.CaveatWithApproval memory lenderCaveat = getLenderSignedCaveat({
details: LenderEnforcer.Details({loan: loan}),
details: details,
signer: lender,
salt: bytes32(0),
enforcer: address(lenderEnforcer)
});

_setApprovalsForSpentItems(lender.addr, loan.debt);

vm.warp(block.timestamp + 1);

vm.prank(loan.borrower);
mockIsValidRefinanceCall(loan.terms.pricing, new SpentItem[](0), new SpentItem[](0), new ConduitTransfer[](0));
LM.refinance(lender.addr, lenderCaveat, loan, "");

mockIsValidRefinanceCall(loan.terms.pricing, loan.debt, new SpentItem[](0), new AdditionalTransfer[](0));

LM.refinance(lender.addr, lenderCaveat, loan, defaultPricingData);
}

//Test caveat enforcement revert
function testRefinanceCaveatFailure() public {
LoanManager.Loan memory loan = newLoanWithDefaultTerms();

CaveatEnforcer.CaveatWithApproval memory lenderCaveat = getLenderSignedCaveat({
details: LenderEnforcer.Details({loan: loan}),
signer: lender,
salt: bytes32(0),
enforcer: address(lenderEnforcer)
});

_setApprovalsForSpentItems(lender.addr, loan.debt);

//Test multiple caveats
vm.prank(loan.borrower);
mockIsValidRefinanceCall(loan.terms.pricing, loan.debt, new SpentItem[](0), new AdditionalTransfer[](0));
vm.expectRevert(LenderEnforcer.InvalidLoanTerms.selector);
LM.refinance(lender.addr, lenderCaveat, loan, defaultPricingData);
}
}
5 changes: 3 additions & 2 deletions test/utils/MockCall.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pragma solidity ^0.8.17;

import {ItemType, SpentItem, ReceivedItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {ConduitTransfer} from "seaport-types/src/conduit/lib/ConduitStructs.sol";
import {AdditionalTransfer} from "starport-core/lib/StarPortLib.sol";
import {TestBase} from "forge-std/Test.sol";
import {SettlementHook} from "src/hooks/SettlementHook.sol";
import {SettlementHandler} from "src/handlers/SettlementHandler.sol";
Expand All @@ -12,11 +12,12 @@ abstract contract MockCall is TestBase {
vm.mockCall(hook, abi.encodeWithSelector(SettlementHook.isActive.selector), abi.encode(status));
}


function mockIsValidRefinanceCall(
address pricing,
SpentItem[] memory considerationPayment,
SpentItem[] memory carryPayment,
ConduitTransfer[] memory additionalTransfers
AdditionalTransfer[] memory additionalTransfers
) public {
vm.mockCall(
pricing,
Expand Down

0 comments on commit 687ef2e

Please sign in to comment.