Skip to content

Commit

Permalink
Fix "coverage stack too deep" issue foundry-rs/foundry#3357
Browse files Browse the repository at this point in the history
  • Loading branch information
aviggiano committed Jan 3, 2024
1 parent a2725dd commit c6097df
Show file tree
Hide file tree
Showing 19 changed files with 145 additions and 97 deletions.
2 changes: 1 addition & 1 deletion script/update_readme_coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -eu

forge coverage --ir-minimum > COVERAGE.txt
forge coverage > COVERAGE.txt

BEGIN=$(grep -n BEGIN_COVERAGE README.md | cut -d : -f 1)
END=$(grep -n END_COVERAGE README.md | cut -d : -f 1)
Expand Down
31 changes: 24 additions & 7 deletions src/SizeStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,40 @@ import {BorrowToken} from "@src/token/BorrowToken.sol";
import {CollateralToken} from "@src/token/CollateralToken.sol";
import {DebtToken} from "@src/token/DebtToken.sol";

struct State {
mapping(address => User) users;
Loan[] loans;
VariableLoan[] variableLoans;
IPriceFeed priceFeed;
struct Tokens {
IERC20Metadata collateralAsset;
IERC20Metadata borrowAsset;
CollateralToken collateralToken;
BorrowToken borrowToken;
DebtToken debtToken;
}

struct Vaults {
address protocol;
address insurance;
}

struct Config {
IPriceFeed priceFeed;
uint256 crOpening;
uint256 crLiquidation;
uint256 collateralPercentagePremiumToLiquidator;
uint256 collateralPercentagePremiumToBorrower;
address protocolVault;
address feeRecipient;
uint256 minimumCredit;
address feeRecipient;
}

struct State {
// slot 0
mapping(address => User) users;
// slot 1
Loan[] loans;
// slot 2
VariableLoan[] variableLoans;
// slot
Tokens tokens;
Vaults vaults;
Config config;
}

abstract contract SizeStorage {
Expand Down
31 changes: 16 additions & 15 deletions src/SizeView.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,32 @@ abstract contract SizeView is SizeStorage, ISizeView {
}

function crOpening() external view returns (uint256) {
return state.crOpening;
return state.config.crOpening;
}

function crLiquidation() external view returns (uint256) {
return state.crLiquidation;
return state.config.crLiquidation;
}

function collateralPercentagePremiumToLiquidator() external view returns (uint256) {
return state.collateralPercentagePremiumToLiquidator;
return state.config.collateralPercentagePremiumToLiquidator;
}

function collateralPercentagePremiumToBorrower() external view returns (uint256) {
return state.collateralPercentagePremiumToBorrower;
return state.config.collateralPercentagePremiumToBorrower;
}

function collateralPercentagePremiumToProtocol() external view returns (uint256) {
return PERCENT - (state.collateralPercentagePremiumToBorrower + state.collateralPercentagePremiumToLiquidator);
return PERCENT
- (state.config.collateralPercentagePremiumToBorrower + state.config.collateralPercentagePremiumToLiquidator);
}

function getUserView(address user) public view returns (UserView memory) {
return UserView({
user: state.users[user],
collateralAmount: state.collateralToken.balanceOf(user),
borrowAmount: state.borrowToken.balanceOf(user),
debtAmount: state.debtToken.balanceOf(user)
collateralAmount: state.tokens.collateralToken.balanceOf(user),
borrowAmount: state.tokens.borrowToken.balanceOf(user),
debtAmount: state.tokens.debtToken.balanceOf(user)
});
}

Expand Down Expand Up @@ -107,22 +108,22 @@ abstract contract SizeView is SizeStorage, ISizeView {
}

function minimumCredit() public view returns (uint256) {
return state.minimumCredit;
return state.config.minimumCredit;
}

function getProtocolVault() public view returns (uint256, uint256, uint256) {
return (
state.collateralToken.balanceOf(state.protocolVault),
state.borrowToken.balanceOf(state.protocolVault),
state.debtToken.balanceOf(state.protocolVault)
state.tokens.collateralToken.balanceOf(state.vaults.protocol),
state.tokens.borrowToken.balanceOf(state.vaults.protocol),
state.tokens.debtToken.balanceOf(state.vaults.protocol)
);
}

function getFeeRecipient() public view returns (uint256, uint256, uint256) {
return (
state.collateralToken.balanceOf(state.feeRecipient),
state.borrowToken.balanceOf(state.feeRecipient),
state.debtToken.balanceOf(state.feeRecipient)
state.tokens.collateralToken.balanceOf(state.config.feeRecipient),
state.tokens.borrowToken.balanceOf(state.config.feeRecipient),
state.tokens.debtToken.balanceOf(state.config.feeRecipient)
);
}
}
17 changes: 17 additions & 0 deletions src/libraries/VariablePoolLibrary.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.20;

import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";

import {PERCENT} from "@src/libraries/MathLibrary.sol";

struct VariablePool {
uint256 liquidityIndex;
uint256 totalLentOut;
uint256 minRate;
uint256 maxRate;
uint256 slope;
uint256 turningPoint;
}

library VariablePoolLibrary {}
12 changes: 7 additions & 5 deletions src/libraries/actions/BorrowAsMarketOrder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ library BorrowAsMarketOrder {
borrower: msg.sender,
faceValue: deltaAmountIn
});
state.borrowToken.transferFrom(params.lender, msg.sender, deltaAmountOut);
state.tokens.borrowToken.transferFrom(params.lender, msg.sender, deltaAmountOut);
loanOffer.maxAmount -= deltaAmountOut;
amountOutLeft -= deltaAmountOut;
}
Expand All @@ -152,13 +152,15 @@ library BorrowAsMarketOrder {
uint256 faceValue = FixedPointMathLib.mulDivUp(params.amount, r, PERCENT);
uint256 minimumCollateralOpening = state.getMinimumCollateralOpening(faceValue);

if (state.collateralToken.balanceOf(msg.sender) < minimumCollateralOpening) {
revert Errors.INSUFFICIENT_COLLATERAL(state.collateralToken.balanceOf(msg.sender), minimumCollateralOpening);
if (state.tokens.collateralToken.balanceOf(msg.sender) < minimumCollateralOpening) {
revert Errors.INSUFFICIENT_COLLATERAL(
state.tokens.collateralToken.balanceOf(msg.sender), minimumCollateralOpening
);
}

state.debtToken.mint(msg.sender, faceValue);
state.tokens.debtToken.mint(msg.sender, faceValue);
state.createFOL({lender: params.lender, borrower: msg.sender, faceValue: faceValue, dueDate: params.dueDate});
state.borrowToken.transferFrom(params.lender, msg.sender, params.amount);
state.tokens.borrowToken.transferFrom(params.lender, msg.sender, params.amount);
loanOffer.maxAmount -= params.amount;
}
}
8 changes: 4 additions & 4 deletions src/libraries/actions/BorrowerExit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ library BorrowerExit {
if (msg.sender != fol.borrower) {
revert Errors.EXITER_IS_NOT_BORROWER(msg.sender, fol.borrower);
}
if (state.borrowToken.balanceOf(msg.sender) < amountIn) {
revert Errors.NOT_ENOUGH_FREE_CASH(state.borrowToken.balanceOf(msg.sender), amountIn);
if (state.tokens.borrowToken.balanceOf(msg.sender) < amountIn) {
revert Errors.NOT_ENOUGH_FREE_CASH(state.tokens.borrowToken.balanceOf(msg.sender), amountIn);
}

// validate loanId
Expand Down Expand Up @@ -67,8 +67,8 @@ library BorrowerExit {
uint256 faceValue = fol.faceValue;
uint256 amountIn = FixedPointMathLib.mulDivUp(faceValue, PERCENT, r);

state.borrowToken.transferFrom(msg.sender, params.borrowerToExitTo, amountIn);
state.debtToken.transferFrom(msg.sender, params.borrowerToExitTo, faceValue);
state.tokens.borrowToken.transferFrom(msg.sender, params.borrowerToExitTo, amountIn);
state.tokens.debtToken.transferFrom(msg.sender, params.borrowerToExitTo, faceValue);
fol.borrower = params.borrowerToExitTo;
borrowOffer.maxAmount -= amountIn;
}
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/actions/Claim.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ library Claim {
function executeClaim(State storage state, ClaimParams calldata params) external {
Loan storage loan = state.loans[params.loanId];

state.borrowToken.transferFrom(state.protocolVault, msg.sender, loan.getCredit());
state.tokens.borrowToken.transferFrom(state.vaults.protocol, msg.sender, loan.getCredit());
loan.faceValueExited = loan.faceValue;

emit Events.Claim(params.loanId);
Expand Down
18 changes: 9 additions & 9 deletions src/libraries/actions/Common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ library Common {
using LoanLibrary for Loan;

function validateMinimumCredit(State storage state, uint256 credit) public view {
if (credit < state.minimumCredit) {
revert Errors.CREDIT_LOWER_THAN_MINIMUM_CREDIT(credit, state.minimumCredit);
if (credit < state.config.minimumCredit) {
revert Errors.CREDIT_LOWER_THAN_MINIMUM_CREDIT(credit, state.config.minimumCredit);
}
}

Expand Down Expand Up @@ -115,8 +115,8 @@ library Common {
}

function getAssignedCollateral(State storage state, Loan memory loan) public view returns (uint256) {
uint256 debt = state.debtToken.balanceOf(loan.borrower);
uint256 collateral = state.collateralToken.balanceOf(loan.borrower);
uint256 debt = state.tokens.debtToken.balanceOf(loan.borrower);
uint256 collateral = state.tokens.collateralToken.balanceOf(loan.borrower);
if (debt > 0) {
return FixedPointMathLib.mulDivDown(collateral, loan.faceValue, debt);
} else {
Expand All @@ -125,9 +125,9 @@ library Common {
}

function collateralRatio(State storage state, address account) public view returns (uint256) {
uint256 collateral = state.collateralToken.balanceOf(account);
uint256 debt = state.debtToken.balanceOf(account);
uint256 price = state.priceFeed.getPrice();
uint256 collateral = state.tokens.collateralToken.balanceOf(account);
uint256 debt = state.tokens.debtToken.balanceOf(account);
uint256 price = state.config.priceFeed.getPrice();

if (debt > 0) {
return FixedPointMathLib.mulDivDown(collateral, price, debt);
Expand All @@ -137,7 +137,7 @@ library Common {
}

function isLiquidatable(State storage state, address account) public view returns (bool) {
return collateralRatio(state, account) < state.crLiquidation;
return collateralRatio(state, account) < state.config.crLiquidation;
}

function validateUserIsNotLiquidatable(State storage state, address account) external view {
Expand All @@ -147,6 +147,6 @@ library Common {
}

function getMinimumCollateralOpening(State storage state, uint256 faceValue) public view returns (uint256) {
return FixedPointMathLib.mulDivUp(faceValue, state.crOpening, state.priceFeed.getPrice());
return FixedPointMathLib.mulDivUp(faceValue, state.config.crOpening, state.config.priceFeed.getPrice());
}
}
9 changes: 5 additions & 4 deletions src/libraries/actions/Deposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ library Deposit {
// validte msg.sender

// validate token
if (params.token != address(state.collateralAsset) && params.token != address(state.borrowAsset)) {
if (params.token != address(state.tokens.collateralAsset) && params.token != address(state.tokens.borrowAsset))
{
revert Errors.INVALID_TOKEN(params.token);
}

Expand All @@ -36,9 +37,9 @@ library Deposit {
}

function executeDeposit(State storage state, DepositParams calldata params) external {
NonTransferrableToken nonTransferrableToken = params.token == address(state.collateralAsset)
? NonTransferrableToken(state.collateralToken)
: NonTransferrableToken(state.borrowToken);
NonTransferrableToken nonTransferrableToken = params.token == address(state.tokens.collateralAsset)
? NonTransferrableToken(state.tokens.collateralToken)
: NonTransferrableToken(state.tokens.borrowToken);
IERC20Metadata token = IERC20Metadata(params.token);
uint256 wad = MathLibrary.amountToWad(params.amount, IERC20Metadata(params.token).decimals());

Expand Down
14 changes: 7 additions & 7 deletions src/libraries/actions/Initialize.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ library Initialize {
InitializeParams memory params,
InitializeExtraParams memory extraParams
) external {
state.priceFeed = IPriceFeed(params.priceFeed);
state.collateralAsset = IERC20Metadata(params.collateralAsset);
state.borrowAsset = IERC20Metadata(params.borrowAsset);
state.collateralToken = CollateralToken(params.collateralToken);
state.borrowToken = BorrowToken(params.borrowToken);
state.debtToken = DebtToken(params.debtToken);
state.protocolVault = params.protocolVault;
state.config.priceFeed = IPriceFeed(params.priceFeed);
state.tokens.collateralAsset = IERC20Metadata(params.collateralAsset);
state.tokens.borrowAsset = IERC20Metadata(params.borrowAsset);
state.tokens.collateralToken = CollateralToken(params.collateralToken);
state.tokens.borrowToken = BorrowToken(params.borrowToken);
state.tokens.debtToken = DebtToken(params.debtToken);
state.vaults.protocol = params.protocolVault;

state.executeUpdateConfig(
UpdateConfigParams({
Expand Down
4 changes: 2 additions & 2 deletions src/libraries/actions/LendAsLimitOrder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ library LendAsLimitOrder {
if (params.maxAmount == 0) {
revert Errors.NULL_AMOUNT();
}
if (params.maxAmount > state.borrowToken.balanceOf(msg.sender)) {
revert Errors.NOT_ENOUGH_FREE_CASH(state.borrowToken.balanceOf(msg.sender), params.maxAmount);
if (params.maxAmount > state.tokens.borrowToken.balanceOf(msg.sender)) {
revert Errors.NOT_ENOUGH_FREE_CASH(state.tokens.borrowToken.balanceOf(msg.sender), params.maxAmount);
}

// validate maxDueDate
Expand Down
8 changes: 4 additions & 4 deletions src/libraries/actions/LendAsMarketOrder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ library LendAsMarketOrder {
if (amountIn > borrowOffer.maxAmount) {
revert Errors.AMOUNT_GREATER_THAN_MAX_AMOUNT(amountIn, borrowOffer.maxAmount);
}
if (state.borrowToken.balanceOf(msg.sender) < amountIn) {
revert Errors.NOT_ENOUGH_FREE_CASH(state.borrowToken.balanceOf(msg.sender), amountIn);
if (state.tokens.borrowToken.balanceOf(msg.sender) < amountIn) {
revert Errors.NOT_ENOUGH_FREE_CASH(state.tokens.borrowToken.balanceOf(msg.sender), amountIn);
}

// validate exactAmountIn
Expand All @@ -70,9 +70,9 @@ library LendAsMarketOrder {
amountIn = FixedPointMathLib.mulDivUp(params.amount, PERCENT, r);
}

state.debtToken.mint(params.borrower, faceValue);
state.tokens.debtToken.mint(params.borrower, faceValue);
state.createFOL({lender: msg.sender, borrower: params.borrower, faceValue: faceValue, dueDate: params.dueDate});
state.borrowToken.transferFrom(msg.sender, params.borrower, amountIn);
state.tokens.borrowToken.transferFrom(msg.sender, params.borrower, amountIn);
borrowOffer.maxAmount -= amountIn;
}
}
30 changes: 18 additions & 12 deletions src/libraries/actions/LiquidateLoan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ library LiquidateLoan {
function validateLiquidateLoan(State storage state, LiquidateLoanParams calldata params) external view {
Loan memory loan = state.loans[params.loanId];
uint256 assignedCollateral = state.getAssignedCollateral(loan);
uint256 debtCollateral =
FixedPointMathLib.mulDivDown(loan.getDebt(), 10 ** state.priceFeed.decimals(), state.priceFeed.getPrice());
uint256 debtCollateral = FixedPointMathLib.mulDivDown(
loan.getDebt(), 10 ** state.config.priceFeed.decimals(), state.config.priceFeed.getPrice()
);

// validate msg.sender

Expand Down Expand Up @@ -55,23 +56,28 @@ library LiquidateLoan {

uint256 assignedCollateral = state.getAssignedCollateral(fol);
uint256 debtBorrowAsset = fol.getDebt();
uint256 debtCollateral =
FixedPointMathLib.mulDivDown(debtBorrowAsset, 10 ** state.priceFeed.decimals(), state.priceFeed.getPrice());
uint256 debtCollateral = FixedPointMathLib.mulDivDown(
debtBorrowAsset, 10 ** state.config.priceFeed.decimals(), state.config.priceFeed.getPrice()
);
uint256 collateralRemainder = assignedCollateral - debtCollateral;

uint256 collateralRemainderToLiquidator =
FixedPointMathLib.mulDivDown(collateralRemainder, state.collateralPercentagePremiumToLiquidator, PERCENT);
uint256 collateralRemainderToBorrower =
FixedPointMathLib.mulDivDown(collateralRemainder, state.collateralPercentagePremiumToBorrower, PERCENT);
uint256 collateralRemainderToLiquidator = FixedPointMathLib.mulDivDown(
collateralRemainder, state.config.collateralPercentagePremiumToLiquidator, PERCENT
);
uint256 collateralRemainderToBorrower = FixedPointMathLib.mulDivDown(
collateralRemainder, state.config.collateralPercentagePremiumToBorrower, PERCENT
);
uint256 collateralRemainderToProtocol =
collateralRemainder - collateralRemainderToLiquidator - collateralRemainderToBorrower;

uint256 liquidatorProfitCollateralAsset = debtCollateral + collateralRemainderToLiquidator;

state.collateralToken.transferFrom(fol.borrower, state.feeRecipient, collateralRemainderToProtocol);
state.collateralToken.transferFrom(fol.borrower, msg.sender, liquidatorProfitCollateralAsset);
state.borrowToken.transferFrom(msg.sender, state.protocolVault, debtBorrowAsset);
state.debtToken.burn(fol.borrower, debtBorrowAsset);
state.tokens.collateralToken.transferFrom(
fol.borrower, state.config.feeRecipient, collateralRemainderToProtocol
);
state.tokens.collateralToken.transferFrom(fol.borrower, msg.sender, liquidatorProfitCollateralAsset);
state.tokens.borrowToken.transferFrom(msg.sender, state.vaults.protocol, debtBorrowAsset);
state.tokens.debtToken.burn(fol.borrower, debtBorrowAsset);
fol.repaid = true;

return liquidatorProfitCollateralAsset;
Expand Down
Loading

0 comments on commit c6097df

Please sign in to comment.