diff --git a/.gas-snapshot b/.gas-snapshot index 8c416940..12013561 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,68 +1,68 @@ -IntegrationTestCaveats:testInvalidCaveatLength() (gas: 130019) -IntegrationTestCaveats:testInvalidCaveats() (gas: 162299) -IntegrationTestCaveats:testOriginateUnapprovedFulfiller() (gas: 332433) -IntegrationTestCaveats:testOriginateWBorrowerApproval() (gas: 283300) -IntegrationTestCaveats:testOriginateWCaveatsAsBorrower() (gas: 308844) -IntegrationTestCaveats:testOriginateWCaveatsExpired() (gas: 159528) -IntegrationTestCaveats:testOriginateWCaveatsIncrementedNonce() (gas: 168043) -IntegrationTestCaveats:testOriginateWCaveatsInvalidSalt() (gas: 317621) -IntegrationTestCaveats:testOriginateWCaveatsInvalidSaltManual() (gas: 142201) -IntegrationTestCaveats:testOriginateWLenderApproval() (gas: 283614) -IntegrationTestCaveats:testRefinanceAsLender() (gas: 1053618) -IntegrationTestCaveats:testRefinanceCaveatFailure() (gas: 407763) -IntegrationTestCaveats:testRefinanceLoanStartAtBlockTimestampInvalidLoan() (gas: 347604) -IntegrationTestCaveats:testRefinanceUnapprovedFulfiller() (gas: 456421) -IntegrationTestCaveats:testRefinanceWCaveatsInvalidSalt() (gas: 377103) -IntegrationTestCaveats:testRefinanceWLenderApproval() (gas: 402755) -ModuleTesting:testFixedTermDutchAuctionSettlement() (gas: 437989) -ModuleTesting:testFixedTermDutchAuctionSettlementAuctionNotStarted() (gas: 441365) -ModuleTesting:testFixedTermDutchAuctionSettlementGetSettlementAuctionExpired() (gas: 440814) -ModuleTesting:testFixedTermDutchAuctionSettlementNotValid() (gas: 437023) -ModuleTesting:testFixedTermDutchAuctionSettlementValid() (gas: 437910) -ModuleTesting:testModuleValidation() (gas: 1274210) +IntegrationTestCaveats:testInvalidCaveatLength() (gas: 130086) +IntegrationTestCaveats:testInvalidCaveats() (gas: 162366) +IntegrationTestCaveats:testOriginateUnapprovedFulfiller() (gas: 332567) +IntegrationTestCaveats:testOriginateWBorrowerApproval() (gas: 283456) +IntegrationTestCaveats:testOriginateWCaveatsAsBorrower() (gas: 308978) +IntegrationTestCaveats:testOriginateWCaveatsExpired() (gas: 159595) +IntegrationTestCaveats:testOriginateWCaveatsIncrementedNonce() (gas: 168066) +IntegrationTestCaveats:testOriginateWCaveatsInvalidSalt() (gas: 317755) +IntegrationTestCaveats:testOriginateWCaveatsInvalidSaltManual() (gas: 142246) +IntegrationTestCaveats:testOriginateWLenderApproval() (gas: 283770) +IntegrationTestCaveats:testRefinanceAsLender() (gas: 1053752) +IntegrationTestCaveats:testRefinanceCaveatFailure() (gas: 407964) +IntegrationTestCaveats:testRefinanceLoanStartAtBlockTimestampInvalidLoan() (gas: 347805) +IntegrationTestCaveats:testRefinanceUnapprovedFulfiller() (gas: 456578) +IntegrationTestCaveats:testRefinanceWCaveatsInvalidSalt() (gas: 377260) +IntegrationTestCaveats:testRefinanceWLenderApproval() (gas: 402978) +ModuleTesting:testFixedTermDutchAuctionSettlement() (gas: 438123) +ModuleTesting:testFixedTermDutchAuctionSettlementAuctionNotStarted() (gas: 441499) +ModuleTesting:testFixedTermDutchAuctionSettlementGetSettlementAuctionExpired() (gas: 440948) +ModuleTesting:testFixedTermDutchAuctionSettlementNotValid() (gas: 437157) +ModuleTesting:testFixedTermDutchAuctionSettlementValid() (gas: 438044) +ModuleTesting:testModuleValidation() (gas: 1274344) PausableNonReentrantImpl:test() (gas: 2464) PausableNonReentrantImpl:testReentrancy() (gas: 2757) TestBorrowerEnforcer:testBERevertAdditionalTransfersFromBorrower() (gas: 76462) TestBorrowerEnforcer:testBERevertInvalidLoanTerms() (gas: 81160) TestBorrowerEnforcer:testBEValidLoanTerms() (gas: 72257) TestBorrowerEnforcer:testBEValidLoanTermsAnyIssuer() (gas: 72343) -TestCustodian:testCannotLazyMintTwice() (gas: 82167) +TestCustodian:testCannotLazyMintTwice() (gas: 82123) TestCustodian:testCannotMintInvalidLoanInvalidCustodian() (gas: 72495) -TestCustodian:testCannotMintInvalidLoanValidCustodian() (gas: 78005) -TestCustodian:testCustodianCannotBeAuthorized() (gas: 142164) +TestCustodian:testCannotMintInvalidLoanValidCustodian() (gas: 77961) +TestCustodian:testCustodianCannotBeAuthorized() (gas: 142120) TestCustodian:testCustodySelector() (gas: 2731962) TestCustodian:testDefaultCustodySelectorRevert() (gas: 72478) -TestCustodian:testGenerateOrderInvalidPostRepayment() (gas: 173046) -TestCustodian:testGenerateOrderInvalidPostSettlement() (gas: 163209) -TestCustodian:testGenerateOrderRepay() (gas: 177204) -TestCustodian:testGenerateOrderRepayAsRepayApprovedBorrower() (gas: 193690) -TestCustodian:testGenerateOrderRepayERC1155AndERC20() (gas: 875911) -TestCustodian:testGenerateOrderRepayERC1155AndERC20HandlerAuthorized() (gas: 804477) +TestCustodian:testGenerateOrderInvalidPostRepayment() (gas: 173134) +TestCustodian:testGenerateOrderInvalidPostSettlement() (gas: 163297) +TestCustodian:testGenerateOrderRepay() (gas: 177292) +TestCustodian:testGenerateOrderRepayAsRepayApprovedBorrower() (gas: 193778) +TestCustodian:testGenerateOrderRepayERC1155AndERC20() (gas: 876355) +TestCustodian:testGenerateOrderRepayERC1155AndERC20HandlerAuthorized() (gas: 804921) TestCustodian:testGenerateOrderRepayInvalidHookAddress() (gas: 97670) TestCustodian:testGenerateOrderRepayInvalidHookReturnType() (gas: 92031) TestCustodian:testGenerateOrderRepayNotBorrower() (gas: 106909) -TestCustodian:testGenerateOrderSettlement() (gas: 154920) -TestCustodian:testGenerateOrderSettlementHandlerAuthorized() (gas: 160317) -TestCustodian:testGenerateOrderSettlementNoActiveLoan() (gas: 163387) +TestCustodian:testGenerateOrderSettlement() (gas: 155008) +TestCustodian:testGenerateOrderSettlementHandlerAuthorized() (gas: 160405) +TestCustodian:testGenerateOrderSettlementNoActiveLoan() (gas: 163475) TestCustodian:testGenerateOrderSettlementUnauthorized() (gas: 101874) -TestCustodian:testGenerateOrdersWithLoanStartAtBlockTimestampInvalidLoan() (gas: 461569) +TestCustodian:testGenerateOrdersWithLoanStartAtBlockTimestampInvalidLoan() (gas: 461703) TestCustodian:testGetBorrower() (gas: 78621) -TestCustodian:testInvalidAction() (gas: 173552) -TestCustodian:testInvalidActionRepayInActiveLoan() (gas: 130196) -TestCustodian:testInvalidActionSettleActiveLoan() (gas: 130134) +TestCustodian:testInvalidAction() (gas: 173464) +TestCustodian:testInvalidActionRepayInActiveLoan() (gas: 130152) +TestCustodian:testInvalidActionSettleActiveLoan() (gas: 130090) TestCustodian:testInvalidEncodedData() (gas: 26160) -TestCustodian:testMintWithApprovalSetAsBorrower() (gas: 366668) +TestCustodian:testMintWithApprovalSetAsBorrower() (gas: 366758) TestCustodian:testMintWithApprovalSetAsBorrowerInvalidLoan() (gas: 64523) TestCustodian:testMintWithApprovalSetNotAuthorized() (gas: 66842) TestCustodian:testName() (gas: 7099) TestCustodian:testNonPayableFunctions() (gas: 215289) TestCustodian:testOnlySeaport() (gas: 17918) -TestCustodian:testPreviewOrderNoActiveLoan() (gas: 105732) -TestCustodian:testPreviewOrderRepay() (gas: 230187) -TestCustodian:testPreviewOrderSettlement() (gas: 191915) -TestCustodian:testPreviewOrderSettlementInvalidFufliller() (gas: 108293) -TestCustodian:testPreviewOrderSettlementInvalidRepayer() (gas: 117004) -TestCustodian:testRatifyOrder() (gas: 184025) +TestCustodian:testPreviewOrderNoActiveLoan() (gas: 105688) +TestCustodian:testPreviewOrderRepay() (gas: 230231) +TestCustodian:testPreviewOrderSettlement() (gas: 191959) +TestCustodian:testPreviewOrderSettlementInvalidFufliller() (gas: 108249) +TestCustodian:testPreviewOrderSettlementInvalidRepayer() (gas: 116960) +TestCustodian:testRatifyOrder() (gas: 184113) TestCustodian:testSeaportMetadata() (gas: 8644) TestCustodian:testSupportsInterface() (gas: 9428) TestCustodian:testSymbol() (gas: 7216) @@ -73,82 +73,83 @@ TestLenderEnforcer:testLERevertInvalidLoanTerms() (gas: 81096) TestLenderEnforcer:testLEValidLoanTerms() (gas: 72169) TestLenderEnforcer:testLEValidLoanTermsAnyBorrower() (gas: 72234) TestLenderEnforcer:testLEValidLoanTermsWithAdditionalTransfers() (gas: 73525) -TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 592756) -TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 599969) -TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 590120) -TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 580004) -TestNewLoan:testBuyNowPayLater() (gas: 3018395) -TestNewLoan:testNewLoanAs1271ProxyAccountSender() (gas: 874061) -TestNewLoan:testNewLoanAs1271ProxyAccountThirdPartyFiller() (gas: 885086) -TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 429501) -TestNewLoan:testNewLoanRefinance() (gas: 589921) -TestNewLoan:testNewLoanViaOriginatorBorrowerApprovalAndLenderApproval() (gas: 324498) -TestNewLoan:testNewLoanViaOriginatorLenderApproval() (gas: 383316) -TestNewLoan:testSettleLoan() (gas: 642059) +TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 592934) +TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 600147) +TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 590365) +TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 580182) +TestNewLoan:testBuyNowPayLater() (gas: 3018529) +TestNewLoan:testNewLoanAs1271ProxyAccountSender() (gas: 874195) +TestNewLoan:testNewLoanAs1271ProxyAccountThirdPartyFiller() (gas: 885220) +TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 429635) +TestNewLoan:testNewLoanRefinance() (gas: 590070) +TestNewLoan:testNewLoanViaOriginatorBorrowerApprovalAndLenderApproval() (gas: 324676) +TestNewLoan:testNewLoanViaOriginatorLenderApproval() (gas: 383472) +TestNewLoan:testSettleLoan() (gas: 642281) TestPausableNonReentrant:testNotOwner() (gas: 21276) TestPausableNonReentrant:testPauseAndUnpause() (gas: 22643) TestPausableNonReentrant:testReentrancy() (gas: 15404) TestPausableNonReentrant:testUnpauseWhenNotPaused() (gas: 12604) -TestRepayLoan:testRepayLoanApprovedRepayer() (gas: 667011) -TestRepayLoan:testRepayLoanBase() (gas: 599797) -TestRepayLoan:testRepayLoanGenerateOrderNotSeaport() (gas: 438643) -TestRepayLoan:testRepayLoanInSettlement() (gas: 585721) -TestRepayLoan:testRepayLoanInvalidRepayer() (gas: 603920) -TestRepayLoan:testRepayLoanThatDoesNotExist() (gas: 858461) +TestRepayLoan:testRepayLoanApprovedRepayer() (gas: 667145) +TestRepayLoan:testRepayLoanBase() (gas: 599975) +TestRepayLoan:testRepayLoanGenerateOrderNotSeaport() (gas: 438777) +TestRepayLoan:testRepayLoanInSettlement() (gas: 585811) +TestRepayLoan:testRepayLoanInvalidRepayer() (gas: 604010) +TestRepayLoan:testRepayLoanThatDoesNotExist() (gas: 858771) TestSimpleInterestPricing:test_calculateInterest() (gas: 881296) TestSimpleInterestPricing:test_getPaymentConsideration() (gas: 928510) TestSimpleInterestPricing:test_getRefinanceConsideration() (gas: 919314) -TestStarport:testAcquireTokensFail() (gas: 60386) -TestStarport:testAcquireTokensSuccess() (gas: 162955) -TestStarport:testActive() (gas: 69291) -TestStarport:testAdditionalTransfers() (gas: 300688) -TestStarport:testAdditionalTransfersOriginate() (gas: 275384) -TestStarport:testAdditionalTransfersRefinance() (gas: 218214) -TestStarport:testApplyRefinanceConsiderationToLoanMalformed() (gas: 129820) -TestStarport:testCannotIssueSameLoanTwice() (gas: 363991) -TestStarport:testCannotOriginateWhilePaused() (gas: 73523) -TestStarport:testCannotSettleInvalidLoan() (gas: 74881) -TestStarport:testCannotSettleUnlessValidCustodian() (gas: 70919) -TestStarport:testCaveatEnforcerRevert() (gas: 102534) -TestStarport:testDefaultFeeRake1() (gas: 387913) -TestStarport:testDefaultFeeRake2() (gas: 450256) -TestStarport:testDefaultFeeRakeExoticDebt() (gas: 397742) -TestStarport:testEIP712Signing() (gas: 83064) -TestStarport:testExoticDebtWithCustomPricingAndRepayment() (gas: 1237672) -TestStarport:testExoticDebtWithCustomPricingAndSettlement() (gas: 1692715) -TestStarport:testExoticDebtWithNoCaveatsNotAsBorrower() (gas: 376786) -TestStarport:testIncrementCaveatNonce() (gas: 35183) -TestStarport:testInitializedFlagSetProperly() (gas: 67416) -TestStarport:testInvalidAdditionalTransfersOriginate() (gas: 230359) -TestStarport:testInvalidAdditionalTransfersRefinance() (gas: 170774) -TestStarport:testInvalidAmountCollateral() (gas: 165901) -TestStarport:testInvalidAmountCollateral721() (gas: 165901) -TestStarport:testInvalidItemType() (gas: 151849) -TestStarport:testInvalidTransferLengthCollateral() (gas: 154118) -TestStarport:testInvalidTransferLengthDebt() (gas: 175917) -TestStarport:testInvalidateCaveatSalt() (gas: 33450) -TestStarport:testNonDefaultCustodianCustodyCallFails() (gas: 264200) -TestStarport:testNonDefaultCustodianCustodyCallSuccess() (gas: 290347) +TestStarport:testAcquireTokensFail() (gas: 60473) +TestStarport:testAcquireTokensSuccess() (gas: 163042) +TestStarport:testActive() (gas: 69358) +TestStarport:testAdditionalTransfers() (gas: 300755) +TestStarport:testAdditionalTransfersOriginate() (gas: 275540) +TestStarport:testAdditionalTransfersRefinance() (gas: 218206) +TestStarport:testApplyRefinanceConsiderationToLoanMalformed() (gas: 129484) +TestStarport:testCannotIssueSameLoanTwice() (gas: 364125) +TestStarport:testCannotOriginateWhilePaused() (gas: 73479) +TestStarport:testCannotSettleInvalidLoan() (gas: 74969) +TestStarport:testCannotSettleUnlessValidCustodian() (gas: 71007) +TestStarport:testCaveatEnforcerRevert() (gas: 102601) +TestStarport:testDefaultFeeRake1() (gas: 383458) +TestStarport:testDefaultFeeRake2() (gas: 445821) +TestStarport:testDefaultFeeRakeExoticDebt() (gas: 394564) +TestStarport:testEIP712Signing() (gas: 83109) +TestStarport:testExcessiveFeeRake() (gas: 19992) +TestStarport:testExoticDebtWithCustomPricingAndRepayment() (gas: 1237783) +TestStarport:testExoticDebtWithCustomPricingAndSettlement() (gas: 1692826) +TestStarport:testExoticDebtWithNoCaveatsNotAsBorrower() (gas: 376831) +TestStarport:testIncrementCaveatNonce() (gas: 35117) +TestStarport:testInitializedFlagSetProperly() (gas: 67372) +TestStarport:testInvalidAdditionalTransfersOriginate() (gas: 230426) +TestStarport:testInvalidAdditionalTransfersRefinance() (gas: 170766) +TestStarport:testInvalidAmountCollateral() (gas: 165968) +TestStarport:testInvalidAmountCollateral721() (gas: 165968) +TestStarport:testInvalidItemType() (gas: 151916) +TestStarport:testInvalidTransferLengthCollateral() (gas: 154185) +TestStarport:testInvalidTransferLengthDebt() (gas: 175984) +TestStarport:testInvalidateCaveatSalt() (gas: 33428) +TestStarport:testNonDefaultCustodianCustodyCallFails() (gas: 264267) +TestStarport:testNonDefaultCustodianCustodyCallSuccess() (gas: 290392) TestStarport:testNonPayableFunctions() (gas: 114479) -TestStarport:testOverrideFeeRake() (gas: 384236) -TestStarport:testPause() (gas: 18193) +TestStarport:testOverrideFeeRake() (gas: 379873) +TestStarport:testPause() (gas: 18127) TestStarport:testRefinancePostRepaymentFails() (gas: 127864) -TestStarport:testStargateGetOwner() (gas: 8786) -TestStarport:testTokenNoCodeCollateral() (gas: 150640) -TestStarport:testTokenNoCodeDebt() (gas: 180913) -TestStarport:testUnpause() (gas: 17275) +TestStarport:testStargateGetOwner() (gas: 8851) +TestStarport:testTokenNoCodeCollateral() (gas: 150707) +TestStarport:testTokenNoCodeDebt() (gas: 180980) +TestStarport:testUnpause() (gas: 17187) TestStrategistOriginator:testEncodeWithAccountCounter() (gas: 12330) TestStrategistOriginator:testGetStrategistData() (gas: 1790990) TestStrategistOriginator:testIncrementCounterAsStrategist() (gas: 38488) TestStrategistOriginator:testIncrementCounterNotAuthorized() (gas: 13423) -TestStrategistOriginator:testInvalidCollateral() (gas: 210224) -TestStrategistOriginator:testInvalidDeadline() (gas: 216045) -TestStrategistOriginator:testInvalidDebt() (gas: 211932) -TestStrategistOriginator:testInvalidDebtAmountAskingMoreThanOffered() (gas: 212306) -TestStrategistOriginator:testInvalidDebtAmountOfferingZero() (gas: 212636) -TestStrategistOriginator:testInvalidDebtAmountRequestingZero() (gas: 212571) -TestStrategistOriginator:testInvalidDebtLength() (gas: 211226) -TestStrategistOriginator:testInvalidOffer() (gas: 427005) -TestStrategistOriginator:testInvalidSigner() (gas: 214364) +TestStrategistOriginator:testInvalidCollateral() (gas: 210380) +TestStrategistOriginator:testInvalidDeadline() (gas: 216201) +TestStrategistOriginator:testInvalidDebt() (gas: 212088) +TestStrategistOriginator:testInvalidDebtAmountAskingMoreThanOffered() (gas: 212462) +TestStrategistOriginator:testInvalidDebtAmountOfferingZero() (gas: 212792) +TestStrategistOriginator:testInvalidDebtAmountRequestingZero() (gas: 212727) +TestStrategistOriginator:testInvalidDebtLength() (gas: 211382) +TestStrategistOriginator:testInvalidOffer() (gas: 427161) +TestStrategistOriginator:testInvalidSigner() (gas: 214520) TestStrategistOriginator:testSetStrategist() (gas: 17884) TestStrategistOriginator:testWithdraw() (gas: 167966) \ No newline at end of file diff --git a/src/Starport.sol b/src/Starport.sol index 7895dd8f..021f47f0 100644 --- a/src/Starport.sol +++ b/src/Starport.sol @@ -55,6 +55,7 @@ contract Starport is PausableNonReentrant { /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error CaveatDeadlineExpired(); + error InvalidFeeRakeBps(); error InvalidCaveat(); error InvalidCaveatLength(); error InvalidCaveatSigner(); @@ -76,14 +77,17 @@ contract Starport is PausableNonReentrant { event CaveatNonceIncremented(address owner, uint256 newNonce); event CaveatSaltInvalidated(address owner, bytes32 salt); event Close(uint256 loanId); - event FeeDataUpdated(address feeTo, uint256[2][] defaultFeeRakeByDecimals); - event FeeOverrideUpdated(address token, uint88 overrideValue, bool enabled); + event FeeDataUpdated(address feeTo, uint88 defaultFeeRakeBps); + event FeeOverrideUpdated(address token, uint88 overrideBps, bool enabled); event Open(uint256 loanId, Starport.Loan loan); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + uint88 public constant MAX_FEE_RAKE_BPS = 500; // 5% + uint88 public constant BPS_DENOMINATOR = 10_000; // 100% + uint256 public constant LOAN_CLOSED_FLAG = 0x0; uint256 public constant LOAN_OPEN_FLAG = 0x1; @@ -131,9 +135,9 @@ contract Starport is PausableNonReentrant { Terms terms; // the actionable terms of the loan } - struct Fee { + struct FeeOverride { bool enabled; - uint88 amount; + uint88 bpsOverride; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -151,8 +155,8 @@ contract Starport is PausableNonReentrant { /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ address public feeTo; - mapping(uint256 => uint256) public defaultFeeRakeByDecimals; - mapping(address => Fee) public feeOverrides; + uint256 public defaultFeeRakeBps; + mapping(address => FeeOverride) public feeOverrides; mapping(address => mapping(address => ApprovalType)) public approvals; mapping(address => mapping(bytes32 => bool)) public invalidSalts; mapping(address => uint256) public caveatNonces; @@ -334,29 +338,32 @@ contract Starport is PausableNonReentrant { /** * @dev Sets the default fee data, only owner can call * @param feeTo_ The feeToAddress - * @param defaultFeeRakeByDecimals_ [decimals, defaultFeeRakeByDecimals] pairs + * @param defaultFeeRakeBps_ The default fee rake in basis points */ - function setFeeData(address feeTo_, uint256[2][] memory defaultFeeRakeByDecimals_) external onlyOwner { - feeTo = feeTo_; - for (uint256 i = 0; i < defaultFeeRakeByDecimals_.length;) { - defaultFeeRakeByDecimals[defaultFeeRakeByDecimals_[i][0]] = defaultFeeRakeByDecimals_[i][1]; - unchecked { - ++i; - } + function setFeeData(address feeTo_, uint88 defaultFeeRakeBps_) external onlyOwner { + if (defaultFeeRakeBps_ > MAX_FEE_RAKE_BPS) { + revert InvalidFeeRakeBps(); } - emit FeeDataUpdated(feeTo_, defaultFeeRakeByDecimals_); + + feeTo = feeTo_; + defaultFeeRakeBps = defaultFeeRakeBps_; + + emit FeeDataUpdated(feeTo_, defaultFeeRakeBps_); } /** * @dev Sets fee overrides for specific tokens, only owner can call * @param token The token to override - * @param overrideValue The new value in decimals base denomination - * to override eg if token has 18 decimals (1e17 = 10%) + * @param bpsOverride The new basis points to override to (1 = 0.01%) * @param enabled Whether or not the override is enabled */ - function setFeeOverride(address token, uint88 overrideValue, bool enabled) external onlyOwner { - feeOverrides[token] = Fee({enabled: enabled, amount: overrideValue}); - emit FeeOverrideUpdated(token, overrideValue, enabled); + function setFeeOverride(address token, uint88 bpsOverride, bool enabled) external onlyOwner { + if (bpsOverride > MAX_FEE_RAKE_BPS) { + revert InvalidFeeRakeBps(); + } + + feeOverrides[token] = FeeOverride({enabled: enabled, bpsOverride: bpsOverride}); + emit FeeOverrideUpdated(token, bpsOverride, enabled); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ @@ -381,7 +388,7 @@ contract Starport is PausableNonReentrant { } if (carryPayment.length > 0) { - SpentItem[] memory newDebt = new SpentItem[](considerationPayment.length); + newDebt = new SpentItem[](considerationPayment.length); uint256 i = 0; for (; i < considerationPayment.length;) { newDebt[i] = considerationPayment[i]; @@ -459,7 +466,7 @@ contract Starport is PausableNonReentrant { * * @return The hash. */ - function _hashCaveat(CaveatEnforcer.Caveat memory caveat) internal view returns (bytes32) { + function _hashCaveat(CaveatEnforcer.Caveat memory caveat) internal pure returns (bytes32) { return keccak256(abi.encode(CAVEAT_TYPEHASH, caveat.enforcer, keccak256(caveat.data))); } @@ -648,32 +655,29 @@ contract Starport is PausableNonReentrant { { feeItems = new SpentItem[](debt.length); paymentToBorrower = new SpentItem[](debt.length); + uint256 _defaultFeeRakeBps = defaultFeeRakeBps; uint256 totalFeeItems; for (uint256 i = 0; i < debt.length;) { uint256 amount; SpentItem memory debtItem = debt[i]; if (debtItem.itemType == ItemType.ERC20) { - Fee memory feeOverride = feeOverrides[debtItem.token]; + FeeOverride memory feeOverride = feeOverrides[debtItem.token]; SpentItem memory feeItem = feeItems[totalFeeItems]; feeItem.identifier = 0; - try ERC20(debtItem.token).decimals() returns (uint8 decimals) { - uint256 defaultFeeRake = defaultFeeRakeByDecimals[decimals]; + uint256 bps = feeOverride.enabled ? feeOverride.bpsOverride : _defaultFeeRakeBps; - if (defaultFeeRake != 0 || feeOverride.enabled) { - amount = debtItem.amount.mulDivUp( - !feeOverride.enabled ? defaultFeeRake : feeOverride.amount, 10 ** decimals - ); - } + amount = debtItem.amount.mulDivUp(bps, BPS_DENOMINATOR); - if (amount > 0) { - feeItem.amount = amount; - feeItem.token = debtItem.token; - feeItem.itemType = debtItem.itemType; + if (amount > 0) { + feeItem.amount = amount; + feeItem.token = debtItem.token; + feeItem.itemType = debtItem.itemType; + unchecked { ++totalFeeItems; } - } catch {} + } } paymentToBorrower[i] = SpentItem({ token: debtItem.token, diff --git a/test/fuzz-testing/TestFuzzStarport.sol b/test/fuzz-testing/TestFuzzStarport.sol index 960d4164..ffec10b3 100644 --- a/test/fuzz-testing/TestFuzzStarport.sol +++ b/test/fuzz-testing/TestFuzzStarport.sol @@ -269,11 +269,9 @@ contract TestFuzzStarport is StarportTest, Bound, DeepEq { vm.assume(!willArithmeticOverflow(loan)); address feeReceiver = address(20); - uint256[2][] memory feeRake = new uint256[2][](1); - feeRake[0][0] = uint256(18); - feeRake[0][1] = _boundMax(0, 1e17); + uint88 feeRakeBps = uint88(_boundMax(0, SP.MAX_FEE_RAKE_BPS())); if (params.feesOn) { - SP.setFeeData(feeReceiver, feeRake); + SP.setFeeData(feeReceiver, feeRakeBps); } _issueAndApproveTarget(loan.collateral, loan.borrower, address(SP)); _issueAndApproveTarget(loan.debt, loan.issuer, address(SP)); @@ -294,7 +292,10 @@ contract TestFuzzStarport is StarportTest, Bound, DeepEq { if (params.feesOn) { assert( ERC20(loan.debt[0].token).balanceOf(loan.borrower) - == (borrowerDebtBalanceBefore + (loan.debt[0].amount - loan.debt[0].amount.mulWad(feeRake[0][1]))) + == ( + borrowerDebtBalanceBefore + + (loan.debt[0].amount - loan.debt[0].amount * feeRakeBps / SP.BPS_DENOMINATOR()) + ) ); } else { assert( diff --git a/test/unit-testing/TestStarport.sol b/test/unit-testing/TestStarport.sol index 6d55d507..5edc16db 100644 --- a/test/unit-testing/TestStarport.sol +++ b/test/unit-testing/TestStarport.sol @@ -607,13 +607,11 @@ contract TestStarport is StarportTest, DeepEq { } function testDefaultFeeRake1() public { - assertEq(SP.defaultFeeRakeByDecimals(18), 0); + assertEq(SP.defaultFeeRakeBps(), 0); address feeReceiver = address(20); - uint256[2][] memory feeRake = new uint256[2][](1); - feeRake[0][0] = uint256(18); - feeRake[0][1] = uint256(1e17); - SP.setFeeData(feeReceiver, feeRake); //10% fees - assertEq(SP.defaultFeeRakeByDecimals(18), 1e17, "fee's not set properly"); + uint88 feeRakeBps = 500; + SP.setFeeData(feeReceiver, feeRakeBps); //5% fees + assertEq(SP.defaultFeeRakeBps(), 500, "fee's not set properly"); Starport.Loan memory originationDetails = _generateOriginationDetails( _getERC721SpentItem(erc721s[0], uint256(2)), _getERC20SpentItem(erc20s[0], borrowAmount), lender.addr @@ -621,17 +619,15 @@ contract TestStarport is StarportTest, DeepEq { Starport.Loan memory loan = newLoan(originationDetails, bytes32(bytes32(msg.sig)), bytes32(bytes32(msg.sig)), lender.addr); - assertEq(erc20s[0].balanceOf(feeReceiver), loan.debt[0].amount * 1e17 / 1e18, "fee receiver not paid properly"); + assertEq(erc20s[0].balanceOf(feeReceiver), loan.debt[0].amount * 5 / 100, "fee receiver not paid properly"); } function testDefaultFeeRake2() public { - assertEq(SP.defaultFeeRakeByDecimals(18), 0); + assertEq(SP.defaultFeeRakeBps(), 0); address feeReceiver = address(20); - uint256[2][] memory feeRake = new uint256[2][](1); - feeRake[0][0] = uint256(18); - feeRake[0][1] = uint256(1e17); - SP.setFeeData(feeReceiver, feeRake); //10% fees - assertEq(SP.defaultFeeRakeByDecimals(18), 1e17, "fee's not set properly"); + uint88 feeRakeBps = 500; + SP.setFeeData(feeReceiver, feeRakeBps); //5% fees + assertEq(SP.defaultFeeRakeBps(), 500, "fee's not set properly"); SpentItem[] memory debt = new SpentItem[](2); debt[0] = _getERC721SpentItem(erc721s[0], uint256(2)); @@ -651,18 +647,28 @@ contract TestStarport is StarportTest, DeepEq { Starport.Loan memory loan = newLoan(originationDetails, bytes32(bytes32(msg.sig)), bytes32(bytes32(msg.sig)), lender.addr); - assertEq(erc20s[0].balanceOf(feeReceiver), loan.debt[1].amount * 1e17 / 1e18, "fee receiver not paid properly"); + assertEq(erc20s[0].balanceOf(feeReceiver), loan.debt[1].amount * 5 / 100, "fee receiver not paid properly"); + } + + function testExcessiveFeeRake() public { + address feeReceiver = address(20); + uint88 feeRakeBps = SP.MAX_FEE_RAKE_BPS() + 1; //5.01% fees + + vm.expectRevert(Starport.InvalidFeeRakeBps.selector); + SP.setFeeData(feeReceiver, feeRakeBps); + + vm.expectRevert(Starport.InvalidFeeRakeBps.selector); + SP.setFeeOverride(address(erc20s[0]), feeRakeBps, true); } function testDefaultFeeRakeExoticDebt() public { - assertEq(SP.defaultFeeRakeByDecimals(18), 0); + assertEq(SP.defaultFeeRakeBps(), 0); + address feeReceiver = address(20); - uint256[2][] memory feeRake = new uint256[2][](1); + uint88 feeRakeBps = 500; + SP.setFeeData(feeReceiver, feeRakeBps); //5% fees + assertEq(SP.defaultFeeRakeBps(), 500); - feeRake[0][0] = uint256(18); - feeRake[0][1] = uint256(1e17); - SP.setFeeData(feeReceiver, feeRake); //10% fees - assertEq(SP.defaultFeeRakeByDecimals(18), 1e17); Starport.Loan memory originationDetails = _generateOriginationDetails( _getERC721SpentItem(erc721s[0], uint256(2)), _getERC1155SpentItem(erc1155s[1]), lender.addr ); @@ -673,13 +679,12 @@ contract TestStarport is StarportTest, DeepEq { } function testOverrideFeeRake() public { - assertEq(SP.defaultFeeRakeByDecimals(18), 0); + assertEq(SP.defaultFeeRakeBps(), 0); address feeReceiver = address(20); - uint256[2][] memory feeRake = new uint256[2][](1); - feeRake[0][0] = uint256(18); - feeRake[0][1] = uint256(1e17); - SP.setFeeData(feeReceiver, feeRake); //10% fees - assertEq(SP.defaultFeeRakeByDecimals(18), 1e17); + uint88 feeRakeBps = 500; + SP.setFeeData(feeReceiver, feeRakeBps); //5% fees + assertEq(SP.defaultFeeRakeBps(), 500); + SP.setFeeOverride(address(erc20s[0]), 0, true); //0% fees Starport.Loan memory originationDetails = _generateOriginationDetails(