Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed tests, edited edge case for ltv on global policy and changes fo… #594

Merged
merged 7 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,13 @@ File | % Stmts | % Branch |
Helpers.sol | 100 | 50 | 100 | 100 | |
contracts\interfaces\ | 100 | 100 | 100 | 100 | |
IMysoTokenManager.sol | 100 | 100 | 100 | 100 | |
contracts\peer-to-peer\ | 99.74 | 94.61 | 98.84 | 98.66 | |
AddressRegistry.sol | 100 | 96.74 | 100 | 99.17 | 117 |
contracts\peer-to-peer\ | 99.75 | 94.5 | 98.82 | 98.2 | |
AddressRegistry.sol | 100 | 96.74 | 100 | 99.17 | 116 |
BorrowerGateway.sol | 98.57 | 90.91 | 90.91 | 96.97 | 241,317,358 |
DataTypesPeerToPeer.sol | 100 | 100 | 100 | 100 | |
LenderVaultFactory.sol | 100 | 87.5 | 100 | 100 | |
LenderVaultImpl.sol | 100 | 93.1 | 100 | 98.92 | 64,207 |
QuoteHandler.sol | 100 | 96.83 | 100 | 98.91 | 266,478 |
LenderVaultImpl.sol | 100 | 93.1 | 100 | 98.91 | 64,207 |
QuoteHandler.sol | 100 | 96.32 | 100 | 97.46 |... 332,333,516 |
contracts\peer-to-peer\callbacks\ | 100 | 75 | 88.89 | 96.88 | |
BalancerV2Looping.sol | 100 | 100 | 100 | 100 | |
UniV3Looping.sol | 100 | 100 | 100 | 100 | |
Expand Down Expand Up @@ -257,6 +257,6 @@ File | % Stmts | % Branch |
IFundingPoolImpl.sol | 100 | 100 | 100 | 100 | |
ILoanProposalImpl.sol | 100 | 100 | 100 | 100 | |
---------------------------------------------------------|----------|----------|----------|----------|----------------|
All files | 99.07 | 89.56 | 98.74 | 96.97 | |
All files | 99.08 | 89.7 | 98.74 | 96.84 | |
---------------------------------------------------------|----------|----------|----------|----------|----------------|
```
6 changes: 4 additions & 2 deletions contracts/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,10 @@ library Errors {
error AlreadyPublished();
error PolicyAlreadySet();
error NoPolicyToDelete();
error InvalidTenors();
error InvalidLoanPerCollOrLtv();
error InvalidTenorBounds();
error InvalidLtvBounds();
error InvalidLoanPerCollBounds();
error InvalidMinApr();
error NoPolicy();
error InvalidMinFee();
}
58 changes: 48 additions & 10 deletions contracts/peer-to-peer/QuoteHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ contract QuoteHandler is IQuoteHandler {
public offChainQuoteIsInvalidated;
mapping(address => mapping(bytes32 => bool)) public isOnChainQuote;
mapping(bytes32 => bool) public isPublishedOnChainQuote;
mapping(bytes32 => uint256) public publishedOnChainQuoteValidUntil;
mapping(address => address) public quotePolicyManagerForVault;
mapping(address => DataTypesPeerToPeer.OnChainQuoteInfo[])
internal onChainQuoteHistory;
internal _onChainQuoteHistory;

constructor(address _addressRegistry) {
if (_addressRegistry == address(0)) {
Expand All @@ -47,7 +48,7 @@ contract QuoteHandler is IQuoteHandler {
revert Errors.OnChainQuoteAlreadyAdded();
}
// @dev: on-chain quote history is append only
onChainQuoteHistory[lenderVault].push(
_onChainQuoteHistory[lenderVault].push(
DataTypesPeerToPeer.OnChainQuoteInfo({
quoteHash: onChainQuoteHash,
validUntil: onChainQuote.generalQuoteInfo.validUntil
Expand Down Expand Up @@ -77,7 +78,7 @@ contract QuoteHandler is IQuoteHandler {
revert Errors.UnknownOnChainQuote();
}
// @dev: on-chain quote history is append only
onChainQuoteHistory[lenderVault].push(
_onChainQuoteHistory[lenderVault].push(
DataTypesPeerToPeer.OnChainQuoteInfo({
quoteHash: newOnChainQuoteHash,
validUntil: newOnChainQuote.generalQuoteInfo.validUntil
Expand Down Expand Up @@ -115,12 +116,21 @@ contract QuoteHandler is IQuoteHandler {
_checkIsVaultAndSenderIsApproved(lenderVault, false);
mapping(bytes32 => bool)
storage isOnChainQuoteFromVault = isOnChainQuote[lenderVault];
uint256 validUntil = publishedOnChainQuoteValidUntil[onChainQuoteHash];
if (
!isPublishedOnChainQuote[onChainQuoteHash] ||
isOnChainQuoteFromVault[onChainQuoteHash]
isOnChainQuoteFromVault[onChainQuoteHash] ||
validUntil < block.timestamp
) {
revert Errors.InvalidQuote();
}
// @dev: on-chain quote history is append only
_onChainQuoteHistory[lenderVault].push(
DataTypesPeerToPeer.OnChainQuoteInfo({
quoteHash: onChainQuoteHash,
validUntil: validUntil
})
);
isOnChainQuoteFromVault[onChainQuoteHash] = true;
emit OnChainQuoteCopied(lenderVault, onChainQuoteHash);
}
Expand All @@ -136,6 +146,9 @@ contract QuoteHandler is IQuoteHandler {
revert Errors.AlreadyPublished();
}
isPublishedOnChainQuote[onChainQuoteHash] = true;
publishedOnChainQuoteValidUntil[onChainQuoteHash] = onChainQuote
.generalQuoteInfo
.validUntil;
emit OnChainQuotePublished(onChainQuote, onChainQuoteHash, msg.sender);
}

Expand Down Expand Up @@ -285,23 +298,48 @@ contract QuoteHandler is IQuoteHandler {
address lenderVault,
uint256 idx
) external view returns (DataTypesPeerToPeer.OnChainQuoteInfo memory) {
if (idx < onChainQuoteHistory[lenderVault].length) {
return onChainQuoteHistory[lenderVault][idx];
if (idx < _onChainQuoteHistory[lenderVault].length) {
return _onChainQuoteHistory[lenderVault][idx];
} else {
revert Errors.InvalidArrayIndex();
}
}

function getFullOnChainQuoteHistory(
address lenderVault
function getOnChainQuoteHistorySlice(
address lenderVault,
uint256 startIdx,
uint256 endIdx
) external view returns (DataTypesPeerToPeer.OnChainQuoteInfo[] memory) {
return onChainQuoteHistory[lenderVault];
uint256 onChainQuoteHistoryLen = _onChainQuoteHistory[lenderVault]
.length;
if (startIdx > endIdx || startIdx >= onChainQuoteHistoryLen) {
revert Errors.InvalidArrayIndex();
}
endIdx = endIdx < onChainQuoteHistoryLen
? endIdx
: onChainQuoteHistoryLen;
if (startIdx == 0 && endIdx == onChainQuoteHistoryLen) {
return _onChainQuoteHistory[lenderVault];
}
DataTypesPeerToPeer.OnChainQuoteInfo[]
memory onChainQuoteHistoryRequested = new DataTypesPeerToPeer.OnChainQuoteInfo[](
endIdx - startIdx
);
for (uint256 i = startIdx; i < endIdx; ) {
onChainQuoteHistoryRequested[i - startIdx] = _onChainQuoteHistory[
lenderVault
][i];
unchecked {
++i;
}
}
return onChainQuoteHistoryRequested;
}

function getOnChainQuoteHistoryLength(
address lenderVault
) external view returns (uint256) {
return onChainQuoteHistory[lenderVault].length;
return _onChainQuoteHistory[lenderVault].length;
}

/**
Expand Down
17 changes: 15 additions & 2 deletions contracts/peer-to-peer/interfaces/IQuoteHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@ interface IQuoteHandler {
bytes32 hashToCheck
) external view returns (bool);

/**
* @notice function returns valid until timestamp of the published on-chain quote
* @param hashToCheck hash of the on chain quote
* @return valid until timestamp of the published on-chain quote
*/
function publishedOnChainQuoteValidUntil(
bytes32 hashToCheck
) external view returns (uint256);

/**
* @notice function returns the address of the policy manager for a vault
* @param lenderVault address of vault
Expand All @@ -241,10 +250,14 @@ interface IQuoteHandler {
/**
* @notice function returns array of structs containing the on-chain quote hash and validUntil timestamp
* @param lenderVault address of vault
* @param startIdx starting index from on chain quote history array
* @param endIdx ending index of on chain quote history array (non-inclusive)
* @return array of quote hash and validUntil data for on-chain quote history of a vault
*/
function getFullOnChainQuoteHistory(
address lenderVault
function getOnChainQuoteHistorySlice(
address lenderVault,
uint256 startIdx,
uint256 endIdx
) external view returns (DataTypesPeerToPeer.OnChainQuoteInfo[] memory);

/**
Expand Down
64 changes: 45 additions & 19 deletions contracts/peer-to-peer/policyManagers/BasicQuotePolicyManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
currSinglePolicy.requiresOracle &&
singlePolicy.minNumOfSignersOverwrite ==
currSinglePolicy.minNumOfSignersOverwrite &&
singlePolicy.minLoanPerCollUnit ==
currSinglePolicy.minLoanPerCollUnit &&
singlePolicy.maxLoanPerCollUnit ==
currSinglePolicy.maxLoanPerCollUnit &&
_equalQuoteBounds(
singlePolicy.quoteBounds,
currSinglePolicy.quoteBounds
Expand All @@ -109,6 +113,13 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
revert Errors.PolicyAlreadySet();
}
_checkNewQuoteBounds(singlePolicy.quoteBounds);
if (
singlePolicy.minLoanPerCollUnit == 0 ||
singlePolicy.minLoanPerCollUnit >
singlePolicy.maxLoanPerCollUnit
) {
revert Errors.InvalidLoanPerCollBounds();
}
if (!_hasSingleQuotingPolicy[loanToken]) {
_hasSingleQuotingPolicy[loanToken] = true;
}
Expand Down Expand Up @@ -146,19 +157,24 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {

// @dev: pair policy (if defined) takes precedence over global policy
bool hasOracle = generalQuoteInfo.oracleAddr != address(0);
bool checkLoanPerColl;
bool requiresOracle;
uint256[2] memory minMaxLoanPerCollUnit;
DataTypesBasicPolicies.QuoteBounds memory quoteBounds;
if (hasPairPolicy) {
DataTypesBasicPolicies.PairPolicy
memory singlePolicy = _pairQuotingPolicies[lenderVault][
generalQuoteInfo.collToken
][generalQuoteInfo.loanToken];
requiresOracle = singlePolicy.requiresOracle;
quoteBounds = singlePolicy.quoteBounds;
minMaxLoanPerCollUnit[0] = singlePolicy.minLoanPerCollUnit;
minMaxLoanPerCollUnit[1] = singlePolicy.maxLoanPerCollUnit;
requiresOracle = singlePolicy.requiresOracle;
minNumOfSignersOverwrite = singlePolicy.minNumOfSignersOverwrite;
checkLoanPerColl = !hasOracle;
} else {
requiresOracle = globalPolicy.requiresOracle;
quoteBounds = globalPolicy.quoteBounds;
requiresOracle = globalPolicy.requiresOracle;
}

if (requiresOracle && !hasOracle) {
Expand All @@ -168,9 +184,11 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
return (
_isAllowedWithBounds(
quoteBounds,
minMaxLoanPerCollUnit,
quoteTuple,
generalQuoteInfo.earliestRepayTenor,
requiresOracle
hasOracle,
checkLoanPerColl
),
minNumOfSignersOverwrite
);
Expand Down Expand Up @@ -229,10 +247,7 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
quoteBounds1.minFee == quoteBounds2.minFee &&
quoteBounds1.minApr == quoteBounds2.minApr &&
quoteBounds1.minLtv == quoteBounds2.minLtv &&
quoteBounds1.maxLtv == quoteBounds2.maxLtv &&
quoteBounds1.minLoanPerCollUnit ==
quoteBounds2.minLoanPerCollUnit &&
quoteBounds1.maxLoanPerCollUnit == quoteBounds2.maxLoanPerCollUnit
quoteBounds1.maxLtv == quoteBounds2.maxLtv
) {
isEqual = true;
}
Expand All @@ -243,24 +258,29 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
) internal pure {
// @dev: allow minTenor == 0 to enable swaps
if (quoteBounds.minTenor > quoteBounds.maxTenor) {
revert Errors.InvalidTenors();
revert Errors.InvalidTenorBounds();
}
if (
quoteBounds.minLtv > quoteBounds.maxLtv ||
quoteBounds.minLoanPerCollUnit > quoteBounds.maxLoanPerCollUnit
quoteBounds.minLtv == 0 || quoteBounds.minLtv > quoteBounds.maxLtv
) {
revert Errors.InvalidLoanPerCollOrLtv();
revert Errors.InvalidLtvBounds();
}
if (quoteBounds.minApr + int(Constants.BASE) <= 0) {
revert Errors.InvalidMinApr();
}
// @dev: if minFee = BASE, then only swaps will be allowed
if (quoteBounds.minFee > Constants.BASE) {
revert Errors.InvalidMinFee();
}
}

function _isAllowedWithBounds(
DataTypesBasicPolicies.QuoteBounds memory quoteBounds,
uint256[2] memory minMaxLoanPerCollUnit,
DataTypesPeerToPeer.QuoteTuple calldata quoteTuple,
uint256 earliestRepayTenor,
bool checkLtv
bool checkLtv,
bool checkLoanPerColl
) internal pure returns (bool) {
if (
quoteTuple.tenor < quoteBounds.minTenor ||
Expand All @@ -269,13 +289,19 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
return false;
}

// @dev: if requires oracle check against LTV bounds, else against loan-per-coll bounds
(uint256 lowerBnd, uint256 upperBnd) = checkLtv
? (quoteBounds.minLtv, quoteBounds.maxLtv)
: (quoteBounds.minLoanPerCollUnit, quoteBounds.maxLoanPerCollUnit);
if (
quoteTuple.loanPerCollUnitOrLtv < lowerBnd ||
quoteTuple.loanPerCollUnitOrLtv > upperBnd
if (checkLtv) {
// @dev: check either against LTV bounds
if (
quoteTuple.loanPerCollUnitOrLtv < quoteBounds.minLtv ||
quoteTuple.loanPerCollUnitOrLtv > quoteBounds.maxLtv
) {
return false;
}
} else if (
// @dev: only check against absolute loan-per-coll bounds on pair policy and if no oracle
checkLoanPerColl &&
(quoteTuple.loanPerCollUnitOrLtv < minMaxLoanPerCollUnit[0] ||
quoteTuple.loanPerCollUnitOrLtv > minMaxLoanPerCollUnit[1])
) {
return false;
}
Expand Down
16 changes: 8 additions & 8 deletions contracts/peer-to-peer/policyManagers/DataTypesBasicPolicies.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@ library DataTypesBasicPolicies {
uint128 minLtv;
// Allowed maximum LTV for the quote
uint128 maxLtv;
// Allowed minimum loan per collateral unit or LTV for the quote
uint128 minLoanPerCollUnit;
// Allowed maximum loan per collateral unit or LTV for the quote
uint128 maxLoanPerCollUnit;
}

struct GlobalPolicy {
// Applicable general bounds
QuoteBounds quoteBounds;
// Flag indicating if an oracle is required for the pair
bool requiresOracle;
// Applicable global bounds
QuoteBounds quoteBounds;
}

struct PairPolicy {
// Applicable general bounds
QuoteBounds quoteBounds;
// Allowed minimum loan per collateral unit or LTV for the quote
uint128 minLoanPerCollUnit;
// Allowed maximum loan per collateral unit or LTV for the quote
uint128 maxLoanPerCollUnit;
// Flag indicating if an oracle is required for the pair
bool requiresOracle;
// Minimum number of signers required for the pair (if zero ignored, otherwise overwrites vault min signers)
// @dev: can overwrite signer threshold to be lower or higher than vault min signers
uint8 minNumOfSignersOverwrite;
// Applicable global bounds
QuoteBounds quoteBounds;
}
}
Loading