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

feat: add min price per product #1299

Draft
wants to merge 3 commits into
base: refactor/remove-yield-token-incidents
Choose a base branch
from
Draft
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
6 changes: 3 additions & 3 deletions contracts/interfaces/ICover.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ interface ICover {

function getGlobalRewardsRatio() external view returns (uint);

function getGlobalMinPriceRatio() external pure returns (uint);
function getDefaultMinPriceRatio() external pure returns (uint);

function getGlobalCapacityAndPriceRatios() external view returns (
uint _globalCapacityRatio,
uint _globalMinPriceRatio
uint _defaultMinPriceRatio
);

function GLOBAL_MIN_PRICE_RATIO() external view returns (uint);
function DEFAULT_MIN_PRICE_RATIO() external view returns (uint);

/* === MUTATIVE FUNCTIONS ==== */

Expand Down
4 changes: 3 additions & 1 deletion contracts/interfaces/ICoverProducts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ interface ICoverProducts {

function getInitialPrices(uint[] calldata productIds) external view returns (uint[] memory);

function getMinPrices(uint[] calldata productIds) external view returns (uint[] memory);

function prepareStakingProductsParams(
ProductInitializationParams[] calldata params
) external returns (
Expand Down Expand Up @@ -129,7 +131,7 @@ interface ICoverProducts {

// Misc
error UnsupportedCoverAssets();
error InitialPriceRatioBelowGlobalMinPriceRatio();
error InitialPriceRatioBelowDefaultMinPriceRatio();
error InitialPriceRatioAbove100Percent();
error CapacityReductionRatioAbove100Percent();

Expand Down
2 changes: 1 addition & 1 deletion contracts/interfaces/IStakingPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct AllocationRequest {
uint globalCapacityRatio;
uint capacityReductionRatio;
uint rewardRatio;
uint globalMinPrice;
uint productMinPrice;
}

struct BurnStakeParams {
Expand Down
4 changes: 2 additions & 2 deletions contracts/interfaces/IStakingProducts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ interface IStakingProducts {
uint coverAmount,
uint initialCapacityUsed,
uint totalCapacity,
uint globalMinPrice,
uint productMinPrice,
bool useFixedPrice,
uint nxmPerAllocationUnit,
uint allocationUnitsPerNxm
Expand Down Expand Up @@ -149,7 +149,7 @@ interface IStakingProducts {
// Staking Pool creation
error ProductDoesntExistOrIsDeprecated();
error InvalidProductType();
error TargetPriceBelowGlobalMinPriceRatio();
error TargetPriceBelowDefaultMinPriceRatio();

// IPFS
error IpfsHashRequired();
Expand Down
4 changes: 2 additions & 2 deletions contracts/mocks/generic/CoverGeneric.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import "../../interfaces/ICoverNFT.sol";

contract CoverGeneric is ICover {

uint public constant GLOBAL_MIN_PRICE_RATIO = 100; // 1%
uint public constant DEFAULT_MIN_PRICE_RATIO = 100; // 1%
uint public constant MAX_COMMISSION_RATIO = 3000; // 30%

function getGlobalMinPriceRatio() public virtual pure returns (uint) {
function getDefaultMinPriceRatio() public virtual pure returns (uint) {
revert("Unsupported");
}

Expand Down
6 changes: 6 additions & 0 deletions contracts/mocks/generic/CoverProductsGeneric.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import "../../interfaces/ICoverProducts.sol";

contract CoverProductsGeneric is ICoverProducts {

uint public constant DEFAULT_MIN_PRICE_RATIO = 100; // 1%

/* ========== VIEWS ========== */

function getProductType(uint) external virtual view returns (ProductType memory) {
Expand Down Expand Up @@ -85,6 +87,10 @@ contract CoverProductsGeneric is ICoverProducts {
revert("Unsupported");
}

function getMinPrices(uint[] calldata) external view virtual returns (uint[] memory) {
revert("Unsupported");
}

function prepareStakingProductsParams(
ProductInitializationParams[] calldata
) external virtual pure returns (
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/modules/Cover/COMockStakingPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ contract COMockStakingPool is StakingPoolGeneric {

uint public constant MAX_PRICE_RATIO = 10_000;
uint constant REWARDS_DENOMINATOR = 10_000;
uint public constant GLOBAL_MIN_PRICE_RATIO = 100; // 1%
uint public constant DEFAULT_MIN_PRICE_RATIO = 100; // 1%
uint public constant ONE_NXM = 1 ether;
uint public constant ALLOCATION_UNITS_PER_NXM = 100;
uint public constant NXM_PER_ALLOCATION_UNIT = ONE_NXM / ALLOCATION_UNITS_PER_NXM;
Expand Down
6 changes: 3 additions & 3 deletions contracts/mocks/modules/Cover/COMockStakingProducts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ contract COMockStakingProducts is StakingProductsGeneric {

mapping(uint => mapping(uint => StakedProduct)) private _products;

uint public constant GLOBAL_MIN_PRICE_RATIO = 100; // 1%
uint public constant DEFAULT_MIN_PRICE_RATIO = 100; // 1%

address public immutable coverContract;
address public immutable tokenControllerContract;
Expand Down Expand Up @@ -78,8 +78,8 @@ contract COMockStakingProducts is StakingProductsGeneric {
// override with initial price and check if pool is allowed
for (uint i = 0; i < numProducts; i++) {

if (productInitParams[i].targetPrice < GLOBAL_MIN_PRICE_RATIO) {
revert TargetPriceBelowGlobalMinPriceRatio();
if (productInitParams[i].targetPrice < DEFAULT_MIN_PRICE_RATIO) {
revert TargetPriceBelowDefaultMinPriceRatio();
}

uint productId = productInitParams[i].productId;
Expand Down
4 changes: 2 additions & 2 deletions contracts/mocks/modules/CoverProducts/CPMockCover.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ contract CPMockCover is CoverGeneric {
}
}

function getGlobalMinPriceRatio() public override pure returns (uint) {
return GLOBAL_MIN_PRICE_RATIO;
function getDefaultMinPriceRatio() public override pure returns (uint) {
return DEFAULT_MIN_PRICE_RATIO;
}

function getProducts() external view returns (Product[] memory) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/modules/StakingPool/SKMockCover.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ contract SKMockCover is CoverGeneric {
_globalCapacityRatio,
product.capacityReductionRatio,
_globalRewardsRatio,
GLOBAL_MIN_PRICE_RATIO
DEFAULT_MIN_PRICE_RATIO
)
);

Expand Down
10 changes: 5 additions & 5 deletions contracts/mocks/modules/StakingPool/SKMockStakingProducts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ contract SKMockStakingProducts is StakingProductsGeneric, MasterAwareV2, Multica
}

uint globalCapacityRatio;
uint globalMinPriceRatio;
uint defaultMinPriceRatio;

uint[] memory initialPriceRatios;
uint[] memory capacityReductionRatios;
Expand All @@ -138,7 +138,7 @@ contract SKMockStakingProducts is StakingProductsGeneric, MasterAwareV2, Multica
ICover _cover = ICover(coverContract);

globalCapacityRatio = _cover.getGlobalCapacityRatio();
globalMinPriceRatio = _cover.getGlobalMinPriceRatio();
defaultMinPriceRatio = _cover.getDefaultMinPriceRatio();

initialPriceRatios = _coverProducts.getInitialPrices(productIds);
capacityReductionRatios = _coverProducts.getCapacityReductionRatios(productIds);
Expand Down Expand Up @@ -169,7 +169,7 @@ contract SKMockStakingProducts is StakingProductsGeneric, MasterAwareV2, Multica
if (_param.targetPrice > TARGET_PRICE_DENOMINATOR) {
revert TargetPriceTooHigh();
}
if (_param.targetPrice < globalMinPriceRatio) {
if (_param.targetPrice < defaultMinPriceRatio) {
revert TargetPriceBelowMin();
}
_product.targetPrice = _param.targetPrice;
Expand Down Expand Up @@ -324,14 +324,14 @@ contract SKMockStakingProducts is StakingProductsGeneric, MasterAwareV2, Multica
uint coverAmount,
uint initialCapacityUsed,
uint totalCapacity,
uint globalMinPrice,
uint productMinPrice,
bool useFixedPrice,
uint nxmPerAllocationUnit,
uint allocationUnitsPerNXM
) public override returns (uint premium) {

StakedProduct memory product = _products[poolId][productId];
uint targetPrice = Math.max(product.targetPrice, globalMinPrice);
uint targetPrice = Math.max(product.targetPrice, productMinPrice);

if (useFixedPrice) {
return calculateFixedPricePremium(period, coverAmount, targetPrice, nxmPerAllocationUnit, TARGET_PRICE_DENOMINATOR);
Expand Down
8 changes: 4 additions & 4 deletions contracts/mocks/modules/StakingProducts/SPMockCover.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ contract SPMockCover is CoverGeneric {
stakingPool[id] = addr;
}

function getGlobalMinPriceRatio() public override pure returns (uint) {
return GLOBAL_MIN_PRICE_RATIO;
function getDefaultMinPriceRatio() public override pure returns (uint) {
return DEFAULT_MIN_PRICE_RATIO;
}

function getGlobalCapacityRatio() public override pure returns (uint) {
return GLOBAL_CAPACITY_RATIO;
}

function getGlobalCapacityAndPriceRatios() public override pure returns (uint, uint) {
return (GLOBAL_CAPACITY_RATIO, GLOBAL_MIN_PRICE_RATIO);
return (GLOBAL_CAPACITY_RATIO, DEFAULT_MIN_PRICE_RATIO);
}

// TODO: remove me. see https://github.com/NexusMutual/smart-contracts/issues/1161
Expand Down Expand Up @@ -87,7 +87,7 @@ contract SPMockCover is CoverGeneric {
GLOBAL_CAPACITY_RATIO,
product.capacityReductionRatio,
GLOBAL_REWARDS_RATIO,
GLOBAL_MIN_PRICE_RATIO
DEFAULT_MIN_PRICE_RATIO
)
);

Expand Down
11 changes: 11 additions & 0 deletions contracts/mocks/modules/StakingProducts/SPMockCoverProducts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,15 @@ contract SPMockCoverProducts is CoverProductsGeneric {
reductionRatios[i] = _products[productIds[i]].capacityReductionRatio;
}
}

function getMinPrices(uint[] calldata productIds) external override view returns (uint[] memory minPrices) {
minPrices = new uint[](productIds.length);
for (uint i = 0; i < productIds.length; i++) {
if (_products[productIds[i]].minPrice != 0) {
minPrices[i] = _products[productIds[i]].minPrice;
} else {
minPrices[i] = DEFAULT_MIN_PRICE_RATIO;
}
}
}
}
16 changes: 10 additions & 6 deletions contracts/modules/cover/Cover.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ contract Cover is ICover, MasterAwareV2, IStakingPoolBeacon, ReentrancyGuard, Mu

uint public constant MAX_COMMISSION_RATIO = 3000; // 30%

uint public constant GLOBAL_MIN_PRICE_RATIO = 100; // 1%
uint public constant DEFAULT_MIN_PRICE_RATIO = 100; // 1%

uint private constant ONE_NXM = 1e18;

Expand Down Expand Up @@ -164,7 +164,11 @@ contract Cover is ICover, MasterAwareV2, IStakingPoolBeacon, ReentrancyGuard, Mu
allocationRequest.globalCapacityRatio = GLOBAL_CAPACITY_RATIO;
allocationRequest.capacityReductionRatio = product.capacityReductionRatio;
allocationRequest.rewardRatio = GLOBAL_REWARDS_RATIO;
allocationRequest.globalMinPrice = GLOBAL_MIN_PRICE_RATIO;
if (product.minPrice != 0) {
allocationRequest.productMinPrice = product.minPrice;
} else {
allocationRequest.productMinPrice = DEFAULT_MIN_PRICE_RATIO;
}
}

uint previousSegmentAmount;
Expand Down Expand Up @@ -638,16 +642,16 @@ contract Cover is ICover, MasterAwareV2, IStakingPoolBeacon, ReentrancyGuard, Mu
return GLOBAL_REWARDS_RATIO;
}

function getGlobalMinPriceRatio() external pure returns (uint) {
return GLOBAL_MIN_PRICE_RATIO;
function getDefaultMinPriceRatio() external pure returns (uint) {
return DEFAULT_MIN_PRICE_RATIO;
}

function getGlobalCapacityAndPriceRatios() external pure returns (
uint _globalCapacityRatio,
uint _globalMinPriceRatio
uint _defaultMinPriceRatio
) {
_globalCapacityRatio = GLOBAL_CAPACITY_RATIO;
_globalMinPriceRatio = GLOBAL_MIN_PRICE_RATIO;
_defaultMinPriceRatio = DEFAULT_MIN_PRICE_RATIO;
}

function isCoverAssetSupported(uint assetId, uint productCoverAssetsBitmap) internal view returns (bool) {
Expand Down
35 changes: 32 additions & 3 deletions contracts/modules/cover/CoverProducts.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,28 @@ contract CoverProducts is ICoverProducts, MasterAwareV2, Multicall {
}
}

function getMinPrices(
uint[] calldata productIds
) external view returns (uint[] memory minPrices) {
uint productCount = _products.length;
minPrices = new uint[](productIds.length);
uint defaultMinPrice = cover().getDefaultMinPriceRatio();

for (uint i = 0; i < productIds.length; i++) {
uint productId = productIds[i];

if (productId >= productCount) {
revert ProductNotFound();
}

if (_products[productId].minPrice == 0) {
minPrices[i] = defaultMinPrice;
} else {
minPrices[i] = _products[productId].minPrice;
}
}
}

function getCapacityReductionRatios(
uint[] calldata productIds
) external view returns (uint[] memory capacityReductionRatios) {
Expand Down Expand Up @@ -191,7 +213,7 @@ contract CoverProducts is ICoverProducts, MasterAwareV2, Multicall {
function setProducts(ProductParam[] calldata productParams) external override onlyAdvisoryBoard {

uint unsupportedCoverAssetsBitmap = type(uint).max;
uint globalMinPriceRatio = cover().getGlobalMinPriceRatio();
uint defaultMinPriceRatio = cover().getDefaultMinPriceRatio();

uint poolCount = stakingProducts().getStakingPoolCount();
Asset[] memory assets = pool().getAssets();
Expand All @@ -217,8 +239,15 @@ contract CoverProducts is ICoverProducts, MasterAwareV2, Multicall {
revert UnsupportedCoverAssets();
}

if (product.initialPriceRatio < globalMinPriceRatio) {
revert InitialPriceRatioBelowGlobalMinPriceRatio();
if (product.minPrice == 0) {
if (product.initialPriceRatio < defaultMinPriceRatio) {
revert InitialPriceRatioBelowDefaultMinPriceRatio();
}
} else {
// TODO: define new error here?
if (product.initialPriceRatio < product.minPrice) {
revert InitialPriceRatioBelowDefaultMinPriceRatio();
}
}

if (product.initialPriceRatio > PRICE_DENOMINATOR) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/modules/staking/StakingPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ contract StakingPool is IStakingPool, Multicall {
coverAllocationAmount,
initialCapacityUsed,
totalCapacity,
request.globalMinPrice,
request.productMinPrice,
request.useFixedPrice,
NXM_PER_ALLOCATION_UNIT,
ALLOCATION_UNITS_PER_NXM
Expand Down
Loading
Loading