Skip to content

Commit

Permalink
feat/originator testing/bnpl /w testing (#39)
Browse files Browse the repository at this point in the history
* feat: implement new origination flow

* fix: integrate with LoanManager, get tests compiling

* fix: fix first integration test

* fix: TestAstariaV1Loan fully working

* fix: custodian tests working

* fix: all test running or commented out

* updates to multiple caveats, tweaks to enforcement flows, gas savings and signature lib updates

* update LM tests for the new orgination flow

* add snapshot

* test for additional transfers

* update pragma to not be fixed to 0.8.17, add bnpl helper and test

* remove dev solc

* strategist originator at 100% coverage, snaphot and foundry added to remove the dev settings

* add pause into loan manager

---------

Co-authored-by: Joseph Delong <[email protected]>
  • Loading branch information
androolloyd and dangerousfood authored Nov 1, 2023
1 parent 16ffdbe commit 0771896
Show file tree
Hide file tree
Showing 48 changed files with 1,239 additions and 637 deletions.
130 changes: 75 additions & 55 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,85 +1,105 @@
DiffFuzzTestStarPortLib:testSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 880466, ~: 883301)
DiffFuzzTestStarPortLib:testUnboundSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 232905, ~: 237832)
TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallBase() (gas: 1039242)
TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLender() (gas: 691152)
TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLiquidation() (gas: 770721)
TestCustodian:testCannotLazyMintTwice() (gas: 76597)
DiffFuzzTestStarPortLib:testSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 880501, ~: 882340)
DiffFuzzTestStarPortLib:testUnboundSpentToReceived((uint8,address,uint256,uint256)[]) (runs: 256, μ: 232899, ~: 237832)
TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallBase() (gas: 1041770)
TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLender() (gas: 693528)
TestAstariaV1Loan:testNewLoanERC721CollateralDefaultTermsRecallLiquidation() (gas: 773097)
TestCustodian:testCannotLazyMintTwice() (gas: 76686)
TestCustodian:testCannotMintInvalidLoanInvalidCustodian() (gas: 66883)
TestCustodian:testCannotMintInvalidLoanValidCustodian() (gas: 72422)
TestCustodian:testCannotMintInvalidLoanValidCustodian() (gas: 72511)
TestCustodian:testCustodySelector() (gas: 2543980)
TestCustodian:testDefaultCustodySelectorRevert() (gas: 70105)
TestCustodian:testGenerateOrderInvalidHandlerExecution() (gas: 132855)
TestCustodian:testGenerateOrderRepay() (gas: 164375)
TestCustodian:testGenerateOrderRepayAsRepayApprovedBorrower() (gas: 190022)
TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNative() (gas: 843710)
TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNativeHandlerAuthorized() (gas: 785342)
TestCustodian:testGenerateOrderRepayERC1155WithRevert() (gas: 518146)
TestCustodian:testGenerateOrderRepay() (gas: 164353)
TestCustodian:testGenerateOrderRepayAsRepayApprovedBorrower() (gas: 190000)
TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNative() (gas: 848490)
TestCustodian:testGenerateOrderRepayERC1155AndERC20AndNativeHandlerAuthorized() (gas: 790122)
TestCustodian:testGenerateOrderRepayERC1155WithRevert() (gas: 520526)
TestCustodian:testGenerateOrderRepayInvalidHookAddress() (gas: 90249)
TestCustodian:testGenerateOrderRepayInvalidHookReturnType() (gas: 84653)
TestCustodian:testGenerateOrderRepayNotBorrower() (gas: 96449)
TestCustodian:testGenerateOrderSettlement() (gas: 151381)
TestCustodian:testGenerateOrderSettlementHandlerAuthorized() (gas: 160421)
TestCustodian:testGenerateOrderSettlementNoActiveLoan() (gas: 155620)
TestCustodian:testGenerateOrderSettlement() (gas: 151359)
TestCustodian:testGenerateOrderSettlementHandlerAuthorized() (gas: 160399)
TestCustodian:testGenerateOrderSettlementNoActiveLoan() (gas: 155598)
TestCustodian:testGenerateOrderSettlementUnauthorized() (gas: 94219)
TestCustodian:testGetBorrower() (gas: 76234)
TestCustodian:testInvalidAction() (gas: 114400)
TestCustodian:testInvalidActionRepayInActiveLoan() (gas: 117327)
TestCustodian:testInvalidActionSettleActiveLoan() (gas: 117287)
TestCustodian:testInvalidAction() (gas: 114489)
TestCustodian:testInvalidActionRepayInActiveLoan() (gas: 117416)
TestCustodian:testInvalidActionSettleActiveLoan() (gas: 117376)
TestCustodian:testName() (gas: 7120)
TestCustodian:testNonPayableFunctions() (gas: 225770)
TestCustodian:testOnlySeaport() (gas: 17917)
TestCustodian:testPayableFunctions() (gas: 41689)
TestCustodian:testPreviewOrderNoActiveLoan() (gas: 98687)
TestCustodian:testPreviewOrderRepay() (gas: 208128)
TestCustodian:testPreviewOrderSettlement() (gas: 182676)
TestCustodian:testPreviewOrderSettlementInvalidFufliller() (gas: 100488)
TestCustodian:testPreviewOrderSettlementInvalidRepayer() (gas: 106646)
TestCustodian:testRatifyOrder() (gas: 170218)
TestCustodian:testPreviewOrderNoActiveLoan() (gas: 98776)
TestCustodian:testPreviewOrderRepay() (gas: 208195)
TestCustodian:testPreviewOrderSettlement() (gas: 182743)
TestCustodian:testPreviewOrderSettlementInvalidFufliller() (gas: 100577)
TestCustodian:testPreviewOrderSettlementInvalidRepayer() (gas: 106735)
TestCustodian:testRatifyOrder() (gas: 170196)
TestCustodian:testSeaportMetadata() (gas: 8567)
TestCustodian:testSetRepayApproval() (gas: 37883)
TestCustodian:testSupportsInterface() (gas: 9428)
TestCustodian:testSymbol() (gas: 7149)
TestCustodian:testTokenURI() (gas: 64839)
TestCustodian:testTokenURIInvalidLoan() (gas: 13218)
TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 530961)
TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 499798)
TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 549718)
TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 539542)
TestLoanCombinations:testLoanSimpleInterestEnglishFixed() (gas: 544202)
TestLoanManager:testAdditionalTransfers() (gas: 293098)
TestLoanManager:testCannotIssueSameLoanTwice() (gas: 331317)
TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 533373)
TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 502230)
TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 552096)
TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 541954)
TestLoanCombinations:testLoanSimpleInterestEnglishFixed() (gas: 546614)
TestLoanManager:testAdditionalTransfers() (gas: 293327)
TestLoanManager:testCannotIssueSameLoanTwice() (gas: 331775)
TestLoanManager:testCannotOriginateWhilePaused() (gas: 87923)
TestLoanManager:testCannotSettleInvalidLoan() (gas: 72594)
TestLoanManager:testCannotSettleUnlessValidCustodian() (gas: 68772)
TestLoanManager:testCaveatEnforcerRevert() (gas: 116691)
TestLoanManager:testDefaultFeeRake() (gas: 350066)
TestLoanManager:testExoticDebtWithNoCaveatsNotAsBorrower() (gas: 342790)
TestLoanManager:testInitializedFlagSetProperly() (gas: 65252)
TestLoanManager:testInvalidAmountCollateral() (gas: 152889)
TestLoanManager:testInvalidAmountCollateral721() (gas: 152987)
TestLoanManager:testInvalidAmountDebt() (gas: 177200)
TestLoanManager:testInvalidItemType() (gas: 138937)
TestLoanManager:testInvalidTransferLengthCollateral() (gas: 161128)
TestLoanManager:testInvalidTransferLengthDebt() (gas: 165661)
TestLoanManager:testIssued() (gas: 67055)
TestLoanManager:testCannotSettleUnlessValidCustodian() (gas: 68750)
TestLoanManager:testCaveatEnforcerRevert() (gas: 119155)
TestLoanManager:testDefaultFeeRake() (gas: 352730)
TestLoanManager:testExoticDebtWithNoCaveatsNotAsBorrower() (gas: 342979)
TestLoanManager:testInitializedFlagSetProperly() (gas: 65262)
TestLoanManager:testInvalidAmountCollateral() (gas: 153078)
TestLoanManager:testInvalidAmountCollateral721() (gas: 153221)
TestLoanManager:testInvalidAmountDebt() (gas: 177389)
TestLoanManager:testInvalidIdentifierDebt() (gas: 197383)
TestLoanManager:testInvalidItemType() (gas: 139126)
TestLoanManager:testInvalidTransferLengthCollateral() (gas: 161295)
TestLoanManager:testInvalidTransferLengthDebt() (gas: 165838)
TestLoanManager:testIssued() (gas: 67144)
TestLoanManager:testName() (gas: 7184)
TestLoanManager:testNonDefaultCustodianCustodyCallFails() (gas: 190232)
TestLoanManager:testNonDefaultCustodianCustodyCallSuccess() (gas: 258505)
TestLoanManager:testNonPayableFunctions() (gas: 173085)
TestLoanManager:testOverrideFeeRake() (gas: 343904)
TestLoanManager:testNonDefaultCustodianCustodyCallFails() (gas: 190465)
TestLoanManager:testNonDefaultCustodianCustodyCallSuccess() (gas: 258714)
TestLoanManager:testNonPayableFunctions() (gas: 175555)
TestLoanManager:testOverrideFeeRake() (gas: 346469)
TestLoanManager:testPause() (gas: 34222)
TestLoanManager:testSupportsInterface() (gas: 9181)
TestLoanManager:testSymbol() (gas: 7127)
TestLoanManager:testTokenNoCodeCollateral() (gas: 137709)
TestLoanManager:testTokenNoCodeDebt() (gas: 170767)
TestLoanManager:testTokenURI() (gas: 64914)
TestLoanManager:testSymbol() (gas: 7235)
TestLoanManager:testTokenNoCodeCollateral() (gas: 137898)
TestLoanManager:testTokenNoCodeDebt() (gas: 170934)
TestLoanManager:testTokenURI() (gas: 64892)
TestLoanManager:testTokenURIInvalidLoan() (gas: 13244)
TestLoanManager:testTransferFromFail() (gas: 80088)
TestNewLoan:testBuyNowPayLater() (gas: 208)
TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 389485)
TestLoanManager:testTransferFromFail() (gas: 80176)
TestLoanManager:testUnPause() (gas: 14291)
TestNewLoan:testBuyNowPayLater() (gas: 2831964)
TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 392402)
TestNewLoan:testNewLoanERC721CollateralLessDebtThanOffered() (gas: 2259)
TestNewLoan:testNewLoanRefinanceNew() (gas: 207)
TestNewLoan:testNewLoanViaOriginatorBorrowerApprovalAndLenderApproval() (gas: 299336)
TestNewLoan:testNewLoanViaOriginatorLenderApproval() (gas: 354219)
TestNewLoan:testSettleLoan() (gas: 163)
TestRefStarPortLib:testSpentToReceived() (gas: 13315)
TestRefStarPortLib:testValidateSalt(address,bytes32) (runs: 256, μ: 33865, ~: 33865)
TestRepayLoan:testRepayLoan() (gas: 207)
TestStarPortLib:testSpentToReceived() (gas: 13315)
TestStarPortLib:testValidateSalt(address,bytes32) (runs: 256, μ: 33865, ~: 33865)
TestStarPortLib:testValidateSalt(address,bytes32) (runs: 256, μ: 33865, ~: 33865)
TestStrategistOriginator:testEncodeWithAccountCounter() (gas: 12307)
TestStrategistOriginator:testGetStrategistData() (gas: 1473217)
TestStrategistOriginator:testIncrementCounterAsStrategist() (gas: 18676)
TestStrategistOriginator:testIncrementCounterNotAuthorized() (gas: 13467)
TestStrategistOriginator:testInvalidCollateral() (gas: 204416)
TestStrategistOriginator:testInvalidDeadline() (gas: 210145)
TestStrategistOriginator:testInvalidDebt() (gas: 206100)
TestStrategistOriginator:testInvalidDebtAmountAskingMoreThanOffered() (gas: 206548)
TestStrategistOriginator:testInvalidDebtAmountOfferingZero() (gas: 186903)
TestStrategistOriginator:testInvalidDebtAmountRequestingZero() (gas: 206801)
TestStrategistOriginator:testInvalidDebtLength() (gas: 205428)
TestStrategistOriginator:testInvalidOffer() (gas: 396592)
TestStrategistOriginator:testInvalidSigner() (gas: 208639)
TestStrategistOriginator:testSetStrategist() (gas: 17818)
3 changes: 2 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[profile.default]
#cancun = true
src = "src"
out = "out"
libs = ["lib"]

#solc = "./bin/solc"
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
138 changes: 138 additions & 0 deletions src/BNPLHelper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
pragma solidity ^0.8.17;

import {
OfferItem,
SpentItem,
ConsiderationItem,
AdvancedOrder,
OrderParameters,
CriteriaResolver,
ItemType,
Fulfillment
} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {ConduitTransfer, ConduitItemType} from "seaport-types/src/conduit/lib/ConduitStructs.sol";

import {Seaport} from "seaport/contracts/Seaport.sol";
import {LoanManager} from "./LoanManager.sol";
import {CaveatEnforcer} from "./enforcers/CaveatEnforcer.sol";
import "forge-std/console.sol";

interface IVault {
function flashLoan(
IFlashLoanRecipient recipient,
address[] calldata tokens,
uint256[] calldata amounts,
bytes memory userData
) external;
}

interface IFlashLoanRecipient {
function receiveFlashLoan(
address[] calldata tokens,
uint256[] calldata amounts,
uint256[] calldata feeAmounts,
bytes memory userData
) external;
}

interface IWETH9 {
function withdraw(uint256) external;
}

interface ERC20 {
function transfer(address, uint256) external returns (bool);
}

// fulfiller

contract BNPLHelper is IFlashLoanRecipient {
address private constant vault = address(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
IWETH9 private immutable WETH;
bytes32 private activeUserDataHash;

constructor(address WETH_) {
WETH = IWETH9(WETH_);
}

struct Execution {
address lm;
address seaport;
address borrower;
CaveatEnforcer.CaveatWithApproval borrowerCaveat;
CaveatEnforcer.CaveatWithApproval lenderCaveat;
LoanManager.Loan loan;
AdvancedOrder[] orders;
CriteriaResolver[] resolvers;
Fulfillment[] fulfillments;
}

error SenderNotSelf();
error DoNotSendETH();
error InvalidUserDataProvided();

function makeFlashLoan(
address[] calldata tokens,
uint256[] calldata amounts,
// uint256[] calldata userProvidedAmounts,
bytes calldata userData
) external {
// assembly {
// // Compute the hash of userData
// let dataHash := keccak256(userData.offset, calldatasize())
//
// // Store the hash in the activeUserDataHash state variable
// tstore(activeUserDataHash.slot, dataHash)
// }
activeUserDataHash = keccak256(userData);

IVault(vault).flashLoan(this, tokens, amounts, userData);
}

function receiveFlashLoan(
address[] calldata tokens, // are all erc20s
uint256[] calldata amounts,
uint256[] calldata feeAmounts,
bytes calldata userData
) external override {
require(msg.sender == vault);

if (activeUserDataHash != keccak256(userData)) {
revert InvalidUserDataProvided();
}
delete activeUserDataHash;

Execution memory execution = abi.decode(userData, (Execution));
//approve seaport
for (uint256 i = 0; i < tokens.length;) {
ERC20(tokens[i]).transfer(execution.borrower, amounts[i]);
unchecked {
++i;
}
}
Seaport(payable(execution.seaport)).matchAdvancedOrders(
execution.orders, execution.resolvers, execution.fulfillments, execution.borrower
);

ConduitTransfer[] memory transfers = new ConduitTransfer[](tokens.length);
for (uint256 i = 0; i < tokens.length;) {
transfers[i] = ConduitTransfer({
itemType: ConduitItemType.ERC20,
identifier: 0,
token: tokens[0],
from: execution.borrower,
to: vault,
amount: amounts[0] + feeAmounts[0]
});
unchecked {
++i;
}
}
LoanManager(execution.lm).originate(transfers, execution.borrowerCaveat, execution.lenderCaveat, execution.loan);
}

receive() external payable {
if (msg.sender != address(WETH)) {
revert DoNotSendETH();
}
}
}
2 changes: 1 addition & 1 deletion src/ConduitHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*
* Chainworks Labs
*/
pragma solidity =0.8.17;
pragma solidity ^0.8.17;

import {ItemType, OfferItem, Schema, SpentItem, ReceivedItem} from "seaport-types/src/lib/ConsiderationStructs.sol";

Expand Down
2 changes: 1 addition & 1 deletion src/Custodian.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*
* Chainworks Labs
*/
pragma solidity =0.8.17;
pragma solidity ^0.8.17;

import {ERC721} from "solady/src/tokens/ERC721.sol";
import {ERC20} from "solady/src/tokens/ERC20.sol";
Expand Down
Loading

0 comments on commit 0771896

Please sign in to comment.