Skip to content
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
121 changes: 102 additions & 19 deletions test/unit/Cover/createStakingPool.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,129 @@
const { assert } = require('chai');
const { expect } = require('chai');
const { ethers } = require('hardhat');

describe('createStakingPool', function () {
it('should create new pool', async function () {
const { cover } = this;

const [stakingPoolCreator, stakingPoolManager] = this.accounts.members;
const initialPoolFee = '5'; // 5%
const maxPoolFee = '5'; // 5%

const depositAmount = '0';
const trancheId = '0';

const productinitializationParams = [
const newPoolFixture = {
initialPoolFee: 5, // 5%
maxPoolFee: 5, // 5%
depositAmount: 0,
trancheId: 0,
poolId: 0,
productInitializationParams: [
{
productId: 0,
weight: 100,
initialPrice: '500',
targetPrice: '500',
},
];
],
};

it('should create and initialize a new pool minimal beacon proxy pool', async function () {
const { cover } = this;

const firstStakingPoolAddress = await cover.stakingPool(0);
const [stakingPoolCreator, stakingPoolManager] = this.accounts.members;

const { initialPoolFee, maxPoolFee, productInitializationParams, depositAmount, trancheId, poolId } =
newPoolFixture;

const firstStakingPoolAddress = await cover.stakingPool(poolId);

await cover.connect(stakingPoolCreator).createStakingPool(
stakingPoolManager.address,
false, // isPrivatePool,
initialPoolFee,
maxPoolFee,
productinitializationParams,
productInitializationParams,
depositAmount,
trancheId,
);

const stakingPoolInstance = await ethers.getContractAt('CoverMockStakingPool', firstStakingPoolAddress);
const proxyInstance = await ethers.getContractAt('MinimalBeaconProxy', firstStakingPoolAddress);

const storedManager = await stakingPoolInstance.manager();
expect(storedManager).to.be.equal(stakingPoolManager.address);

const beacon = await proxyInstance.beacon();
expect(beacon).to.be.equal(cover.address);

// validate variable is initialized
const contractPoolId = await stakingPoolInstance.poolId();
expect(contractPoolId).to.be.equal(poolId);
});

it('allows anyone to create a new pool', async function () {
const { cover } = this;

const [stakingPoolCreator, stakingPoolManager] = this.accounts.generalPurpose;

const { initialPoolFee, maxPoolFee, productInitializationParams, depositAmount, trancheId, poolId } =
newPoolFixture;

const firstStakingPoolAddress = await cover.stakingPool(poolId);

await cover.connect(stakingPoolCreator).createStakingPool(
stakingPoolManager.address,
false, // isPrivatePool,
initialPoolFee,
maxPoolFee,
productInitializationParams,
depositAmount,
trancheId,
);

const stakingPoolInstance = await ethers.getContractAt('IStakingPool', firstStakingPoolAddress);
const storedManager = await stakingPoolInstance.manager();
assert.equal(storedManager, stakingPoolManager.address);
expect(storedManager).to.be.equal(stakingPoolManager.address);
});

const proxyInstance = await ethers.getContractAt('MinimalBeaconProxy', firstStakingPoolAddress);
it('emits StakingPoolCreated event', async function () {
const { cover } = this;

const beacon = await proxyInstance.beacon();
const [stakingPoolCreator, stakingPoolManager] = this.accounts.members;

const { initialPoolFee, maxPoolFee, productInitializationParams, depositAmount, trancheId, poolId } =
newPoolFixture;

const stakingPoolImplementation = await cover.stakingPoolImplementation();

const firstStakingPoolAddress = await cover.stakingPool(poolId);

await expect(
cover.connect(stakingPoolCreator).createStakingPool(
stakingPoolManager.address,
false, // isPrivatePool,
initialPoolFee,
maxPoolFee,
productInitializationParams,
depositAmount,
trancheId,
),
)
.to.emit(cover, 'StakingPoolCreated')
.withArgs(firstStakingPoolAddress, poolId, stakingPoolManager.address, stakingPoolImplementation);
});

it('increments staking pool count', async function () {
const { cover } = this;

const [stakingPoolCreator, stakingPoolManager] = this.accounts.members;

const { initialPoolFee, maxPoolFee, productInitializationParams, depositAmount, trancheId } = newPoolFixture;

const stakingPoolCountBefore = await cover.stakingPoolCount();

await cover.connect(stakingPoolCreator).createStakingPool(
stakingPoolManager.address,
false, // isPrivatePool,
initialPoolFee,
maxPoolFee,
productInitializationParams,
depositAmount,
trancheId,
);

await assert.equal(beacon, cover.address);
const stakingPoolCountAfter = await cover.stakingPoolCount();
expect(stakingPoolCountAfter).to.be.equal(stakingPoolCountBefore.add(1));
});
});
35 changes: 23 additions & 12 deletions test/unit/Cover/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,11 @@ async function assertCoverFields(
expect(segment.priceRatio).to.be.equal(targetPriceRatio);
}

async function buyCoverOnOnePool({
productId,
coverAsset,
period,
amount,
targetPriceRatio,
priceDenominator,
activeCover,
capacity,
}) {
async function buyCoverOnOnePool(params) {
const { cover } = this;
const [coverBuyer, stakingPoolManager] = this.accounts.members;
const [, stakingPoolManager] = this.accounts.members;

const { productId, capacity, activeCover, targetPriceRatio, amount } = params;

await createStakingPool(
cover,
Expand All @@ -80,6 +73,23 @@ async function buyCoverOnOnePool({
targetPriceRatio,
);

const allocationRequest = [{ poolId: 0, coverAmountInAsset: amount }];

return buyCoverOnMultiplePools.call(this, { ...params, allocationRequest });
}

async function buyCoverOnMultiplePools({
productId,
coverAsset,
period,
amount,
targetPriceRatio,
priceDenominator,
allocationRequest,
}) {
const { cover } = this;
const [coverBuyer] = this.accounts.members;

const expectedPremium = amount
.mul(targetPriceRatio)
.div(priceDenominator)
Expand All @@ -100,7 +110,7 @@ async function buyCoverOnOnePool({
commissionDestination: AddressZero,
ipfsData: '',
},
[{ poolId: '0', coverAmountInAsset: amount }],
allocationRequest,
{ value: expectedPremium },
);

Expand Down Expand Up @@ -129,4 +139,5 @@ module.exports = {
buyCoverOnOnePool,
MAX_COVER_PERIOD,
createStakingPool,
buyCoverOnMultiplePools,
};
166 changes: 159 additions & 7 deletions test/unit/Cover/performStakeBurn.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { ethers } = require('hardhat');
const { assertCoverFields, buyCoverOnOnePool } = require('./helpers');
const { bnEqual } = require('../utils').helpers;
const { assertCoverFields, buyCoverOnOnePool, buyCoverOnMultiplePools, createStakingPool } = require('./helpers');
const { expect } = require('chai');

const { parseEther } = ethers.utils;
const gracePeriodInDays = 120;
Expand Down Expand Up @@ -37,7 +37,7 @@ describe('performStakeBurn', function () {

const burnAmountDivisor = 2;

const burnAmount = coverBuyFixture.amount.div(burnAmountDivisor);
const burnAmount = amount.div(burnAmountDivisor);
const remainingAmount = amount.sub(burnAmount);

const segmentAllocation = await cover.coverSegmentAllocations(expectedCoverId, segmentId, '0');
Expand All @@ -61,11 +61,163 @@ describe('performStakeBurn', function () {

const burnStakeCalledWith = await stakingPool.burnStakeCalledWith();

bnEqual(burnStakeCalledWith.productId, productId);
bnEqual(burnStakeCalledWith.period, period);
bnEqual(burnStakeCalledWith.amount, expectedBurnAmount);
expect(burnStakeCalledWith.productId).to.be.equal(productId);
expect(burnStakeCalledWith.period).to.be.equal(period);
expect(burnStakeCalledWith.amount).to.be.equal(expectedBurnAmount);

const activeCoverAmount = await cover.totalActiveCoverInAsset(coverAsset);
bnEqual(activeCoverAmount, amount.sub(burnAmount));
expect(activeCoverAmount).to.be.equal(amount.sub(burnAmount));
});

it('reverts if caller is not an internal contract', async function () {
const { cover } = this;

const {
members: [member],
} = this.accounts;

const { amount } = coverBuyFixture;

const { segmentId, coverId: expectedCoverId } = await buyCoverOnOnePool.call(this, coverBuyFixture);

const burnAmountDivisor = 2;

const burnAmount = amount.div(burnAmountDivisor);

await expect(cover.connect(member).performStakeBurn(expectedCoverId, segmentId, burnAmount)).to.be.revertedWith(
'Caller is not an internal contract',
);
});

it('does not update total active cover if tracking is not enabled', async function () {
const { cover } = this;

const {
internalContracts: [internal1],
} = this.accounts;

const { coverAsset, amount } = coverBuyFixture;

const { segmentId, coverId: expectedCoverId } = await buyCoverOnOnePool.call(this, coverBuyFixture);

const burnAmountDivisor = 2;
const burnAmount = amount.div(burnAmountDivisor);

const activeCoverAmountBefore = await cover.totalActiveCoverInAsset(coverAsset);

await cover.connect(internal1).performStakeBurn(expectedCoverId, segmentId, burnAmount);

const activeCoverAmountAfter = await cover.totalActiveCoverInAsset(coverAsset);
expect(activeCoverAmountAfter).to.be.equal(activeCoverAmountBefore);
});

it('updates segment allocation cover amount in nxm', async function () {
const { cover } = this;

const {
internalContracts: [internal1],
} = this.accounts;

const { amount } = coverBuyFixture;

const { segmentId, coverId: expectedCoverId } = await buyCoverOnOnePool.call(this, coverBuyFixture);

const burnAmountDivisor = 2;

const burnAmount = amount.div(burnAmountDivisor);

const segmentAllocationBefore = await cover.coverSegmentAllocations(expectedCoverId, segmentId, 0);

const expectedBurnAmount = segmentAllocationBefore.coverAmountInNXM.div(burnAmountDivisor);

await cover.connect(internal1).performStakeBurn(expectedCoverId, segmentId, burnAmount);

const segmentAllocationAfter = await cover.coverSegmentAllocations(expectedCoverId, segmentId, 0);
expect(segmentAllocationAfter.coverAmountInNXM).to.be.equal(
segmentAllocationBefore.coverAmountInNXM.sub(expectedBurnAmount),
);
});

it('should perform a burn on a cover with 1 segment and 2 pool allocations', async function () {
const { cover } = this;

const {
internalContracts: [internal1],
members: [, stakingPoolManager],
emergencyAdmin,
} = this.accounts;

const { productId, coverAsset, period, amount, targetPriceRatio, capacity, activeCover } = coverBuyFixture;

await cover.connect(emergencyAdmin).enableActiveCoverAmountTracking([], []);
await cover.connect(emergencyAdmin).commitActiveCoverAmounts();

const amountOfPools = 4;

const amountPerPool = amount.div(amountOfPools);
const allocationRequest = [];

for (let i = 0; i < amountOfPools; i++) {
await createStakingPool(
cover,
productId,
capacity,
targetPriceRatio,
activeCover,
stakingPoolManager,
stakingPoolManager,
targetPriceRatio,
);
allocationRequest.push({ poolId: i, coverAmountInAsset: amountPerPool });
}

const { segmentId, coverId: expectedCoverId } = await buyCoverOnMultiplePools.call(this, {
...coverBuyFixture,
allocationRequest,
});

const burnAmountDivisor = 2;

const burnAmount = amount.div(burnAmountDivisor);
const remainingAmount = amount.sub(burnAmount);

const segmentAllocationsBefore = [];
for (let i = 0; i < amountOfPools; i++) {
const segmentAllocationBefore = await cover.coverSegmentAllocations(expectedCoverId, segmentId, i);
segmentAllocationsBefore.push(segmentAllocationBefore);
}

const expectedBurnAmountPerPool = segmentAllocationsBefore[0].coverAmountInNXM.div(burnAmountDivisor);

await cover.connect(internal1).performStakeBurn(expectedCoverId, segmentId, burnAmount);

await assertCoverFields(cover, expectedCoverId, {
productId,
coverAsset,
period,
amount: remainingAmount,
targetPriceRatio,
gracePeriodInDays,
segmentId,
amountPaidOut: burnAmount,
});

const activeCoverAmount = await cover.totalActiveCoverInAsset(coverAsset);
expect(activeCoverAmount).to.be.equal(amount.sub(burnAmount));

for (let i = 0; i < amountOfPools; i++) {
const stakingPool = await ethers.getContractAt('CoverMockStakingPool', await cover.stakingPool(i));

const burnStakeCalledWith = await stakingPool.burnStakeCalledWith();

expect(burnStakeCalledWith.productId).to.be.equal(productId);
expect(burnStakeCalledWith.period).to.be.equal(period);
expect(burnStakeCalledWith.amount).to.be.equal(expectedBurnAmountPerPool);

const segmentAllocationAfter = await cover.coverSegmentAllocations(expectedCoverId, segmentId, i);
expect(segmentAllocationAfter.coverAmountInNXM).to.be.equal(
segmentAllocationsBefore[i].coverAmountInNXM.sub(expectedBurnAmountPerPool),
);
}
});
});