Skip to content

Commit

Permalink
Merge branch 'master' into feat/license-cleanup-imports
Browse files Browse the repository at this point in the history
  • Loading branch information
justingreenberg authored Nov 20, 2023
2 parents b5374b8 + 4e0b967 commit 036beea
Show file tree
Hide file tree
Showing 12 changed files with 685 additions and 268 deletions.
240 changes: 121 additions & 119 deletions .gas-snapshot

Large diffs are not rendered by default.

96 changes: 64 additions & 32 deletions src/Starport.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ contract Starport is PausableNonReentrant {
BORROWER,
LENDER
}
enum FieldFlags {
INACTIVE,
ACTIVE
}

uint256 public constant LOAN_INACTIVE_FLAG = 0x0;
uint256 public constant LOAN_ACTIVE_FLAG = 0x1;

struct Terms {
address status; // the address of the status module
Expand Down Expand Up @@ -195,12 +194,13 @@ contract Starport is PausableNonReentrant {

_settle(loan);
_postRepaymentExecute(loan, msg.sender);
loan = applyRefinanceConsiderationToLoan(loan, considerationPayment, carryPayment, pricingData);

StarportLib.transferSpentItems(considerationPayment, lender, loan.issuer, false);
if (carryPayment.length > 0) {
StarportLib.transferSpentItems(carryPayment, lender, loan.originator, false);
}
loan.debt = applyRefinanceConsiderationToLoan(considerationPayment, carryPayment);
loan.terms.pricingData = pricingData;

loan.issuer = lender;
loan.originator = address(0);
Expand Down Expand Up @@ -232,44 +232,47 @@ contract Starport is PausableNonReentrant {

/**
* @dev Refinances an existing loan with new pricing data, its the only thing that can be changed
* @param loan The target loan
* @param considerationPayment the payment consideration
* @param carryPayment The loan to be issued
* @param pricingData The new pricing data
*/
function applyRefinanceConsiderationToLoan(
Starport.Loan memory loan,
SpentItem[] memory considerationPayment,
SpentItem[] memory carryPayment,
bytes calldata pricingData
) public pure returns (Starport.Loan memory) {
function applyRefinanceConsiderationToLoan(SpentItem[] memory considerationPayment, SpentItem[] memory carryPayment)
public
pure
returns (SpentItem[] memory newDebt)
{
if (
considerationPayment.length == 0
|| (carryPayment.length != 0 && considerationPayment.length != carryPayment.length)
|| considerationPayment.length != loan.debt.length
) {
revert MalformedRefinance();
}

uint256 i = 0;
if (carryPayment.length > 0) {
SpentItem[] memory newDebt = new SpentItem[](considerationPayment.length);
uint256 i = 0;
for (; i < considerationPayment.length;) {
loan.debt[i].amount = considerationPayment[i].amount + carryPayment[i].amount;

newDebt[i] = considerationPayment[i];
newDebt[i].amount += carryPayment[i].amount;
if (newDebt[i].itemType == ItemType.ERC721 && newDebt[i].amount > 1) {
revert MalformedRefinance();
}
unchecked {
++i;
}
}
return newDebt;
} else {
uint256 i = 0;
for (; i < considerationPayment.length;) {
loan.debt[i].amount = considerationPayment[i].amount;
if (considerationPayment[i].itemType == ItemType.ERC721 && considerationPayment[i].amount > 1) {
revert MalformedRefinance();
}
unchecked {
++i;
}
}
return considerationPayment;
}
loan.terms.pricingData = pricingData;
return loan;
}

/**
Expand Down Expand Up @@ -438,7 +441,7 @@ contract Starport is PausableNonReentrant {
* @return bool True if the loan is active
*/
function active(uint256 loanId) public view returns (bool) {
return loanState[loanId] == uint256(FieldFlags.ACTIVE);
return loanState[loanId] == LOAN_ACTIVE_FLAG;
}

/**
Expand All @@ -447,11 +450,11 @@ contract Starport is PausableNonReentrant {
* @return bool True if the loan is inactive
*/
function inactive(uint256 loanId) public view returns (bool) {
return loanState[loanId] == uint256(FieldFlags.INACTIVE);
return loanState[loanId] == LOAN_INACTIVE_FLAG;
}

/**
* @dev Helper to check if a loan is initialized(ie. has never been opened)
* @dev Helper to settle a loan
* guarded to ensure only the loan.custodian can call it
* @param loan The entire loan struct
*/
Expand All @@ -462,17 +465,32 @@ contract Starport is PausableNonReentrant {
_settle(loan);
}

bytes32 private constant _INVALID_LOAN = 0x045f33d100000000000000000000000000000000000000000000000000000000;
bytes32 private constant _LOAN_EXISTS = 0x14ec57fc00000000000000000000000000000000000000000000000000000000;

/**
* @dev Internal helper to check if a loan is initialized
* @dev Internal helper to settle a loan
* @param loan The entire loan struct
*/
function _settle(Loan memory loan) internal {
uint256 loanId = loan.getId();
if (inactive(loanId)) {
revert InvalidLoan();
}
assembly {
mstore(0x0, loanId)
mstore(0x20, loanState.slot)

loanState[loanId] = uint256(FieldFlags.INACTIVE);
// loanState[loanId]

let loc := keccak256(0x0, 0x40)

// if (inactive(loanId)) {
if iszero(sload(loc)) {
//revert InvalidLoan()
mstore(0x0, _INVALID_LOAN)
revert(0x0, 0x04)
}

sstore(loc, LOAN_INACTIVE_FLAG)
}

emit Close(loanId);
}
Expand Down Expand Up @@ -558,11 +576,25 @@ contract Starport is PausableNonReentrant {
loan.originator = loan.originator != address(0) ? loan.originator : msg.sender;

uint256 loanId = loan.getId();
if (active(loanId)) {
revert LoanExists();
}
// if (active(loanId)) {
// revert LoanExists();
// }
//
assembly {
mstore(0x0, loanId)
mstore(0x20, loanState.slot)

//loanState[loanId]
let loc := keccak256(0x0, 0x40)
// if (active(loanId))
if iszero(iszero(sload(loc))) {
//revert LoanExists()
mstore(0x0, _LOAN_EXISTS)
revert(0x0, 0x04)
}

loanState[loanId] = uint256(FieldFlags.ACTIVE);
sstore(loc, LOAN_ACTIVE_FLAG)
}
emit Open(loanId, loan);
}
}
2 changes: 1 addition & 1 deletion src/enforcers/BorrowerEnforcer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ contract BorrowerEnforcer is CaveatEnforcer {
Details memory details
) internal pure {
details.loan.issuer = loan.issuer;

details.loan.originator = loan.originator;
if (keccak256(abi.encode(loan)) != keccak256(abi.encode(details.loan))) revert InvalidLoanTerms();

if (additionalTransfers.length > 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/enforcers/BorrowerEnforcerBNPL.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ contract BorrowerEnforcerBNPL is CaveatEnforcer {
revert BorrowerOnlyEnforcer();
}
details.loan.issuer = loan.issuer;

details.loan.originator = loan.originator;
if (loanHash != keccak256(abi.encode(details.loan))) {
revert InvalidLoanTerms();
}
Expand Down
1 change: 1 addition & 0 deletions src/enforcers/LenderEnforcer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ contract LenderEnforcer is CaveatEnforcer {
Details memory details
) internal pure {
details.loan.borrower = loan.borrower;
details.loan.originator = loan.originator;

if (keccak256(abi.encode(loan)) != keccak256(abi.encode(details.loan))) {
revert InvalidLoanTerms();
Expand Down
2 changes: 1 addition & 1 deletion src/pricing/SimpleInterestPricing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ contract SimpleInterestPricing is BasePricing {
Details memory oldDetails = abi.decode(loan.terms.pricingData, (Details));
Details memory newDetails = abi.decode(newPricingData, (Details));

if ((newDetails.rate < oldDetails.rate)) {
if (oldDetails.decimals == newDetails.decimals && (newDetails.rate < oldDetails.rate)) {
(repayConsideration, carryConsideration) = getPaymentConsideration(loan);
additionalConsideration = new AdditionalTransfer[](0);
} else {
Expand Down
17 changes: 6 additions & 11 deletions test/StarportTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ contract StarportTest is BaseOrderTest {
) internal returns (Starport.Loan memory) {
(CaveatEnforcer.SignedCaveats memory borrowerCaveat, CaveatEnforcer.SignedCaveats memory lenderCaveat) =
newLoanOriginationSetup(loan, borrower, borrowerSalt, lender, lenderSalt, invalidateLender);
vm.roll(1);
return newLoan(loan, borrowerCaveat, lenderCaveat, fulfiller);
}

Expand Down Expand Up @@ -482,16 +483,6 @@ contract StarportTest is BaseOrderTest {
return refinanceLoan(loan, newPricingData, asWho, lenderCaveat, lender, "");
}

function getRefinanceCaveat(Starport.Loan memory loan, bytes memory pricingData, address fulfiller)
public
view
returns (Starport.Loan memory)
{
(SpentItem[] memory considerationPayment, SpentItem[] memory carryPayment,) =
Pricing(loan.terms.pricing).getRefinanceConsideration(loan, pricingData, fulfiller);
return SP.applyRefinanceConsiderationToLoan(loan, considerationPayment, carryPayment, pricingData);
}

function refinanceLoan(
Starport.Loan memory loan,
bytes memory pricingData,
Expand Down Expand Up @@ -583,7 +574,11 @@ contract StarportTest is BaseOrderTest {
(SpentItem[] memory offer, ReceivedItem[] memory paymentConsideration) = Custodian(
payable(activeLoan.custodian)
).previewOrder(
address(consideration), fulfiller, new SpentItem[](0), new SpentItem[](0), abi.encode(activeLoan)
address(consideration),
fulfiller,
new SpentItem[](0),
new SpentItem[](0),
abi.encode(Custodian.Command(Actions.Settlement, activeLoan, ""))
);

OrderParameters memory op = _buildContractOrder(
Expand Down
Loading

0 comments on commit 036beea

Please sign in to comment.