It will also increase by itself as the protocol become more popular (has more people who call increasePosition
at a given day). Or if there is a spike in deposits (calls to increasePosition
) from users/bots.
const { expect } = require("chai");
const { ethers, network } = require("hardhat");
const { BigNumber } = ethers;
const { mockTokenManager, DEFAULT_COLLATERAL_RATE, TOKEN_ID, rewardAmountForAsset, DAY, fastForward, POOL_FEE_PERCENTAGE, DEFAULT_EUR_USD_PRICE } = require("./common");
describe('LiquidationPool', async () => {
let user1, user2, user3, Protocol, LiquidationPoolManager, LiquidationPool, MockSmartVaultManager,
ERC20MockFactory, TST, EUROs;
beforeEach(async () => {
[ user1, user2, user3, Protocol, ] = await ethers.getSigners();
ERC20MockFactory = await ethers.getContractFactory('ERC20Mock');
TST = await ERC20MockFactory.deploy('The Standard Token', 'TST', 18);
EUROs = await (await ethers.getContractFactory('EUROsMock')).deploy();
const EurUsd = await (await ethers.getContractFactory('ChainlinkMock')).deploy('EUR / USD');
await EurUsd.setPrice(DEFAULT_EUR_USD_PRICE);
const { TokenManager } = await mockTokenManager();
MockSmartVaultManager = await (await ethers.getContractFactory('MockSmartVaultManager')).deploy(DEFAULT_COLLATERAL_RATE, TokenManager.address);
LiquidationPoolManager = await (await ethers.getContractFactory('LiquidationPoolManager')).deploy(
TST.address, EUROs.address, MockSmartVaultManager.address, EurUsd.address, Protocol.address, POOL_FEE_PERCENTAGE
);
LiquidationPool = await ethers.getContractAt('LiquidationPool', await LiquidationPoolManager.pool());
await EUROs.grantRole(await EUROs.BURNER_ROLE(), LiquidationPool.address)
});
afterEach(async () => {
await network.provider.send("hardhat_reset")
});
describe('increase position', async () => {
it('counts gas used for `increasePosition`', async () => {
const wallets = await createWallets(5);
const [, ...gasUsed] = await Promise.all(wallets.map(deposit));
console.log(`getDeltas`, getDeltas(gasUsed));
});
it('counts gas used for `distributeFees`', async () => {
const wallets = await createWallets(5);
const distributeFees = async (wallet) => {
await deposit(wallet);
await EUROs.mint(LiquidationPoolManager.address, ethers.utils.parseEther('1'));
const tx = await LiquidationPoolManager.distributeFees();
const receipt = await tx.wait();
return receipt.gasUsed;
}
let gasUsed = [];
for (const wallet of wallets) {
const gas = await distributeFees(wallet);
gasUsed.push(gas);
}
console.log('gasUsed', gasUsed);
console.log('getDeltas', getDeltas(gasUsed));
});
describe('`consolidatePendingStakes`', async () => {
async function testConsolidatePendingStakes(walletsCount) {
const wallets = await createWallets(walletsCount);
await Promise.all(wallets.map(deposit));
fastForward(DAY);
const tx = await LiquidationPool.decreasePosition(0, 0, { gasLimit: 30_000_000 });
const receipt = await tx.wait();
return receipt.gasUsed;
}
it('Exceeds gas limit for big wallets count for `decreasePosition`', async () => {
const highWalletCount = 150;
try {
await testConsolidatePendingStakes(highWalletCount);
expect.fail('Transaction should have failed but did not');
} catch (error) {
console.log(error.message);
expect(error.message).to.include(
'Transaction ran out of gas',
'Transaction failed for an unexpected reason'
);
}
});
it('Exceeds gas limit for big wallets count for `distributeAssets`', async () => {
const highWalletCount = 150;
try {
const wallets = await createWallets(highWalletCount);
await Promise.all(wallets.map(deposit));
fastForward(DAY);
await LiquidationPool.distributeAssets([], 1, 1, { gasLimit: 30_000_000 });
expect.fail('Transaction should have failed but did not');
} catch (error) {
console.log(error.message);
expect(error.message).to.include(
'Transaction ran out of gas',
'Transaction failed for an unexpected reason'
);
}
});
const walletCounts = [10, 20, 30];
const gasUsedResults = [];
for (const count of walletCounts) {
it(`${count} wallets`, async () => {
const gasUsed = await testConsolidatePendingStakes(count);
gasUsedResults.push({ count, gasUsed });
console.log(`Gas used for ${count} wallets:`, gasUsed.toString());
});
}
after(() => {
console.log("Gas used deltas:");
for (let i = 1; i < gasUsedResults.length; i++) {
const delta = gasUsedResults[i].gasUsed.sub(gasUsedResults[i - 1].gasUsed);
console.log(`Delta between ${gasUsedResults[i - 1].count} and ${gasUsedResults[i].count} wallets:`, delta.toString());
}
});
});
});
function getDeltas(gasUsed) {
const deltas = [];
for (let i = 1; i < gasUsed.length; i++) {
const delta = gasUsed[i].sub(gasUsed[i - 1]);
deltas.push(delta);
}
return deltas;
}
async function createWallets(numberOfWallets) {
const wallets = [];
for (let i = 0; i < numberOfWallets; i++) {
const wallet = ethers.Wallet.createRandom().connect(ethers.provider);
wallets.push(wallet);
const tx = await user1.sendTransaction({
to: wallet.address,
value: ethers.utils.parseEther("0.1"),
});
await tx.wait();
}
return wallets;
}
async function deposit(wallet) {
const balance = ethers.utils.parseEther('5000');
await TST.mint(wallet.address, balance);
await EUROs.mint(wallet.address, balance);
let { _position} = await LiquidationPool.position(wallet.address);
expect(_position.TST).to.equal('0');
expect(_position.EUROs).to.equal('0');
await TST.connect(wallet).approve(LiquidationPool.address, balance);
await EUROs.connect(wallet).approve(LiquidationPool.address, balance);
const tx = await LiquidationPool.connect(wallet).increasePosition(1, 1);
const receipt = await tx.wait();
return receipt.gasUsed;
}
});
Consider rewriting the code in a way that does not use arrays that has no fixed length in a for-loop