Skip to content

Commit

Permalink
Merge pull request #592 from mysofinance/statemind-171-173-175
Browse files Browse the repository at this point in the history
added fixes for statemind-171, 173 and 175
  • Loading branch information
jpick713 authored Aug 10, 2023
2 parents 93bf122 + ceb3a68 commit 4d5038f
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 113 deletions.
1 change: 0 additions & 1 deletion contracts/peer-to-peer/AddressRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ contract AddressRegistry is Initializable, Ownable2Step, IAddressRegistry {
address public borrowerGateway;
address public quoteHandler;
address public mysoTokenManager;
address public quotePolicyManager;
address public erc721Wrapper;
address public erc20Wrapper;
mapping(address => bool) public isRegisteredVault;
Expand Down
6 changes: 1 addition & 5 deletions contracts/peer-to-peer/LenderVaultImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -414,10 +414,6 @@ contract LenderVaultImpl is
return _loans.length;
}

function totalNumSigners() external view returns (uint256) {
return signers.length;
}

function getTokenBalancesAndLockedAmounts(
address[] calldata tokens
)
Expand All @@ -443,7 +439,7 @@ contract LenderVaultImpl is
}
}

function numSigners() external view returns (uint256) {
function totalNumSigners() external view returns (uint256) {
return signers.length;
}

Expand Down
6 changes: 0 additions & 6 deletions contracts/peer-to-peer/interfaces/IAddressRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,6 @@ interface IAddressRegistry {
*/
function mysoTokenManager() external view returns (address);

/**
* @notice Returns the address of the quote policy manager
* @return Address of the quote policy manager contract
*/
function quotePolicyManager() external view returns (address);

/**
* @notice Returns boolean flag indicating whether given address is a registered vault
* @param addr Address to check if it is a registered vault
Expand Down
12 changes: 3 additions & 9 deletions contracts/peer-to-peer/interfaces/ILenderVaultImpl.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {DataTypesPeerToPeer} from "../DataTypesPeerToPeer.sol";
interface ILenderVaultImpl {
event AddedSigners(address[] _signers);

event MinNumberOfSignersSet(uint256 numSigners);
event MinNumberOfSignersSet(uint256 minNumSigners);

event RemovedSigner(
address signerRemoved,
Expand Down Expand Up @@ -237,10 +237,10 @@ interface ILenderVaultImpl {
function pendingOwner() external view returns (address);

/**
* @notice function to return number of signers
* @notice function to return the total number of signers
* @return number of signers
*/
function numSigners() external view returns (uint256);
function totalNumSigners() external view returns (uint256);

/**
* @notice function to return unlocked token balances
Expand Down Expand Up @@ -316,10 +316,4 @@ interface ILenderVaultImpl {
* @return total number of loans
*/
function totalNumLoans() external view returns (uint256);

/**
* @notice function returns total number of signers
* @return total number of signers
*/
function totalNumSigners() external view returns (uint256);
}
16 changes: 11 additions & 5 deletions contracts/peer-to-peer/policyManagers/BasicQuotePolicyManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
addressRegistry = _addressRegistry;
}

// @dev: When no global policy is set (default case), all pairs are automatically blocked except
// for those where a pair policy is explicitly set. In the case where a global policy is set,
// all pairs are assumed to be allowed (no blocking).
function setGlobalPolicy(
address lenderVault,
bytes calldata globalPolicyData
Expand All @@ -42,7 +45,6 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
DataTypesBasicPolicies.GlobalPolicy
memory currGlobalPolicy = _globalQuotingPolicies[lenderVault];
if (
globalPolicy.allowAllPairs == currGlobalPolicy.allowAllPairs &&
globalPolicy.requiresOracle ==
currGlobalPolicy.requiresOracle &&
_equalQuoteBounds(
Expand All @@ -67,6 +69,9 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
emit GlobalPolicySet(lenderVault, globalPolicyData);
}

// @dev: If no global policy is set, then setting a pair policy allows one to explicitly unblock a specific pair;
// in the other case where a global policy is set, setting a pair policy allows overwriting global policy
// parameters as well as overwriting minimum signer threshold requirements.
function setPairPolicy(
address lenderVault,
address collToken,
Expand Down Expand Up @@ -135,7 +140,7 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
bool hasPairPolicy = _hasPairQuotingPolicy[lenderVault][
generalQuoteInfo.collToken
][generalQuoteInfo.loanToken];
if (!globalPolicy.allowAllPairs && !hasPairPolicy) {
if (!_hasGlobalQuotingPolicy[lenderVault] && !hasPairPolicy) {
return (false, 0);
}

Expand Down Expand Up @@ -294,10 +299,11 @@ contract BasicQuotePolicyManager is IQuotePolicyManager {
) {
return false;
}
}

if (quoteTuple.upfrontFeePctInBase < quoteBounds.minFee) {
return false;
// @dev: only check upfront fee for loans (can skip for swaps where tenor=0)
if (quoteTuple.upfrontFeePctInBase < quoteBounds.minFee) {
return false;
}
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ library DataTypesBasicPolicies {
}

struct GlobalPolicy {
// Flag indicating if all pairs are allowed (=true) or
// per default only pairs with explicitly defined pair policy (=false)
bool allowAllPairs;
// Flag indicating if an oracle is required for the pair
bool requiresOracle;
// Applicable global bounds
Expand Down
5 changes: 2 additions & 3 deletions test/peer-to-peer/helpers/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,14 +335,13 @@ export type QuoteBounds = {
maxLoanPerCollUnitOrLtv: BigNumber
}

export const encodeGlobalPolicy = (allowAllPairs: boolean, requiresOracle: boolean, quoteBounds: QuoteBounds): string => {
export const encodeGlobalPolicy = (requiresOracle: boolean, quoteBounds: QuoteBounds): string => {
return ethers.utils.defaultAbiCoder.encode(
[
'bool allowAllPairs',
'bool requiresOracle',
'tuple(uint32 minTenor, uint32 maxTenor, uint80 minFee, int80 minApr, uint32 minEarliestRepayTenor, uint128 minLoanPerCollUnitOrLtv, uint128 maxLoanPerCollUnitOrLtv) quoteBounds'
],
[allowAllPairs, requiresOracle, quoteBounds]
[requiresOracle, quoteBounds]
)
}

Expand Down
100 changes: 41 additions & 59 deletions test/peer-to-peer/local-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1807,11 +1807,10 @@ describe('Peer-to-Peer: Local Tests', function () {
)

// reverts when trying to remove with signer idx that is out-of-bounds
let numSigners = Number((await lenderVault.numSigners()).toString())
await expect(lenderVault.connect(lender).removeSigner(borrower.address, numSigners)).to.be.revertedWithCustomError(
lenderVault,
'InvalidArrayIndex'
)
let totalNumSigners = Number((await lenderVault.totalNumSigners()).toString())
await expect(
lenderVault.connect(lender).removeSigner(borrower.address, totalNumSigners)
).to.be.revertedWithCustomError(lenderVault, 'InvalidArrayIndex')

// reverts when trying to remove unknown signer address
await expect(lenderVault.connect(lender).removeSigner(weth.address, 0)).to.be.revertedWithCustomError(
Expand All @@ -1830,10 +1829,10 @@ describe('Peer-to-Peer: Local Tests', function () {
await lenderVault.connect(lender).removeSigner(signerAddr, 0)

// remove all signers (always remove last one to test edge case handling)
numSigners = Number((await lenderVault.numSigners()).toString())
for (let i = 0; i < numSigners; i++) {
const lastSignerAddr = await lenderVault.signers(numSigners - i - 1)
await lenderVault.connect(lender).removeSigner(lastSignerAddr, numSigners - i - 1)
totalNumSigners = Number((await lenderVault.totalNumSigners()).toString())
for (let i = 0; i < totalNumSigners; i++) {
const lastSignerAddr = await lenderVault.signers(totalNumSigners - i - 1)
await lenderVault.connect(lender).removeSigner(lastSignerAddr, totalNumSigners - i - 1)
}

// set borrower whitelist
Expand Down Expand Up @@ -6012,7 +6011,7 @@ describe('Peer-to-Peer: Local Tests', function () {
maxLoanPerCollUnitOrLtv: BASE.div(2)
}

const globalPolicyData = encodeGlobalPolicy(true, false, quoteBounds)
const globalPolicyData = encodeGlobalPolicy(false, quoteBounds)

const pairPolicyData = encodePairPolicy(true, 1, quoteBounds)

Expand Down Expand Up @@ -6084,30 +6083,22 @@ describe('Peer-to-Peer: Local Tests', function () {
await expect(
basicPolicyManager
.connect(lender)
.setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(true, false, { ...quoteBounds, minTenor: ONE_DAY.mul(40) })
)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(false, { ...quoteBounds, minTenor: ONE_DAY.mul(40) }))
).to.be.revertedWithCustomError(basicPolicyManager, 'InvalidTenors')

await expect(
basicPolicyManager
.connect(lender)
.setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(true, false, { ...quoteBounds, minLoanPerCollUnitOrLtv: BASE })
)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(false, { ...quoteBounds, minLoanPerCollUnitOrLtv: BASE }))
).to.be.revertedWithCustomError(basicPolicyManager, 'InvalidLoanPerCollOrLtv')

await expect(
basicPolicyManager
.connect(lender)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(true, false, { ...quoteBounds, minApr: BASE.mul(-2) }))
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(false, { ...quoteBounds, minApr: BASE.mul(-2) }))
).to.be.revertedWithCustomError(basicPolicyManager, 'InvalidMinApr')

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(true, true, quoteBounds))
await basicPolicyManager.connect(lender).setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(true, quoteBounds))

// borrow should fail without oracle address
await expect(
Expand All @@ -6118,7 +6109,7 @@ describe('Peer-to-Peer: Local Tests', function () {

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(true, false, { ...quoteBounds, minTenor: ONE_DAY.mul(35) }))
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(false, { ...quoteBounds, minTenor: ONE_DAY.mul(35) }))

// borrow fail if tenor less than min tenor
await expect(
Expand All @@ -6129,7 +6120,7 @@ describe('Peer-to-Peer: Local Tests', function () {

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(true, false, { ...quoteBounds, maxTenor: ONE_DAY.mul(25) }))
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(false, { ...quoteBounds, maxTenor: ONE_DAY.mul(25) }))

// borrow fail if tenor greater than max tenor
await expect(
Expand All @@ -6140,10 +6131,7 @@ describe('Peer-to-Peer: Local Tests', function () {

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(true, false, { ...quoteBounds, minFee: BASE.mul(9).div(10) })
)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(false, { ...quoteBounds, minFee: BASE.mul(9).div(10) }))

// borrow should fail if upfront fee is below min fee
await expect(
Expand All @@ -6154,7 +6142,7 @@ describe('Peer-to-Peer: Local Tests', function () {

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(true, false, { ...quoteBounds, minApr: BASE.mul(10) }))
.setGlobalPolicy(lenderVault.address, encodeGlobalPolicy(false, { ...quoteBounds, minApr: BASE.mul(10) }))

// borrow should fail if apr is below min apr
await expect(
Expand All @@ -6163,32 +6151,28 @@ describe('Peer-to-Peer: Local Tests', function () {
.borrowWithOnChainQuote(lenderVault.address, borrowInstructions1, onChainQuote1, quoteTupleIdx1)
).to.be.revertedWithCustomError(quoteHandler, 'QuoteViolatesPolicy')

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(true, false, {
...quoteBounds,
minLoanPerCollUnitOrLtv: BASE.mul(4).div(5),
maxLoanPerCollUnitOrLtv: BASE.mul(9).div(10)
})
)
await basicPolicyManager.connect(lender).setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(false, {
...quoteBounds,
minLoanPerCollUnitOrLtv: BASE.mul(4).div(5),
maxLoanPerCollUnitOrLtv: BASE.mul(9).div(10)
})
)

// borrow should go through even if loanPerCollUnitOrLtv is below minLoanPerCollUnitOrLtv if no oracle required
await borrowerGateway
.connect(borrower)
.borrowWithOnChainQuote(lenderVault.address, borrowInstructions1, onChainQuote1, quoteTupleIdx1)

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(true, false, {
...quoteBounds,
minLoanPerCollUnitOrLtv: ethers.BigNumber.from(0),
maxLoanPerCollUnitOrLtv: ethers.BigNumber.from(0)
})
)
await basicPolicyManager.connect(lender).setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(false, {
...quoteBounds,
minLoanPerCollUnitOrLtv: ethers.BigNumber.from(0),
maxLoanPerCollUnitOrLtv: ethers.BigNumber.from(0)
})
)

// borrow should go through even if loanPerCollUnitOrLtv is above maxLoanPerCollUnitOrLtv if no oracle required
await borrowerGateway
Expand Down Expand Up @@ -6227,16 +6211,14 @@ describe('Peer-to-Peer: Local Tests', function () {
'OnChainQuoteAdded'
)

await basicPolicyManager
.connect(lender)
.setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(true, false, {
...quoteBounds,
minApr: BASE.mul(-99).div(100),
minEarliestRepayTenor: ONE_DAY.mul(20)
})
)
await basicPolicyManager.connect(lender).setGlobalPolicy(
lenderVault.address,
encodeGlobalPolicy(false, {
...quoteBounds,
minApr: BASE.mul(-99).div(100),
minEarliestRepayTenor: ONE_DAY.mul(20)
})
)

// borrow with negative interest rate should fail if earliest min repay is too short
await expect(
Expand Down
Loading

0 comments on commit 4d5038f

Please sign in to comment.