Skip to content

Commit

Permalink
add mock erc1271 proxy to demonstrate ERC1271 sig working
Browse files Browse the repository at this point in the history
  • Loading branch information
androolloyd committed Nov 15, 2023
1 parent 3485cc2 commit c662f01
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 43 deletions.
82 changes: 42 additions & 40 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ IntegrationTestCaveats:testOriginateWCaveatsIncrementedNonce() (gas: 205798)
IntegrationTestCaveats:testOriginateWCaveatsInvalidSalt() (gas: 303644)
IntegrationTestCaveats:testOriginateWCaveatsInvalidSaltManual() (gas: 179719)
IntegrationTestCaveats:testOriginateWLenderApproval() (gas: 323375)
IntegrationTestCaveats:testRefinanceAsLender() (gas: 1090532)
IntegrationTestCaveats:testRefinanceCaveatFailure() (gas: 439685)
IntegrationTestCaveats:testRefinanceLoanStartAtBlockTimestampInvalidLoan() (gas: 386956)
IntegrationTestCaveats:testRefinanceUnapprovedFulfiller() (gas: 497489)
IntegrationTestCaveats:testRefinanceWCaveatsInvalidSalt() (gas: 416353)
IntegrationTestCaveats:testRefinanceWLenderApproval() (gas: 439616)
ModuleTesting:testFixedTermDutchAuctionSettlement() (gas: 435806)
ModuleTesting:testFixedTermDutchAuctionSettlementGetSettlementAuctionExpired() (gas: 438584)
ModuleTesting:testFixedTermDutchAuctionSettlementNotValid() (gas: 434694)
ModuleTesting:testFixedTermDutchAuctionSettlementValid() (gas: 435558)
IntegrationTestCaveats:testRefinanceAsLender() (gas: 1088316)
IntegrationTestCaveats:testRefinanceCaveatFailure() (gas: 437472)
IntegrationTestCaveats:testRefinanceLoanStartAtBlockTimestampInvalidLoan() (gas: 384742)
IntegrationTestCaveats:testRefinanceUnapprovedFulfiller() (gas: 495279)
IntegrationTestCaveats:testRefinanceWCaveatsInvalidSalt() (gas: 414143)
IntegrationTestCaveats:testRefinanceWLenderApproval() (gas: 437399)
ModuleTesting:testFixedTermDutchAuctionSettlement() (gas: 436114)
ModuleTesting:testFixedTermDutchAuctionSettlementGetSettlementAuctionExpired() (gas: 438892)
ModuleTesting:testFixedTermDutchAuctionSettlementNotValid() (gas: 435002)
ModuleTesting:testFixedTermDutchAuctionSettlementValid() (gas: 435866)
PausableNonReentrantImpl:test() (gas: 2442)
PausableNonReentrantImpl:testReentrancy() (gas: 2735)
TestBorrowerEnforcer:testBERevertAdditionalTransfers() (gas: 75662)
Expand All @@ -31,22 +31,22 @@ TestCustodian:testGenerateOrderInvalidPostRepayment() (gas: 178774)
TestCustodian:testGenerateOrderInvalidPostSettlement() (gas: 163188)
TestCustodian:testGenerateOrderRepay() (gas: 182892)
TestCustodian:testGenerateOrderRepayAsRepayApprovedBorrower() (gas: 199361)
TestCustodian:testGenerateOrderRepayERC1155AndERC20() (gas: 881395)
TestCustodian:testGenerateOrderRepayERC1155AndERC20HandlerAuthorized() (gas: 802829)
TestCustodian:testGenerateOrderRepayERC1155AndERC20() (gas: 882011)
TestCustodian:testGenerateOrderRepayERC1155AndERC20HandlerAuthorized() (gas: 803445)
TestCustodian:testGenerateOrderRepayInvalidHookAddress() (gas: 97601)
TestCustodian:testGenerateOrderRepayInvalidHookReturnType() (gas: 91984)
TestCustodian:testGenerateOrderRepayNotBorrower() (gas: 106802)
TestCustodian:testGenerateOrderSettlement() (gas: 154943)
TestCustodian:testGenerateOrderSettlementHandlerAuthorized() (gas: 160340)
TestCustodian:testGenerateOrderSettlementNoActiveLoan() (gas: 163351)
TestCustodian:testGenerateOrderSettlementUnauthorized() (gas: 101822)
TestCustodian:testGenerateOrdersWithLoanStartAtBlockTimestampInvalidLoan() (gas: 460672)
TestCustodian:testGenerateOrdersWithLoanStartAtBlockTimestampInvalidLoan() (gas: 460980)
TestCustodian:testGetBorrower() (gas: 78641)
TestCustodian:testInvalidAction() (gas: 173284)
TestCustodian:testInvalidActionRepayInActiveLoan() (gas: 130104)
TestCustodian:testInvalidActionSettleActiveLoan() (gas: 130086)
TestCustodian:testInvalidEncodedData() (gas: 26192)
TestCustodian:testMintWithApprovalSetAsBorrower() (gas: 364940)
TestCustodian:testMintWithApprovalSetAsBorrower() (gas: 362721)
TestCustodian:testMintWithApprovalSetAsBorrowerInvalidLoan() (gas: 60792)
TestCustodian:testMintWithApprovalSetNotAuthorized() (gas: 76759)
TestCustodian:testName() (gas: 7121)
Expand All @@ -63,40 +63,42 @@ TestCustodian:testSupportsInterface() (gas: 9428)
TestCustodian:testSymbol() (gas: 7105)
TestCustodian:testTokenURI() (gas: 67024)
TestCustodian:testTokenURIInvalidLoan() (gas: 13151)
TestFuzzStarport:testFuzzNewOrigination((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8)) (runs: 256, μ: 480560, ~: 477975)
TestFuzzStarport:testFuzzRefinance(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),string,uint8,uint256,uint256,uint256)) (runs: 256, μ: 1319546, ~: 1321205)
TestFuzzStarport:testFuzzRepaymentFails(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),(uint8,address,uint256,uint256)[10],(uint8,address,uint256,uint256)[10],address[3],uint256)) (runs: 256, μ: 804943, ~: 799555)
TestFuzzStarport:testFuzzRepaymentSuccess(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),(uint8,address,uint256,uint256)[10],(uint8,address,uint256,uint256)[10],address[3],uint256)) (runs: 256, μ: 674643, ~: 673107)
TestFuzzStarport:testFuzzSettlementFails(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),(uint8,address,uint256,uint256)[10],(uint8,address,uint256,uint256)[10],address[3],uint256)) (runs: 256, μ: 784821, ~: 783762)
TestFuzzStarport:testFuzzSettlementSuccess(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),uint256)) (runs: 256, μ: 658947, ~: 656208)
TestFuzzStarport:testFuzzNewOrigination((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8)) (runs: 256, μ: 482689, ~: 480860)
TestFuzzStarport:testFuzzRefinance(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),string,uint8,uint256,uint256,uint256)) (runs: 256, μ: 1319456, ~: 1319887)
TestFuzzStarport:testFuzzRepaymentFails(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),(uint8,address,uint256,uint256)[10],(uint8,address,uint256,uint256)[10],address[3],uint256)) (runs: 256, μ: 804336, ~: 801869)
TestFuzzStarport:testFuzzRepaymentSuccess(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),(uint8,address,uint256,uint256)[10],(uint8,address,uint256,uint256)[10],address[3],uint256)) (runs: 256, μ: 673412, ~: 676288)
TestFuzzStarport:testFuzzSettlementFails(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),(uint8,address,uint256,uint256)[10],(uint8,address,uint256,uint256)[10],address[3],uint256)) (runs: 256, μ: 784447, ~: 787224)
TestFuzzStarport:testFuzzSettlementSuccess(((bool,address,uint256,uint256,uint256,uint256,(uint8,address,uint256,uint256)[],uint8),uint256)) (runs: 256, μ: 654443, ~: 651971)
TestLenderEnforcer:testLERevertAdditionalTransfersFromLender() (gas: 76210)
TestLenderEnforcer:testLERevertInvalidLoanTerms() (gas: 80962)
TestLenderEnforcer:testLEValidLoanTerms() (gas: 71955)
TestLenderEnforcer:testLEValidLoanTermsAnyBorrower() (gas: 72087)
TestLenderEnforcer:testLEValidLoanTermsWithAdditionalTransfers() (gas: 73310)
TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 598751)
TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 605964)
TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 597045)
TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 586855)
TestNewLoan:testBuyNowPayLater() (gas: 2872284)
TestNewLoan:testInvalidSenderBNPL() (gas: 1613698)
TestLoanCombinations:testLoan20For721SimpleInterestDutchFixedRepay() (gas: 599059)
TestLoanCombinations:testLoan20for20SimpleInterestDutchFixedRepay() (gas: 606272)
TestLoanCombinations:testLoan721for20SimpleInterestDutchFixedRepay() (gas: 597353)
TestLoanCombinations:testLoanAstariaSettlementRepay() (gas: 587163)
TestNewLoan:testBuyNowPayLater() (gas: 2872468)
TestNewLoan:testInvalidSenderBNPL() (gas: 1613720)
TestNewLoan:testInvalidUserDataHashBNPL() (gas: 1616299)
TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 427647)
TestNewLoan:testNewLoanRefinance() (gas: 589048)
TestNewLoan:testNewLoanViaOriginatorBorrowerApprovalAndLenderApproval() (gas: 328481)
TestNewLoan:testNewLoanViaOriginatorLenderApproval() (gas: 384557)
TestNewLoan:testSettleLoan() (gas: 639688)
TestNewLoan:testNewLoanAs1271ProxyAccountSender() (gas: 864031)
TestNewLoan:testNewLoanAs1271ProxyAccountThirdPartyFiller() (gas: 873452)
TestNewLoan:testNewLoanERC721CollateralDefaultTerms2() (gas: 427278)
TestNewLoan:testNewLoanRefinance() (gas: 588737)
TestNewLoan:testNewLoanViaOriginatorBorrowerApprovalAndLenderApproval() (gas: 328366)
TestNewLoan:testNewLoanViaOriginatorLenderApproval() (gas: 384660)
TestNewLoan:testSettleLoan() (gas: 639318)
TestPausableNonReentrant:testNotOwner() (gas: 21254)
TestPausableNonReentrant:testPauseAndUnpause() (gas: 22555)
TestPausableNonReentrant:testReentrancy() (gas: 15360)
TestPausableNonReentrant:testUnpauseWhenNotPaused() (gas: 12582)
TestRefStarportLib:testValidateSalt(address,bytes32) (runs: 256, μ: 33998, ~: 33998)
TestRepayLoan:testRepayLoanApprovedRepayer() (gas: 672362)
TestRepayLoan:testRepayLoanBase() (gas: 608565)
TestRepayLoan:testRepayLoanGenerateOrderNotSeaport() (gas: 436001)
TestRepayLoan:testRepayLoanInSettlement() (gas: 582969)
TestRepayLoan:testRepayLoanInvalidRepayer() (gas: 606735)
TestRepayLoan:testRepayLoanThatDoesNotExist() (gas: 884110)
TestRepayLoan:testRepayLoanApprovedRepayer() (gas: 672670)
TestRepayLoan:testRepayLoanBase() (gas: 608873)
TestRepayLoan:testRepayLoanGenerateOrderNotSeaport() (gas: 436309)
TestRepayLoan:testRepayLoanInSettlement() (gas: 583277)
TestRepayLoan:testRepayLoanInvalidRepayer() (gas: 607043)
TestRepayLoan:testRepayLoanThatDoesNotExist() (gas: 884418)
TestSimpleInterestPricing:test_calculateInterest() (gas: 881308)
TestSimpleInterestPricing:test_getPaymentConsideration() (gas: 928516)
TestSimpleInterestPricing:test_getRefinanceConsideration() (gas: 919289)
Expand All @@ -110,8 +112,8 @@ TestStarport:testCannotOriginateWhilePaused() (gas: 73457)
TestStarport:testCannotSettleInvalidLoan() (gas: 74915)
TestStarport:testCannotSettleUnlessValidCustodian() (gas: 70985)
TestStarport:testCaveatEnforcerRevert() (gas: 99214)
TestStarport:testDefaultFeeRake() (gas: 363566)
TestStarport:testDefaultFeeRakeExoticDebt() (gas: 373079)
TestStarport:testDefaultFeeRake() (gas: 361348)
TestStarport:testDefaultFeeRakeExoticDebt() (gas: 370860)
TestStarport:testExoticDebtWithNoCaveatsNotAsBorrower() (gas: 377331)
TestStarport:testIncrementCaveatNonce() (gas: 35208)
TestStarport:testInitializedFlagSetProperly() (gas: 67393)
Expand All @@ -126,7 +128,7 @@ TestStarport:testInvalidateCaveatSalt() (gas: 33463)
TestStarport:testNonDefaultCustodianCustodyCallFails() (gas: 264374)
TestStarport:testNonDefaultCustodianCustodyCallSuccess() (gas: 290587)
TestStarport:testNonPayableFunctions() (gas: 112043)
TestStarport:testOverrideFeeRake() (gas: 359463)
TestStarport:testOverrideFeeRake() (gas: 357244)
TestStarport:testPause() (gas: 18093)
TestStarport:testRefinancePostRepaymentFails() (gas: 120804)
TestStarport:testTokenNoCodeCollateral() (gas: 148242)
Expand Down
7 changes: 6 additions & 1 deletion test/StarportTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,12 @@ contract StarportTest is BaseOrderTest {
) internal returns (Starport.Loan memory originatedLoan) {
vm.recordLogs();
vm.startPrank(fulfiller);
SP.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, loan);
SP.originate(
new AdditionalTransfer[](0),
fulfiller != borrower.addr ? borrowerCaveat : _emptyCaveat(),
fulfiller != lender.addr ? lenderCaveat : _emptyCaveat(),
loan
);
vm.stopPrank();

Vm.Log[] memory logs = vm.getRecordedLogs();
Expand Down
179 changes: 177 additions & 2 deletions test/integration-testing/TestNewLoan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "starport-test/StarportTest.sol";
import {StarportLib, Actions} from "starport-core/lib/StarportLib.sol";
import {BNPLHelper, IFlashLoanRecipient} from "starport-core/BNPLHelper.sol";
import {Originator} from "starport-core/originators/Originator.sol";
import {SignatureCheckerLib} from "solady/src/utils/SignatureCheckerLib.sol";

contract FlashLoan {
function flashLoan(
Expand Down Expand Up @@ -51,10 +52,44 @@ contract FlashLoan {
}
}

contract ERC1271Proxy {
address public immutable owner;

constructor(address owner_) {
owner = owner_;
}

struct Action {
address to;
bytes data;
}

function execute(bytes[] calldata encodedAction, bytes calldata signature) public payable {
if (msg.sender != owner) {
require(
SignatureCheckerLib.isValidSignatureNowCalldata(owner, keccak256(abi.encode(encodedAction)), signature),
"invalid signature"
);
}
for (uint256 i = 0; i < encodedAction.length; i++) {
Action memory action = abi.decode(encodedAction[i], (Action));
(bool success, bytes memory returnData) = action.to.call(action.data);
require(success, string(returnData));
}
}

function isValidSignature(bytes32 _messageHash, bytes calldata _signature)
public
view
returns (bytes4 magicValue)
{
require(SignatureCheckerLib.isValidSignatureNowCalldata(owner, _messageHash, _signature), "invalid signature");
return this.isValidSignature.selector;
}
}

contract TestNewLoan is StarportTest {
function testNewLoanERC721CollateralDefaultTerms2() public returns (Starport.Loan memory) {
Custodian custody = Custodian(SP.defaultCustodian());

Starport.Terms memory terms = Starport.Terms({
status: address(status),
settlement: address(settlement),
Expand Down Expand Up @@ -398,4 +433,144 @@ contract TestNewLoan is StarportTest {
recipient: address(0)
});
}

function testNewLoanAs1271ProxyAccountSender() public {
ERC1271Proxy proxy = new ERC1271Proxy(borrower.addr);

uint256 initial721Balance = erc721s[0].balanceOf(borrower.addr);
assertTrue(initial721Balance > 0, "Test must have at least one erc721 token");
uint256 initial20Balance = erc20s[0].balanceOf(borrower.addr);

Starport.Loan memory originationDetails = _generateOriginationDetails(
_getERC721SpentItem(erc721s[0]), _getERC20SpentItem(erc20s[0], 100), lender.addr
);
originationDetails.borrower = address(proxy);
_setApprovalsForSpentItems(originationDetails.issuer, originationDetails.debt);

CaveatEnforcer.SignedCaveats memory borrowerCaveat = _generateSignedCaveatsBorrowerProxy(
originationDetails, address(proxy), borrower, address(borrowerEnforcer), bytes32(msg.sig), true
);
CaveatEnforcer.SignedCaveats memory lenderCaveat =
_generateSignedCaveatLender(originationDetails, lender, bytes32(msg.sig), true);

vm.prank(borrower.addr);
erc721s[0].approve(address(proxy), 1);
vm.prank(lender.addr);
erc20s[0].transfer(address(proxy), 1);
bytes[] memory actions = new bytes[](4);
actions[0] = abi.encode(
ERC1271Proxy.Action({
to: address(erc721s[0]),
data: abi.encodeWithSelector(ERC721.transferFrom.selector, borrower.addr, address(proxy), 1)
})
);
actions[1] = abi.encode(
ERC1271Proxy.Action({
to: address(erc721s[0]),
data: abi.encodeWithSelector(ERC721.approve.selector, address(SP), 1)
})
);
actions[2] = abi.encode(
ERC1271Proxy.Action({
to: address(SP),
data: abi.encodeWithSelector(
Starport.originate.selector,
new AdditionalTransfer[](0),
_emptyCaveat(),
lenderCaveat,
originationDetails
)
})
);
actions[3] = abi.encode(
ERC1271Proxy.Action({
to: address(erc20s[0]),
data: abi.encodeWithSelector(ERC20.transfer.selector, borrower.addr, originationDetails.debt[0].amount)
})
);

bytes32 hash = keccak256(abi.encode(actions));

(uint8 v, bytes32 r, bytes32 s) = vm.sign(borrower.key, hash);
vm.startPrank(fulfiller.addr);
proxy.execute(actions, abi.encodePacked(r, s, v));
}

function testNewLoanAs1271ProxyAccountThirdPartyFiller() public {
ERC1271Proxy proxy = new ERC1271Proxy(borrower.addr);

Starport.Loan memory originationDetails = _generateOriginationDetails(
_getERC721SpentItem(erc721s[0]), _getERC20SpentItem(erc20s[0], 100), lender.addr
);
originationDetails.borrower = address(proxy);
_setApprovalsForSpentItems(originationDetails.issuer, originationDetails.debt);

CaveatEnforcer.SignedCaveats memory borrowerCaveat = _generateSignedCaveatsBorrowerProxy(
originationDetails, address(proxy), borrower, address(borrowerEnforcer), bytes32(msg.sig), true
);
CaveatEnforcer.SignedCaveats memory lenderCaveat =
_generateSignedCaveatLender(originationDetails, lender, bytes32(msg.sig), true);

vm.prank(borrower.addr);
erc721s[0].approve(address(proxy), 1);
vm.prank(lender.addr);
erc20s[0].transfer(address(proxy), 1);
bytes[] memory actions = new bytes[](2);
actions[0] = abi.encode(
ERC1271Proxy.Action({
to: address(erc721s[0]),
data: abi.encodeWithSelector(ERC721.transferFrom.selector, borrower.addr, address(proxy), 1)
})
);
actions[1] = abi.encode(
ERC1271Proxy.Action({
to: address(erc721s[0]),
data: abi.encodeWithSelector(ERC721.approve.selector, address(SP), 1)
})
);

bytes32 hash = keccak256(abi.encode(actions));

(uint8 v, bytes32 r, bytes32 s) = vm.sign(borrower.key, hash);
vm.startPrank(fulfiller.addr);
proxy.execute(actions, abi.encodePacked(r, s, v));
SP.originate(new AdditionalTransfer[](0), borrowerCaveat, lenderCaveat, originationDetails);
}

function signCaveatForProxyAccount(
CaveatEnforcer.Caveat memory caveat,
bytes32 salt,
address account,
Account memory signer,
bool invalidate
) public view returns (CaveatEnforcer.SignedCaveats memory signedCaveats) {
signedCaveats = CaveatEnforcer.SignedCaveats({
signature: "",
singleUse: invalidate,
deadline: block.timestamp + 1 days,
salt: salt,
caveats: new CaveatEnforcer.Caveat[](1)
});

signedCaveats.caveats[0] = caveat;
bytes32 hash = SP.hashCaveatWithSaltAndNonce(
account, signedCaveats.singleUse, salt, signedCaveats.deadline, signedCaveats.caveats
);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(signer.key, hash);
signedCaveats.signature = abi.encodePacked(r, s, v);
}

function _generateSignedCaveatsBorrowerProxy(
Starport.Loan memory loan,
address account,
Account memory signer,
address enforcer,
bytes32 salt,
bool invalidate
) public view returns (CaveatEnforcer.SignedCaveats memory) {
LenderEnforcer.Details memory details = LenderEnforcer.Details({loan: loan});
return signCaveatForProxyAccount(
CaveatEnforcer.Caveat({enforcer: enforcer, data: abi.encode(details)}), salt, account, signer, invalidate
);
}
}

0 comments on commit c662f01

Please sign in to comment.