Skip to content

Commit

Permalink
Fix test converting eth premium to nxm
Browse files Browse the repository at this point in the history
  • Loading branch information
kyledewy authored and 0xdewy committed Apr 12, 2023
1 parent 4ae8c0c commit e72cc93
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 52 deletions.
2 changes: 2 additions & 0 deletions test/fork/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
describe('fork tests', function () {
require('./migrated-claims');
require('./recalculate-effective-weights');
require('./recalculate-effective-weights-bug-fix');
});
79 changes: 44 additions & 35 deletions test/fork/recalculate-effective-weights.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
calculateSurgePremium,
calculatePriceBump,
} = require('../unit/StakingPool/helpers');
const { ethToNXM, NXMToEth } = require('../integration/utils/assetPricing');
const { verifyPoolWeights } = require('./staking-pool-utils');
const evm = require('./evm')();
describe('recalculateEffectiveWeight', function () {
Expand All @@ -25,6 +26,8 @@ describe('recalculateEffectiveWeight', function () {

// Upgrade StakingProducts
const codes = ['SP'].map(code => toUtf8Bytes(code));
const pool = await ethers.getContractAt('Pool', V2Addresses.Pool);
const priceFeedOracle = await ethers.getContractAt('PriceFeedOracle', V2Addresses.PriceFeedOracle);
const governance = await ethers.getContractAt('Governance', V2Addresses.Governance);
const cover = await ethers.getContractAt('Cover', V2Addresses.Cover);
const stakingProducts = await ethers.getContractAt('StakingProducts', V2Addresses.StakingProducts);
Expand Down Expand Up @@ -57,6 +60,8 @@ describe('recalculateEffectiveWeight', function () {
this.stakingPool = stakingPool2;
this.cover = cover;
this.stakingProducts = stakingProducts;
this.pool = pool;
this.priceFeedOracle = priceFeedOracle;

this.config = await getConfig.call(this);
});
Expand All @@ -74,29 +79,33 @@ describe('recalculateEffectiveWeight', function () {

it('should buy a cover and bump the price towards the target weight', async function () {
// Note this test doesn't fix the effective weights first
const { stakingProducts, cover, config } = this;
const { stakingProducts, cover, config, pool } = this;

// cover buy details
const coverAsset = 0; // ETH
const poolId = 2;
const amount = parseEther('1');
const amountETH = parseEther('1');
const amountInNXM = await ethToNXM(pool, amountETH, config);
const period = daysToSeconds(45);
const commissionRatio = 0;

// get random product in pool with target weight > 0
const productsInThisPool = await getProductsInPool.call(this, { poolId });
// pick a random product
const randomProduct = productsInThisPool[Math.floor(Math.random() * (productsInThisPool.length - 1))];
console.log('buying cover for product: ', randomProduct.productId, 'in pool: ', poolId);
const { capacityReductionRatio } = await cover.products(randomProduct.productId);
console.log('random product: ', randomProduct);
const { capacityReductionRatio, useFixedPrice, isDeprecated } = await cover.products(randomProduct.productId);

expect(isDeprecated).to.be.equal(false);

const { totalCapacity } = await this.stakingPool.getActiveTrancheCapacities(
randomProduct.productId,
config.GLOBAL_CAPACITY_RATIO,
capacityReductionRatio,
);

const allocations = await this.stakingPool.getActiveAllocations(randomProduct.productId);
let initialCapacityUsed = BigNumber.from(0);

for (const allocation of allocations) {
initialCapacityUsed = initialCapacityUsed.add(allocation);
}
Expand All @@ -106,42 +115,40 @@ describe('recalculateEffectiveWeight', function () {
const basePrice = calculateBasePrice(now, randomProduct, config.PRICE_CHANGE_PER_DAY);

const priceBump = calculatePriceBump(
amount,
amountInNXM,
config.PRICE_BUMP_RATIO,
totalCapacity,
config.NXM_PER_ALLOCATION_UNIT,
);

const basePremium = calculateBasePremium(amount, basePrice, period, config);
const basePremium = calculateBasePremium(amountInNXM, basePrice, period, config);

const { surgePremium, surgePremiumSkipped } = calculateSurgePremium(
amount,
amountInNXM,
initialCapacityUsed,
totalCapacity,
period,
config,
);

// TODO: fix maxPremiumInAsset calculations
const maxPremiumInAssetTooLow = basePremium.add(surgePremium).sub(surgePremiumSkipped);
console.log('maxPremiumInAssetTooLow', maxPremiumInAssetTooLow.toString());
const maxPremiumInAsset = amount;
const maxPremiumInNXM = basePremium.add(surgePremium).sub(surgePremiumSkipped);
const maxPremiumInAsset = await NXMToEth(pool, maxPremiumInNXM, config);

await cover.connect(this.hugh).buyCover(
{
coverId: 0,
owner: this.hugh.address,
productId: randomProduct.productId,
coverAsset,
amount,
amount: amountETH,
period, // 30 days
maxPremiumInAsset,
paymentAsset: coverAsset,
commissionRatio,
commissionDestination: this.hugh.address,
ipfsData: '',
},
[{ poolId, coverAmountInAsset: amount, skip: false }],
[{ poolId, coverAmountInAsset: amountETH, skip: false }],
{ value: maxPremiumInAsset },
);

Expand All @@ -151,28 +158,30 @@ describe('recalculateEffectiveWeight', function () {
randomProduct.productId,
);

// check bumped price
if (BigNumber.from(bumpedPrice).eq(targetPrice)) {
expect(bumpedPrice).to.be.equal(randomProduct.targetPrice);
} else if (BigNumber.from(bumpedPrice).gt(targetPrice)) {
// TODO: price bump calculation is off for product 71
console.log('priceBump', priceBump.toString());
expect(bumpedPrice).to.be.equal(basePrice.add(priceBump));
} else if (BigNumber.from(bumpedPrice).lt(targetPrice)) {
console.log('bumped price is below target price');
console.log('bumpedPrice', bumpedPrice.toString());
console.log('targetPrice', targetPrice.toString());
// expect(bumpedPrice).to.be.gt(randomProduct.bumpedPrice);
if (!useFixedPrice) {
// check bumped price
if (BigNumber.from(bumpedPrice).eq(targetPrice)) {
expect(bumpedPrice).to.be.equal(randomProduct.targetPrice);
} else if (BigNumber.from(bumpedPrice).gt(targetPrice)) {
expect(bumpedPrice).to.be.equal(basePrice.add(priceBump));
} else if (BigNumber.from(bumpedPrice).lt(targetPrice)) {
throw new Error('bumped price is less than target price');
}

// if it was already bumped in the last day, it shouldn't be bumped again
if (timestamp - randomProduct.bumpedPriceUpdateTime < daysToSeconds(1)) {
expect(bumpedPriceUpdateTime).to.be.eq(randomProduct.bumpedPriceUpdateTime);
expect(bumpedPrice).to.be.eq(randomProduct.bumpedPrice);
} else {
expect(bumpedPriceUpdateTime).to.be.equal(timestamp);
}
}

// if it was already bumped in the last day, it shouldn't be bumped again
// TODO: see if this is still failing after this is merged:
// https://github.com/NexusMutual/smart-contracts/pull/824
if (timestamp - randomProduct.bumpedPriceUpdateTime < daysToSeconds(1)) {
expect(bumpedPriceUpdateTime).to.be.eq(randomProduct.bumpedPriceUpdateTime);
expect(bumpedPrice).to.be.eq(randomProduct.bumpedPrice);
} else {
expect(bumpedPriceUpdateTime).to.be.equal(timestamp);
if (useFixedPrice) {
console.log('\nusing fixed price');
expect(targetPrice).to.be.equal(randomProduct.targetPrice);
expect(bumpedPrice).to.be.equal(randomProduct.bumpedPrice);
// the following products are failing the check above
// failing products: 68, 44, 2
}
});
});
3 changes: 2 additions & 1 deletion test/fork/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ async function getConfig() {
SURGE_THRESHOLD_RATIO: stakingProducts.SURGE_THRESHOLD_RATIO(),
NXM_PER_ALLOCATION_UNIT: stakingPool.NXM_PER_ALLOCATION_UNIT(),
ALLOCATION_UNITS_PER_NXM: stakingPool.ALLOCATION_UNITS_PER_NXM(),
ONE_NXM: stakingPool.ONE_NXM(),
INITIAL_PRICE_DENOMINATOR: stakingProducts.INITIAL_PRICE_DENOMINATOR(),
REWARDS_DENOMINATOR: stakingPool.REWARDS_DENOMINATOR(),
WEIGHT_DENOMINATOR: stakingPool.WEIGHT_DENOMINATOR(),
Expand All @@ -248,7 +249,7 @@ async function getConfig() {
GLOBAL_REWARDS_RATIO: cover.globalRewardsRatio(),
GLOBAL_MIN_PRICE_RATIO: cover.GLOBAL_MIN_PRICE_RATIO(),
};
await Promise.all(Object.keys(config).map(async key => (config[key] = await config[key])));
await Promise.all(Object.keys(config).map(async key => (config[key] = BigNumber.from(await config[key]))));
return config;
}

Expand Down
29 changes: 22 additions & 7 deletions test/integration/utils/assetPricing.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,29 @@ async function assetToEthWithPrecisionLoss(pool, coverAmountInAsset, assetToEthR
return coverAmountInNXM.mul(nxmEthPrice).div(config.ONE_NXM);
}

// Replicates the amount stored when buying cover with asset other than NXM
async function ethToNXM(pool, amountInEth, config) {
const nxmPriceInCoverAsset = BigNumber.from(await pool.getTokenPriceInAsset(ETH_ASSET_ID));
const ethWithDecimals = BigNumber.from(amountInEth).mul(config.ONE_NXM);
const amountInNXMRaw = divCeil(ethWithDecimals, nxmPriceInCoverAsset);
const amountInNXM = roundUpToNearestAllocationUnit(amountInNXMRaw, config.NXM_PER_ALLOCATION_UNIT);
return amountInNXM;
}

async function NXMToEth(pool, amountInNXM, config) {
const nxmPriceInCoverAsset = BigNumber.from(await pool.getTokenPriceInAsset(ETH_ASSET_ID));
const nxmWithDecimals = BigNumber.from(amountInNXM).mul(config.ONE_NXM);
const amountInEthRaw = divCeil(nxmWithDecimals, nxmPriceInCoverAsset);
const amountInEth = roundUpToNearestAllocationUnit(amountInEthRaw, config.NXM_PER_ALLOCATION_UNIT);
return amountInEth;
}

// Converts amount in asset to NXM and back to asset with precision loss
async function assetWithPrecisionLoss(pool, amountInAsset, assetID, config) {
const nxmPriceInCoverAsset = await pool.getTokenPriceInAsset(assetID);
const amountInNXM = roundUpToNearestAllocationUnit(
divCeil(amountInAsset.mul(config.ONE_NXM), nxmPriceInCoverAsset),
config.NXM_PER_ALLOCATION_UNIT,
);
const nxmPriceInCoverAsset = BigNumber.from(await pool.getTokenPriceInAsset(assetID));
const nxmRoundedUp = BigNumber.from(amountInAsset).mul(config.ONE_NXM);
const amountInNXMRaw = divCeil(nxmRoundedUp, nxmPriceInCoverAsset);
const amountInNXM = roundUpToNearestAllocationUnit(amountInNXMRaw, config.NXM_PER_ALLOCATION_UNIT);
return amountInNXM.mul(nxmPriceInCoverAsset).div(config.ONE_NXM);
}

module.exports = { assetToEthWithPrecisionLoss, assetWithPrecisionLoss };
module.exports = { assetToEthWithPrecisionLoss, assetWithPrecisionLoss, ethToNXM, NXMToEth };
10 changes: 1 addition & 9 deletions test/unit/StakingPool/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@ function calculateBasePrice(timestamp, product, priceChangePerDay) {
return BigNumber.from(Math.max(basePrice, product.targetPrice));
}

function calculateBasePremiumPerYear(coverAmount, basePrice, config) {
expect(BigNumber.isBigNumber(coverAmount)).to.be.equal(true);
expect(BigNumber.isBigNumber(basePrice)).to.be.equal(true);
const allocationAmount = divCeil(coverAmount, config.NXM_PER_ALLOCATION_UNIT);
return basePrice.mul(allocationAmount).mul(config.NXM_PER_ALLOCATION_UNIT).div(config.INITIAL_PRICE_DENOMINATOR);
}

function calculateBasePremium(coverAmount, basePrice, period, config) {
// validate inputs
expect(BigNumber.isBigNumber(coverAmount)).to.be.equal(true);
Expand Down Expand Up @@ -113,6 +106,7 @@ function calculatePriceBump(coverAmount, priceBumpRatio, totalCapacity, NXM_PER_
// Rounds an integer up to the nearest multiple of NXM_PER_ALLOCATION_UNIT
function roundUpToNearestAllocationUnit(amount, nxmPerAllocationUnit) {
amount = BigNumber.from(amount);
nxmPerAllocationUnit = BigNumber.from(nxmPerAllocationUnit);
return divCeil(amount, nxmPerAllocationUnit).mul(nxmPerAllocationUnit);
}

Expand Down Expand Up @@ -221,10 +215,8 @@ module.exports = {
setTime,
calculateBasePrice,
calculateBasePremium,
calculateBasePremiumPerYear,
calculatePriceBump,
calculateSurgePremium,
calculateSurgePremiumPerYear,
divCeil,
roundUpToNearestAllocationUnit,
getTranches,
Expand Down

0 comments on commit e72cc93

Please sign in to comment.