297 lines
14 KiB
TypeScript
297 lines
14 KiB
TypeScript
import {expect} from "chai";
|
|
import hre from "hardhat";
|
|
import {getBytes, solidityPackedKeccak256, ZeroAddress} from "ethers";
|
|
import {loadFixture} from "@nomicfoundation/hardhat-toolbox/network-helpers";
|
|
import {expandDecimals, getBlockTime, increaseTime, mineBlock} from "./shared/utilities";
|
|
|
|
const secondsPerYear = BigInt(365 * 24 * 60 * 60);
|
|
const rewardPerSecond = BigInt(1.5 * 10 ** 18) / secondsPerYear ;
|
|
|
|
|
|
describe("Vester", function () {
|
|
async function deployOneContract() {
|
|
// Contracts are deployed using the first signer/account by default
|
|
const [owner, otherAccount] = await hre.ethers.getSigners();
|
|
const verifier = owner.address;
|
|
const chainId = hre.network.config.chainId;
|
|
|
|
const Cec = await hre.ethers.getContractFactory("EsToken");
|
|
const cec = await Cec.deploy("test cec", "cec");
|
|
const esCec = await Cec.deploy("test esCec", "esCec");
|
|
|
|
await cec.setMinter(owner.address, true);
|
|
await esCec.setMinter(owner.address, true);
|
|
|
|
|
|
const RewardTracker = await hre.ethers.getContractFactory("RewardTracker");
|
|
|
|
const stakedCecTracker = await RewardTracker.deploy(esCec.target, cec.target, rewardPerSecond, 18);
|
|
|
|
const Vester = await hre.ethers.getContractFactory("Vester");
|
|
const vester = await Vester.deploy(
|
|
"Vested CEC",
|
|
"veCEC",
|
|
secondsPerYear,
|
|
esCec.target,
|
|
cec.target,
|
|
stakedCecTracker.target,
|
|
ZeroAddress,
|
|
true
|
|
);
|
|
await cec.mint(owner.address, expandDecimals(100000, 18));
|
|
await esCec.mint(owner.address, expandDecimals(100000, 18));
|
|
|
|
return {owner, otherAccount, chainId, cec, esCec, vester, stakedCecTracker};
|
|
}
|
|
describe("Deployment", function () {
|
|
it("should deploy Vester", async function () {
|
|
const {cec, esCec, vester, stakedCecTracker} = await loadFixture(deployOneContract);
|
|
expect(await vester.name()).eq("Vested CEC");
|
|
expect(await vester.symbol()).eq("veCEC");
|
|
expect(await vester.vestingDuration()).eq(secondsPerYear);
|
|
expect(await vester.esToken()).eq(esCec.target);
|
|
expect(await vester.claimableToken()).eq(cec.target);
|
|
expect(await vester.rewardTrackerCEC()).eq(stakedCecTracker.target);
|
|
expect(await vester.hasRewardTrackerCEC()).eq(true);
|
|
});
|
|
|
|
it("setCumulativeRewardDeductions", async () => {
|
|
const {owner, otherAccount, cec, esCec, vester} = await loadFixture(deployOneContract);
|
|
await expect(vester.setCumulativeRewardDeductions(owner.address, 200)).to.be.revertedWith("Vester: forbidden");
|
|
|
|
await vester.setHandler(owner.address, true);
|
|
|
|
expect(await vester.cumulativeRewardDeductions(owner.address)).eq(0);
|
|
await vester.setCumulativeRewardDeductions(owner.address, 200);
|
|
expect(await vester.cumulativeRewardDeductions(owner.address)).eq(200);
|
|
});
|
|
|
|
it("setBonusRewards", async () => {
|
|
const {owner, otherAccount, cec, esCec, vester} = await loadFixture(deployOneContract);
|
|
|
|
await expect(vester.setBonusRewards(owner.address, 200)).to.be.revertedWith("Vester: forbidden");
|
|
|
|
await vester.setHandler(owner.address, true);
|
|
|
|
expect(await vester.bonusRewards(owner.address)).eq(0);
|
|
await vester.setBonusRewards(owner.address, 200);
|
|
expect(await vester.bonusRewards(owner.address)).eq(200);
|
|
});
|
|
|
|
it("deposit, claim, withdraw", async () => {
|
|
const {owner, otherAccount, cec, esCec, vester, stakedCecTracker} = await loadFixture(deployOneContract);
|
|
const wallet = owner;
|
|
const user0 = otherAccount;
|
|
const provider = wallet.provider;
|
|
await vester.setHandler(wallet.address, true);
|
|
await esCec.setMinter(vester.target, true);
|
|
// @ts-ignore
|
|
await expect(vester.connect(user0).deposit(0)).to.be.revertedWith("Vester: invalid _amount");
|
|
// @ts-ignore
|
|
await expect(vester.connect(user0).deposit(expandDecimals(1000, 18))).to.be.revertedWith(
|
|
"ERC20: insufficient allowance",
|
|
);
|
|
await esCec.setHandler(vester.target, true);
|
|
await esCec.setInPrivateTransferMode(true);
|
|
await esCec.setHandler(wallet.address, true);
|
|
// @ts-ignore
|
|
// await esCec.connect(user0).approve(vester.target, expandDecimals(1000, 18));
|
|
// @ts-ignore
|
|
await expect(vester.connect(user0).deposit(expandDecimals(1000, 18))).to.be.revertedWith(
|
|
"ERC20: transfer amount exceeds balance",
|
|
);
|
|
|
|
expect(await vester.balanceOf(user0.address)).eq(0);
|
|
expect(await vester.getTotalVested(user0.address)).eq(0);
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimable(user0.address)).eq(0);
|
|
expect(await vester.lastVestingTimes(user0.address)).eq(0);
|
|
|
|
await esCec.mint(user0.address, expandDecimals(1000, 18));
|
|
await vester.setBonusRewards(user0.address, expandDecimals(10_000, 18));
|
|
|
|
// @ts-ignore
|
|
await expect(vester.connect(user0).deposit(expandDecimals(1000, 18))).to.be.revertedWith(
|
|
"Vester: insufficient cec balance",
|
|
);
|
|
|
|
await stakedCecTracker.setHandler(user0.address, true);
|
|
await cec.setMinter(wallet.address, true);
|
|
await cec.mint(user0.address, expandDecimals(1000, 18));
|
|
// @ts-ignore
|
|
await cec.connect(user0).approve(stakedCecTracker.target, expandDecimals(1000, 18));
|
|
// @ts-ignore
|
|
await stakedCecTracker.connect(user0).stakeForAccount(user0.address, user0.address, cec.target, expandDecimals(1000, 18));
|
|
|
|
// @ts-ignore
|
|
await vester.connect(user0).deposit(expandDecimals(1000, 18));
|
|
|
|
let blockTime = await getBlockTime(provider);
|
|
|
|
expect(await vester.balanceOf(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.getTotalVested(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimable(user0.address)).eq(0);
|
|
expect(await vester.lastVestingTimes(user0.address)).eq(blockTime);
|
|
|
|
await increaseTime(provider, 24 * 60 * 60);
|
|
await mineBlock(provider);
|
|
|
|
expect(await esCec.balanceOf(user0.address)).eq(0);
|
|
expect(await cec.balanceOf(user0.address)).eq(0);
|
|
expect(await vester.balanceOf(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.getTotalVested(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(0);
|
|
let lastDepositTime = await vester.lastDepositTimes(user0.address);
|
|
let lastVestingTime = BigInt(await vester.lastVestingTimes(user0.address));
|
|
expect(lastDepositTime).eq(lastVestingTime);
|
|
let now = await getBlockTime(provider);
|
|
let total = BigInt(1000) * BigInt(10 ** 18) * (BigInt(now) - lastDepositTime) / BigInt(secondsPerYear);
|
|
expect(await vester.claimable(user0.address)).eq(total);
|
|
expect(await vester.lastVestingTimes(user0.address)).eq(blockTime);
|
|
// @ts-ignore
|
|
await expect(vester.connect(user0).claim()).to.be.revertedWith("ERC20: transfer amount exceeds balance");
|
|
await cec.mint(vester.target, expandDecimals(2000, 18));
|
|
|
|
// @ts-ignore
|
|
await vester.connect(user0).claim();
|
|
blockTime = await getBlockTime(provider);
|
|
lastDepositTime = await vester.lastDepositTimes(user0.address);
|
|
|
|
now = await getBlockTime(provider);
|
|
total = BigInt(1000) * (now - lastDepositTime) * BigInt(10 ** 18) / BigInt(secondsPerYear);
|
|
expect(await esCec.balanceOf(user0.address)).eq(0);
|
|
expect(await cec.balanceOf(user0.address)).eq(total);
|
|
|
|
let cecAmount = await cec.balanceOf(user0.address);
|
|
let claimed = cecAmount;
|
|
expect(await vester.balanceOf(user0.address)).eq(expandDecimals(1000, 18) - cecAmount);
|
|
expect(cecAmount).eq(total);
|
|
expect(await vester.getTotalVested(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimable(user0.address)).eq(0);
|
|
expect(await vester.lastVestingTimes(user0.address)).eq(blockTime);
|
|
|
|
await increaseTime(provider, 48 * 60 * 60);
|
|
await mineBlock(provider);
|
|
|
|
lastDepositTime = await vester.lastDepositTimes(user0.address);
|
|
let pre = now
|
|
now = await getBlockTime(provider);
|
|
let _claimable = BigInt(1000) * (now - pre) * BigInt(10 ** 18) / BigInt(secondsPerYear);
|
|
lastVestingTime = BigInt(await vester.lastVestingTimes(user0.address));
|
|
expect(pre).eq(lastVestingTime);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimable(user0.address)).eq(total - claimed + _claimable);
|
|
|
|
await increaseTime(provider, parseInt(365 / 2 - 1 + "") * 24 * 60 * 60);
|
|
await mineBlock(provider);
|
|
|
|
|
|
let tmpNow = await getBlockTime(provider);
|
|
_claimable = BigInt(1000) * (tmpNow - pre) * BigInt(10 ** 18) / BigInt(secondsPerYear);
|
|
|
|
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimable(user0.address)).eq(total - cecAmount + _claimable);
|
|
// @ts-ignore
|
|
await vester.connect(user0).claim();
|
|
blockTime = await getBlockTime(provider);
|
|
now = await getBlockTime(provider);
|
|
_claimable = BigInt(1000) * (now - pre) * BigInt(10 ** 18) / BigInt(secondsPerYear);
|
|
total += _claimable;
|
|
pre = now;
|
|
cecAmount += (total - cecAmount)
|
|
expect(await esCec.balanceOf(user0.address)).eq(0);
|
|
expect(await cec.balanceOf(user0.address)).eq(cecAmount);
|
|
|
|
|
|
cecAmount = await cec.balanceOf(user0.address);
|
|
expect(await vester.balanceOf(user0.address)).eq(expandDecimals(1000, 18) - cecAmount);
|
|
|
|
expect(await vester.getTotalVested(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimable(user0.address)).eq(0);
|
|
expect(await vester.lastVestingTimes(user0.address)).eq(blockTime);
|
|
|
|
await increaseTime(provider, 24 * 60 * 60);
|
|
await mineBlock(provider);
|
|
|
|
// vesting rate should be the same even after claiming
|
|
tmpNow = await getBlockTime(provider);
|
|
_claimable = BigInt(1000) * (tmpNow - pre) * BigInt(10 ** 18) / BigInt(secondsPerYear);
|
|
expect(await vester.claimable(user0.address)).eq(total - cecAmount + _claimable); // 1000 / 365 => ~2.739
|
|
|
|
|
|
await esCec.mint(user0.address, expandDecimals(500, 18));
|
|
// @ts-ignore
|
|
// await esCec.connect(user0).approve(vester.target, expandDecimals(500, 18));
|
|
|
|
// @ts-ignore
|
|
await vester.connect(user0).deposit(expandDecimals(500, 18));
|
|
tmpNow = await getBlockTime(provider);
|
|
_claimable = BigInt(1000) * (tmpNow - pre) * BigInt(10 ** 18) / BigInt(secondsPerYear);
|
|
let _balance1 = await vester.balanceOf(user0.address);
|
|
let _balance2 = (BigInt(1000) * BigInt(10 ** 18) - cecAmount) + BigInt(500) * BigInt(10 ** 18) - _claimable
|
|
expect(_balance1).eq(_balance2);
|
|
let vestTotal = await vester.vestingTotal(user0.address);
|
|
expect(vestTotal).eq(_balance2);
|
|
total += _claimable;
|
|
pre = tmpNow;
|
|
lastVestingTime = BigInt(await vester.lastVestingTimes(user0.address));
|
|
expect(pre).eq(lastVestingTime);
|
|
|
|
await increaseTime(provider, 24 * 60 * 60);
|
|
await mineBlock(provider);
|
|
|
|
tmpNow = await getBlockTime(provider);
|
|
_claimable = BigInt(_balance2) * (tmpNow - pre) / BigInt(secondsPerYear);
|
|
|
|
expect(await esCec.balanceOf(user0.address)).eq(0);
|
|
expect(await cec.balanceOf(user0.address)).eq(cecAmount);
|
|
expect(await vester.claimable(user0.address)).eq(total - cecAmount + _claimable);
|
|
|
|
// @ts-ignore
|
|
await vester.connect(user0).withdraw();
|
|
tmpNow = await getBlockTime(provider);
|
|
_claimable = BigInt(_balance2) * (tmpNow - pre) / BigInt(secondsPerYear);
|
|
cecAmount += (total - cecAmount + _claimable);
|
|
|
|
expect(await cec.balanceOf(user0.address)).eq(cecAmount);
|
|
|
|
expect(await vester.balanceOf(user0.address)).eq(0);
|
|
expect(await vester.getTotalVested(user0.address)).eq(0);
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimable(user0.address)).eq(0);
|
|
expect(await vester.lastVestingTimes(user0.address)).eq(0);
|
|
|
|
// @ts-ignore
|
|
// await esCec.connect(user0).approve(vester.target, expandDecimals(1000, 18));
|
|
await esCec.mint(user0.address, expandDecimals(1000, 18));
|
|
// @ts-ignore
|
|
await vester.connect(user0).deposit(expandDecimals(1000, 18));
|
|
blockTime = await getBlockTime(provider);
|
|
|
|
await increaseTime(provider, 24 * 60 * 60);
|
|
await mineBlock(provider);
|
|
|
|
expect(await vester.balanceOf(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.getTotalVested(user0.address)).eq(expandDecimals(1000, 18));
|
|
expect(await vester.cumulativeClaimAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimedAmounts(user0.address)).eq(0);
|
|
expect(await vester.claimable(user0.address)).gt("2730000000000000000"); // 1000 / 365 => ~2.739
|
|
expect(await vester.claimable(user0.address)).lt("2750000000000000000");
|
|
expect(await vester.lastVestingTimes(user0.address)).eq(blockTime);
|
|
// @ts-ignore
|
|
await vester.connect(user0).claim();
|
|
});
|
|
});
|
|
});
|