proposal-47/test/Proposal.js

224 lines
11 KiB
JavaScript
Raw Normal View History

2024-01-31 15:04:44 +03:00
const { ethers, network } = require("hardhat");
const contentHash = require("content-hash");
const { expect, assert } = require("chai");
const { time } = require("@nomicfoundation/hardhat-toolbox/network-helpers");
2024-02-10 21:43:54 +03:00
const { deployAndExecuteProposal, getGovernance, getTorn } = require("./utils");
2024-01-31 15:04:44 +03:00
const tornAddr = "0x77777FeDdddFfC19Ff86DB637967013e6C6A116C";
const sablierAddr = "0xCD18eAa163733Da39c232722cBC4E8940b1D8888";
const governanceAddr = "0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce";
async function getManyEth(addr) {
await network.provider.send("hardhat_setBalance", [addr, "0x111166630153555558483537"]);
}
async function getEnsRegistry() {
const ensAddr = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
return await ethers.getContractAt(require("./abi/ensRegistry.abi.json"), ensAddr);
}
async function getEnsResolver(ensName) {
const ensRegistry = await getEnsRegistry();
const resolverAddr = await ensRegistry.resolver(ethers.namehash(ensName));
return await ethers.getContractAt(require("./abi/ensResolver.abi.json"), resolverAddr);
}
async function resolveAddr(ensName) {
if (ethers.isAddress(ensName)) return ensName;
const ensResolver = await getEnsResolver(ensName);
return await ensResolver.addr(ethers.namehash(ensName));
}
async function getTornContract() {
return await ethers.getContractAt(require("./abi/torn.abi.json"), tornAddr);
}
async function getSablierContract() {
return await ethers.getContractAt(require("./abi/sabler.abi.json"), sablierAddr);
}
async function getMe() {
return await resolveAddr("butterfly-attractor.eth");
}
describe("Proposal results check", function () {
beforeEach(async function () {
await network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: config.networks.hardhat.forking.url,
blockNumber: config.networks.hardhat.forking.blockNumber,
},
},
],
});
});
2024-02-10 21:43:54 +03:00
async function getEvents(contract, eventName, fromBlock = 0) {
const filter = contract.filters[eventName];
const events = await contract.queryFilter(filter, fromBlock); //config.networks.hardhat.forking.blockNumber - 1
return events;
2024-01-31 15:04:44 +03:00
}
2024-02-10 21:43:54 +03:00
function normalizeAirdropAmount(amount) {
const halfYear = 180 * 24 * 60 * 60;
return amount - (amount % BigInt(halfYear));
}
it("Airdrop recipients storage contracts should deployed successfully", async function () {
const { airdropRecipientsContract } = await deployAndExecuteProposal();
expect(await ethers.provider.getCode(await airdropRecipientsContract.getAddress())).to.not.be.equal("0x");
});
it("Airdrop recipients deposits sum should be almost equal 1m", async function () {
const { airdropRecipientsContract } = await deployAndExecuteProposal();
const recipients = await airdropRecipientsContract.getAirdropRecipients();
const airdropSum = await recipients.reduce((acc, r) => acc + r[1], 0n);
const decimals = 10n ** 18n;
const millionTorn = 1000n * 1000n * decimals;
expect(airdropSum).to.greaterThan(millionTorn - 1n * decimals);
expect(airdropSum).to.lessThan(millionTorn + 1n * decimals);
});
it("Airdrop recipient deposit should calculated correctly", async function () {
const someRecipient = await resolveAddr("butterfly-effect.eth");
const governance = await getGovernance();
const recipientLockedBalance = await governance.lockedBalance(someRecipient);
const decimals = 10n ** 18n;
const millionTorn = 1000n * 1000n * decimals;
const { airdropRecipientsContract } = await deployAndExecuteProposal();
const recipients = await airdropRecipientsContract.getAirdropRecipients();
const airdropLockedSum = await recipients.reduce((acc, r) => acc + r[2], 0n);
const selectedRecipient = recipients.find((r) => r[0] === someRecipient);
const expectedRecipientAirdrop =
(recipientLockedBalance * ((millionTorn * decimals) / airdropLockedSum)) / decimals;
expect(selectedRecipient[1]).to.be.equal(expectedRecipientAirdrop);
});
it("Airdrop should start", async function () {
const { airdropContract } = await deployAndExecuteProposal();
const filter = airdropContract.filters.CreateAirdrop;
const events = await airdropContract.queryFilter(filter);
const args = events[0].args;
expect(args[1] - args[0]).to.be.equal(180 * 24 * 60 * 60);
expect(args[2]).to.be.equal([...require("../data/airdropRecipients.json")].length);
expect(args[3]).to.be.equal(1);
});
it("Airdrop recipient should be able to withdraw funds", async function () {
const someRecipient = await resolveAddr("butterfly-effect.eth");
const { airdropContract, airdropRecipientsContract } = await deployAndExecuteProposal();
const recipients = await airdropRecipientsContract.getAirdropRecipients();
const selectedRecipientInfo = recipients.find((r) => r[0] === someRecipient);
const recipientAirdropAmount = selectedRecipientInfo[1];
const halfYear = 180 * 24 * 60 * 60;
const normalizedAmount = recipientAirdropAmount - (recipientAirdropAmount % BigInt(halfYear));
const events = await getEvents(airdropContract, "CreateStream");
const recipientStreamId = events.find((e) => e.args[1] === someRecipient).args[0];
await time.increase(halfYear);
const torn = await getTorn();
const recipientBalance = await torn.balanceOf(someRecipient);
const connectedAirdrop = airdropContract.connect(await ethers.getImpersonatedSigner(someRecipient));
2024-02-12 12:27:34 +03:00
await connectedAirdrop.withdrawFromStream(recipientStreamId);
2024-02-10 21:43:54 +03:00
expect(await torn.balanceOf(someRecipient)).to.be.equal(recipientBalance + normalizedAmount);
});
2024-02-12 12:27:34 +03:00
it("Airdrop recipient should be able to withdraw part of funds early", async function () {
2024-02-10 21:43:54 +03:00
const someRecipient = await resolveAddr("butterfly-effect.eth");
2024-02-12 12:27:34 +03:00
const { airdropContract } = await deployAndExecuteProposal();
2024-02-10 21:43:54 +03:00
const halfYear = 180 * 24 * 60 * 60;
const events = await getEvents(airdropContract, "CreateStream");
const recipientStreamId = events.find((e) => e.args[1] === someRecipient).args[0];
await time.increase(halfYear / 2);
2024-02-12 12:27:34 +03:00
const torn = await getTorn();
const recipientBalance = await torn.balanceOf(someRecipient);
2024-02-10 21:43:54 +03:00
const connectedAirdrop = airdropContract.connect(await ethers.getImpersonatedSigner(someRecipient));
2024-02-12 12:27:34 +03:00
// Add timestamps and manual calculation bcs withdrawFromStream call mine next block and increase stream balance
const streamBalance = await connectedAirdrop.balanceOf(recipientStreamId, someRecipient);
const beforeWithdrawalTimestamp = (await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp;
await connectedAirdrop.withdrawFromStream(recipientStreamId);
const afterWithdrawalTimestamp = (await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp;
const blockChangeTime = afterWithdrawalTimestamp - beforeWithdrawalTimestamp;
const stream = await connectedAirdrop.getStream(recipientStreamId);
const ratePerSecond = stream[5];
const addedInCurrentBlock = BigInt(blockChangeTime) * ratePerSecond;
expect(await torn.balanceOf(someRecipient)).to.be.equal(recipientBalance + streamBalance + addedInCurrentBlock);
2024-02-10 21:43:54 +03:00
});
it("Airdrop recipient should not be able to withdraw funds if his stake balance is lower than initial", async function () {
const someRecipient = await resolveAddr("butterfly-effect.eth");
2024-02-12 12:27:34 +03:00
const { airdropContract } = await deployAndExecuteProposal();
2024-02-10 21:43:54 +03:00
const halfYear = 180 * 24 * 60 * 60;
const events = await getEvents(airdropContract, "CreateStream");
const recipientStreamId = events.find((e) => e.args[1] === someRecipient).args[0];
await time.increase(halfYear);
const governance = await getGovernance(await ethers.getImpersonatedSigner(someRecipient));
governance.unlock(1000n * 10n ** 18n);
const connectedAirdrop = airdropContract.connect(await ethers.getImpersonatedSigner(someRecipient));
2024-02-12 12:27:34 +03:00
await expect(connectedAirdrop.withdrawFromStream(recipientStreamId)).to.be.revertedWith(
2024-02-10 21:43:54 +03:00
"not enough locked tokens in governance",
);
});
it("Airdrop recipient should not be able to withdraw funds if stream is canceled", async function () {
const someRecipient = await resolveAddr("butterfly-effect.eth");
const { airdropContract, airdropRecipientsContract } = await deployAndExecuteProposal();
const halfYear = 180 * 24 * 60 * 60;
const events = await getEvents(airdropContract, "CreateStream");
const recipientStreamId = events.find((e) => e.args[1] === someRecipient).args[0];
await time.increase(halfYear);
await airdropContract.cancelStream(recipientStreamId);
const connectedAirdrop = airdropContract.connect(await ethers.getImpersonatedSigner(someRecipient));
2024-02-12 12:27:34 +03:00
await expect(connectedAirdrop.withdrawFromStream(recipientStreamId)).to.be.revertedWith(
2024-02-10 21:43:54 +03:00
"stream does not exist",
);
});
it("Airdrop recipient should not be able to withdraw funds if airdrop is canceled", async function () {
const someRecipient = await resolveAddr("butterfly-effect.eth");
const { airdropContract, airdropRecipientsContract } = await deployAndExecuteProposal();
const recipients = await airdropRecipientsContract.getAirdropRecipients();
const halfYear = 180 * 24 * 60 * 60;
const events = await getEvents(airdropContract, "CreateStream");
const recipientStreamId = events.find((e) => e.args[1] === someRecipient).args[0];
await time.increase(halfYear);
await airdropContract.cancelAirdrop(1, recipients.length);
const connectedAirdrop = airdropContract.connect(await ethers.getImpersonatedSigner(someRecipient));
2024-02-12 12:27:34 +03:00
await expect(connectedAirdrop.withdrawFromStream(recipientStreamId)).to.be.revertedWith(
2024-02-10 21:43:54 +03:00
"stream does not exist",
);
});
it("Airdrop cancelation should return tokens to governance", async function () {
const torn = await getTorn();
const tornDecimals = 10n ** 18n;
const govBalanceBeforeProposal = await torn.balanceOf(governanceAddr);
const { airdropContract, airdropAddr, airdropRecipientsContract } = await deployAndExecuteProposal();
const recipients = await airdropRecipientsContract.getAirdropRecipients();
const airdropSum = await recipients.reduce((acc, r) => acc + normalizeAirdropAmount(r[1]), 0n);
const governanceBalance = await torn.balanceOf(governanceAddr);
const airdropContractBalance = await torn.balanceOf(airdropAddr);
await airdropContract.cancelAirdrop(1, recipients.length);
expect(await torn.balanceOf(governanceAddr)).to.be.equal(governanceBalance + airdropSum);
expect(await torn.balanceOf(airdropAddr)).to.be.equal(airdropContractBalance - airdropSum);
expect((await torn.balanceOf(airdropAddr)) < 1n * tornDecimals);
await airdropContract.withdrawFunds();
expect(await torn.balanceOf(airdropAddr)).to.be.equal(0);
expect(await torn.balanceOf(governanceAddr)).to.be.equal(govBalanceBeforeProposal);
2024-01-31 15:04:44 +03:00
});
});