From 01e1c267e7a3fe83f2bda90a9bbb606cb35dc921 Mon Sep 17 00:00:00 2001 From: Joseph Delong Date: Fri, 3 Nov 2023 10:06:17 -0500 Subject: [PATCH] Feat/compound (#48) * feat: compound interest * feat: add tests and cleanup * format & snapshot --------- Co-authored-by: androolloyd --- .gas-snapshot | 180 +++++++++--------- src/LoanManager.sol | 68 +------ src/enforcers/AstariaV1LenderEnforcer.sol | 51 +++++ src/handlers/AstariaV1SettlementHandler.sol | 18 +- src/handlers/DutchAuctionHandler.sol | 16 +- src/lib/StarPortLib.sol | 122 ++++++++++-- src/pricing/BasePricing.sol | 2 +- src/pricing/CompoundInterestPricing.sol | 7 +- src/pricing/SimpleInterestPricing.sol | 3 +- test/AstariaV1Test.sol | 4 +- .../integration-testing/TestAstariaV1Loan.sol | 20 +- test/unit-testing/TestCompoundInterest.sol | 46 +++++ test/unit-testing/TestLoanManager.sol | 55 +----- test/unit-testing/TestV1Handler.sol | 6 +- 14 files changed, 334 insertions(+), 264 deletions(-) create mode 100644 src/enforcers/AstariaV1LenderEnforcer.sol create mode 100644 test/unit-testing/TestCompoundInterest.sol diff --git a/.gas-snapshot b/.gas-snapshot index 216e4604..d2ef4797 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,58 +1,62 @@ -DiffFuzzTestStarPortLib:testSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 880457, ~: 882299) -DiffFuzzTestStarPortLib:testUnboundSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 232905, ~: 237832) -IntegrationTestCaveats:testOriginateUnapprovedFulfiller() (gas: 341266) -IntegrationTestCaveats:testOriginateWBorrowerApproval() (gas: 296157) -IntegrationTestCaveats:testOriginateWCaveats() (gas: 272197) +DiffFuzzTestStarPortLib:testSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 880514, ~: 882644) +DiffFuzzTestStarPortLib:testUnboundSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 232893, ~: 237832) +IntegrationTestCaveats:testOriginateUnapprovedFulfiller() (gas: 341364) +IntegrationTestCaveats:testOriginateWBorrowerApproval() (gas: 296255) +IntegrationTestCaveats:testOriginateWCaveats() (gas: 272295) IntegrationTestCaveats:testOriginateWCaveatsIncrementedNonce() (gas: 200191) -IntegrationTestCaveats:testOriginateWCaveatsInvalidSalt() (gas: 257806) +IntegrationTestCaveats:testOriginateWCaveatsInvalidSalt() (gas: 257950) IntegrationTestCaveats:testOriginateWCaveatsInvalidSaltManual() (gas: 175868) -IntegrationTestCaveats:testOriginateWLenderApproval() (gas: 296276) -IntegrationTestCaveats:testRefinanceAsLender() (gas: 1056340) -IntegrationTestCaveats:testRefinanceCaveatFailure() (gas: 422075) -IntegrationTestCaveats:testRefinanceUnapprovedFulfiller() (gas: 479978) -IntegrationTestCaveats:testRefinanceWCaveatsInvalidSalt() (gas: 400966) -IntegrationTestCaveats:testRefinanceWLenderApproval() (gas: 423604) +IntegrationTestCaveats:testOriginateWLenderApproval() (gas: 296374) +IntegrationTestCaveats:testRefinanceAsLender() (gas: 1056510) +IntegrationTestCaveats:testRefinanceCaveatFailure() (gas: 422245) +IntegrationTestCaveats:testRefinanceUnapprovedFulfiller() (gas: 480148) +IntegrationTestCaveats:testRefinanceWCaveatsInvalidSalt() (gas: 401136) +IntegrationTestCaveats:testRefinanceWLenderApproval() (gas: 423774) PausableNonReentrantImpl:test() (gas: 2442) PausableNonReentrantImpl:testReentrancy() (gas: 2735) -TestAstariaV1Handler:testGetAuctionStart() (gas: 427553) -TestAstariaV1Handler:testGetAuctionStartNotStarted() (gas: 427126) -TestAstariaV1Handler:testGetCurrentAuctionPrice() (gas: 442408) -TestAstariaV1Handler:testGetCurrentAuctionPriceNoAuction() (gas: 430757) -TestAstariaV1Handler:testGetSettlementDutchAuctionSettlementAbove() (gas: 484940) -TestAstariaV1Handler:testGetSettlementFailedDutchAuction() (gas: 442731) -TestAstariaV1Handler:testGetSettlementLoanNotRecalled() (gas: 433233) -TestAstariaV1Handler:testV1SettlementHandlerExecute() (gas: 413740) -TestAstariaV1Handler:testV1SettlementHandlerValidate() (gas: 413852) -TestAstariaV1Handler:testV1SettlementHandlerValidateInvalidHandler() (gas: 413976) -TestAstariaV1Hook:testCannotRecallTwice() (gas: 569694) -TestAstariaV1Hook:testCannotWithdrawLoanHasNotBeenRefinanced() (gas: 419557) -TestAstariaV1Hook:testCannotWithdrawWithdrawDoesNotExist() (gas: 425996) -TestAstariaV1Hook:testGenerateRecallConsideration() (gas: 469070) -TestAstariaV1Hook:testInvalidRecallInvalidStakeType() (gas: 486195) -TestAstariaV1Hook:testInvalidRecallLoanDoesNotExist() (gas: 515422) -TestAstariaV1Hook:testIsActive() (gas: 426738) -TestAstariaV1Hook:testIsRecalledInsideWindow() (gas: 562926) -TestAstariaV1Hook:testIsRecalledOutsideWindow() (gas: 560827) -TestAstariaV1Hook:testRecallRateActiveRecall() (gas: 548487) -TestAstariaV1Hook:testRecallRateEmptyRecall() (gas: 424392) -TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallBase() (gas: 1016002) -TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLender() (gas: 719993) -TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLiquidation() (gas: 747659) +TestAstariaV1Handler:testGetAuctionStart() (gas: 433724) +TestAstariaV1Handler:testGetAuctionStartNotStarted() (gas: 433297) +TestAstariaV1Handler:testGetCurrentAuctionPrice() (gas: 448579) +TestAstariaV1Handler:testGetCurrentAuctionPriceNoAuction() (gas: 436928) +TestAstariaV1Handler:testGetSettlementDutchAuctionSettlementAbove() (gas: 490549) +TestAstariaV1Handler:testGetSettlementFailedDutchAuction() (gas: 448902) +TestAstariaV1Handler:testGetSettlementLoanNotRecalled() (gas: 439404) +TestAstariaV1Handler:testV1SettlementHandlerExecute() (gas: 419911) +TestAstariaV1Handler:testV1SettlementHandlerValidate() (gas: 420023) +TestAstariaV1Handler:testV1SettlementHandlerValidateInvalidHandler() (gas: 420147) +TestAstariaV1Hook:testCannotRecallTwice() (gas: 580637) +TestAstariaV1Hook:testCannotWithdrawLoanHasNotBeenRefinanced() (gas: 425728) +TestAstariaV1Hook:testCannotWithdrawWithdrawDoesNotExist() (gas: 432167) +TestAstariaV1Hook:testGenerateRecallConsideration() (gas: 481691) +TestAstariaV1Hook:testInvalidRecallInvalidStakeType() (gas: 507972) +TestAstariaV1Hook:testInvalidRecallLoanDoesNotExist() (gas: 523979) +TestAstariaV1Hook:testIsActive() (gas: 432909) +TestAstariaV1Hook:testIsRecalledInsideWindow() (gas: 571483) +TestAstariaV1Hook:testIsRecalledOutsideWindow() (gas: 569384) +TestAstariaV1Hook:testRecallRateActiveRecall() (gas: 557044) +TestAstariaV1Hook:testRecallRateEmptyRecall() (gas: 430563) +TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallBase() (gas: 1043573) +TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLender() (gas: 728313) +TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLiquidation() (gas: 767096) TestBorrowerEnforcer:testBERevertAdditionalTransfers() (gas: 73195) TestBorrowerEnforcer:testBERevertInvalidLoanTerms() (gas: 78316) TestBorrowerEnforcer:testBEValidLoanTerms() (gas: 69518) TestBorrowerEnforcer:testBEValidLoanTermsAnyIssuer() (gas: 69581) +TestCompoundInterest:testAmountMax() (gas: 65767) +TestCompoundInterest:testRateMax() (gas: 68106) +TestCompoundInterest:testRateTooLowOne() (gas: 73157) +TestCompoundInterest:testRateTooLowZero() (gas: 68419) TestCustodian:testCannotLazyMintTwice() (gas: 76589) TestCustodian:testCannotMintInvalidLoanInvalidCustodian() (gas: 66861) TestCustodian:testCannotMintInvalidLoanValidCustodian() (gas: 72392) TestCustodian:testCustodySelector() (gas: 2718590) TestCustodian:testDefaultCustodySelectorRevert() (gas: 70083) TestCustodian:testGenerateOrderInvalidHandlerExecution() (gas: 133022) -TestCustodian:testGenerateOrderRepay() (gas: 173924) -TestCustodian:testGenerateOrderRepayAsRepayApprovedBorrower() (gas: 199549) -TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNative() (gas: 868168) -TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNativeHandlerAuthorized() (gas: 793746) -TestCustodian:testGenerateOrderRepayERC1155WithRevert() (gas: 532529) +TestCustodian:testGenerateOrderRepay() (gas: 174635) +TestCustodian:testGenerateOrderRepayAsRepayApprovedBorrower() (gas: 200260) +TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNative() (gas: 869852) +TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNativeHandlerAuthorized() (gas: 794008) +TestCustodian:testGenerateOrderRepayERC1155WithRevert() (gas: 533358) TestCustodian:testGenerateOrderRepayInvalidHookAddress() (gas: 90307) TestCustodian:testGenerateOrderRepayInvalidHookReturnType() (gas: 84624) TestCustodian:testGenerateOrderRepayNotBorrower() (gas: 96398) @@ -69,11 +73,11 @@ TestCustodian:testNonPayableFunctions() (gas: 225770) TestCustodian:testOnlySeaport() (gas: 17895) TestCustodian:testPayableFunctions() (gas: 41667) TestCustodian:testPreviewOrderNoActiveLoan() (gas: 98628) -TestCustodian:testPreviewOrderRepay() (gas: 225769) +TestCustodian:testPreviewOrderRepay() (gas: 227191) TestCustodian:testPreviewOrderSettlement() (gas: 183136) TestCustodian:testPreviewOrderSettlementInvalidFufliller() (gas: 100751) TestCustodian:testPreviewOrderSettlementInvalidRepayer() (gas: 106676) -TestCustodian:testRatifyOrder() (gas: 180093) +TestCustodian:testRatifyOrder() (gas: 180804) TestCustodian:testSeaportMetadata() (gas: 8567) TestCustodian:testSetRepayApproval() (gas: 37861) TestCustodian:testSupportsInterface() (gas: 9428) @@ -85,67 +89,65 @@ TestLenderEnforcer:testLERevertInvalidLoanTerms() (gas: 78341) TestLenderEnforcer:testLEValidLoanTerms() (gas: 69496) TestLenderEnforcer:testLEValidLoanTermsAnyBorrower() (gas: 69494) TestLenderEnforcer:testLEValidLoanTermsWithAdditionalTransfers() (gas: 70740) -TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 555315) -TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 542898) -TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 573042) -TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 562881) -TestLoanCombinations:testLoanSimpleInterestEnglishFixed() (gas: 568355) -TestLoanManager:testActive() (gas: 67048) -TestLoanManager:testAdditionalTransfers() (gas: 295623) -TestLoanManager:testCannotIssueSameLoanTwice() (gas: 336855) +TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 556835) +TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 544464) +TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 574562) +TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 564401) +TestLoanCombinations:testLoanSimpleInterestEnglishFixed() (gas: 569877) +TestLoanManager:testActive() (gas: 67003) +TestLoanManager:testAdditionalTransfers() (gas: 296003) +TestLoanManager:testCannotIssueSameLoanTwice() (gas: 337165) TestLoanManager:testCannotOriginateWhilePaused() (gas: 70834) TestLoanManager:testCannotSettleInvalidLoan() (gas: 72745) -TestLoanManager:testCannotSettleUnlessValidCustodian() (gas: 68816) -TestLoanManager:testCaveatEnforcerRevert() (gas: 124049) -TestLoanManager:testDefaultFeeRake() (gas: 355038) -TestLoanManager:testExoticDebtWithNoCaveatsNotAsBorrower() (gas: 371270) -TestLoanManager:testIncrementCaveatNonce() (gas: 34560) +TestLoanManager:testCannotSettleUnlessValidCustodian() (gas: 68838) +TestLoanManager:testCaveatEnforcerRevert() (gas: 124071) +TestLoanManager:testDefaultFeeRake() (gas: 355208) +TestLoanManager:testExoticDebtWithNoCaveatsNotAsBorrower() (gas: 371351) +TestLoanManager:testIncrementCaveatNonce() (gas: 34582) TestLoanManager:testInitializedFlagSetProperly() (gas: 65344) -TestLoanManager:testInvalidAmountCollateral() (gas: 157784) -TestLoanManager:testInvalidAmountCollateral721() (gas: 157949) -TestLoanManager:testInvalidAmountDebt() (gas: 182139) -TestLoanManager:testInvalidIdentifierDebt() (gas: 202133) -TestLoanManager:testInvalidItemType() (gas: 143832) -TestLoanManager:testInvalidTransferLengthCollateral() (gas: 166018) -TestLoanManager:testInvalidTransferLengthDebt() (gas: 170605) -TestLoanManager:testInvalidateCaveatSalt() (gas: 32830) +TestLoanManager:testInvalidAmountCollateral() (gas: 157920) +TestLoanManager:testInvalidAmountCollateral721() (gas: 157897) +TestLoanManager:testInvalidItemType() (gas: 143819) +TestLoanManager:testInvalidTransferLengthCollateral() (gas: 165976) +TestLoanManager:testInvalidTransferLengthDebt() (gas: 170546) +TestLoanManager:testInvalidateCaveatSalt() (gas: 32852) TestLoanManager:testIssued() (gas: 67216) -TestLoanManager:testName() (gas: 7206) -TestLoanManager:testNonDefaultCustodianCustodyCallFails() (gas: 195269) -TestLoanManager:testNonDefaultCustodianCustodyCallSuccess() (gas: 261010) +TestLoanManager:testName() (gas: 7228) +TestLoanManager:testNonDefaultCustodianCustodyCallFails() (gas: 195229) +TestLoanManager:testNonDefaultCustodianCustodyCallSuccess() (gas: 261108) TestLoanManager:testNonPayableFunctions() (gas: 180369) -TestLoanManager:testOverrideFeeRake() (gas: 348799) -TestLoanManager:testPause() (gas: 17164) +TestLoanManager:testOverrideFeeRake() (gas: 348919) +TestLoanManager:testPause() (gas: 17208) TestLoanManager:testSupportsInterface() (gas: 9181) -TestLoanManager:testSymbol() (gas: 7257) -TestLoanManager:testTokenNoCodeCollateral() (gas: 142648) -TestLoanManager:testTokenNoCodeDebt() (gas: 175748) -TestLoanManager:testTokenURI() (gas: 64879) +TestLoanManager:testSymbol() (gas: 7279) +TestLoanManager:testTokenNoCodeCollateral() (gas: 142676) +TestLoanManager:testTokenNoCodeDebt() (gas: 175694) +TestLoanManager:testTokenURI() (gas: 64923) TestLoanManager:testTokenURIInvalidLoan() (gas: 13296) TestLoanManager:testTransferFromFail() (gas: 80110) -TestLoanManager:testUnpause() (gas: 16199) -TestNewLoan:testBuyNowPayLater() (gas: 2832660) -TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 394514) +TestLoanManager:testUnpause() (gas: 16221) +TestNewLoan:testBuyNowPayLater() (gas: 2832994) +TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 394612) TestNewLoan:testNewLoanERC721CollateralLessDebtThanOffered() (gas: 2348) TestNewLoan:testNewLoanRefinanceNew() (gas: 207) -TestNewLoan:testNewLoanViaOriginatorBorrowerApprovalAndLenderApproval() (gas: 301900) -TestNewLoan:testNewLoanViaOriginatorLenderApproval() (gas: 356531) -TestNewLoan:testSettleLoan() (gas: 630607) +TestNewLoan:testNewLoanViaOriginatorBorrowerApprovalAndLenderApproval() (gas: 301998) +TestNewLoan:testNewLoanViaOriginatorLenderApproval() (gas: 356629) +TestNewLoan:testSettleLoan() (gas: 628057) TestPausableNonReentrant:testNotOwner() (gas: 21254) TestPausableNonReentrant:testPauseAndUnpause() (gas: 22555) TestPausableNonReentrant:testReentrancy() (gas: 15360) TestPausableNonReentrant:testUnpauseWhenNotPaused() (gas: 12582) TestRefStarPortLib:testSpentToReceived() (gas: 13315) TestRefStarPortLib:testValidateSalt(address,bytes32) (runs: 256, μ: 33865, ~: 33865) -TestRepayLoan:testRepayLoanApprovedRepayer() (gas: 646307) -TestRepayLoan:testRepayLoanBase() (gas: 582601) -TestRepayLoan:testRepayLoanGenerateOrderNotSeaport() (gas: 402435) -TestRepayLoan:testRepayLoanInSettlement() (gas: 545252) -TestRepayLoan:testRepayLoanInvalidRepayer() (gas: 562730) -TestRepayLoan:testRepayLoanThatDoesNotExist() (gas: 851564) -TestSimpleInterestPricing:test_calculateInterest() (gas: 780091) -TestSimpleInterestPricing:test_getPaymentConsideration() (gas: 862975) -TestSimpleInterestPricing:test_isValidRefinance() (gas: 857743) +TestRepayLoan:testRepayLoanApprovedRepayer() (gas: 649261) +TestRepayLoan:testRepayLoanBase() (gas: 585555) +TestRepayLoan:testRepayLoanGenerateOrderNotSeaport() (gas: 402533) +TestRepayLoan:testRepayLoanInSettlement() (gas: 549847) +TestRepayLoan:testRepayLoanInvalidRepayer() (gas: 564256) +TestRepayLoan:testRepayLoanThatDoesNotExist() (gas: 856651) +TestSimpleInterestPricing:test_calculateInterest() (gas: 808104) +TestSimpleInterestPricing:test_getPaymentConsideration() (gas: 889542) +TestSimpleInterestPricing:test_isValidRefinance() (gas: 883589) TestStarPortLib:testSpentToReceived() (gas: 13315) TestStarPortLib:testValidateSalt(address,bytes32) (runs: 256, μ: 33865, ~: 33865) TestStrategistOriginator:testEncodeWithAccountCounter() (gas: 12307) @@ -159,6 +161,6 @@ TestStrategistOriginator:testInvalidDebtAmountAskingMoreThanOffered() (gas: 2066 TestStrategistOriginator:testInvalidDebtAmountOfferingZero() (gas: 187017) TestStrategistOriginator:testInvalidDebtAmountRequestingZero() (gas: 206893) TestStrategistOriginator:testInvalidDebtLength() (gas: 205520) -TestStrategistOriginator:testInvalidOffer() (gas: 398913) +TestStrategistOriginator:testInvalidOffer() (gas: 399011) TestStrategistOriginator:testInvalidSigner() (gas: 208731) TestStrategistOriginator:testSetStrategist() (gas: 17818) \ No newline at end of file diff --git a/src/LoanManager.sol b/src/LoanManager.sol index 56c6ffb1..a0879ca7 100644 --- a/src/LoanManager.sol +++ b/src/LoanManager.sol @@ -117,11 +117,6 @@ contract LoanManager is ERC721, PausableNonReentrant { error InvalidRefinance(); error InvalidCustodian(); error InvalidLoan(); - error InvalidItemAmount(); - error InvalidItemIdentifier(); //must be zero for ERC20's - error InvalidItemTokenNoCode(); - error InvalidItemType(); - error InvalidTransferLength(); error CannotTransferLoans(); error AdditionalTransferError(); error LoanExists(); @@ -198,17 +193,17 @@ contract LoanManager is ERC721, PausableNonReentrant { _validateAndEnforceCaveats(lenderCaveat, issuer, additionalTransfers, loan); } - _transferSpentItems(loan.collateral, borrower, loan.custodian); + StarPortLib.transferSpentItems(loan.collateral, borrower, loan.custodian, true); _callCustody(loan); if (feeRecipient == address(0)) { - _transferSpentItems(loan.debt, issuer, borrower); + StarPortLib.transferSpentItems(loan.debt, issuer, borrower, false); } else { (SpentItem[] memory feeItems, SpentItem[] memory sentToBorrower) = _feeRake(loan.debt); if (feeItems.length > 0) { - _transferSpentItems(feeItems, issuer, feeRecipient); + StarPortLib.transferSpentItems(feeItems, issuer, feeRecipient, false); } - _transferSpentItems(sentToBorrower, issuer, borrower); + StarPortLib.transferSpentItems(sentToBorrower, issuer, borrower, false); } if (additionalTransfers.length > 0) { @@ -235,10 +230,9 @@ contract LoanManager is ERC721, PausableNonReentrant { _settle(loan); loan = applyRefinanceConsiderationToLoan(loan, considerationPayment, carryPayment, pricingData); - _transferSpentItems(considerationPayment, lender, loan.issuer); - + StarPortLib.transferSpentItems(considerationPayment, lender, loan.issuer, false); if (carryPayment.length > 0) { - _transferSpentItems(carryPayment, lender, loan.originator); + StarPortLib.transferSpentItems(carryPayment, lender, loan.originator, false); } loan.issuer = lender; @@ -378,56 +372,6 @@ contract LoanManager is ERC721, PausableNonReentrant { } } - function _transferItem( - ItemType itemType, - address token, - uint256 identifier, - uint256 amount, - address from, - address to - ) internal { - if (token.code.length == 0) { - revert InvalidItemTokenNoCode(); - } - if (amount > 0) { - if (itemType == ItemType.ERC20) { - if (identifier > 0) { - revert InvalidItemIdentifier(); - } - SafeTransferLib.safeTransferFrom(token, from, to, amount); - } else if (itemType == ItemType.ERC721) { - // erc721 transfer - if (amount > 1) { - revert InvalidItemAmount(); - } - ERC721(token).transferFrom(from, to, identifier); - } else if (itemType == ItemType.ERC1155) { - // erc1155 transfer - ERC1155(token).safeTransferFrom(from, to, identifier, amount, new bytes(0)); - } else { - revert InvalidItemType(); - } - } else { - revert InvalidItemAmount(); - } - } - - function _transferSpentItems(SpentItem[] memory transfers, address from, address to) internal { - if (transfers.length > 0) { - uint256 i = 0; - for (i; i < transfers.length;) { - _transferItem( - transfers[i].itemType, transfers[i].token, transfers[i].identifier, transfers[i].amount, from, to - ); - unchecked { - ++i; - } - } - } else { - revert InvalidTransferLength(); - } - } - function hashCaveatWithSaltAndNonce(address validator, bytes32 salt, CaveatEnforcer.Caveat[] calldata caveat) public view diff --git a/src/enforcers/AstariaV1LenderEnforcer.sol b/src/enforcers/AstariaV1LenderEnforcer.sol new file mode 100644 index 00000000..0aee8586 --- /dev/null +++ b/src/enforcers/AstariaV1LenderEnforcer.sol @@ -0,0 +1,51 @@ +pragma solidity ^0.8.17; + +import {LenderEnforcer} from "starport-core/enforcers/LenderEnforcer.sol"; +import {AdditionalTransfer} from "starport-core/lib/StarPortLib.sol"; +import {LoanManager} from "starport-core/LoanManager.sol"; +import {BasePricing} from "starport-core/pricing/BasePricing.sol"; +import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; +import {StarPortLib} from "starport-core/lib/StarPortLib.sol"; +import "forge-std/console2.sol"; + +contract AstariaV1LenderEnforcer is LenderEnforcer { + using FixedPointMathLib for uint256; + using FixedPointMathLib for int256; + + error LoanAmountExceedsMaxAmount(); + error LoanAmountExceedsMaxRate(); + error InterestAccrualRoundingMinimum(); + + int256 constant MAX_SIGNED_INT = 2 ** 255 - 1; + uint256 constant MAX_UNSIGNED_INT = 2 ** 256 - 1; + + uint256 constant MAX_AMOUNT = 1e27; // 1_000_000_000 ether + uint256 constant MAX_COMBINED_RATE_AND_DURATION = MAX_UNSIGNED_INT / MAX_AMOUNT; + int256 constant MAX_DURATION = int256(3 * 365 * 1 days); // 3 years + // int256 immutable MAX_RATE = int256(MAX_COMBINED_RATE_AND_DURATION).lnWad() / MAX_DURATION; // 780371100103 (IPR), 24.609783012848208000 (WAD), 2460.9783012848208000% (Percentage APY) + int256 constant MAX_RATE = int256(780371100103); + + function validate( + AdditionalTransfer[] calldata additionalTransfers, + LoanManager.Loan calldata loan, + bytes calldata caveatData + ) public view virtual override { + BasePricing.Details memory pricingDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details)); + + if (loan.debt[0].amount > MAX_AMOUNT) { + revert LoanAmountExceedsMaxAmount(); + } + + if (pricingDetails.rate > uint256(MAX_SIGNED_INT) || int256(pricingDetails.rate) > MAX_RATE) { + revert LoanAmountExceedsMaxRate(); + } + + // calculate interest for 1 second of time + uint256 interest = StarPortLib.calculateCompoundInterest(1, loan.debt[0].amount, pricingDetails.rate); + if (interest == 0) { + // interest does not accrue at least 1 wei per second + revert InterestAccrualRoundingMinimum(); + } + super.validate(additionalTransfers, loan, caveatData); + } +} diff --git a/src/handlers/AstariaV1SettlementHandler.sol b/src/handlers/AstariaV1SettlementHandler.sol index edeed16a..214914dd 100644 --- a/src/handlers/AstariaV1SettlementHandler.sol +++ b/src/handlers/AstariaV1SettlementHandler.sol @@ -9,6 +9,7 @@ import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; import {Pricing} from "starport-core/pricing/Pricing.sol"; import {BasePricing} from "starport-core/pricing/BasePricing.sol"; +import "forge-std/console2.sol"; contract AstariaV1SettlementHandler is DutchAuctionHandler { using {StarPortLib.getId} for LoanManager.Loan; @@ -96,23 +97,12 @@ contract AstariaV1SettlementHandler is DutchAuctionHandler { uint256 carry = interest.mulWad(pricingDetails.carryRate); - if (loan.debt[0].amount + interest <= settlementPrice) { + if (carry > 0 && loan.debt[0].amount + interest - carry < settlementPrice) { + uint256 excess = settlementPrice - loan.debt[0].amount + interest - carry; consideration[i] = ReceivedItem({ itemType: loan.debt[0].itemType, identifier: loan.debt[0].identifier, - amount: carry, - token: loan.debt[0].token, - recipient: payable(loan.originator) - }); - settlementPrice -= consideration[i].amount; - unchecked { - ++i; - } - } else if (loan.debt[0].amount + interest - carry <= settlementPrice) { - consideration[i] = ReceivedItem({ - itemType: loan.debt[0].itemType, - identifier: loan.debt[0].identifier, - amount: (settlementPrice - loan.debt[0].amount + interest - carry), + amount: (excess > carry) ? carry : excess, token: loan.debt[0].token, recipient: payable(loan.originator) }); diff --git a/src/handlers/DutchAuctionHandler.sol b/src/handlers/DutchAuctionHandler.sol index 37467cb1..015e8bee 100644 --- a/src/handlers/DutchAuctionHandler.sol +++ b/src/handlers/DutchAuctionHandler.sol @@ -66,23 +66,13 @@ abstract contract DutchAuctionHandler is SettlementHandler, AmountDeriver { uint256 carry = interest.mulWad(pricingDetails.carryRate); - if (loan.debt[0].amount + interest <= settlementPrice) { + if (carry > 0 && loan.debt[0].amount + interest - carry < settlementPrice) { consideration = new ReceivedItem[](2); + uint256 excess = settlementPrice - loan.debt[0].amount + interest - carry; consideration[0] = ReceivedItem({ itemType: loan.debt[0].itemType, identifier: loan.debt[0].identifier, - amount: carry, - token: loan.debt[0].token, - recipient: payable(loan.originator) - }); - - settlementPrice -= consideration[0].amount; - } else if (loan.debt[0].amount + interest - carry <= settlementPrice) { - consideration = new ReceivedItem[](2); - consideration[0] = ReceivedItem({ - itemType: loan.debt[0].itemType, - identifier: loan.debt[0].identifier, - amount: (settlementPrice - loan.debt[0].amount + interest - carry), + amount: (excess > carry) ? carry : excess, token: loan.debt[0].token, recipient: payable(loan.originator) }); diff --git a/src/lib/StarPortLib.sol b/src/lib/StarPortLib.sol index 513c83b3..6c37772a 100644 --- a/src/lib/StarPortLib.sol +++ b/src/lib/StarPortLib.sol @@ -7,6 +7,8 @@ import {ERC721} from "solady/src/tokens/ERC721.sol"; import {ERC20} from "solady/src/tokens/ERC20.sol"; import {ERC1155} from "solady/src/tokens/ERC1155.sol"; import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol"; +import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; +import "forge-std/console2.sol"; enum Actions { Nothing, @@ -24,14 +26,22 @@ struct AdditionalTransfer { } library StarPortLib { + using FixedPointMathLib for uint256; + using FixedPointMathLib for int256; + error InvalidSalt(); error InvalidItemAmount(); error NativeAssetsNotSupported(); + error InvalidItemTokenNoCode(); + error InvalidItemIdentifier(); //must be zero for ERC20's + error InvalidItemType(); + error InvalidTransferLength(); uint256 internal constant _INVALID_SALT = 0x81e69d9b00000000000000000000000000000000000000000000000000000000; uint256 internal constant ONE_WORD = 0x20; uint256 internal constant CUSTODIAN_WORD_OFFSET = 0x40; + int256 constant NATURAL_NUMBER_SIGNED_WAD = int256(2718281828459045235); function getAction(bytes calldata data) internal pure returns (Actions action) { assembly { @@ -245,32 +255,108 @@ library StarPortLib { function transferAdditionalTransfers(AdditionalTransfer[] memory transfers) internal { uint256 i = 0; - uint256 amount = 0; for (i; i < transfers.length;) { - amount = transfers[i].amount; - if (amount > 0) { - if (transfers[i].itemType == ItemType.ERC20) { - // erc20 transfer - - SafeTransferLib.safeTransferFrom(transfers[i].token, transfers[i].from, transfers[i].to, amount); - } else if (transfers[i].itemType == ItemType.ERC721) { - // erc721 transfer - if (amount > 1) { - revert InvalidItemAmount(); - } - ERC721(transfers[i].token).transferFrom(transfers[i].from, transfers[i].to, transfers[i].identifier); - } else if (transfers[i].itemType == ItemType.ERC1155) { - // erc1155 transfer + if (transfers[i].token.code.length == 0) { + revert InvalidItemTokenNoCode(); + } + if (transfers[i].itemType == ItemType.ERC20) { + // erc20 transfer + if (transfers[i].amount > 0) { + SafeTransferLib.safeTransferFrom( + transfers[i].token, transfers[i].from, transfers[i].to, transfers[i].amount + ); + } + } else if (transfers[i].itemType == ItemType.ERC721) { + // erc721 transfer + ERC721(transfers[i].token).transferFrom(transfers[i].from, transfers[i].to, transfers[i].identifier); + } else if (transfers[i].itemType == ItemType.ERC1155) { + // erc1155 transfer + if (transfers[i].amount > 0) { ERC1155(transfers[i].token).safeTransferFrom( - transfers[i].from, transfers[i].to, transfers[i].identifier, amount, new bytes(0) + transfers[i].from, transfers[i].to, transfers[i].identifier, transfers[i].amount, new bytes(0) ); - } else { - revert NativeAssetsNotSupported(); } + } else { + revert NativeAssetsNotSupported(); } unchecked { ++i; } } } + + function calculateCompoundInterest( + uint256 delta_t, + uint256 amount, + uint256 rate // expressed as SPR seconds per rate + ) public pure returns (uint256) { + return amount.mulWad(uint256(NATURAL_NUMBER_SIGNED_WAD.powWad(int256(rate * delta_t)))) - amount; + } + + function calculateSimpleInterest( + uint256 delta_t, + uint256 amount, + uint256 rate // expressed as SPR seconds per rate + ) public pure returns (uint256) { + return (delta_t * rate).mulWad(amount); + } + + function _transferItem( + ItemType itemType, + address token, + uint256 identifier, + uint256 amount, + address from, + address to, + bool safe + ) internal { + if (token.code.length == 0) { + revert InvalidItemTokenNoCode(); + } + if (itemType == ItemType.ERC20) { + if (identifier > 0 && safe) { + revert InvalidItemIdentifier(); + } + if (amount == 0 && safe) { + revert InvalidItemAmount(); + } + SafeTransferLib.safeTransferFrom(token, from, to, amount); + } else if (itemType == ItemType.ERC721) { + if (amount != 1 && safe) { + revert InvalidItemAmount(); + } + // erc721 transfer + ERC721(token).transferFrom(from, to, identifier); + } else if (itemType == ItemType.ERC1155) { + if (amount == 0 && safe) { + revert InvalidItemAmount(); + } + // erc1155 transfer + ERC1155(token).safeTransferFrom(from, to, identifier, amount, new bytes(0)); + } else { + revert InvalidItemType(); + } + } + + function transferSpentItems(SpentItem[] memory transfers, address from, address to, bool safe) internal { + if (transfers.length > 0) { + uint256 i = 0; + for (i; i < transfers.length;) { + _transferItem( + transfers[i].itemType, + transfers[i].token, + transfers[i].identifier, + transfers[i].amount, + from, + to, + safe + ); + unchecked { + ++i; + } + } + } else { + revert InvalidTransferLength(); + } + } } diff --git a/src/pricing/BasePricing.sol b/src/pricing/BasePricing.sol index 17b79767..4ee479cb 100644 --- a/src/pricing/BasePricing.sol +++ b/src/pricing/BasePricing.sol @@ -89,7 +89,7 @@ abstract contract BasePricing is Pricing { returns (uint256) { uint256 delta_t = end - start; - return calculateInterest(delta_t, rate, loan.debt[index].amount); + return calculateInterest(delta_t, loan.debt[index].amount, rate); } function calculateInterest( diff --git a/src/pricing/CompoundInterestPricing.sol b/src/pricing/CompoundInterestPricing.sol index ac88ec4f..390e6ee0 100644 --- a/src/pricing/CompoundInterestPricing.sol +++ b/src/pricing/CompoundInterestPricing.sol @@ -2,17 +2,16 @@ pragma solidity ^0.8.17; import {LoanManager} from "starport-core/LoanManager.sol"; import {BasePricing} from "starport-core/pricing/BasePricing.sol"; -import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; import {BaseRecallPricing} from "starport-core/pricing/BaseRecallPricing.sol"; +import {StarPortLib} from "starport-core/lib/StarPortLib.sol"; abstract contract CompoundInterestPricing is BaseRecallPricing { - using FixedPointMathLib for uint256; - function calculateInterest( uint256 delta_t, uint256 amount, uint256 rate // expressed as SPR seconds per rate ) public pure override returns (uint256) { - return (delta_t * rate).mulWad(amount); + // return (delta_t * rate).mulWad(amount); + return StarPortLib.calculateCompoundInterest(delta_t, amount, rate); } } diff --git a/src/pricing/SimpleInterestPricing.sol b/src/pricing/SimpleInterestPricing.sol index 071a7d59..1c78c35d 100644 --- a/src/pricing/SimpleInterestPricing.sol +++ b/src/pricing/SimpleInterestPricing.sol @@ -26,6 +26,7 @@ import {LoanManager} from "starport-core/LoanManager.sol"; import {Pricing} from "starport-core/pricing/Pricing.sol"; import {AdditionalTransfer} from "starport-core/lib/StarPortLib.sol"; import {SpentItem, ReceivedItem} from "seaport-types/src/lib/ConsiderationStructs.sol"; +import {StarPortLib} from "starport-core/lib/StarPortLib.sol"; contract SimpleInterestPricing is BasePricing { using FixedPointMathLib for uint256; @@ -37,7 +38,7 @@ contract SimpleInterestPricing is BasePricing { uint256 amount, uint256 rate // expressed as SPR seconds per rate ) public pure override returns (uint256) { - return (delta_t * rate).mulWad(amount); + return StarPortLib.calculateSimpleInterest(delta_t, amount, rate); } function isValidRefinance(LoanManager.Loan memory loan, bytes memory newPricingData, address caller) diff --git a/test/AstariaV1Test.sol b/test/AstariaV1Test.sol index d194ca2c..d7a33d96 100644 --- a/test/AstariaV1Test.sol +++ b/test/AstariaV1Test.sol @@ -12,7 +12,7 @@ import {AstariaV1SettlementHook} from "starport-core/hooks/AstariaV1SettlementHo import {BaseRecall} from "starport-core/hooks/BaseRecall.sol"; import {AstariaV1SettlementHandler} from "starport-core/handlers/AstariaV1SettlementHandler.sol"; -import {LenderEnforcer} from "starport-core/enforcers/LenderEnforcer.sol"; +import {AstariaV1LenderEnforcer} from "starport-core/enforcers/AstariaV1LenderEnforcer.sol"; import {BorrowerEnforcer} from "starport-core/enforcers/BorrowerEnforcer.sol"; // import "forge-std/console2.sol"; import {CaveatEnforcer} from "starport-core/enforcers/CaveatEnforcer.sol"; @@ -31,6 +31,8 @@ contract AstariaV1Test is StarPortTest { handler = new AstariaV1SettlementHandler(LM); hook = new AstariaV1SettlementHook(LM); + lenderEnforcer = new AstariaV1LenderEnforcer(); + vm.startPrank(recaller.addr); erc20s[0].approve(address(hook), 1e18); vm.stopPrank(); diff --git a/test/integration-testing/TestAstariaV1Loan.sol b/test/integration-testing/TestAstariaV1Loan.sol index 5bde741f..40bf670a 100644 --- a/test/integration-testing/TestAstariaV1Loan.sol +++ b/test/integration-testing/TestAstariaV1Loan.sol @@ -74,7 +74,7 @@ contract TestAstariaV1Loan is AstariaV1Test { stake = BasePricing(address(pricing)).calculateInterest( details.recallStakeDuration, loan.debt[0].amount, pricingDetails.rate ); - assertEq(balanceBefore, balanceAfter + stake, "Recaller balance not transfered correctly"); + assertEq(balanceBefore - stake, balanceAfter, "Recaller balance not transfered correctly"); assertEq( recallContractBalanceBefore + stake, recallContractBalanceAfter, @@ -153,15 +153,14 @@ contract TestAstariaV1Loan is AstariaV1Test { uint256 delta_t = block.timestamp - loan.start; BasePricing.Details memory pricingDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details)); - uint256 interest = CompoundInterestPricing(address(pricing)).calculateInterest( - delta_t, loan.debt[0].amount, pricingDetails.rate - ); + uint256 interest = + BasePricing(address(pricing)).calculateInterest(delta_t, loan.debt[0].amount, pricingDetails.rate); { uint256 oldLenderAfter = erc20s[0].balanceOf(lender.addr); assertEq( oldLenderAfter, - oldLenderBefore + loan.debt[0].amount + interest.mulWad(1e18 - pricingDetails.carryRate), + oldLenderBefore + loan.debt[0].amount + interest.mulWadUp(1e18 - pricingDetails.carryRate), "Payment to old lender calculated incorrectly" ); } @@ -347,12 +346,14 @@ contract TestAstariaV1Loan is AstariaV1Test { _createLoan721Collateral20Debt({lender: lender.addr, borrowAmount: 1e18, terms: terms}); uint256 loanId = loan.getId(); + uint256 elapsedTime; uint256 stake; { uint256 balanceBefore = erc20s[0].balanceOf(recaller.addr); uint256 recallContractBalanceBefore = erc20s[0].balanceOf(address(hook)); BaseRecall.Details memory details = abi.decode(loan.terms.hookData, (BaseRecall.Details)); vm.warp(block.timestamp + details.honeymoon); + elapsedTime += details.honeymoon; vm.startPrank(recaller.addr); BaseRecall recallContract = BaseRecall(address(hook)); @@ -366,7 +367,7 @@ contract TestAstariaV1Loan is AstariaV1Test { stake = BasePricing(address(pricing)).calculateInterest( details.recallStakeDuration, loan.debt[0].amount, pricingDetails.rate ); - assertEq(balanceBefore, balanceAfter + stake, "Recaller balance not transfered correctly"); + assertEq(balanceBefore - stake, balanceAfter, "Recaller balance not transfered correctly"); assertEq( recallContractBalanceBefore + stake, recallContractBalanceAfter, @@ -378,7 +379,7 @@ contract TestAstariaV1Loan is AstariaV1Test { BaseRecall.Details memory details = abi.decode(loan.terms.hookData, (BaseRecall.Details)); // warp past the end of the recall window vm.warp(block.timestamp + details.recallWindow + 1); - + elapsedTime += (details.recallWindow + 1); OfferItem[] memory repayOffering = new OfferItem[]( loan.collateral.length ); @@ -405,7 +406,10 @@ contract TestAstariaV1Loan is AstariaV1Test { ); assertEq(restricted, address(0), "SettlementConsideration should be unrestricted"); { - uint256 carry = uint256(1643840372884797); + BasePricing.Details memory pricingDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details)); + uint256 interest = + StarPortLib.calculateCompoundInterest(elapsedTime, loan.debt[0].amount, pricingDetails.rate); + uint256 carry = interest.mulWad(pricingDetails.carryRate); uint256 settlementPrice = 500 ether - carry; uint256 recallerReward = settlementPrice.mulWad(10e16); assertEq(settlementConsideration[0].amount, carry, "Settlement consideration for carry incorrect"); diff --git a/test/unit-testing/TestCompoundInterest.sol b/test/unit-testing/TestCompoundInterest.sol new file mode 100644 index 00000000..2d3bec48 --- /dev/null +++ b/test/unit-testing/TestCompoundInterest.sol @@ -0,0 +1,46 @@ +pragma solidity ^0.8.17; + +import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol"; +import {StarPortLib, AdditionalTransfer} from "starport-core/lib/StarPortLib.sol"; +import {LoanManager} from "starport-core/LoanManager.sol"; +import {AstariaV1LenderEnforcer} from "starport-core/enforcers/AstariaV1LenderEnforcer.sol"; + +import "starport-test/AstariaV1Test.sol"; + +contract TestCompoundInterest is AstariaV1Test, AstariaV1LenderEnforcer { + using FixedPointMathLib for uint256; + using FixedPointMathLib for int256; + + function testRateMax() public { + defaultPricingData = abi.encode(BasePricing.Details({carryRate: 0, rate: uint256(MAX_RATE) + 1})); + LoanManager.Loan memory loan = generateDefaultLoanTerms(); + vm.expectRevert(abi.encodeWithSelector(AstariaV1LenderEnforcer.LoanAmountExceedsMaxRate.selector)); + lenderEnforcer.validate(new AdditionalTransfer[](0), loan, ""); + } + + function testAmountMax() public { + LoanManager.Loan memory loan = generateDefaultLoanTerms(); + + loan.debt[0].amount = MAX_AMOUNT + 1; + vm.expectRevert(abi.encodeWithSelector(AstariaV1LenderEnforcer.LoanAmountExceedsMaxAmount.selector)); + lenderEnforcer.validate(new AdditionalTransfer[](0), loan, ""); + } + + function testRateTooLowZero() public { + defaultPricingData = abi.encode(BasePricing.Details({carryRate: 0, rate: 0})); + LoanManager.Loan memory loan = generateDefaultLoanTerms(); + vm.expectRevert(abi.encodeWithSelector(AstariaV1LenderEnforcer.InterestAccrualRoundingMinimum.selector)); + lenderEnforcer.validate(new AdditionalTransfer[](0), loan, ""); + } + + function testRateTooLowOne() public { + defaultPricingData = abi.encode(BasePricing.Details({carryRate: 0, rate: 1})); + LoanManager.Loan memory loan = generateDefaultLoanTerms(); + vm.expectRevert(abi.encodeWithSelector(AstariaV1LenderEnforcer.InterestAccrualRoundingMinimum.selector)); + lenderEnforcer.validate(new AdditionalTransfer[](0), loan, ""); + } + // function testPrecision() public { + // uint256 result = StarPortLib.calculateCompoundInterest(uint256(MAX_DURATION), MAX_AMOUNT, uint256(MAX_RATE)) + MAX_AMOUNT; + // assertEq(result, MAX_UNSIGNED_INT, "Precision bounds not matching"); + // } +} diff --git a/test/unit-testing/TestLoanManager.sol b/test/unit-testing/TestLoanManager.sol index 044c40d6..b30725eb 100644 --- a/test/unit-testing/TestLoanManager.sol +++ b/test/unit-testing/TestLoanManager.sol @@ -265,48 +265,7 @@ contract TestLoanManager is StarPortTest, DeepEq { _setApprovalsForSpentItems(loan.borrower, loan.collateral); _setApprovalsForSpentItems(loan.issuer, loan.debt); vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidTransferLength.selector)); - LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); - vm.stopPrank(); - } - - function testInvalidAmountDebt() public { - CaveatEnforcer.CaveatWithApproval memory borrowerCaveat; - - LoanManager.Loan memory loan = generateDefaultLoanTerms(); - loan.collateral[0].identifier = uint256(2); - loan.debt[0].amount = 0; - CaveatEnforcer.CaveatWithApproval memory lenderCaveat = getLenderSignedCaveat({ - details: LenderEnforcer.Details({loan: loan}), - signer: lender, - salt: bytes32(0), - enforcer: address(lenderEnforcer) - }); - _setApprovalsForSpentItems(loan.borrower, loan.collateral); - _setApprovalsForSpentItems(loan.issuer, loan.debt); - vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidItemAmount.selector)); - LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); - vm.stopPrank(); - } - - function testInvalidIdentifierDebt() public { - CaveatEnforcer.CaveatWithApproval memory borrowerCaveat; - - LoanManager.Loan memory loan = generateDefaultLoanTerms(); - loan.collateral[0].identifier = uint256(2); - loan.debt[0].identifier = uint256(2); - - CaveatEnforcer.CaveatWithApproval memory lenderCaveat = getLenderSignedCaveat({ - details: LenderEnforcer.Details({loan: loan}), - signer: lender, - salt: bytes32(0), - enforcer: address(lenderEnforcer) - }); - _setApprovalsForSpentItems(loan.borrower, loan.collateral); - _setApprovalsForSpentItems(loan.issuer, loan.debt); - vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidItemIdentifier.selector)); + vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidTransferLength.selector)); LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); vm.stopPrank(); } @@ -327,7 +286,7 @@ contract TestLoanManager is StarPortTest, DeepEq { _setApprovalsForSpentItems(loan.borrower, loan.collateral); _setApprovalsForSpentItems(loan.issuer, loan.debt); vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidItemAmount.selector)); + vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidItemAmount.selector)); LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); vm.stopPrank(); } @@ -347,7 +306,7 @@ contract TestLoanManager is StarPortTest, DeepEq { _setApprovalsForSpentItems(loan.borrower, loan.collateral); vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidItemType.selector)); + vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidItemType.selector)); LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); vm.stopPrank(); } @@ -367,7 +326,7 @@ contract TestLoanManager is StarPortTest, DeepEq { _setApprovalsForSpentItems(loan.borrower, loan.collateral); vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidItemTokenNoCode.selector)); + vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidItemTokenNoCode.selector)); LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); vm.stopPrank(); } @@ -389,7 +348,7 @@ contract TestLoanManager is StarPortTest, DeepEq { // _setApprovalsForSpentItems(loan.borrower, loan.collateral); // _setApprovalsForSpentItems(loan.issuer, loan.debt); vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidItemTokenNoCode.selector)); + vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidItemTokenNoCode.selector)); LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); vm.stopPrank(); } @@ -410,7 +369,7 @@ contract TestLoanManager is StarPortTest, DeepEq { _setApprovalsForSpentItems(loan.borrower, loan.collateral); _setApprovalsForSpentItems(loan.issuer, loan.debt); vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidItemAmount.selector)); + vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidItemAmount.selector)); LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); vm.stopPrank(); } @@ -429,7 +388,7 @@ contract TestLoanManager is StarPortTest, DeepEq { _setApprovalsForSpentItems(loan.borrower, loan.collateral); _setApprovalsForSpentItems(loan.issuer, loan.debt); vm.startPrank(loan.borrower); - vm.expectRevert(abi.encodeWithSelector(LoanManager.InvalidTransferLength.selector)); + vm.expectRevert(abi.encodeWithSelector(StarPortLib.InvalidTransferLength.selector)); LM.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan); vm.stopPrank(); } diff --git a/test/unit-testing/TestV1Handler.sol b/test/unit-testing/TestV1Handler.sol index 3468c634..a133a76f 100644 --- a/test/unit-testing/TestV1Handler.sol +++ b/test/unit-testing/TestV1Handler.sol @@ -103,11 +103,7 @@ contract TestAstariaV1Handler is AstariaV1Test, DeepEq { SettlementHandler(loan.terms.handler).getSettlement(loan); BaseRecall.Details memory hookDetails = abi.decode(loan.terms.hookData, (BaseRecall.Details)); - assertEq( - settlementConsideration[0].amount, - currentAuctionPrice - loan.debt[0].amount + interest - carry, - "Settlement 0 (originator payment) incorrect" - ); + assertEq(settlementConsideration[0].amount, carry, "Settlement 0 (originator payment) incorrect"); assertEq( settlementConsideration[1].amount, (currentAuctionPrice - settlementConsideration[0].amount).mulWad(hookDetails.recallerRewardRatio),