Skip to content

Commit

Permalink
finalize validate testing
Browse files Browse the repository at this point in the history
  • Loading branch information
androolloyd committed Nov 20, 2023
1 parent 8c1e9b3 commit 3f3af1a
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 55 deletions.
2 changes: 1 addition & 1 deletion lib/starport
28 changes: 17 additions & 11 deletions src/pricing/AstariaV1Pricing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,17 @@ contract AstariaV1Pricing is CompoundInterestPricing {
// check if a recall is occuring
AstariaV1Status status = AstariaV1Status(loan.terms.status);

if (!status.isRecalled(loan)) {
Details memory newDetails = abi.decode(newPricingData, (Details));
Details memory oldDetails = abi.decode(loan.terms.pricingData, (Details));
if (!status.isRecalled(loan) || newDetails.decimals != oldDetails.decimals || newDetails.rate == 0) {
revert InvalidRefinance();
}
Details memory newDetails = abi.decode(newPricingData, (Details));
uint256 rate = status.getRecallRate(loan);
// offered loan did not meet the terms of the recall auction
if (newDetails.rate > rate) {
revert InsufficientRefinance();
}

Details memory oldDetails = abi.decode(loan.terms.pricingData, (Details));

uint256 proportion;
address payable receiver = payable(loan.issuer);
uint256 loanId = loan.getId();
Expand All @@ -75,13 +74,20 @@ contract AstariaV1Pricing is CompoundInterestPricing {
}

// @inheritdoc Validation
function validate(Starport.Loan calldata loan) external pure virtual override returns (bytes4) {
uint256 loanRate = abi.decode(loan.terms.pricingData, (BasePricing.Details)).rate;
uint256 loanAmount = loan.debt[0].amount;
uint256 recallMax = AstariaV1Lib.getBaseRecallRecallMax(loan.terms.statusData);
uint256 decimals = AstariaV1Lib.getBasePricingDecimals(loan.terms.pricingData);
function validate(Starport.Loan calldata loan) external view virtual override returns (bytes4 selector) {
if (msg.sender == address(this)) {
uint256 loanRate = abi.decode(loan.terms.pricingData, (BasePricing.Details)).rate;
uint256 loanAmount = loan.debt[0].amount;
uint256 recallMax = AstariaV1Lib.getBaseRecallRecallMax(loan.terms.statusData);
uint256 decimals = AstariaV1Lib.getBasePricingDecimals(loan.terms.pricingData);

AstariaV1Lib.validateCompoundInterest(loanAmount, loanRate, recallMax, decimals);
return Validation.validate.selector;
AstariaV1Lib.validateCompoundInterest(loanAmount, loanRate, recallMax, decimals);
} else {
try Validation(address(this)).validate(loan) {
selector = Validation.validate.selector;
} catch {
selector = bytes4(0xFFFFFFFF);
}
}
}
}
3 changes: 0 additions & 3 deletions src/settlement/AstariaV1Settlement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,6 @@ contract AstariaV1Settlement is DutchAuctionSettlement {

// @inheritdoc Validation
function validate(Starport.Loan calldata loan) external view virtual override returns (bytes4) {
if (loan.terms.settlement != address(this)) {
revert InvalidHandler();
}
Details memory details = abi.decode(loan.terms.settlementData, (Details)); // Will revert if this fails
return (details.startingPrice > details.endingPrice) ? Validation.validate.selector : bytes4(0xFFFFFFFF);
}
Expand Down
5 changes: 1 addition & 4 deletions src/status/AstariaV1Status.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,7 @@ contract AstariaV1Status is BaseStatus, BaseRecall {
Details memory details = abi.decode(loan.terms.statusData, (Details));
BasePricing.Details memory pDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details));
bool valid = true;
if (
details.recallerRewardRatio > 10 ** pDetails.decimals || details.recallMax > 10 * 10 ** pDetails.decimals
|| details.honeymoon == 0
) {
if (details.recallerRewardRatio > 10 ** pDetails.decimals || details.recallMax > 10 * 10 ** pDetails.decimals) {
valid = false;
}
return valid ? Validation.validate.selector : bytes4(0xFFFFFFFF);
Expand Down
64 changes: 31 additions & 33 deletions test/TestV1Pricing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {AstariaV1Lib} from "v1-core/lib/AstariaV1Lib.sol";
import {DeepEq} from "starport-test/utils/DeepEq.sol";
import {SpentItemLib} from "seaport-sol/src/lib/SpentItemLib.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
import {Validation} from "starport-core/lib/Validation.sol";

contract TestAstariaV1Pricing is AstariaV1Test, DeepEq {
using Cast for *;
Expand Down Expand Up @@ -96,50 +97,33 @@ contract TestAstariaV1Pricing is AstariaV1Test, DeepEq {
_deepEq(expectedAdditionalTransfers, additionalTransfers);
}

//TODO: is 0 rate allowed?
function testGetRefinanceConsiderationZeroRate() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
loan.start = uint256(1);
loan.originator = address(this);
vm.warp(2);
BasePricing.Details memory baseDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details));
bytes memory newPricingData = abi.encode(BasePricing.Details({carryRate: 0, rate: 0, decimals: 18}));
BaseRecall.Details memory statusDetails = abi.decode(loan.terms.statusData, (BaseRecall.Details));
uint256 proportion = 1e18 - (baseDetails.rate - 0).divWad(baseDetails.rate);
vm.mockCall(
loan.terms.status, abi.encodeWithSelector(AstariaV1Status.isRecalled.selector, loan), abi.encode(true)
);
SpentItem[] memory expectedConsideration = new SpentItem[](1);
expectedConsideration[0] = SpentItem({
itemType: loan.debt[0].itemType,
amount: loan.debt[0].amount
+ AstariaV1Lib.calculateCompoundInterest(
block.timestamp - loan.start, loan.debt[0].amount, baseDetails.rate, 18
),
identifier: loan.debt[0].identifier,
token: loan.debt[0].token
});
SpentItem[] memory expectedCarryConsideration = new SpentItem[](0);
AdditionalTransfer[] memory expectedAdditionalTransfers = new AdditionalTransfer[](1);
expectedAdditionalTransfers[0] = AdditionalTransfer({
identifier: loan.debt[0].identifier,
itemType: loan.debt[0].itemType,
token: loan.debt[0].token,
amount: AstariaV1Lib.calculateCompoundInterest(
statusDetails.recallStakeDuration, loan.debt[0].amount, baseDetails.rate, 18
).mulWad(proportion),
to: loan.issuer,
from: address(this)
});
vm.expectRevert(Pricing.InvalidRefinance.selector);
Pricing(loan.terms.pricing).getRefinanceConsideration(loan, newPricingData, address(this));
}

(
SpentItem[] memory consideration,
SpentItem[] memory carryConsideration,
AdditionalTransfer[] memory additionalTransfers
) = Pricing(loan.terms.pricing).getRefinanceConsideration(loan, newPricingData, address(this));
_deepEq(consideration, expectedConsideration);
_deepEq(carryConsideration, expectedCarryConsideration);
_deepEq(expectedAdditionalTransfers, additionalTransfers);
function testGetRefinanceNewDecimalMismatch() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
loan.start = uint256(1);
loan.originator = address(this);
vm.warp(2);
BasePricing.Details memory baseDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details));
bytes memory newPricingData =
abi.encode(BasePricing.Details({carryRate: 0, rate: baseDetails.rate, decimals: 6}));
vm.mockCall(
loan.terms.status, abi.encodeWithSelector(AstariaV1Status.isRecalled.selector, loan), abi.encode(true)
);
vm.expectRevert(Pricing.InvalidRefinance.selector);
Pricing(loan.terms.pricing).getRefinanceConsideration(loan, newPricingData, address(this));
}

function testGetRefinanceConsiderationValidEqualRate() public {
Expand Down Expand Up @@ -304,4 +288,18 @@ contract TestAstariaV1Pricing is AstariaV1Test, DeepEq {
_deepEq(carryConsideration, expectedCarryConsideration);
_deepEq(expectedAdditionalTransfers, additionalTransfers);
}

function testV1PricingValidateValid() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
assert(Validation(loan.terms.pricing).validate(loan) == Validation.validate.selector);
}

function testV1PricingValidateInvalid() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
BasePricing.Details memory baseDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details));
baseDetails.rate = 0;

loan.terms.pricingData = abi.encode(baseDetails);
assert(Validation(loan.terms.pricing).validate(loan) == bytes4(0xFFFFFFFF));
}
}
15 changes: 15 additions & 0 deletions test/TestV1Settlement.sol
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,19 @@ contract TestAstariaV1Settlement is AstariaV1Test, DeepEq {
vm.expectRevert(abi.encodeWithSelector(AstariaV1Settlement.InvalidHandler.selector));
AstariaV1Settlement(settlement).validate(loan);
}

function testV1SettlementValidateValid() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
assert(Validation(loan.terms.settlement).validate(loan) == Validation.validate.selector);
}

function testV1SettlementValidateInvalid() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
DutchAuctionSettlement.Details memory details =
abi.decode(loan.terms.settlementData, (DutchAuctionSettlement.Details));
details.endingPrice = 10;
details.startingPrice = 1;
loan.terms.settlementData = abi.encode(details);
assert(Validation(loan.terms.settlement).validate(loan) == bytes4(0xFFFFFFFF));
}
}
21 changes: 21 additions & 0 deletions test/TestV1Status.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {StarportLib, Actions} from "starport-core/lib/StarportLib.sol";
import {DeepEq} from "starport-test/utils/DeepEq.sol";
import {SpentItemLib} from "seaport-sol/src/lib/SpentItemLib.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
import {Validation} from "starport-core/lib/Validation.sol";

contract TestAstariaV1Status is AstariaV1Test, DeepEq {
using Cast for *;
Expand Down Expand Up @@ -314,6 +315,26 @@ contract TestAstariaV1Status is AstariaV1Test, DeepEq {
vm.expectRevert(abi.encodeWithSelector(BaseRecall.LoanHasNotBeenRefinanced.selector));
AstariaV1Status(loan.terms.status).withdraw(loan, payable(address(this)));
}

function testV1StatusValidateValid() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
assert(Validation(loan.terms.status).validate(loan) == Validation.validate.selector);
}

//if (details.recallerRewardRatio > 10 ** pDetails.decimals || details.recallMax > 10 * 10 ** pDetails.decimals) {
function testV1StatusValidateInValid() public {
Starport.Loan memory loan = generateDefaultLoanTerms();
bytes memory defaultDetailsData = loan.terms.statusData;
BaseRecall.Details memory details = abi.decode(loan.terms.statusData, (BaseRecall.Details));
details.recallerRewardRatio = 10 ** 19;
loan.terms.statusData = abi.encode(details);
assert(Validation(loan.terms.status).validate(loan) == bytes4(0xFFFFFFFF));
details = abi.decode(defaultDetailsData, (BaseRecall.Details));
details.recallMax = 1000 ** 19;
loan.terms.statusData = abi.encode(details);
assert(Validation(loan.terms.status).validate(loan) == bytes4(0xFFFFFFFF));
}

// //TODO: this needs to be done because withdraw is being looked at
// function testRecallWithdraw() public {
// Starport.Terms memory terms = Starport.Terms({
Expand Down
24 changes: 21 additions & 3 deletions test/fuzz-testing/TestFuzzV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,23 @@ contract TestFuzzV1 is AstariaV1Test, TestFuzzStarport {
skip(_boundMax(1, uint256(3 * 365 days)));
}

function willArithmeticOverflow(Starport.Loan memory loan) internal view virtual override returns (bool) {
BasePricing.Details memory pricingDetails = abi.decode(loan.terms.pricingData, (BasePricing.Details));
try Pricing(loan.terms.pricing).getPaymentConsideration(loan) returns (
SpentItem[] memory repayConsideration, SpentItem[] memory carryConsideration
) {
unchecked {
uint256 newSupply = erc20s[0].totalSupply() + repayConsideration[0].amount;
if (newSupply < erc20s[0].totalSupply() || newSupply < repayConsideration[0].amount) {
return true;
}
}
return false;
} catch {
return true;
}
}

function _skipToSettlement(Starport.Loan memory goodLoan) internal virtual override {
BasePricing.Details memory pricingDetails = abi.decode(goodLoan.terms.pricingData, (BasePricing.Details));
BaseRecall.Details memory details = abi.decode(goodLoan.terms.statusData, (BaseRecall.Details));
Expand Down Expand Up @@ -263,9 +280,10 @@ contract TestFuzzV1 is AstariaV1Test, TestFuzzStarport {
SpentItem[] memory carryPayment,
bytes memory pricingData
) internal virtual returns (CaveatEnforcer.SignedCaveats memory signedCaveats) {
LenderEnforcer.Details memory details = LenderEnforcer.Details({
loan: SP.applyRefinanceConsiderationToLoan(goodLoan, considerationPayment, carryPayment, pricingData)
});
Starport.Loan memory refiLoan = loanCopy(goodLoan);
refiLoan.terms.pricingData = pricingData;
refiLoan.debt = SP.applyRefinanceConsiderationToLoan(considerationPayment, carryPayment);
LenderEnforcer.Details memory details = LenderEnforcer.Details({loan: refiLoan});

AstariaV1LenderEnforcer.V1LenderDetails memory lenderDetails =
AstariaV1LenderEnforcer.V1LenderDetails({matchIdentifier: true, details: details});
Expand Down

0 comments on commit 3f3af1a

Please sign in to comment.