From 9b5da171ba6d1456ade59a314b2ebca9ca1add4b Mon Sep 17 00:00:00 2001 From: Jay Maree Date: Thu, 16 Dec 2021 08:52:23 +0100 Subject: [PATCH 1/2] updated contract to latest version, includes the cliff strategy --- contracts/DecubateVesting.sol | 908 +++++++++++++++++----------------- 1 file changed, 454 insertions(+), 454 deletions(-) diff --git a/contracts/DecubateVesting.sol b/contracts/DecubateVesting.sol index 1f64a95..e62d8da 100644 --- a/contracts/DecubateVesting.sol +++ b/contracts/DecubateVesting.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT -//** Decubate Locking Contract */ -//** Author Aaron & Vipin : Decubate Vesting Contract 2021.6 */ +//** Decubate Vesting Contract */ +//** Author Aaron & Aceson : Decubate Vesting Contract 2021.12 */ pragma solidity ^0.8.8; @@ -13,467 +13,467 @@ import "./interfaces/IDecubateVesting.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; contract DecubateVesting is IDecubateVesting, Ownable, ReentrancyGuard { - using SafeMath for uint256; - using SafeERC20 for IERC20; - - /** - * - * @dev whitelistPools store all active whitelist members. - * - */ - - MaxTokenTransferValue public maxTokenTransfer; - VestingPool[] public vestingPools; - - IERC20 private _token; - - constructor(address token) Ownable() { - _token = IERC20(token); + using SafeMath for uint256; + using SafeERC20 for IERC20; + + /** + * + * @dev whitelistPools store all active whitelist members. + * + */ + + MaxTokenTransferValue public maxTokenTransfer; + VestingPool[] public vestingPools; + + IERC20 private _token; + + constructor(address token) { + _token = IERC20(token); + } + + modifier optionExists(uint256 _option) { + require(_option < vestingPools.length, "Vesting option does not exist"); + _; + } + + modifier userInWhitelist(uint256 _option, address _wallet) { + require(_option < vestingPools.length, "Vesting option does not exist"); + require( + vestingPools[_option].hasWhitelist[_wallet].active, + "User is not in whitelist" + ); + _; + } + + function addVestingStrategy( + string memory _name, + uint256 _cliff, + uint256 _start, + uint256 _duration, + uint256 _initialUnlockPercent, + bool _revocable + ) external override onlyOwner returns (bool) { + VestingPool storage newStrategy = vestingPools.push(); + + newStrategy.cliff = _start.add(_cliff); + newStrategy.name = _name; + newStrategy.start = _start; + newStrategy.duration = _duration; + newStrategy.initialUnlockPercent = _initialUnlockPercent; + newStrategy.revocable = _revocable; + + return true; + } + + function setVestingStrategy( + uint256 _strategy, + string memory _name, + uint256 _cliff, + uint256 _start, + uint256 _duration, + uint256 _initialUnlockPercent, + bool _revocable + ) external override onlyOwner returns (bool) { + require(_strategy < vestingPools.length, "Strategy does not exist"); + + VestingPool storage vest = vestingPools[_strategy]; + + vest.cliff = _start.add(_cliff); + vest.name = _name; + vest.start = _start; + vest.duration = _duration; + vest.initialUnlockPercent = _initialUnlockPercent; + vest.revocable = _revocable; + + return true; + } + + function setMaxTokenTransfer(uint256 _amount, bool _active) + external + onlyOwner + returns (bool) + { + maxTokenTransfer.amount = _amount; + maxTokenTransfer.active = _active; + return true; + } + + function getAllVestingPools() external view returns (VestingInfo[] memory) { + VestingInfo[] memory infoArr = new VestingInfo[](vestingPools.length); + + for (uint256 i = 0; i < vestingPools.length; i++) { + infoArr[i] = getVestingInfo(i); } - modifier optionExists(uint256 _option) { - require(_option < vestingPools.length, "Vesting option does not exist"); - _; + return infoArr; + } + + /** + * + * @dev get vesting info + * + * @param {uint256} strategy of vesting info + * + * @return return vesting strategy + * + */ + function getVestingInfo(uint256 _strategy) + public + view + optionExists(_strategy) + returns (VestingInfo memory) + { + return + VestingInfo({ + name: vestingPools[_strategy].name, + cliff: vestingPools[_strategy].cliff, + start: vestingPools[_strategy].start, + duration: vestingPools[_strategy].duration, + initialUnlockPercent: vestingPools[_strategy].initialUnlockPercent, + revocable: vestingPools[_strategy].revocable + }); + } + + /** + * + * @dev add the address to whitelist + * + * @param {address} address of the user + * + * @return {bool} return status of the whitelist + * + */ + function addWhitelist( + address _wallet, + uint256 _dcbAmount, + uint256 _option + ) public override onlyOwner optionExists(_option) returns (bool) { + HasWhitelist storage whitelist = vestingPools[_option].hasWhitelist[ + _wallet + ]; + require(!whitelist.active, "Whitelist already available"); + + WhitelistInfo[] storage pool = vestingPools[_option].whitelistPool; + + whitelist.active = true; + whitelist.arrIdx = pool.length; + + pool.push( + WhitelistInfo({ + wallet: _wallet, + dcbAmount: _dcbAmount, + distributedAmount: 0, + joinDate: block.timestamp, + revoke: false, + disabled: false + }) + ); + + emit AddWhitelist(_wallet); + + return true; + } + + function batchAddWhitelist( + address[] memory wallets, + uint256[] memory amounts, + uint256 option + ) external onlyOwner returns (bool) { + require(wallets.length == amounts.length, "Sizes of inputs do not match"); + + for (uint256 i = 0; i < wallets.length; i++) { + addWhitelist(wallets[i], amounts[i], option); } - modifier userInWhitelist(uint256 _option, address _wallet) { - require(_option < vestingPools.length, "Vesting option does not exist"); - require( - vestingPools[_option].hasWhitelist[_wallet].active, - "User is not in whitelist" + return true; + } + + /** + * + * @dev set the address as whitelist user address + * + * @param {address} address of the user + * + * @return {bool} return status of the whitelist + * + */ + function setWhitelist( + address _wallet, + uint256 _dcbAmount, + uint256 _option + ) + external + override + onlyOwner + userInWhitelist(_option, _wallet) + returns (bool) + { + uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; + WhitelistInfo storage info = vestingPools[_option].whitelistPool[idx]; + info.dcbAmount = _dcbAmount; + + return true; + } + + /** + * + * @dev set the address as whitelist user address + * + * @param {address} address of the user + * + * @return {Whitelist} return whitelist instance + * + */ + function getWhitelist(uint256 _option, address _wallet) + external + view + userInWhitelist(_option, _wallet) + returns (WhitelistInfo memory) + { + uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; + return vestingPools[_option].whitelistPool[idx]; + } + + /** + * + * @dev set token address for contract + * + * @param {_token} address of IERC20 instance + * @return {bool} return status of token address + * + */ + function setToken(address _addr) external override onlyOwner returns (bool) { + _token = IERC20(_addr); + return true; + } + + /** + * + * @dev getter function for deployed decubate token address + * + * @return {address} return deployment address of decubate token + * + */ + function getToken() external view override returns (address) { + return address(_token); + } + + /** + * + * @dev calculate the total vested amount by the time + * + * @param {address} user wallet address + * + * @return {uint256} return vested amount + * + */ + function calculateVestAmount(uint256 _option, address _wallet) + internal + view + userInWhitelist(_option, _wallet) + returns (uint256) + { + uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; + WhitelistInfo memory whitelist = vestingPools[_option].whitelistPool[idx]; + VestingPool storage vest = vestingPools[_option]; + + // initial unlock + uint256 initial = whitelist.dcbAmount.mul(vest.initialUnlockPercent).div( + 1000 ); - _; - } - - function addVestingStrategy( - string memory _name, - uint256 _cliff, - uint256 _start, - uint256 _duration, - uint256 _initialUnlockPercent, - bool _revocable - ) external override onlyOwner returns (bool) { - VestingPool storage newStrategy = vestingPools.push(); - - newStrategy.cliff = _start.add(_cliff); - newStrategy.name = _name; - newStrategy.start = _start; - newStrategy.duration = _duration; - newStrategy.initialUnlockPercent = _initialUnlockPercent; - newStrategy.revocable = _revocable; - - return true; - } - function setVestingStrategy( - uint256 _strategy, - string memory _name, - uint256 _cliff, - uint256 _start, - uint256 _duration, - uint256 _initialUnlockPercent, - bool _revocable - ) external override onlyOwner returns (bool) { - require(_strategy < vestingPools.length, "Strategy does not exist"); - - VestingPool storage vest = vestingPools[_strategy]; - - vest.cliff = _start.add(_cliff); - vest.name = _name; - vest.start = _start; - vest.duration = _duration; - vest.initialUnlockPercent = _initialUnlockPercent; - vest.revocable = _revocable; - - return true; + if(whitelist.revoke) { + return whitelist.dcbAmount; } - - function setMaxTokenTransfer(uint256 _amount, bool _active) - external - onlyOwner - returns (bool) - { - maxTokenTransfer.amount = _amount; - maxTokenTransfer.active = _active; - return true; - } - - function getAllVestingPools() external view returns (VestingInfo[] memory) { - VestingInfo[] memory infoArr = new VestingInfo[](vestingPools.length); - - for (uint256 i = 0; i < vestingPools.length; i++) { - infoArr[i] = getVestingInfo(i); - } - - return infoArr; - } - - /** - * - * @dev get vesting info - * - * @param {uint256} strategy of vesting info - * - * @return return vesting strategy - * - */ - function getVestingInfo(uint256 _strategy) - public - view - optionExists(_strategy) - returns (VestingInfo memory) - { + if (block.timestamp < vest.start) { + return 0; + } + else if(block.timestamp >= vest.start && block.timestamp < vest.cliff) { + return initial; + } + else if(block.timestamp >= vest.cliff && block.timestamp < vest.cliff.add(vest.duration)) { + // remaining locked token + uint256 remaining = whitelist.dcbAmount.sub(initial); //More accurate + + // return initial unlock + remaining x % of time passed return - VestingInfo({ - name: vestingPools[_strategy].name, - cliff: vestingPools[_strategy].cliff, - start: vestingPools[_strategy].start, - duration: vestingPools[_strategy].duration, - initialUnlockPercent: vestingPools[_strategy].initialUnlockPercent, - revocable: vestingPools[_strategy].revocable - }); + initial + + remaining.mul(block.timestamp.sub(vest.cliff)).div(vest.duration); + } + else { + return whitelist.dcbAmount; } - - /** - * - * @dev add the address to whitelist - * - * @param {address} address of the user - * - * @return {bool} return status of the whitelist - * - */ - function addWhitelist( - address _wallet, - uint256 _dcbAmount, - uint256 _option - ) public override onlyOwner optionExists(_option) returns (bool) { - HasWhitelist storage whitelist = vestingPools[_option].hasWhitelist[ - _wallet - ]; - require(!whitelist.active, "Whitelist already available"); - - WhitelistInfo[] storage pool = vestingPools[_option].whitelistPool; - - whitelist.active = true; - whitelist.arrIdx = pool.length; - - pool.push( - WhitelistInfo({ - wallet: _wallet, - dcbAmount: _dcbAmount, - distributedAmount: 0, - joinDate: block.timestamp, - revoke: false, - disabled: false - }) + } + + /** + * + * @dev calculate releasable amount by subtracting distributed amount + * + * @param {address} investor wallet address + * + * @return {uint256} releasable amount of the whitelist + * + */ + function calculateReleasableAmount(uint256 _option, address _wallet) + internal + view + userInWhitelist(_option, _wallet) + returns (uint256) + { + uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; + return + calculateVestAmount(_option, _wallet).sub( + vestingPools[_option].whitelistPool[idx].distributedAmount ); - - emit AddWhitelist(_wallet); - - return true; - } - - function batchAddWhitelist( - address[] memory wallets, - uint256[] memory amounts, - uint256 option - ) external onlyOwner returns (bool) { - require(wallets.length == amounts.length, "Sizes of inputs do not match"); - - for (uint256 i = 0; i < wallets.length; i++) { - addWhitelist(wallets[i], amounts[i], option); - } - - return true; + } + + /** + * + * @dev distribute the token to the investors + * + * @param {address} wallet address of the investor + * + * @return {bool} return status of distribution + * + */ + function claimDistribution(uint256 _option, address _wallet) + external + override + nonReentrant + returns (bool) + { + uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; + WhitelistInfo storage whitelist = vestingPools[_option].whitelistPool[idx]; + + require(!whitelist.disabled, "User is disabled from claiming token"); + + uint256 releaseAmount = calculateReleasableAmount(_option, _wallet); + + require(releaseAmount > 0, "Zero amount to claim"); + + if (maxTokenTransfer.active && releaseAmount > maxTokenTransfer.amount) { + releaseAmount = maxTokenTransfer.amount; } - /** - * - * @dev set the address as whitelist user address - * - * @param {address} address of the user - * - * @return {bool} return status of the whitelist - * - */ - function setWhitelist( - address _wallet, - uint256 _dcbAmount, - uint256 _option - ) - external - override - onlyOwner - userInWhitelist(_option, _wallet) - returns (bool) - { - uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; - WhitelistInfo storage info = vestingPools[_option].whitelistPool[idx]; - info.dcbAmount = _dcbAmount; - - return true; - } - - /** - * - * @dev set the address as whitelist user address - * - * @param {address} address of the user - * - * @return {Whitelist} return whitelist instance - * - */ - function getWhitelist(uint256 _option, address _wallet) - external - view - userInWhitelist(_option, _wallet) - returns (WhitelistInfo memory) - { - uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; - return vestingPools[_option].whitelistPool[idx]; - } - - /** - * - * @dev set token address for contract - * - * @param {_token} address of IERC20 instance - * @return {bool} return status of token address - * - */ - function setToken(address _addr) external override onlyOwner returns (bool) { - _token = IERC20(_addr); - return true; - } - - /** - * - * @dev getter function for deployed decubate token address - * - * @return {address} return deployment address of decubate token - * - */ - function getToken() external view override returns (address) { - return address(_token); - } - - /** - * - * @dev calculate the total vested amount by the time - * - * @param {address} user wallet address - * - * @return {uint256} return vested amount - * - */ - function calculateVestAmount(uint256 _option, address _wallet) - internal - view - userInWhitelist(_option, _wallet) - returns (uint256) - { - uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; - WhitelistInfo memory whitelist = vestingPools[_option].whitelistPool[idx]; - VestingPool storage vest = vestingPools[_option]; - - // initial unlock - uint256 initial = whitelist.dcbAmount.mul(vest.initialUnlockPercent).div( - 1000 - ); - - if(whitelist.revoke) { - return whitelist.dcbAmount; - } - if (block.timestamp < vest.start) { - return 0; - } - else if(block.timestamp >= vest.start && block.timestamp < vest.cliff) { - return initial; - } - else if(block.timestamp >= vest.cliff && block.timestamp < vest.start.add(vest.duration)) { - // remaining locked token - uint256 remaining = whitelist.dcbAmount.sub(initial); //More accurate - - // return initial unlock + remaining x % of time passed - return - initial + - remaining.mul(block.timestamp.sub(vest.cliff)).div(vest.duration); - } - else { - return whitelist.dcbAmount; - } - } - - /** - * - * @dev calculate releasable amount by subtracting distributed amount - * - * @param {address} investor wallet address - * - * @return {uint256} releasable amount of the whitelist - * - */ - function calculateReleasableAmount(uint256 _option, address _wallet) - internal - view - userInWhitelist(_option, _wallet) - returns (uint256) - { - uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; - return - calculateVestAmount(_option, _wallet).sub( - vestingPools[_option].whitelistPool[idx].distributedAmount - ); - } - - /** - * - * @dev distribute the token to the investors - * - * @param {address} wallet address of the investor - * - * @return {bool} return status of distribution - * - */ - function claimDistribution(uint256 _option, address _wallet) - external - override - nonReentrant - returns (bool) - { - uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; - WhitelistInfo storage whitelist = vestingPools[_option].whitelistPool[idx]; - - require(!whitelist.disabled, "User is disabled from claiming token"); - - uint256 releaseAmount = calculateReleasableAmount(_option, _wallet); - - require(releaseAmount > 0, "Zero amount to claim"); - - if (maxTokenTransfer.active && releaseAmount > maxTokenTransfer.amount) { - releaseAmount = maxTokenTransfer.amount; - } - - whitelist.distributedAmount = whitelist.distributedAmount.add( - releaseAmount - ); - - _token.transfer(_wallet, releaseAmount); - - emit Claim(_wallet, releaseAmount, _option, block.timestamp); - - return true; - } - - /** - * - * @dev allow the owner to revoke the vesting - * - */ - function revoke(uint256 _option, address _wallet) - public - onlyOwner - userInWhitelist(_option, _wallet) - { - uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; - WhitelistInfo storage whitelist = vestingPools[_option].whitelistPool[idx]; - - require(vestingPools[_option].revocable, "Strategy is not revocable"); - require(!whitelist.revoke, "already revoked"); - - whitelist.revoke = true; - - emit Revoked(_wallet); - } - - /** - * - * @dev allow the owner to enable/disable the vesting - * - * User will not be able to claim his tokens, but claimable balance remains unchanged - * - */ - function setVesting(uint256 _option, address _wallet, bool _status) - public - onlyOwner - userInWhitelist(_option, _wallet) - { - uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; - WhitelistInfo storage whitelist = vestingPools[_option].whitelistPool[idx]; - - whitelist.disabled = _status; - - emit StatusChanged(_wallet,_status); - } - - /** - * - * @dev Allow owner to transfer token from contract - * - * @param {address} contract address of corresponding token - * @param {uint256} amount of token to be transferred - * - * This is a generalized function which can be used to transfer any accidentally - * sent (including DCB) out of the contract to wowner - * - */ - function transferToken(address _addr, uint256 _amount) - external - onlyOwner - returns (bool) - { - IERC20 token = IERC20(_addr); - bool success = token.transfer(address(owner()), _amount); - return success; - } - - /** - * - * @dev Retrieve total amount of token from the contract - * - * @param {address} address of the token - * - * @return {uint256} total amount of token - * - */ - function getTotalToken(address _addr) external view returns (uint256) { - IERC20 token = IERC20(_addr); - return token.balanceOf(address(this)); - } - - function hasWhitelist(uint256 _option, address _wallet) - external - view - returns (bool) - { - return vestingPools[_option].hasWhitelist[_wallet].active; - } - - function getVestAmount(uint256 _option, address _wallet) - external - view - override - returns (uint256) - { - return calculateVestAmount(_option, _wallet); - } - - function getReleasableAmount(uint256 _option, address _wallet) - external - view - override - returns (uint256) - { - return calculateReleasableAmount(_option, _wallet); - } - - function getWhitelistPool(uint256 _option) - external - view - optionExists(_option) - returns (WhitelistInfo[] memory) - { - return vestingPools[_option].whitelistPool; - } -} \ No newline at end of file + whitelist.distributedAmount = whitelist.distributedAmount.add( + releaseAmount + ); + + _token.transfer(_wallet, releaseAmount); + + emit Claim(_wallet, releaseAmount, _option, block.timestamp); + + return true; + } + + /** + * + * @dev allow the owner to revoke the vesting + * + */ + function revoke(uint256 _option, address _wallet) + public + onlyOwner + userInWhitelist(_option, _wallet) + { + uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; + WhitelistInfo storage whitelist = vestingPools[_option].whitelistPool[idx]; + + require(vestingPools[_option].revocable, "Strategy is not revocable"); + require(!whitelist.revoke, "already revoked"); + + whitelist.revoke = true; + + emit Revoked(_wallet); + } + + /** + * + * @dev allow the owner to enable/disable the vesting + * + * User will not be able to claim his tokens, but claimable balance remains unchanged + * + */ + function setVesting(uint256 _option, address _wallet, bool _status) + public + onlyOwner + userInWhitelist(_option, _wallet) + { + uint256 idx = vestingPools[_option].hasWhitelist[_wallet].arrIdx; + WhitelistInfo storage whitelist = vestingPools[_option].whitelistPool[idx]; + + whitelist.disabled = _status; + + emit StatusChanged(_wallet,_status); + } + + /** + * + * @dev Allow owner to transfer token from contract + * + * @param {address} contract address of corresponding token + * @param {uint256} amount of token to be transferred + * + * This is a generalized function which can be used to transfer any accidentally + * sent (including DCB) out of the contract to wowner + * + */ + function transferToken(address _addr, uint256 _amount) + external + onlyOwner + returns (bool) + { + IERC20 token = IERC20(_addr); + bool success = token.transfer(address(owner()), _amount); + return success; + } + + /** + * + * @dev Retrieve total amount of token from the contract + * + * @param {address} address of the token + * + * @return {uint256} total amount of token + * + */ + function getTotalToken(address _addr) external view returns (uint256) { + IERC20 token = IERC20(_addr); + return token.balanceOf(address(this)); + } + + function hasWhitelist(uint256 _option, address _wallet) + external + view + returns (bool) + { + return vestingPools[_option].hasWhitelist[_wallet].active; + } + + function getVestAmount(uint256 _option, address _wallet) + external + view + override + returns (uint256) + { + return calculateVestAmount(_option, _wallet); + } + + function getReleasableAmount(uint256 _option, address _wallet) + external + view + override + returns (uint256) + { + return calculateReleasableAmount(_option, _wallet); + } + + function getWhitelistPool(uint256 _option) + external + view + optionExists(_option) + returns (WhitelistInfo[] memory) + { + return vestingPools[_option].whitelistPool; + } +} From 71b690ecd346db7a89f9b8ae75a9683de5d9f651 Mon Sep 17 00:00:00 2001 From: Jay Maree Date: Thu, 16 Dec 2021 08:54:53 +0100 Subject: [PATCH 2/2] added extra tests --- extra-vesting-tests.js | 172 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 extra-vesting-tests.js diff --git a/extra-vesting-tests.js b/extra-vesting-tests.js new file mode 100644 index 0000000..a6d334c --- /dev/null +++ b/extra-vesting-tests.js @@ -0,0 +1,172 @@ +describe("getReleasableAmount", () => { + it("should return the releasable amount", async function () { + const current = Number(await time.latest()); + await this.dcbVesting.setVestingStrategy( + 0, + "", + 100000, + current+100, + 60 * 60, + 100, + false + ); + + const amount = await this.dcbVesting.getReleasableAmount(0, accounts[0]); + assert.equal(amount, 0); + }); + }); + +describe("disable", () => { + it("should disable and enable back a user from claiming vesting", async function () { + await this.dcbVesting.addWhitelist(accounts[1], "1000000", 0); + await this.dcbVesting.setVesting(0, accounts[1],true); + await this.dcbVesting.setVesting(0, accounts[1],false); + }); + }); + + describe("claimDistribution", () => { + it("should throw an error as there is not tokens to claim", async function () { + await expectRevert( + this.dcbVesting.claimDistribution(0, accounts[0]), + "Zero amount to claim" + ); + }); + it("should throw an error as user is disabled from claiming tokens", async function () { + await this.dcbVesting.setVesting(0, accounts[1],true); + await expectRevert( + this.dcbVesting.claimDistribution(0, accounts[1]), + "User is disabled from claiming token" + ); + }); + + it("should successfully claim 1 token as that is the max tranfer amount", async function () { + const current = Number(await time.latest()); + await this.dcbVesting.setVestingStrategy( + 0, + "", + 0, + current, + 0, + 100, + false + ); + await this.dcbVesting.setMaxTokenTransfer(1, true); + + const bal_before = await this.dcbToken.balanceOf(accounts[0]); + + await this.dcbVesting.claimDistribution(0, accounts[0]); + await this.dcbVesting.setMaxTokenTransfer(0, false); + + const bal_after = await this.dcbToken.balanceOf(accounts[0]); + + assert.equal(bal_after.sub(bal_before), "1"); + }); + + it("should successfully claim tokens", async function () { + const current = Number(await time.latest()); + await this.dcbVesting.setVestingStrategy( + 0, + "", + 0, + current, + 0, + 100, + false + ); + + const bal_before = Number(await this.dcbToken.balanceOf(accounts[0])); + + await this.dcbVesting.claimDistribution(0, accounts[0]); + + const bal_after = Number(await this.dcbToken.balanceOf(accounts[0])); + + assert.equal(bal_after - bal_before, "999999"); + }); + }); + +describe("getVestAmount", () => { + it("should return 0 as start has not been reached", async function () { + const current = Number(await time.latest()); + await this.dcbVesting.setVestingStrategy( + 0, + "", + 100000, + current+100, + 60 * 60, + 100, + false + ); + const amount = await this.dcbVesting.getVestAmount(0, accounts[0]); + assert.equal(amount, 0); + }); + + it("should return initial unlock as start has been reached", async function () { + const current = Number(await time.latest()); + await this.dcbVesting.setVestingStrategy( + 0, + "", + 100000, + current+100, + 60 * 60, + 100, + false + ); + await time.increase(101); + const amount = await this.dcbVesting.getVestAmount(0, accounts[0]); + assert.equal(amount, '100000'); + }); + + it("should return full amount as total duration has been reached", async function () { + const current = Number(await time.latest()); + await this.dcbVesting.setVestingStrategy( + 0, + "", + 0, + current, + 0, + 100, + false + ); + + const amount = await this.dcbVesting.getVestAmount(0, accounts[0]); + assert.equal(amount, "1000000"); + }); + + it("should return the initial unlock and unlock amount at different intervals", async function () { + const current = Number(await time.latest()); + await this.dcbVesting.setVestingStrategy( + 0, + "", + 100, + current + 50, + 1000, + 100, + false + ); + + let amount = Number(await this.dcbVesting.getVestAmount(0, accounts[0])); + assert.equal(amount,0); //Start hasn't been reached, so 0 amount + await time.increase(50); + amount = Number(await this.dcbVesting.getVestAmount(0, accounts[0])); + assert.equal(amount,100000); //Start has reached, so initial unlock + await time.increase(200); + + //Total deposit = 1000000 + //100 seconds passed, initial unlock activated + //Initial inlock = 1000000/10 = 100000 + //Remaining token = 1000000 - 100000 = 900000 + //Another 100 seconds passed, of total 10000 seconds. So 1% of remaining should be unlocked + //Total = 100000 + 900000/100 = 109000 + amount = Number(await this.dcbVesting.getVestAmount(0, accounts[0])); + assert.isAbove(amount,109000); + await time.increase(850); + amount = Number(await this.dcbVesting.getVestAmount(0, accounts[0])); + assert.isBelow(amount,1000000); //End date haven't reached, so will not get full amount + await time.increase(100); + amount = Number(await this.dcbVesting.getVestAmount(0, accounts[0])); + assert.equal(amount,1000000);//End date over, so full amount + await time.increase(60*60*24*7); + amount = Number(await this.dcbVesting.getVestAmount(0, accounts[0])); + assert.equal(amount,1000000);//One week passed after enddate, still same amount + }); + });