Skip to content
Open
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
Binary file added .DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions contracts/TokenVesting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,7 @@ contract TokenVesting is Ownable, AccessControl {
function setRevoked(uint256 paymentPlan, bool revoke) external onlyRole(VESTING_ADMIN) planNotRevoked(paymentPlan) {
paymentPlans[paymentPlan].revoked = revoke;
}
function getRevoked(uint256 paymentPlan) external view returns(bool){
return paymentPlans[paymentPlan].revoked;
}
}
16 changes: 8 additions & 8 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ const config: HardhatUserConfig = {
allowUnlimitedContractSize: true,
accounts: accounts,
},
mumbai: {
url: "https://rpc-mumbai.maticvigil.com",
chainId: 80001,
accounts: [secret],
gas: "auto",
gasPrice: 1000000000, // 1 gwei
gasMultiplier: 1.5,
},
// mumbai: {
// url: "https://rpc-mumbai.maticvigil.com",
// chainId: 80001,
// accounts: [secret],
// gas: "auto",
// gasPrice: 1000000000, // 1 gwei
// gasMultiplier: 1.5,
// },
// rinkeby: {
// url: `https://rinkeby.infura.io/v3/${process.env.INFURA_API_KEY}`,
// accounts: [secret],
Expand Down
232 changes: 232 additions & 0 deletions test/TokenVestingTest2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import chai, { expect } from "chai";
import { BigNumber, Signer } from "ethers";
import { solidity } from "ethereum-waffle";
import { ethers } from "hardhat";

import { TokenVesting__factory } from "../typechain/factories/TokenVesting__factory";
import { TokenMock__factory } from "../typechain/factories/TokenMock__factory";
import { TokenMock } from "../typechain/TokenMock";
import {
expandTo18Decimals
} from "./shared/utilities";
import { TokenVesting } from "../typechain/TokenVesting";
import { version } from "os";
import { stat } from "fs";

chai.use(solidity);

async function increaseTime(timeToAdd: number) {
await ethers.provider.send("evm_increaseTime", [timeToAdd]);
await ethers.provider.send("evm_mine", []);
}

describe("Payment Plan Creation", function(){
// Variables
let accounts: Signer[];
let token: TokenMock;

// Initial Setup
beforeEach(async () => {
accounts = await ethers.getSigners();
token = await new TokenMock__factory(accounts[0]).deploy("Token", "TST");
});

// Tests
it("Vesting Admin Creates a Payment Plan", async function () {
this.timeout(0);
// Deploy TokenVesting
const vesting = await new TokenVesting__factory(accounts[0]).deploy(token.address);
// Mint initial token amount for the admin
await token.mint(await accounts[0].getAddress(), expandTo18Decimals(10000));
await token.connect(accounts[0]).approve(vesting.address, expandTo18Decimals(10000000));
// Create a Payment Plan
await vesting.connect(accounts[0]).addPaymentPlan(1000, 10, 2);
// Check if the Plan has been created
let payment_plans = await vesting.connect(accounts[0]).paymentPlansCount();
expect(payment_plans).gte(0);
});
it("User Tries to Create a Payment Plan (Should REVERT)", async function () {
this.timeout(0);
// Deploy TokenVesting & Handle Other Configs
const vesting = await new TokenVesting__factory(accounts[0]).deploy(token.address);
const vestor = await accounts[1].getAddress();
// Mint initial token amount for the admin
await token.mint(await accounts[0].getAddress(), expandTo18Decimals(10000));
await token.connect(accounts[0]).approve(vesting.address, expandTo18Decimals(10000000));
// Mint some amount of token for the vestor
await token.mint(vestor, expandTo18Decimals(1000));
await token.connect(accounts[1]).approve(vesting.address, expandTo18Decimals(10000));
// Try to Create a Payment Plan & Revert
await expect(vesting.connect(vestor).addPaymentPlan(100, 10, 2)).to.be.reverted;
});
});

describe("Fund Locking", () =>{
// Variables
let accounts: Signer[];
let token: TokenMock;
let vesting: TokenVesting;

// Initial Setup
beforeEach(async () => {
accounts = await ethers.getSigners();
token = await new TokenMock__factory(accounts[0]).deploy("Token", "TST");
// Deploy TokenVesting
vesting = await new TokenVesting__factory(accounts[0]).deploy(token.address);
// Mint initial token amount for the admin
await token.mint(await accounts[0].getAddress(), expandTo18Decimals(10000));
await token.connect(accounts[0]).approve(vesting.address, expandTo18Decimals(10000000));
// Create Payment Plans
await vesting.connect(accounts[0]).addPaymentPlan(1000, 10, 2);
});

// Tests
it("Vesting Admin Successfully Locks Some Funds into a Vesting Plan for a User address", async function() {
this.timeout(0);
const vestor1 = await accounts[1].getAddress();
const currentTime = (await ethers.provider.getBlock("latest")).timestamp;
// Lock Funds
expect(await vesting.connect(accounts[0]).lock(vestor1, expandTo18Decimals(1000), BigNumber.from(currentTime + 2000),0)).to.be.to.emit(vesting, "TokensLocked");
});
it("Vesting Admin Tries to Lock Some Funds to a Revoked Plan (Should REVERT)", async () => {
const currentTime = (await ethers.provider.getBlock("latest")).timestamp;
// Vestor Setup
const vestor = await accounts[1].getAddress();
// Revoke the Payment Plan
let tx = await vesting.connect(accounts[0]).setRevoked(0, true);
await tx.wait();
// Vestor Tries to Lock Funds into the Revoked Payment Plan
await expect(vesting.connect(accounts[0]).lock(vestor, expandTo18Decimals(1000), BigNumber.from(currentTime + 2000),0)).to.be.revertedWith("Payment Plan has Already Revoked");
});
it("Vesting Admin Tries to Lock Some Funds to a Non-Existing Plan (Should REVERT)", async () => {
const currentTime = (await ethers.provider.getBlock("latest")).timestamp;
// Vestor Setup
const vestor = await accounts[1].getAddress();
// Vestor Tries to Lock Funds
await expect(vesting.connect(accounts[0]).lock(vestor, expandTo18Decimals(1000), BigNumber.from(currentTime + 2000),1)).to.be.reverted;
});
});

describe("Fund Releasing", function(){
// Variables
let accounts: Signer[];
let token: TokenMock;
let vesting: TokenVesting;

// Initial Setup
beforeEach(async () => {
accounts = await ethers.getSigners();
token = await new TokenMock__factory(accounts[0]).deploy("Token", "TST");
// Deploy TokenVesting
vesting = await new TokenVesting__factory(accounts[0]).deploy(token.address);
// Mint initial token amount for the admin
await token.mint(await accounts[0].getAddress(), expandTo18Decimals(10000));
await token.connect(accounts[0]).approve(vesting.address, expandTo18Decimals(10000000));
// Create a Payment Plan
await vesting.connect(accounts[0]).addPaymentPlan(1000, 10, 2);
// Vestor Setup
const currentTime = (await ethers.provider.getBlock("latest")).timestamp;
const vestor = await accounts[1].getAddress();
let tx = await token.mint(vestor, expandTo18Decimals(10000));
await tx.wait();
tx = await token.connect(accounts[1]).approve(vesting.address, expandTo18Decimals(10000000));
await tx.wait();
// Vestor Locks Funds
expect(await vesting.connect(accounts[1]).lock(vestor,expandTo18Decimals(1000), BigNumber.from(currentTime + 2000),0)).to.be.to.emit(vesting, "TokensLocked");
});

// Tests
it("Releasable Amount is 0 Before Start", async function() {
expect(await vesting.releasableAmount(await accounts[1].getAddress())).to.be.equal(0);
});
it("Releasable Amount is 0 During Cliff", async function() {
// Advance Time
await increaseTime(2000);
expect(await vesting.releasableAmount(await accounts[1].getAddress())).to.be.equal(0);
});
it("User Cannot Release during Cliff Period", async function() {
// Advance Time
await increaseTime(2000);
const vestor = await accounts[1].getAddress();
// Try to Release
await expect(vesting.connect(accounts[1]).release(vestor)).to.be.revertedWith("TokenVesting: no tokens available");
});
it("Releasable Amount is > 0 After Cliff", async function() {
// Advance Time
await increaseTime(4000);
const vestor = await accounts[1].getAddress();
// Check
expect(await vesting.releasableAmount(await accounts[1].getAddress())).to.be.gte(0);
});
it("User Successfully Releases his Locked Funds to Himself after Cliff Period Ends", async function() {
// Advance Time
await increaseTime(4000);
const vestor = await accounts[1].getAddress();
// Release Funds
await expect(vesting.connect(accounts[1]).release(vestor)).to.be.to.emit(vesting, "TokensReleased");
// Check Release
expect(await token.balanceOf(vestor)).to.be.equal(expandTo18Decimals(9200));
});
it("User Successfully Releases his Locked Funds to Himself After Plan Ends", async function() {
// Advance Time
await increaseTime(13000);
const vestor = await accounts[1].getAddress();
// Release Funds
await expect(vesting.connect(accounts[1]).release(vestor)).to.be.to.emit(vesting, "TokensReleased");
// Check Release
expect(await token.balanceOf(vestor)).to.be.equal(expandTo18Decimals(10000));
});
it("Releasable Amount is 0 After a Release", async function() {
// Advance Time
await increaseTime(4000);
const vestor = await accounts[1].getAddress();
// Release Funds
let tx = await vesting.connect(accounts[1]).release(vestor);
await tx.wait();
// Check Funds
await expect(vesting.connect(accounts[1]).release(vestor)).to.be.revertedWith("TokenVesting: no tokens available");
});
});

describe("Revoking Payment Plans", function(){
// Variables
let accounts: Signer[];
let token: TokenMock;
let vesting: TokenVesting;

// Initial Setup
beforeEach(async () => {
accounts = await ethers.getSigners();
token = await new TokenMock__factory(accounts[0]).deploy("Token", "TST");
// Deploy TokenVesting
vesting = await new TokenVesting__factory(accounts[0]).deploy(token.address);
// Mint initial token amount for the admin
await token.mint(await accounts[0].getAddress(), expandTo18Decimals(10000));
await token.connect(accounts[0]).approve(vesting.address, expandTo18Decimals(10000000));
// Create Payment Plans
await vesting.connect(accounts[0]).addPaymentPlan(1000, 10, 2);
});

// Tests
it("Vesting Admin Successfully Revokes a Plan", async function() {
// Revoke
let tx = await vesting.connect(accounts[0]).setRevoked(0, true);
await tx.wait();
let stats = await vesting.connect(accounts[0]).getRevoked(0);
// Check
expect(stats).to.be.equal(true);
});
it("Vesting Admin Tries to Revoke an Already Revoked Plan (SHOULD REVERT)", async function() {
// Vesting Admin Revokes A Plan
let tx = await vesting.connect(accounts[0]).setRevoked(0, true);
await tx.wait();
// Then Tries to Revoke it Again
await expect(vesting.connect(accounts[0]).setRevoked(0, true)).to.be.revertedWith("Payment Plan has Already Revoked");
});
it("A User Tries to Revoke a Plan (SHOULD REVERT)", async function() {
// Vestor Setup
const vestor = await accounts[1].getAddress();
// Vestor Tries to Revoke the Plan
await expect(vesting.connect(accounts[1]).setRevoked(0, true)).to.be.reverted;
});
});