From c3e34edc768510a03b4215a779eadb96848d3155 Mon Sep 17 00:00:00 2001 From: belbix <7453635@gmail.com> Date: Sat, 6 Apr 2024 14:38:56 +0300 Subject: [PATCH 1/3] remove ve historical balances --- contracts/interfaces/IController.sol | 3 +- contracts/interfaces/IVeDistributorV2.sol | 13 + contracts/interfaces/IVeTetu.sol | 10 +- contracts/test/MockPawnshop.sol | 3 - contracts/tools/BribeDistribution.sol | 142 ++-- contracts/ve/TetuEmitter.sol | 348 ++++---- contracts/ve/VeDistributor.sol | 794 +++++++++--------- contracts/ve/VeDistributorV2.sol | 408 ++++----- contracts/ve/VeTetu.sol | 109 +-- scripts/addresses/polygon.ts | 4 +- scripts/deploy/DeployAllProd.ts | 5 +- scripts/deploy/DeployAllTestnet.ts | 3 +- scripts/deploy/DeployTetuEmitter.ts | 19 - scripts/deploy/DeployVeDistV2.ts | 24 - scripts/utils/DeployerUtils.ts | 45 - test/infrastructure/ControllerV2Test.ts | 28 +- test/test-utils.ts | 4 +- test/tools/BribeDistributorTest.ts | 168 ++-- test/ve/TetuEmitterTest.ts | 262 +++--- test/ve/VeDistributorTest.ts | 644 +++++++------- test/ve/VeDistributorV2Test.ts | 445 +++++----- test/ve/VeDistributorWithAlwaysMaxLockTest.ts | 636 +++++++------- test/ve/VeTetuTest.ts | 123 +-- 23 files changed, 2000 insertions(+), 2240 deletions(-) create mode 100644 contracts/interfaces/IVeDistributorV2.sol delete mode 100644 scripts/deploy/DeployTetuEmitter.ts delete mode 100644 scripts/deploy/DeployVeDistV2.ts diff --git a/contracts/interfaces/IController.sol b/contracts/interfaces/IController.sol index a7577a9..35cc974 100644 --- a/contracts/interfaces/IController.sol +++ b/contracts/interfaces/IController.sol @@ -15,7 +15,8 @@ interface IController { function investFund() external view returns (address); - function veDistributor() external view returns (address); + // deprecated +// function veDistributor() external view returns (address); function platformVoter() external view returns (address); diff --git a/contracts/interfaces/IVeDistributorV2.sol b/contracts/interfaces/IVeDistributorV2.sol new file mode 100644 index 0000000..0c00801 --- /dev/null +++ b/contracts/interfaces/IVeDistributorV2.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.17; + +import "./IVeDistributor.sol"; + +interface IVeDistributorV2 is IVeDistributor { + + function epoch() external view returns (uint); + + function lastPaidEpoch(uint veId) external view returns (uint); + +} diff --git a/contracts/interfaces/IVeTetu.sol b/contracts/interfaces/IVeTetu.sol index 9c9cf69..a3c63a5 100644 --- a/contracts/interfaces/IVeTetu.sol +++ b/contracts/interfaces/IVeTetu.sol @@ -39,8 +39,6 @@ interface IVeTetu is IERC721Metadata { function balanceOfNFT(uint) external view returns (uint); - function balanceOfNFTAt(uint _tokenId, uint _t) external view returns (uint); - function isApprovedOrOwner(address, uint) external view returns (bool); function createLockFor(address _token, uint _value, uint _lockDuration, address _to) external returns (uint); @@ -49,10 +47,6 @@ interface IVeTetu is IERC721Metadata { function epoch() external view returns (uint); - function userPointHistory(uint tokenId, uint loc) external view returns (Point memory); - - function pointHistory(uint loc) external view returns (Point memory); - function checkpoint() external; function increaseAmount(address _token, uint _tokenId, uint _value) external; @@ -65,7 +59,5 @@ interface IVeTetu is IERC721Metadata { function abstain(uint tokenId) external; - function totalSupplyAt(uint _block) external view returns (uint); - - function totalSupplyAtT(uint timestamp) external view returns (uint); + function totalSupply() external view returns (uint); } diff --git a/contracts/test/MockPawnshop.sol b/contracts/test/MockPawnshop.sol index 1ef1fa9..7979d76 100644 --- a/contracts/test/MockPawnshop.sol +++ b/contracts/test/MockPawnshop.sol @@ -26,13 +26,10 @@ contract MockPawnshop is IERC721Receiver{ function veFlashTransfer(address ve, uint tokenId) external { IERC721(ve).safeTransferFrom(msg.sender, address(this), tokenId); require(IVeTetu(ve).balanceOfNFT(tokenId) == 0, "not zero balance"); - IVeTetu(ve).totalSupplyAt(block.number); IVeTetu(ve).checkpoint(); IVeTetu(ve).checkpoint(); IVeTetu(ve).checkpoint(); IVeTetu(ve).checkpoint(); - IVeTetu(ve).totalSupplyAt(block.number); - IVeTetu(ve).totalSupplyAt(block.number - 1); IERC721(ve).safeTransferFrom(address(this), msg.sender, tokenId); } diff --git a/contracts/tools/BribeDistribution.sol b/contracts/tools/BribeDistribution.sol index e2ca6b3..decb455 100644 --- a/contracts/tools/BribeDistribution.sol +++ b/contracts/tools/BribeDistribution.sol @@ -6,76 +6,76 @@ import "../interfaces/IERC20.sol"; import "../interfaces/IVeDistributor.sol"; contract BribeDistribution { - - string public constant VERSION = "1.0.0"; - - address public owner; - address public pendingOwner; - address public operator; - - IVeDistributor public immutable veDist; - address public immutable token; - uint public round; - - constructor(address veDist_, address _token) { - veDist = IVeDistributor(veDist_); - token = _token; - owner = msg.sender; - } - - modifier onlyOwner() { - require(msg.sender == owner, "NOT_OWNER"); - _; - } - - modifier onlyOperator() { - require(msg.sender == operator || msg.sender == owner, "NOT_OPERATOR"); - _; - } - - function offerOwnership(address newOwner) external onlyOwner { - require(newOwner != address(0), "ZERO_ADDRESS"); - pendingOwner = newOwner; - } - - function acceptOwnership() external { - require(msg.sender == pendingOwner, "NOT_OWNER"); - owner = pendingOwner; - } - - function setOperator(address operator_) external onlyOwner { - operator = operator_; - } - - ////////////////// MAIN LOGIC ////////////////////// - - function autoNotify() external onlyOperator { - _notify(IERC20(token).balanceOf(msg.sender), round % 2 == 0); - round++; - } - - function manualNotify(uint amount, bool fresh) external onlyOperator { - _notify(amount, fresh); - } - - function _notify(uint amount, bool fresh) internal { - if (amount != 0) { - IERC20(token).transferFrom(msg.sender, address(this), amount); - } - - uint toRewards = IERC20(token).balanceOf(address(this)); - require(toRewards != 0, "ZERO_BALANCE"); - - // assume we will have bribes once per 2 weeks. Need to use a half of the current balance in case of start of new 2 weeks epoch. - if (fresh) { - toRewards = toRewards / 2; - } - - IVeDistributor _veDist = veDist; - - IERC20(token).transfer(address(_veDist), toRewards); - _veDist.checkpoint(); - _veDist.checkpointTotalSupply(); - } +// +// string public constant VERSION = "1.0.0"; +// +// address public owner; +// address public pendingOwner; +// address public operator; +// +// IVeDistributor public immutable veDist; +// address public immutable token; +// uint public round; +// +// constructor(address veDist_, address _token) { +// veDist = IVeDistributor(veDist_); +// token = _token; +// owner = msg.sender; +// } +// +// modifier onlyOwner() { +// require(msg.sender == owner, "NOT_OWNER"); +// _; +// } +// +// modifier onlyOperator() { +// require(msg.sender == operator || msg.sender == owner, "NOT_OPERATOR"); +// _; +// } +// +// function offerOwnership(address newOwner) external onlyOwner { +// require(newOwner != address(0), "ZERO_ADDRESS"); +// pendingOwner = newOwner; +// } +// +// function acceptOwnership() external { +// require(msg.sender == pendingOwner, "NOT_OWNER"); +// owner = pendingOwner; +// } +// +// function setOperator(address operator_) external onlyOwner { +// operator = operator_; +// } +// +// ////////////////// MAIN LOGIC ////////////////////// +// +// function autoNotify() external onlyOperator { +// _notify(IERC20(token).balanceOf(msg.sender), round % 2 == 0); +// round++; +// } +// +// function manualNotify(uint amount, bool fresh) external onlyOperator { +// _notify(amount, fresh); +// } +// +// function _notify(uint amount, bool fresh) internal { +// if (amount != 0) { +// IERC20(token).transferFrom(msg.sender, address(this), amount); +// } +// +// uint toRewards = IERC20(token).balanceOf(address(this)); +// require(toRewards != 0, "ZERO_BALANCE"); +// +// // assume we will have bribes once per 2 weeks. Need to use a half of the current balance in case of start of new 2 weeks epoch. +// if (fresh) { +// toRewards = toRewards / 2; +// } +// +// IVeDistributor _veDist = veDist; +// +// IERC20(token).transfer(address(_veDist), toRewards); +// _veDist.checkpoint(); +// _veDist.checkpointTotalSupply(); +// } } diff --git a/contracts/ve/TetuEmitter.sol b/contracts/ve/TetuEmitter.sol index d8f9e76..28c8e45 100644 --- a/contracts/ve/TetuEmitter.sol +++ b/contracts/ve/TetuEmitter.sol @@ -9,179 +9,179 @@ import "../interfaces/IVoter.sol"; import "../interfaces/IBribe.sol"; contract TetuEmitter is ControllableV3 { - using SafeERC20 for IERC20; - - // ************************************************************* - // CONSTANTS - // ************************************************************* - - /// @dev Version of this contract. Adjust manually on each code modification. - string public constant EMITTER_VERSION = "1.0.0"; - /// @dev Epoch period delay - uint public constant EPOCH_LENGTH = 7 days; - /// @dev Denominator for different ratios. It is default for the whole platform. - uint public constant RATIO_DENOMINATOR = 100_000; - - // ************************************************************* - // VARIABLES - // Keep names and ordering! - // Add only in the bottom. - // ************************************************************* - - /// @dev Token for distribution - address public token; - /// @dev Caller of start epoch - address public operator; - /// @dev Current epoch, for statistic purposes - uint public epoch; - /// @dev Timestamp when the current epoch was started - uint public startEpochTS; - /// @dev Minimal amount of token for start epoch. Preventing human mistakes and duplicate calls. - uint public minAmountPerEpoch; - /// @dev How much amount will be send to VeDistributor. Change will be used to gauge rewards. - uint public toVeRatio; - /// @dev Bribe address for trigger new epoch start. - address public bribe; - - // ************************************************************* - // EVENTS - // ************************************************************* - - event EpochStarted(uint epoch, uint startEpochTS, uint balance, uint toVe, uint toVoter); - event OperatorChanged(address operator); - event MinAmountPerEpochChanged(uint value); - event ToVeRatioChanged(uint value); - - // ************************************************************* - // INIT - // ************************************************************* - - function init(address _controller, address _token, address _bribe) external initializer { - __Controllable_init(_controller); - _requireERC20(_token); - _requireInterface(_bribe, InterfaceIds.I_BRIBE); - - operator = msg.sender; - token = _token; - bribe = _bribe; - emit OperatorChanged(msg.sender); - } - - // ************************************************************* - // RESTRICTIONS - // ************************************************************* - - function _onlyOperator() internal view { - require(operator == msg.sender, "!operator"); - } - - function _olyGov() internal view { - require(isGovernance(msg.sender), "!gov"); - } - - // ************************************************************* - // VIEWS - // ************************************************************* - - /// @dev Return true if a new epoch can be started. - function isReadyToStart() public view returns (bool) { - return startEpochTS + EPOCH_LENGTH < block.timestamp; - } - - // ************************************************************* - // GOV ACTIONS - // ************************************************************* - - /// @dev Change operator address. - function changeOperator(address _operator) external { - _olyGov(); - require(_operator != address(0), "WRONG_INPUT"); - - operator = _operator; - emit OperatorChanged(_operator); - } - - /// @dev Set minimal amount of token for starting new epoch. - function setMinAmountPerEpoch(uint value) external { - _olyGov(); - minAmountPerEpoch = value; - emit MinAmountPerEpochChanged(value); - } - - /// @dev How much % of tokens will go to VeDistributor - function setToVeRatio(uint value) external { - _olyGov(); - require(value <= RATIO_DENOMINATOR, "too high"); - toVeRatio = value; - emit ToVeRatioChanged(value); - } - - // ************************************************************* - // MAIN LOGIC - // ************************************************************* - - /// @dev Start new epoch with given token amount. - /// Amount should be higher than token balance and `minAmountPerEpoch`. - /// With zero amount we will just start a new epoch without additional rewards. - function startEpoch(uint amount) external { - _onlyOperator(); - - require(isReadyToStart(), "too early"); - address _token = token; - uint balance = IERC20(_token).balanceOf(address(this)); - require(amount <= balance && amount >= minAmountPerEpoch, "!amount"); - - IController _controller = IController(controller()); - - uint toVe = amount * toVeRatio / RATIO_DENOMINATOR; - uint toVoter = amount - toVe; - - if (toVe != 0) { - address veDistributor = _controller.veDistributor(); - IERC20(_token).safeTransfer(veDistributor, toVe); - IVeDistributor(veDistributor).checkpoint(); - IVeDistributor(veDistributor).checkpointTotalSupply(); - } - - if (toVoter != 0) { - address tetuVoter = _controller.voter(); - _approveIfNeed(_token, tetuVoter, toVoter); - IVoter(tetuVoter).notifyRewardAmount(toVoter); - } - - address _bribe = bribe; - IBribe(_bribe).increaseEpoch(); - - startEpochTS = block.timestamp; - epoch++; - - emit EpochStarted(epoch, startEpochTS, balance, toVe, toVoter); - } - - function gelatoResolver() external view returns (bool canExec, bytes memory execPayload) { - if (!isReadyToStart()) { - return (false, bytes("Not ready yet")); - } - - uint _minAmountPerEpoch = minAmountPerEpoch; - uint balance = IERC20(token).balanceOf(address(this)); - - if (balance >= _minAmountPerEpoch) { - return (true, abi.encodeWithSelector(TetuEmitter.startEpoch.selector, _minAmountPerEpoch)); - } else { - return (false, bytes("Not enough tokens")); - } - } - - // ************************************************************* - // INTERNAL LOGIC - // ************************************************************* - - function _approveIfNeed(address _token, address dst, uint amount) internal { - if (IERC20(_token).allowance(address(this), dst) < amount) { - IERC20(_token).safeApprove(dst, 0); - IERC20(_token).safeApprove(dst, type(uint).max); - } - } +// using SafeERC20 for IERC20; +// +// // ************************************************************* +// // CONSTANTS +// // ************************************************************* +// +// /// @dev Version of this contract. Adjust manually on each code modification. +// string public constant EMITTER_VERSION = "1.0.0"; +// /// @dev Epoch period delay +// uint public constant EPOCH_LENGTH = 7 days; +// /// @dev Denominator for different ratios. It is default for the whole platform. +// uint public constant RATIO_DENOMINATOR = 100_000; +// +// // ************************************************************* +// // VARIABLES +// // Keep names and ordering! +// // Add only in the bottom. +// // ************************************************************* +// +// /// @dev Token for distribution +// address public token; +// /// @dev Caller of start epoch +// address public operator; +// /// @dev Current epoch, for statistic purposes +// uint public epoch; +// /// @dev Timestamp when the current epoch was started +// uint public startEpochTS; +// /// @dev Minimal amount of token for start epoch. Preventing human mistakes and duplicate calls. +// uint public minAmountPerEpoch; +// /// @dev How much amount will be send to VeDistributor. Change will be used to gauge rewards. +// uint public toVeRatio; +// /// @dev Bribe address for trigger new epoch start. +// address public bribe; +// +// // ************************************************************* +// // EVENTS +// // ************************************************************* +// +// event EpochStarted(uint epoch, uint startEpochTS, uint balance, uint toVe, uint toVoter); +// event OperatorChanged(address operator); +// event MinAmountPerEpochChanged(uint value); +// event ToVeRatioChanged(uint value); +// +// // ************************************************************* +// // INIT +// // ************************************************************* +// +// function init(address _controller, address _token, address _bribe) external initializer { +// __Controllable_init(_controller); +// _requireERC20(_token); +// _requireInterface(_bribe, InterfaceIds.I_BRIBE); +// +// operator = msg.sender; +// token = _token; +// bribe = _bribe; +// emit OperatorChanged(msg.sender); +// } +// +// // ************************************************************* +// // RESTRICTIONS +// // ************************************************************* +// +// function _onlyOperator() internal view { +// require(operator == msg.sender, "!operator"); +// } +// +// function _olyGov() internal view { +// require(isGovernance(msg.sender), "!gov"); +// } +// +// // ************************************************************* +// // VIEWS +// // ************************************************************* +// +// /// @dev Return true if a new epoch can be started. +// function isReadyToStart() public view returns (bool) { +// return startEpochTS + EPOCH_LENGTH < block.timestamp; +// } +// +// // ************************************************************* +// // GOV ACTIONS +// // ************************************************************* +// +// /// @dev Change operator address. +// function changeOperator(address _operator) external { +// _olyGov(); +// require(_operator != address(0), "WRONG_INPUT"); +// +// operator = _operator; +// emit OperatorChanged(_operator); +// } +// +// /// @dev Set minimal amount of token for starting new epoch. +// function setMinAmountPerEpoch(uint value) external { +// _olyGov(); +// minAmountPerEpoch = value; +// emit MinAmountPerEpochChanged(value); +// } +// +// /// @dev How much % of tokens will go to VeDistributor +// function setToVeRatio(uint value) external { +// _olyGov(); +// require(value <= RATIO_DENOMINATOR, "too high"); +// toVeRatio = value; +// emit ToVeRatioChanged(value); +// } +// +// // ************************************************************* +// // MAIN LOGIC +// // ************************************************************* +// +// /// @dev Start new epoch with given token amount. +// /// Amount should be higher than token balance and `minAmountPerEpoch`. +// /// With zero amount we will just start a new epoch without additional rewards. +// function startEpoch(uint amount) external { +// _onlyOperator(); +// +// require(isReadyToStart(), "too early"); +// address _token = token; +// uint balance = IERC20(_token).balanceOf(address(this)); +// require(amount <= balance && amount >= minAmountPerEpoch, "!amount"); +// +// IController _controller = IController(controller()); +// +// uint toVe = amount * toVeRatio / RATIO_DENOMINATOR; +// uint toVoter = amount - toVe; +// +// if (toVe != 0) { +// address veDistributor = _controller.veDistributor(); +// IERC20(_token).safeTransfer(veDistributor, toVe); +// IVeDistributor(veDistributor).checkpoint(); +// IVeDistributor(veDistributor).checkpointTotalSupply(); +// } +// +// if (toVoter != 0) { +// address tetuVoter = _controller.voter(); +// _approveIfNeed(_token, tetuVoter, toVoter); +// IVoter(tetuVoter).notifyRewardAmount(toVoter); +// } +// +// address _bribe = bribe; +// IBribe(_bribe).increaseEpoch(); +// +// startEpochTS = block.timestamp; +// epoch++; +// +// emit EpochStarted(epoch, startEpochTS, balance, toVe, toVoter); +// } +// +// function gelatoResolver() external view returns (bool canExec, bytes memory execPayload) { +// if (!isReadyToStart()) { +// return (false, bytes("Not ready yet")); +// } +// +// uint _minAmountPerEpoch = minAmountPerEpoch; +// uint balance = IERC20(token).balanceOf(address(this)); +// +// if (balance >= _minAmountPerEpoch) { +// return (true, abi.encodeWithSelector(TetuEmitter.startEpoch.selector, _minAmountPerEpoch)); +// } else { +// return (false, bytes("Not enough tokens")); +// } +// } +// +// // ************************************************************* +// // INTERNAL LOGIC +// // ************************************************************* +// +// function _approveIfNeed(address _token, address dst, uint amount) internal { +// if (IERC20(_token).allowance(address(this), dst) < amount) { +// IERC20(_token).safeApprove(dst, 0); +// IERC20(_token).safeApprove(dst, type(uint).max); +// } +// } } diff --git a/contracts/ve/VeDistributor.sol b/contracts/ve/VeDistributor.sol index bf63fa9..ecc658a 100644 --- a/contracts/ve/VeDistributor.sol +++ b/contracts/ve/VeDistributor.sol @@ -13,402 +13,402 @@ import "../proxy/ControllableV3.sol"; /// Rewards will be staked to the veNFT without extending lock period. /// Based on Solidly contract. /// @author belbix -contract VeDistributor is ControllableV3, IVeDistributor { - using SafeERC20 for IERC20; - - // for contract internal purposes, don't need to store in the interface - struct ClaimCalculationResult { - uint toDistribute; - uint userEpoch; - uint weekCursor; - uint maxUserEpoch; - bool success; - } - - // ************************************************************* - // CONSTANTS - // ************************************************************* - - /// @dev Version of this contract. Adjust manually on each code modification. - string public constant VE_DIST_VERSION = "1.0.2"; - uint internal constant WEEK = 7 * 86400; - - // ************************************************************* - // VARIABLES - // Keep names and ordering! - // Add only in the bottom. - // ************************************************************* - - /// @dev Voting escrow token address - IVeTetu public ve; - /// @dev Token for ve rewards - address public override rewardToken; - - // --- CHECKPOINT - - /// @dev Cursor for the current epoch - uint public activePeriod; - /// @dev Tokens per week stored on checkpoint call. Predefined array size = max weeks size - uint[1000000000000000] public tokensPerWeek; - /// @dev Ve supply checkpoints. Predefined array size = max weeks size - uint[1000000000000000] public veSupply; - /// @dev Ve supply checkpoint time cursor - uint public timeCursor; - /// @dev Token balance updated on checkpoint/claim - uint public tokenLastBalance; - /// @dev Last checkpoint time - uint public lastTokenTime; - - // --- CLAIM - - /// @dev Timestamp when this contract was inited - uint public startTime; - /// @dev veID => week cursor stored on the claim action - mapping(uint => uint) public timeCursorOf; - /// @dev veID => epoch stored on the claim action - mapping(uint => uint) public userEpochOf; - - // ************************************************************* - // EVENTS - // ************************************************************* - - event CheckpointToken( - uint time, - uint tokens - ); - - event Claimed( - uint tokenId, - uint amount, - uint claimEpoch, - uint maxEpoch - ); - - // ************************************************************* - // INIT - // ************************************************************* - - /// @dev Proxy initialization. Call it after contract deploy. - function init( - address controller_, - address _ve, - address _rewardToken - ) external initializer { - __Controllable_init(controller_); - _requireERC20(_rewardToken); - _requireInterface(_ve, InterfaceIds.I_VE_TETU); - - uint _t = block.timestamp / WEEK * WEEK; - startTime = _t; - lastTokenTime = _t; - timeCursor = _t; - - rewardToken = _rewardToken; - ve = IVeTetu(_ve); - - IERC20(_rewardToken).safeApprove(_ve, type(uint).max); - } - - function emergencyWithdraw() external { - require(isGovernance(msg.sender), "not gov"); - IERC20(rewardToken).safeTransfer(msg.sender, IERC20(rewardToken).balanceOf(address(this))); - } - - // ************************************************************* - // CHECKPOINT - // ************************************************************* - - function checkpoint() external override { - uint _period = activePeriod; - // only trigger if new week - if (block.timestamp >= _period + 1 weeks) { - // set new period rounded to weeks - activePeriod = block.timestamp / 1 weeks * 1 weeks; - // checkpoint token balance that was just minted in veDist - _checkpointToken(); - // checkpoint supply - _checkpointTotalSupply(); - } - } - - /// @dev Update tokensPerWeek value - function _checkpointToken() internal { - uint tokenBalance = IERC20(rewardToken).balanceOf(address(this)); - uint toDistribute = tokenBalance - tokenLastBalance; - tokenLastBalance = tokenBalance; - - uint t = lastTokenTime; - uint sinceLast = block.timestamp - t; - lastTokenTime = block.timestamp; - uint thisWeek = t / WEEK * WEEK; - uint nextWeek = 0; - - // checkpoint should be called at least once per 20 weeks - for (uint i = 0; i < 20; i++) { - nextWeek = thisWeek + WEEK; - if (block.timestamp < nextWeek) { - tokensPerWeek[thisWeek] += adjustToDistribute(toDistribute, block.timestamp, t, sinceLast); - break; - } else { - tokensPerWeek[thisWeek] += adjustToDistribute(toDistribute, nextWeek, t, sinceLast); - } - t = nextWeek; - thisWeek = nextWeek; - } - emit CheckpointToken(block.timestamp, toDistribute); - } - - /// @dev Adjust value based on time since last update - function adjustToDistribute( - uint toDistribute, - uint t0, - uint t1, - uint sinceLast - ) public pure returns (uint) { - if (t0 <= t1 || t0 - t1 == 0 || sinceLast == 0) { - return toDistribute; - } - return toDistribute * (t0 - t1) / sinceLast; - } - - /// @dev Search in the loop given timestamp through ve points history. - /// Return minimal possible epoch. - function findTimestampEpoch(IVeTetu _ve, uint _timestamp) public view returns (uint) { - uint _min = 0; - uint _max = _ve.epoch(); - for (uint i = 0; i < 128; i++) { - if (_min >= _max) break; - uint _mid = (_min + _max + 2) / 2; - IVeTetu.Point memory pt = _ve.pointHistory(_mid); - if (pt.ts <= _timestamp) { - _min = _mid; - } else { - _max = _mid - 1; - } - } - return _min; - } - - /// @dev Search in the loop given timestamp through ve user points history. - /// Return minimal possible epoch. - function findTimestampUserEpoch( - IVeTetu _ve, - uint tokenId, - uint _timestamp, - uint maxUserEpoch - ) public view returns (uint) { - uint _min = 0; - uint _max = maxUserEpoch; - for (uint i = 0; i < 128; i++) { - if (_min >= _max) break; - uint _mid = (_min + _max + 2) / 2; - IVeTetu.Point memory pt = _ve.userPointHistory(tokenId, _mid); - if (pt.ts <= _timestamp) { - _min = _mid; - } else { - _max = _mid - 1; - } - } - return _min; - } - - /// @dev Call ve checkpoint and write veSupply at the current timeCursor - function checkpointTotalSupply() external override { - _checkpointTotalSupply(); - } - - function _checkpointTotalSupply() internal { - IVeTetu _ve = ve; - uint t = timeCursor; - uint roundedTimestamp = block.timestamp / WEEK * WEEK; - _ve.checkpoint(); - - // assume will be called more frequently than 20 weeks - for (uint i = 0; i < 20; i++) { - if (t > roundedTimestamp) { - break; - } else { - uint epoch = findTimestampEpoch(_ve, t); - IVeTetu.Point memory pt = _ve.pointHistory(epoch); - veSupply[t] = adjustVeSupply(t, pt.ts, pt.bias, pt.slope); - } - t += WEEK; - } - timeCursor = t; - } - - /// @dev Calculate ve supply based on bias and slop for the given timestamp - function adjustVeSupply(uint t, uint ptTs, int128 ptBias, int128 ptSlope) public pure returns (uint) { - if (t < ptTs) { - return 0; - } - int128 dt = int128(int256(t - ptTs)); - if (ptBias < ptSlope * dt) { - return 0; - } - return uint(int256(_positiveInt128(ptBias - ptSlope * dt))); - } - - // ************************************************************* - // CLAIM - // ************************************************************* - - /// @dev Return available to claim earned amount - function claimable(uint _tokenId) external view override returns (uint) { - uint _lastTokenTime = lastTokenTime / WEEK * WEEK; - ClaimCalculationResult memory result = _calculateClaim(_tokenId, ve, _lastTokenTime); - return result.toDistribute; - } - - /// @dev Claim rewards for given veID - function claim(uint _tokenId) external override returns (uint) { - IVeTetu _ve = ve; - if (block.timestamp >= timeCursor) _checkpointTotalSupply(); - uint _lastTokenTime = lastTokenTime; - _lastTokenTime = _lastTokenTime / WEEK * WEEK; - uint amount = _claim(_tokenId, _ve, _lastTokenTime); - if (amount != 0) { - address owner = _ve.ownerOf(_tokenId); - IERC20(rewardToken).safeTransfer(owner, amount); - tokenLastBalance -= amount; - } - return amount; - } - - /// @dev Claim rewards for given veIDs - function claimMany(uint[] memory _tokenIds) external returns (bool) { - if (block.timestamp >= timeCursor) _checkpointTotalSupply(); - uint _lastTokenTime = lastTokenTime; - _lastTokenTime = _lastTokenTime / WEEK * WEEK; - IVeTetu _votingEscrow = ve; - uint total = 0; - - for (uint i = 0; i < _tokenIds.length; i++) { - uint _tokenId = _tokenIds[i]; - if (_tokenId == 0) break; - uint amount = _claim(_tokenId, _votingEscrow, _lastTokenTime); - if (amount != 0) { - address owner = _votingEscrow.ownerOf(_tokenId); - IERC20(rewardToken).safeTransfer(owner, amount); - total += amount; - } - } - if (total != 0) { - tokenLastBalance -= total; - } - - return true; - } - - function _claim(uint _tokenId, IVeTetu _ve, uint _lastTokenTime) internal returns (uint) { - ClaimCalculationResult memory result = _calculateClaim(_tokenId, _ve, _lastTokenTime); - if (result.success) { - userEpochOf[_tokenId] = result.userEpoch; - timeCursorOf[_tokenId] = result.weekCursor; - emit Claimed(_tokenId, result.toDistribute, result.userEpoch, result.maxUserEpoch); - } - return result.toDistribute; - } - - function _calculateClaim( - uint _tokenId, - IVeTetu _ve, - uint _lastTokenTime - ) internal view returns (ClaimCalculationResult memory) { - uint userEpoch; - uint maxUserEpoch = _ve.userPointEpoch(_tokenId); - uint _startTime = startTime; - - if (maxUserEpoch == 0) { - return ClaimCalculationResult(0, 0, 0, 0, false); - } - - uint weekCursor = timeCursorOf[_tokenId]; - - if (weekCursor == 0) { - userEpoch = findTimestampUserEpoch(_ve, _tokenId, _startTime, maxUserEpoch); - } else { - userEpoch = userEpochOf[_tokenId]; - } - - if (userEpoch == 0) userEpoch = 1; - - IVeTetu.Point memory userPoint = _ve.userPointHistory(_tokenId, userEpoch); - if (weekCursor == 0) { - weekCursor = (userPoint.ts + WEEK - 1) / WEEK * WEEK; - } - if (weekCursor >= lastTokenTime) { - return ClaimCalculationResult(0, 0, 0, 0, false); - } - if (weekCursor < _startTime) { - weekCursor = _startTime; - } - - return calculateToDistribute( - _tokenId, - weekCursor, - _lastTokenTime, - userPoint, - userEpoch, - maxUserEpoch, - _ve - ); - } - - function calculateToDistribute( - uint _tokenId, - uint weekCursor, - uint _lastTokenTime, - IVeTetu.Point memory userPoint, - uint userEpoch, - uint maxUserEpoch, - IVeTetu _ve - ) public view returns (ClaimCalculationResult memory) { - IVeTetu.Point memory oldUserPoint; - uint toDistribute; - for (uint i = 0; i < 50; i++) { - if (weekCursor >= _lastTokenTime) { - break; - } - if (weekCursor >= userPoint.ts && userEpoch <= maxUserEpoch) { - userEpoch += 1; - oldUserPoint = userPoint; - if (userEpoch > maxUserEpoch) { - userPoint = IVeTetu.Point(0, 0, 0, 0); - } else { - userPoint = _ve.userPointHistory(_tokenId, userEpoch); - } - } else { - int128 dt = int128(int256(weekCursor - oldUserPoint.ts)); - uint balanceOf = uint(int256(_positiveInt128(oldUserPoint.bias - dt * oldUserPoint.slope))); - if (balanceOf == 0 && userEpoch > maxUserEpoch) { - break; - } - toDistribute += balanceOf * tokensPerWeek[weekCursor] / veSupply[weekCursor]; - weekCursor += WEEK; - } - } - return ClaimCalculationResult( - toDistribute, - Math.min(maxUserEpoch, userEpoch - 1), - weekCursor, - maxUserEpoch, - true - ); - } - - function _positiveInt128(int128 value) internal pure returns (int128) { - return value < 0 ? int128(0) : value; - } - - /// @dev Block timestamp rounded to weeks - function timestamp() external view returns (uint) { - return block.timestamp / WEEK * WEEK; - } - - /// @dev See {IERC165-supportsInterface}. - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == InterfaceIds.I_VE_DISTRIBUTOR || super.supportsInterface(interfaceId); - } +contract VeDistributor /*is ControllableV3, IVeDistributor*/ { +// using SafeERC20 for IERC20; +// +// // for contract internal purposes, don't need to store in the interface +// struct ClaimCalculationResult { +// uint toDistribute; +// uint userEpoch; +// uint weekCursor; +// uint maxUserEpoch; +// bool success; +// } +// +// // ************************************************************* +// // CONSTANTS +// // ************************************************************* +// +// /// @dev Version of this contract. Adjust manually on each code modification. +// string public constant VE_DIST_VERSION = "1.0.2"; +// uint internal constant WEEK = 7 * 86400; +// +// // ************************************************************* +// // VARIABLES +// // Keep names and ordering! +// // Add only in the bottom. +// // ************************************************************* +// +// /// @dev Voting escrow token address +// IVeTetu public ve; +// /// @dev Token for ve rewards +// address public override rewardToken; +// +// // --- CHECKPOINT +// +// /// @dev Cursor for the current epoch +// uint public activePeriod; +// /// @dev Tokens per week stored on checkpoint call. Predefined array size = max weeks size +// uint[1000000000000000] public tokensPerWeek; +// /// @dev Ve supply checkpoints. Predefined array size = max weeks size +// uint[1000000000000000] public veSupply; +// /// @dev Ve supply checkpoint time cursor +// uint public timeCursor; +// /// @dev Token balance updated on checkpoint/claim +// uint public tokenLastBalance; +// /// @dev Last checkpoint time +// uint public lastTokenTime; +// +// // --- CLAIM +// +// /// @dev Timestamp when this contract was inited +// uint public startTime; +// /// @dev veID => week cursor stored on the claim action +// mapping(uint => uint) public timeCursorOf; +// /// @dev veID => epoch stored on the claim action +// mapping(uint => uint) public userEpochOf; +// +// // ************************************************************* +// // EVENTS +// // ************************************************************* +// +// event CheckpointToken( +// uint time, +// uint tokens +// ); +// +// event Claimed( +// uint tokenId, +// uint amount, +// uint claimEpoch, +// uint maxEpoch +// ); +// +// // ************************************************************* +// // INIT +// // ************************************************************* +// +// /// @dev Proxy initialization. Call it after contract deploy. +// function init( +// address controller_, +// address _ve, +// address _rewardToken +// ) external initializer { +// __Controllable_init(controller_); +// _requireERC20(_rewardToken); +// _requireInterface(_ve, InterfaceIds.I_VE_TETU); +// +// uint _t = block.timestamp / WEEK * WEEK; +// startTime = _t; +// lastTokenTime = _t; +// timeCursor = _t; +// +// rewardToken = _rewardToken; +// ve = IVeTetu(_ve); +// +// IERC20(_rewardToken).safeApprove(_ve, type(uint).max); +// } +// +// function emergencyWithdraw() external { +// require(isGovernance(msg.sender), "not gov"); +// IERC20(rewardToken).safeTransfer(msg.sender, IERC20(rewardToken).balanceOf(address(this))); +// } +// +// // ************************************************************* +// // CHECKPOINT +// // ************************************************************* +// +// function checkpoint() external override { +// uint _period = activePeriod; +// // only trigger if new week +// if (block.timestamp >= _period + 1 weeks) { +// // set new period rounded to weeks +// activePeriod = block.timestamp / 1 weeks * 1 weeks; +// // checkpoint token balance that was just minted in veDist +// _checkpointToken(); +// // checkpoint supply +// _checkpointTotalSupply(); +// } +// } +// +// /// @dev Update tokensPerWeek value +// function _checkpointToken() internal { +// uint tokenBalance = IERC20(rewardToken).balanceOf(address(this)); +// uint toDistribute = tokenBalance - tokenLastBalance; +// tokenLastBalance = tokenBalance; +// +// uint t = lastTokenTime; +// uint sinceLast = block.timestamp - t; +// lastTokenTime = block.timestamp; +// uint thisWeek = t / WEEK * WEEK; +// uint nextWeek = 0; +// +// // checkpoint should be called at least once per 20 weeks +// for (uint i = 0; i < 20; i++) { +// nextWeek = thisWeek + WEEK; +// if (block.timestamp < nextWeek) { +// tokensPerWeek[thisWeek] += adjustToDistribute(toDistribute, block.timestamp, t, sinceLast); +// break; +// } else { +// tokensPerWeek[thisWeek] += adjustToDistribute(toDistribute, nextWeek, t, sinceLast); +// } +// t = nextWeek; +// thisWeek = nextWeek; +// } +// emit CheckpointToken(block.timestamp, toDistribute); +// } +// +// /// @dev Adjust value based on time since last update +// function adjustToDistribute( +// uint toDistribute, +// uint t0, +// uint t1, +// uint sinceLast +// ) public pure returns (uint) { +// if (t0 <= t1 || t0 - t1 == 0 || sinceLast == 0) { +// return toDistribute; +// } +// return toDistribute * (t0 - t1) / sinceLast; +// } +// +// /// @dev Search in the loop given timestamp through ve points history. +// /// Return minimal possible epoch. +// function findTimestampEpoch(IVeTetu _ve, uint _timestamp) public view returns (uint) { +// uint _min = 0; +// uint _max = _ve.epoch(); +// for (uint i = 0; i < 128; i++) { +// if (_min >= _max) break; +// uint _mid = (_min + _max + 2) / 2; +// IVeTetu.Point memory pt = _ve.pointHistory(_mid); +// if (pt.ts <= _timestamp) { +// _min = _mid; +// } else { +// _max = _mid - 1; +// } +// } +// return _min; +// } +// +// /// @dev Search in the loop given timestamp through ve user points history. +// /// Return minimal possible epoch. +// function findTimestampUserEpoch( +// IVeTetu _ve, +// uint tokenId, +// uint _timestamp, +// uint maxUserEpoch +// ) public view returns (uint) { +// uint _min = 0; +// uint _max = maxUserEpoch; +// for (uint i = 0; i < 128; i++) { +// if (_min >= _max) break; +// uint _mid = (_min + _max + 2) / 2; +// IVeTetu.Point memory pt = _ve.userPointHistory(tokenId, _mid); +// if (pt.ts <= _timestamp) { +// _min = _mid; +// } else { +// _max = _mid - 1; +// } +// } +// return _min; +// } +// +// /// @dev Call ve checkpoint and write veSupply at the current timeCursor +// function checkpointTotalSupply() external override { +// _checkpointTotalSupply(); +// } +// +// function _checkpointTotalSupply() internal { +// IVeTetu _ve = ve; +// uint t = timeCursor; +// uint roundedTimestamp = block.timestamp / WEEK * WEEK; +// _ve.checkpoint(); +// +// // assume will be called more frequently than 20 weeks +// for (uint i = 0; i < 20; i++) { +// if (t > roundedTimestamp) { +// break; +// } else { +// uint epoch = findTimestampEpoch(_ve, t); +// IVeTetu.Point memory pt = _ve.pointHistory(epoch); +// veSupply[t] = adjustVeSupply(t, pt.ts, pt.bias, pt.slope); +// } +// t += WEEK; +// } +// timeCursor = t; +// } +// +// /// @dev Calculate ve supply based on bias and slop for the given timestamp +// function adjustVeSupply(uint t, uint ptTs, int128 ptBias, int128 ptSlope) public pure returns (uint) { +// if (t < ptTs) { +// return 0; +// } +// int128 dt = int128(int256(t - ptTs)); +// if (ptBias < ptSlope * dt) { +// return 0; +// } +// return uint(int256(_positiveInt128(ptBias - ptSlope * dt))); +// } +// +// // ************************************************************* +// // CLAIM +// // ************************************************************* +// +// /// @dev Return available to claim earned amount +// function claimable(uint _tokenId) external view override returns (uint) { +// uint _lastTokenTime = lastTokenTime / WEEK * WEEK; +// ClaimCalculationResult memory result = _calculateClaim(_tokenId, ve, _lastTokenTime); +// return result.toDistribute; +// } +// +// /// @dev Claim rewards for given veID +// function claim(uint _tokenId) external override returns (uint) { +// IVeTetu _ve = ve; +// if (block.timestamp >= timeCursor) _checkpointTotalSupply(); +// uint _lastTokenTime = lastTokenTime; +// _lastTokenTime = _lastTokenTime / WEEK * WEEK; +// uint amount = _claim(_tokenId, _ve, _lastTokenTime); +// if (amount != 0) { +// address owner = _ve.ownerOf(_tokenId); +// IERC20(rewardToken).safeTransfer(owner, amount); +// tokenLastBalance -= amount; +// } +// return amount; +// } +// +// /// @dev Claim rewards for given veIDs +// function claimMany(uint[] memory _tokenIds) external returns (bool) { +// if (block.timestamp >= timeCursor) _checkpointTotalSupply(); +// uint _lastTokenTime = lastTokenTime; +// _lastTokenTime = _lastTokenTime / WEEK * WEEK; +// IVeTetu _votingEscrow = ve; +// uint total = 0; +// +// for (uint i = 0; i < _tokenIds.length; i++) { +// uint _tokenId = _tokenIds[i]; +// if (_tokenId == 0) break; +// uint amount = _claim(_tokenId, _votingEscrow, _lastTokenTime); +// if (amount != 0) { +// address owner = _votingEscrow.ownerOf(_tokenId); +// IERC20(rewardToken).safeTransfer(owner, amount); +// total += amount; +// } +// } +// if (total != 0) { +// tokenLastBalance -= total; +// } +// +// return true; +// } +// +// function _claim(uint _tokenId, IVeTetu _ve, uint _lastTokenTime) internal returns (uint) { +// ClaimCalculationResult memory result = _calculateClaim(_tokenId, _ve, _lastTokenTime); +// if (result.success) { +// userEpochOf[_tokenId] = result.userEpoch; +// timeCursorOf[_tokenId] = result.weekCursor; +// emit Claimed(_tokenId, result.toDistribute, result.userEpoch, result.maxUserEpoch); +// } +// return result.toDistribute; +// } +// +// function _calculateClaim( +// uint _tokenId, +// IVeTetu _ve, +// uint _lastTokenTime +// ) internal view returns (ClaimCalculationResult memory) { +// uint userEpoch; +// uint maxUserEpoch = _ve.userPointEpoch(_tokenId); +// uint _startTime = startTime; +// +// if (maxUserEpoch == 0) { +// return ClaimCalculationResult(0, 0, 0, 0, false); +// } +// +// uint weekCursor = timeCursorOf[_tokenId]; +// +// if (weekCursor == 0) { +// userEpoch = findTimestampUserEpoch(_ve, _tokenId, _startTime, maxUserEpoch); +// } else { +// userEpoch = userEpochOf[_tokenId]; +// } +// +// if (userEpoch == 0) userEpoch = 1; +// +// IVeTetu.Point memory userPoint = _ve.userPointHistory(_tokenId, userEpoch); +// if (weekCursor == 0) { +// weekCursor = (userPoint.ts + WEEK - 1) / WEEK * WEEK; +// } +// if (weekCursor >= lastTokenTime) { +// return ClaimCalculationResult(0, 0, 0, 0, false); +// } +// if (weekCursor < _startTime) { +// weekCursor = _startTime; +// } +// +// return calculateToDistribute( +// _tokenId, +// weekCursor, +// _lastTokenTime, +// userPoint, +// userEpoch, +// maxUserEpoch, +// _ve +// ); +// } +// +// function calculateToDistribute( +// uint _tokenId, +// uint weekCursor, +// uint _lastTokenTime, +// IVeTetu.Point memory userPoint, +// uint userEpoch, +// uint maxUserEpoch, +// IVeTetu _ve +// ) public view returns (ClaimCalculationResult memory) { +// IVeTetu.Point memory oldUserPoint; +// uint toDistribute; +// for (uint i = 0; i < 50; i++) { +// if (weekCursor >= _lastTokenTime) { +// break; +// } +// if (weekCursor >= userPoint.ts && userEpoch <= maxUserEpoch) { +// userEpoch += 1; +// oldUserPoint = userPoint; +// if (userEpoch > maxUserEpoch) { +// userPoint = IVeTetu.Point(0, 0, 0, 0); +// } else { +// userPoint = _ve.userPointHistory(_tokenId, userEpoch); +// } +// } else { +// int128 dt = int128(int256(weekCursor - oldUserPoint.ts)); +// uint balanceOf = uint(int256(_positiveInt128(oldUserPoint.bias - dt * oldUserPoint.slope))); +// if (balanceOf == 0 && userEpoch > maxUserEpoch) { +// break; +// } +// toDistribute += balanceOf * tokensPerWeek[weekCursor] / veSupply[weekCursor]; +// weekCursor += WEEK; +// } +// } +// return ClaimCalculationResult( +// toDistribute, +// Math.min(maxUserEpoch, userEpoch - 1), +// weekCursor, +// maxUserEpoch, +// true +// ); +// } +// +// function _positiveInt128(int128 value) internal pure returns (int128) { +// return value < 0 ? int128(0) : value; +// } +// +// /// @dev Block timestamp rounded to weeks +// function timestamp() external view returns (uint) { +// return block.timestamp / WEEK * WEEK; +// } +// +// /// @dev See {IERC165-supportsInterface}. +// function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { +// return interfaceId == InterfaceIds.I_VE_DISTRIBUTOR || super.supportsInterface(interfaceId); +// } } diff --git a/contracts/ve/VeDistributorV2.sol b/contracts/ve/VeDistributorV2.sol index 46f1c09..e7a2b0f 100644 --- a/contracts/ve/VeDistributorV2.sol +++ b/contracts/ve/VeDistributorV2.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.17; import "../interfaces/IERC20.sol"; import "../interfaces/IVeTetu.sol"; -import "../interfaces/IVeDistributor.sol"; +import "../interfaces/IVeDistributorV2.sol"; import "../openzeppelin/SafeERC20.sol"; import "../openzeppelin/Math.sol"; import "../proxy/ControllableV3.sol"; @@ -14,208 +14,208 @@ import "../proxy/ControllableV3.sol"; /// Pay all rewards at once for individual user. /// No need to wait any epoch delays /// @author belbix -contract VeDistributorV2 is ControllableV3, IVeDistributor { - using SafeERC20 for IERC20; - - struct EpochInfo { - uint ts; - uint rewardsPerToken; - uint tokenBalance; - uint veTotalSupply; - } - - // ************************************************************* - // CONSTANTS - // ************************************************************* - - /// @dev Version of this contract. Adjust manually on each code modification. - string public constant VE_DIST_VERSION = "2.0.0"; - uint internal constant WEEK = 7 days; - - // ************************************************************* - // VARIABLES - // Keep ordering! - // Add only in the bottom. - // ************************************************************* - - /// @dev Voting escrow token address - IVeTetu public ve; - /// @dev Token for ve rewards - address public override rewardToken; - - // --- CHECKPOINT INFO - - uint public epoch; - /// @dev epoch => EpochInfo - mapping(uint => EpochInfo) public epochInfos; - - uint public tokensClaimedSinceLastSnapshot; - - // --- USER INFO - - /// @dev tokenId => paid epoch - mapping(uint => uint) public lastPaidEpoch; - - // ************************************************************* - // EVENTS - // ************************************************************* - - event Checkpoint( - uint epoch, - uint newEpochTs, - uint tokenBalance, - uint prevTokenBalance, - uint tokenDiff, - uint rewardsPerToken, - uint veTotalSupply - ); - event RewardsClaimed(uint tokenId, address owner, uint amount); - - // ************************************************************* - // INIT - // ************************************************************* - - /// @dev Proxy initialization. Call it after contract deploy. - function init( - address controller_, - address _ve, - address _rewardToken - ) external initializer { - __Controllable_init(controller_); - _requireERC20(_rewardToken); - _requireInterface(_ve, InterfaceIds.I_VE_TETU); - - rewardToken = _rewardToken; - ve = IVeTetu(_ve); - } - - /// @dev Governance can claim all tokens in emergency case. Assume this will never happen. - /// After withdraw this contract will be broken and require redeploy. - function emergencyWithdraw() external { - require(isGovernance(msg.sender), "not gov"); - IERC20(rewardToken).safeTransfer(msg.sender, IERC20(rewardToken).balanceOf(address(this))); - } - - // ************************************************************* - // CHECKPOINT - // ************************************************************* - - /// @dev Make checkpoint and start new epoch. Anyone can call it. - /// This call can be done from multiple places and must not have reverts. - function checkpoint() external override { - uint _epoch = epoch; - address _rewardToken = rewardToken; - uint tokenBalance = IERC20(_rewardToken).balanceOf(address(this)); - - // do not start new epoch if zero balance - if (tokenBalance == 0) { - return; - } - - EpochInfo memory _epochInfo = epochInfos[_epoch]; - uint newEpochTs = block.timestamp / WEEK * WEEK; - - // check epoch time only if we already started - if (_epoch != 0 && _epochInfo.ts >= newEpochTs) { - return; - } - - uint tokenDiff = tokenBalance + tokensClaimedSinceLastSnapshot - _epochInfo.tokenBalance; - // do nothing if no new rewards - if (tokenDiff == 0) { - return; - } - - IVeTetu _ve = ve; - _ve.checkpoint(); - uint veTotalSupply = _ve.totalSupplyAtT(newEpochTs); - // we can use a simple invariant - sum of all balanceOfNFTAt must be equal to totalSupplyAtT - uint rewardsPerToken = tokenDiff * 1e18 / veTotalSupply; - - // write states - tokensClaimedSinceLastSnapshot = 0; - epoch = _epoch + 1; - epochInfos[_epoch + 1] = EpochInfo({ - ts: newEpochTs, - rewardsPerToken: rewardsPerToken, - tokenBalance: tokenBalance, - veTotalSupply: veTotalSupply - }); - - emit Checkpoint( - _epoch + 1, - newEpochTs, - tokenBalance, - _epochInfo.tokenBalance, - tokenDiff, - rewardsPerToken, - veTotalSupply - ); - } - - /// @dev Deprecated, keep for interface support - function checkpointTotalSupply() external pure override { - // noop - } - - // ************************************************************* - // CLAIM - // ************************************************************* - - /// @dev Return available to claim earned amount - function claimable(uint _tokenId) public view override returns (uint rewardsAmount) { - uint curEpoch = epoch; - uint _lastPaidEpoch = lastPaidEpoch[_tokenId]; - - uint unpaidEpochCount = curEpoch > _lastPaidEpoch ? curEpoch - _lastPaidEpoch : 0; - - if (unpaidEpochCount == 0) { - return 0; - } - - // max depth is 50 epochs (~1 year), early rewards will be lost for this ve - if (unpaidEpochCount > 50) { - unpaidEpochCount = 50; - } - - IVeTetu _ve = ve; - - for (uint i; i < unpaidEpochCount; ++i) { - EpochInfo storage _epochInfo = epochInfos[_lastPaidEpoch + i + 1]; - uint balanceAtEpoch = _ve.balanceOfNFTAt(_tokenId, _epochInfo.ts); - rewardsAmount += balanceAtEpoch * _epochInfo.rewardsPerToken / 1e18; - } - - return rewardsAmount; - } - - /// @dev Claim rewards for given veID - function claim(uint _tokenId) public override returns (uint toClaim) { - toClaim = claimable(_tokenId); - - if (toClaim != 0) { - address owner = ve.ownerOf(_tokenId); - require(msg.sender == owner, "not owner"); - IERC20(rewardToken).safeTransfer(owner, toClaim); - - lastPaidEpoch[_tokenId] = epoch; - tokensClaimedSinceLastSnapshot += toClaim; - - emit RewardsClaimed(_tokenId, owner, toClaim); - } - } - - /// @dev Claim rewards for given veIDs - function claimMany(uint[] memory _tokenIds) external returns (bool success) { - for (uint i = 0; i < _tokenIds.length; i++) { - claim(_tokenIds[i]); - } - return true; - } - - /// @dev See {IERC165-supportsInterface}. - function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { - return interfaceId == InterfaceIds.I_VE_DISTRIBUTOR || super.supportsInterface(interfaceId); - } +contract VeDistributorV2 /*is ControllableV3, IVeDistributorV2*/ { +// using SafeERC20 for IERC20; +// +// struct EpochInfo { +// uint ts; +// uint rewardsPerToken; +// uint tokenBalance; +// uint veTotalSupply; +// } +// +// // ************************************************************* +// // CONSTANTS +// // ************************************************************* +// +// /// @dev Version of this contract. Adjust manually on each code modification. +// string public constant VE_DIST_VERSION = "2.0.0"; +// uint internal constant WEEK = 7 days; +// +// // ************************************************************* +// // VARIABLES +// // Keep ordering! +// // Add only in the bottom. +// // ************************************************************* +// +// /// @dev Voting escrow token address +// IVeTetu public ve; +// /// @dev Token for ve rewards +// address public override rewardToken; +// +// // --- CHECKPOINT INFO +// +// uint public override epoch; +// /// @dev epoch => EpochInfo +// mapping(uint => EpochInfo) public epochInfos; +// +// uint public tokensClaimedSinceLastSnapshot; +// +// // --- USER INFO +// +// /// @dev tokenId => paid epoch +// mapping(uint => uint) public override lastPaidEpoch; +// +// // ************************************************************* +// // EVENTS +// // ************************************************************* +// +// event Checkpoint( +// uint epoch, +// uint newEpochTs, +// uint tokenBalance, +// uint prevTokenBalance, +// uint tokenDiff, +// uint rewardsPerToken, +// uint veTotalSupply +// ); +// event RewardsClaimed(uint tokenId, address owner, uint amount); +// +// // ************************************************************* +// // INIT +// // ************************************************************* +// +// /// @dev Proxy initialization. Call it after contract deploy. +// function init( +// address controller_, +// address _ve, +// address _rewardToken +// ) external initializer { +// __Controllable_init(controller_); +// _requireERC20(_rewardToken); +// _requireInterface(_ve, InterfaceIds.I_VE_TETU); +// +// rewardToken = _rewardToken; +// ve = IVeTetu(_ve); +// } +// +// /// @dev Governance can claim all tokens in emergency case. Assume this will never happen. +// /// After withdraw this contract will be broken and require redeploy. +// function emergencyWithdraw() external { +// require(isGovernance(msg.sender), "not gov"); +// IERC20(rewardToken).safeTransfer(msg.sender, IERC20(rewardToken).balanceOf(address(this))); +// } +// +// // ************************************************************* +// // CHECKPOINT +// // ************************************************************* +// +// /// @dev Make checkpoint and start new epoch. Anyone can call it. +// /// This call can be done from multiple places and must not have reverts. +// function checkpoint() external override { +// uint _epoch = epoch; +// address _rewardToken = rewardToken; +// uint tokenBalance = IERC20(_rewardToken).balanceOf(address(this)); +// +// // do not start new epoch if zero balance +// if (tokenBalance == 0) { +// return; +// } +// +// EpochInfo memory _epochInfo = epochInfos[_epoch]; +// uint newEpochTs = block.timestamp / WEEK * WEEK; +// +// // check epoch time only if we already started +// if (_epoch != 0 && _epochInfo.ts >= newEpochTs) { +// return; +// } +// +// uint tokenDiff = tokenBalance + tokensClaimedSinceLastSnapshot - _epochInfo.tokenBalance; +// // do nothing if no new rewards +// if (tokenDiff == 0) { +// return; +// } +// +// IVeTetu _ve = ve; +// _ve.checkpoint(); +// uint veTotalSupply = _ve.totalSupplyAtT(newEpochTs); +// // we can use a simple invariant - sum of all balanceOfNFTAt must be equal to totalSupplyAtT +// uint rewardsPerToken = tokenDiff * 1e18 / veTotalSupply; +// +// // write states +// tokensClaimedSinceLastSnapshot = 0; +// epoch = _epoch + 1; +// epochInfos[_epoch + 1] = EpochInfo({ +// ts: newEpochTs, +// rewardsPerToken: rewardsPerToken, +// tokenBalance: tokenBalance, +// veTotalSupply: veTotalSupply +// }); +// +// emit Checkpoint( +// _epoch + 1, +// newEpochTs, +// tokenBalance, +// _epochInfo.tokenBalance, +// tokenDiff, +// rewardsPerToken, +// veTotalSupply +// ); +// } +// +// /// @dev Deprecated, keep for interface support +// function checkpointTotalSupply() external pure override { +// // noop +// } +// +// // ************************************************************* +// // CLAIM +// // ************************************************************* +// +// /// @dev Return available to claim earned amount +// function claimable(uint _tokenId) public view override returns (uint rewardsAmount) { +// uint curEpoch = epoch; +// uint _lastPaidEpoch = lastPaidEpoch[_tokenId]; +// +// uint unpaidEpochCount = curEpoch > _lastPaidEpoch ? curEpoch - _lastPaidEpoch : 0; +// +// if (unpaidEpochCount == 0) { +// return 0; +// } +// +// // max depth is 50 epochs (~1 year), early rewards will be lost for this ve +// if (unpaidEpochCount > 50) { +// unpaidEpochCount = 50; +// } +// +// IVeTetu _ve = ve; +// +// for (uint i; i < unpaidEpochCount; ++i) { +// EpochInfo storage _epochInfo = epochInfos[_lastPaidEpoch + i + 1]; +// uint balanceAtEpoch = _ve.balanceOfNFTAt(_tokenId, _epochInfo.ts); +// rewardsAmount += balanceAtEpoch * _epochInfo.rewardsPerToken / 1e18; +// } +// +// return rewardsAmount; +// } +// +// /// @dev Claim rewards for given veID +// function claim(uint _tokenId) public override returns (uint toClaim) { +// toClaim = claimable(_tokenId); +// +// if (toClaim != 0) { +// address owner = ve.ownerOf(_tokenId); +// require(msg.sender == owner, "not owner"); +// IERC20(rewardToken).safeTransfer(owner, toClaim); +// +// lastPaidEpoch[_tokenId] = epoch; +// tokensClaimedSinceLastSnapshot += toClaim; +// +// emit RewardsClaimed(_tokenId, owner, toClaim); +// } +// } +// +// /// @dev Claim rewards for given veIDs +// function claimMany(uint[] memory _tokenIds) external returns (bool success) { +// for (uint i = 0; i < _tokenIds.length; i++) { +// claim(_tokenIds[i]); +// } +// return true; +// } +// +// /// @dev See {IERC165-supportsInterface}. +// function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { +// return interfaceId == InterfaceIds.I_VE_DISTRIBUTOR || super.supportsInterface(interfaceId); +// } } diff --git a/contracts/ve/VeTetu.sol b/contracts/ve/VeTetu.sol index 12729f4..6de3d0c 100644 --- a/contracts/ve/VeTetu.sol +++ b/contracts/ve/VeTetu.sol @@ -11,7 +11,6 @@ import "../interfaces/IController.sol"; import "../interfaces/IVoter.sol"; import "../interfaces/IPlatformVoter.sol"; import "../interfaces/ISmartVault.sol"; -import "../interfaces/IVeDistributor.sol"; import "../proxy/ControllableV3.sol"; import "./VeTetuLib.sol"; @@ -352,35 +351,8 @@ contract VeTetu is ControllableV3, ReentrancyGuard, IVeTetu { return _balanceOfNFT(_tokenId, block.timestamp); } - function balanceOfNFTAt(uint _tokenId, uint _t) external view override returns (uint) { - return _balanceOfNFT(_tokenId, _t); - } - - function totalSupply() external view returns (uint) { - return totalSupplyAtT(block.timestamp); - } - - function balanceOfAtNFT(uint _tokenId, uint _block) external view returns (uint) { - return _balanceOfAtNFT(_tokenId, _block); - } - - function userPointHistory(uint _tokenId, uint _loc) external view override returns (Point memory point) { - if (isAlwaysMaxLock[_tokenId]) { - return Point({ - bias: int128(int256(lockedDerivedAmount[_tokenId])), - slope: 0, - ts: (block.timestamp - MAX_TIME) / WEEK * WEEK, // this represent a simulation that we locked MAX TIME ago, need for VeDist - blk: block.number - }); - } - - point = _userPointHistory[_tokenId][_loc]; - } - - function pointHistory(uint _loc) external view override returns (Point memory point) { - point = _pointHistory[_loc]; - // we have a big simplification of the logic at this moment and just return current extra supply at any request epoch - point.bias = point.bias + int128(int256(additionalTotalSupply)); + function totalSupply() external override view returns (uint) { + return VeTetuLib.supplyAt(_pointHistory[epoch], block.timestamp, slopeChanges) + additionalTotalSupply; } function isVoted(uint _tokenId) public view override returns (bool) { @@ -810,9 +782,6 @@ contract VeTetu is ControllableV3, ReentrancyGuard, IVeTetu { require(isApprovedOrOwner(msg.sender, _tokenId), "NOT_OWNER"); require(status != isAlwaysMaxLock[_tokenId], "WRONG_INPUT"); - // additional protection against wrong calculation inside VeDist for keep invariant with balances. - require(IVeDistributor(IController(controller()).veDistributor()).claimable(_tokenId) == 0, 'CLAIM_REWARDS'); - _setAlwaysMaxLock(_tokenId, status); } @@ -1189,7 +1158,12 @@ contract VeTetu is ControllableV3, ReentrancyGuard, IVeTetu { function _balanceOfNFT(uint _tokenId, uint ts) internal view returns (uint) { // with max lock return balance as is if (isAlwaysMaxLock[_tokenId]) { - return lockedDerivedAmount[_tokenId]; + // if requested too old block return zero to protect wrong function usage + if(ts < block.timestamp) { + return 0; + } else { + return lockedDerivedAmount[_tokenId]; + } } uint _epoch = userPointEpoch[_tokenId]; @@ -1242,47 +1216,32 @@ contract VeTetu is ControllableV3, ReentrancyGuard, IVeTetu { ); } - /// @notice Measure voting power of `_tokenId` at block height `_block` - /// @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime - /// @param _tokenId User's wallet NFT - /// @param _block Block to calculate the voting power at - /// @return Voting power - function _balanceOfAtNFT(uint _tokenId, uint _block) internal view returns (uint) { - // for always max lock just return full derived amount - if (isAlwaysMaxLock[_tokenId]) { - return lockedDerivedAmount[_tokenId]; - } - - return VeTetuLib.balanceOfAtNFT( - _tokenId, - _block, - epoch, - lockedDerivedAmount[_tokenId], - userPointEpoch, - _userPointHistory, - _pointHistory - ); - } - - /// @notice Calculate total voting power - /// @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility - /// @return Total voting power - function totalSupplyAtT(uint t) public view override returns (uint) { - Point memory lastPoint = _pointHistory[epoch]; - return VeTetuLib.supplyAt(lastPoint, t, slopeChanges) + additionalTotalSupply; - } - - /// @notice Calculate total voting power at some point in the past - /// @param _block Block to calculate the total voting power at - /// @return Total voting power at `_block` - function totalSupplyAt(uint _block) external view override returns (uint) { - return VeTetuLib.totalSupplyAt( - _block, - epoch, - _pointHistory, - slopeChanges - ) + additionalTotalSupply; - } +// /// @notice Measure voting power of `_tokenId` at block height `_block` +// /// @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime +// /// @param _tokenId User's wallet NFT +// /// @param _block Block to calculate the voting power at +// /// @return Voting power +// function _balanceOfAtNFT(uint _tokenId, uint _block) internal view returns (uint) { +// // for always max lock just return full derived amount +// if (isAlwaysMaxLock[_tokenId]) { +// // if requested too old block return zero to protect wrong function usage +// if(_block < block.number) { +// return 0; +// } else { +// return lockedDerivedAmount[_tokenId]; +// } +// } +// +// return VeTetuLib.balanceOfAtNFT( +// _tokenId, +// _block, +// epoch, +// lockedDerivedAmount[_tokenId], +// userPointEpoch, +// _userPointHistory, +// _pointHistory +// ); +// } /// @notice Record global data to checkpoint function checkpoint() external override { diff --git a/scripts/addresses/polygon.ts b/scripts/addresses/polygon.ts index 20af31b..f67001e 100644 --- a/scripts/addresses/polygon.ts +++ b/scripts/addresses/polygon.ts @@ -30,14 +30,14 @@ export class PolygonAddresses { public static GOVERNANCE = "0xcc16d636dd05b52ff1d8b9ce09b09bc62b11412b".toLowerCase(); // Additional TETU contracts - public static TETU_EMITTER = "0x04eE7A5364803AAbE6021816146C34B4616c74D3".toLowerCase(); + // public static TETU_EMITTER = "0x04eE7A5364803AAbE6021816146C34B4616c74D3".toLowerCase(); public static HARDWORK_RESOLVER = "0xD578141F36BE210c90e8C734819db889e55A305b".toLowerCase(); public static FORWARDER_RESOLVER = "0x6d16Fa76f61F2BEe0093D1DCbab29bcA4FBC8628".toLowerCase(); public static SPLITTER_REBALANCE_RESOLVER = "0x9618D3e9c8a133d081dE37b99c6ECf108C1e82F2".toLowerCase(); public static PERF_FEE_TREASURY = "0x9Cc199D4353b5FB3e6C8EEBC99f5139e0d8eA06b".toLowerCase(); public static TETU_BRIDGED_PROCESSING = "0x1950a09fc28Dd3C36CaC89485357844Af0739C07".toLowerCase(); public static REWARDS_REDIRECTOR = "0xA9947d0815d6EA3077805E2112FB19572DD4dc9E".toLowerCase(); - public static BRIBE_DISTRIBUTION = "0xd1f8b86EfBA4bCEB0E2434337F2d504087F6C4d0".toLowerCase(); // old 0x3220Fa5BD9Be44C2A7BbB137dA6E5Cd3b6bf7124 + // public static BRIBE_DISTRIBUTION = "0xd1f8b86EfBA4bCEB0E2434337F2d504087F6C4d0".toLowerCase(); // old 0x3220Fa5BD9Be44C2A7BbB137dA6E5Cd3b6bf7124 // PROTOCOL ADRS public static DEPOSIT_HELPER_V2 = "0xab2422A4d8Ac985AE98F5Da3713988b420f24165".toLowerCase(); diff --git a/scripts/deploy/DeployAllProd.ts b/scripts/deploy/DeployAllProd.ts index 4c6d933..f33268a 100644 --- a/scripts/deploy/DeployAllProd.ts +++ b/scripts/deploy/DeployAllProd.ts @@ -13,7 +13,6 @@ async function main() { const tetu = core.tetu; const controller = await DeployerUtils.deployController(signer); const ve = await DeployerUtils.deployVeTetu(signer, tetu, controller.address, BigNumber.from(1000)); - const veDist = await DeployerUtils.deployVeDistributor(signer, controller.address, ve.address, tetu); const gauge = await DeployerUtils.deployMultiGauge(signer, controller.address, ve.address, tetu); const bribe = await DeployerUtils.deployMultiBribe(signer, controller.address, ve.address, tetu); const tetuVoter = await DeployerUtils.deployTetuVoter(signer, controller.address, ve.address, tetu, gauge.address, bribe.address); @@ -40,7 +39,7 @@ async function main() { await RunHelper.runAndWait(() => controller.announceAddressChange(4, tools.liquidator)); // PLATFORM_VOTER await RunHelper.runAndWait(() => controller.announceAddressChange(5, forwarder.address)); // FORWARDER await RunHelper.runAndWait(() => controller.announceAddressChange(6, fundAdr)); // INVEST_FUND - await RunHelper.runAndWait(() => controller.announceAddressChange(7, veDist.address)); // VE_DIST + await RunHelper.runAndWait(() => controller.announceAddressChange(7, signer.address)); // VE_DIST await RunHelper.runAndWait(() => controller.changeAddress(2)); // TETU_VOTER @@ -54,7 +53,7 @@ async function main() { "${tetu}", // tetu "${controller.address}", // controller "${ve.address}", // ve - "${veDist.address}", // veDist + "${signer.address}", // veDist "${gauge.address}", // gauge "${bribe.address}", // bribe "${tetuVoter.address}", // tetuVoter diff --git a/scripts/deploy/DeployAllTestnet.ts b/scripts/deploy/DeployAllTestnet.ts index 3c6197b..6726061 100644 --- a/scripts/deploy/DeployAllTestnet.ts +++ b/scripts/deploy/DeployAllTestnet.ts @@ -10,7 +10,6 @@ async function main() { const tetu = await DeployerUtils.deployMockToken(signer, 'TETU'); const controller = await DeployerUtils.deployController(signer); const ve = await DeployerUtils.deployVeTetu(signer, tetu.address, controller.address); - const veDist = await DeployerUtils.deployVeDistributor(signer, controller.address, ve.address, tetu.address); const gauge = await DeployerUtils.deployMultiGauge(signer, controller.address, ve.address, tetu.address); const bribe = await DeployerUtils.deployMultiBribe(signer, controller.address, ve.address, tetu.address); const tetuVoter = await DeployerUtils.deployTetuVoter(signer, controller.address, ve.address, tetu.address, gauge.address, bribe.address); @@ -37,7 +36,7 @@ async function main() { // await controller.announceAddressChange(4, .address); // LIQUIDATOR await RunHelper.runAndWait(() => controller.announceAddressChange(5, forwarder.address)); // FORWARDER await RunHelper.runAndWait(() => controller.announceAddressChange(6, fundAdr)); // INVEST_FUND - await RunHelper.runAndWait(() => controller.announceAddressChange(7, veDist.address)); // VE_DIST + await RunHelper.runAndWait(() => controller.announceAddressChange(7, signer.address)); // VE_DIST await RunHelper.runAndWait(() => controller.changeAddress(2)); // TETU_VOTER diff --git a/scripts/deploy/DeployTetuEmitter.ts b/scripts/deploy/DeployTetuEmitter.ts deleted file mode 100644 index 70c3893..0000000 --- a/scripts/deploy/DeployTetuEmitter.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {ethers} from "hardhat"; -import {DeployerUtils} from "../utils/DeployerUtils"; -import {Addresses} from "../addresses/addresses"; -import {PolygonAddresses} from "../addresses/polygon"; - - -async function main() { - const signer = (await ethers.getSigners())[0]; - const core = Addresses.getCore(); - const ctr = await DeployerUtils.deployTetuEmitter(signer, core.controller, PolygonAddresses.TETU_TOKEN, core.bribe) - console.log("Emitter deployed to:", ctr.address); -} - -main() - .then(() => process.exit(0)) - .catch(error => { - console.error(error); - process.exit(1); - }); diff --git a/scripts/deploy/DeployVeDistV2.ts b/scripts/deploy/DeployVeDistV2.ts deleted file mode 100644 index c232e53..0000000 --- a/scripts/deploy/DeployVeDistV2.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {ethers} from "hardhat"; -import {DeployerUtils} from "../utils/DeployerUtils"; -import {Addresses} from "../addresses/addresses"; - - -async function main() { - const signer = (await ethers.getSigners())[0]; - const core = Addresses.getCore(); - const veDist = await DeployerUtils.deployVeDistributorV2( - signer, - core.controller, - core.ve, - core.tetu, - ); - - console.log('veDist', veDist.address); -} - -main() - .then(() => process.exit(0)) - .catch(error => { - console.error(error); - process.exit(1); - }); diff --git a/scripts/utils/DeployerUtils.ts b/scripts/utils/DeployerUtils.ts index d8c966d..7c331e9 100644 --- a/scripts/utils/DeployerUtils.ts +++ b/scripts/utils/DeployerUtils.ts @@ -32,8 +32,6 @@ import { TetuVoterSimplified__factory, VaultFactory, VaultInsurance, - VeDistributor__factory, - VeDistributorV2__factory, VeTetu, VeTetu__factory } from "../../typechain"; @@ -212,40 +210,6 @@ export class DeployerUtils { return await DeployerUtils.deployContract(signer, 'MockVoter', ve) as MockVoter; } - public static async deployVeDistributor( - signer: SignerWithAddress, - controller: string, - ve: string, - rewardToken: string, - ) { - const logic = await DeployerUtils.deployContract(signer, 'VeDistributor'); - const proxy = await DeployerUtils.deployContract(signer, 'ProxyControlled') as ProxyControlled; - await RunHelper.runAndWait2(proxy.populateTransaction.initProxy(logic.address)); - await RunHelper.runAndWait2(VeDistributor__factory.connect(proxy.address, signer).populateTransaction.init( - controller, - ve, - rewardToken - )); - return VeDistributor__factory.connect(proxy.address, signer); - } - - public static async deployVeDistributorV2( - signer: SignerWithAddress, - controller: string, - ve: string, - rewardToken: string, - ) { - const logic = await DeployerUtils.deployContract(signer, 'VeDistributorV2'); - const proxy = await DeployerUtils.deployContract(signer, 'ProxyControlled') as ProxyControlled; - await RunHelper.runAndWait2(proxy.populateTransaction.initProxy(logic.address)); - await RunHelper.runAndWait2(VeDistributorV2__factory.connect(proxy.address, signer).populateTransaction.init( - controller, - ve, - rewardToken - )); - return VeDistributorV2__factory.connect(proxy.address, signer); - } - public static async deployTetuVaultV2( signer: SignerWithAddress, controller: string, @@ -350,15 +314,6 @@ export class DeployerUtils { return controller; } - public static async deployTetuEmitter(signer: SignerWithAddress, controller: string, token: string, bribe: string) { - const logic = await DeployerUtils.deployContract(signer, 'TetuEmitter') as ControllerV2; - const proxy = await DeployerUtils.deployContract(signer, 'ProxyControlled') as ProxyControlled; - await RunHelper.runAndWait2(proxy.populateTransaction.initProxy(logic.address)); - const contract = TetuEmitter__factory.connect(proxy.address, signer); - await RunHelper.runAndWait2(contract.populateTransaction.init(controller, token, bribe)); - return contract; - } - public static async deployVaultFactory( signer: SignerWithAddress, controller: string, diff --git a/test/infrastructure/ControllerV2Test.ts b/test/infrastructure/ControllerV2Test.ts index 39d6fe1..aae6190 100644 --- a/test/infrastructure/ControllerV2Test.ts +++ b/test/infrastructure/ControllerV2Test.ts @@ -4,7 +4,7 @@ import chai from "chai"; import {TimeUtils} from "../TimeUtils"; import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; import {Misc} from "../../scripts/utils/Misc"; -import {ControllerV2, ForwarderV3, PlatformVoter, ProxyControlled__factory, VeDistributor} from "../../typechain"; +import {ControllerV2, ForwarderV3, PlatformVoter, ProxyControlled__factory} from "../../typechain"; const {expect} = chai; @@ -103,19 +103,19 @@ describe("controller v2 tests", function () { expect(await controller.investFund()).eq(signer.address); }); - it("change veDistributor test", async function () { - const type = 7; - const veDistributor = await DeployerUtils.deployContract(signer, 'VeDistributor') as VeDistributor; - await controller.announceAddressChange(type, veDistributor.address); - await controller.changeAddress(type); - expect(await controller.veDistributor()).eq(veDistributor.address); - - const veDistributor2 = await DeployerUtils.deployContract(signer, 'VeDistributor') as VeDistributor; - await controller.announceAddressChange(type, veDistributor2.address); - await TimeUtils.advanceBlocksOnTs(LOCK); - await controller.changeAddress(type); - expect(await controller.veDistributor()).eq(veDistributor2.address); - }); + // it("change veDistributor test", async function () { + // const type = 7; + // const veDistributor = await DeployerUtils.deployContract(signer, 'VeDistributor') as VeDistributor; + // await controller.announceAddressChange(type, veDistributor.address); + // await controller.changeAddress(type); + // expect(await controller.veDistributor()).eq(veDistributor.address); + // + // const veDistributor2 = await DeployerUtils.deployContract(signer, 'VeDistributor') as VeDistributor; + // await controller.announceAddressChange(type, veDistributor2.address); + // await TimeUtils.advanceBlocksOnTs(LOCK); + // await controller.changeAddress(type); + // expect(await controller.veDistributor()).eq(veDistributor2.address); + // }); it("change platformVoter test", async function () { const type = 3; diff --git a/test/test-utils.ts b/test/test-utils.ts index c4fbefb..c58ebd9 100644 --- a/test/test-utils.ts +++ b/test/test-utils.ts @@ -21,13 +21,13 @@ export async function checkTotalVeSupplyAtTS(ve: VeTetu, ts: number) { console.log('additionalTotalSupply', formatUnits(await ve.additionalTotalSupply())) - const total = +formatUnits(await ve.totalSupplyAtT(ts)); + const total = +formatUnits(await ve.totalSupply()); console.log('total', total) const nftCount = (await ve.tokenId()).toNumber(); let sum = 0; for (let i = 1; i <= nftCount; ++i) { - const bal = +formatUnits(await ve.balanceOfNFTAt(i, ts)) + const bal = +formatUnits(await ve.balanceOfNFT(i)) console.log('bal', i, bal) sum += bal; } diff --git a/test/tools/BribeDistributorTest.ts b/test/tools/BribeDistributorTest.ts index 6fc296b..e0a6a75 100644 --- a/test/tools/BribeDistributorTest.ts +++ b/test/tools/BribeDistributorTest.ts @@ -1,84 +1,84 @@ -import chai from "chai"; -import chaiAsPromised from "chai-as-promised"; -import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import {BribeDistribution, MockToken,} from "../../typechain"; -import {TimeUtils} from "../TimeUtils"; -import {ethers} from "hardhat"; -import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; - -const {expect} = chai; -chai.use(chaiAsPromised); - -describe("BribeDistributorTest", function () { - let snapshotBefore: string; - let snapshot: string; - let signer: SignerWithAddress; - let signer2: SignerWithAddress; - - let distr: BribeDistribution; - let token: MockToken; - - - before(async function () { - this.timeout(1200000); - snapshotBefore = await TimeUtils.snapshot(); - [signer, signer2] = await ethers.getSigners(); - - token = await DeployerUtils.deployMockToken(signer, 'TETU', 18); - const controller = await DeployerUtils.deployMockController(signer); - const ve = await DeployerUtils.deployVeTetu(signer, token.address, controller.address); - - const veDist = await DeployerUtils.deployVeDistributor( - signer, - controller.address, - ve.address, - token.address, - ); - - distr = await DeployerUtils.deployContract(signer, "BribeDistribution", veDist.address, token.address) as BribeDistribution; - }) - - after(async function () { - await TimeUtils.rollback(snapshotBefore); - }); - - beforeEach(async function () { - snapshot = await TimeUtils.snapshot(); - }); - - afterEach(async function () { - await TimeUtils.rollback(snapshot); - }); - - it("set new owner test", async () => { - await expect(distr.connect(signer2).offerOwnership(signer2.address)).revertedWith('NOT_OWNER'); - await distr.offerOwnership(signer2.address) - await expect(distr.acceptOwnership()).revertedWith('NOT_OWNER'); - await distr.connect(signer2).acceptOwnership() - expect(await distr.owner()).eq(signer2.address) - await expect(distr.offerOwnership(signer2.address)).revertedWith('NOT_OWNER'); - }) - - it("manualNotify test", async () => { - await token.approve(distr.address, 1000) - const veDist = await distr.veDist(); - - await distr.manualNotify(1000, true) - expect(await token.balanceOf(veDist)).eq(500); - - await distr.manualNotify(0, false) - expect(await token.balanceOf(veDist)).eq(1000); - }) - - it("autoNotify test", async () => { - const bal = await token.balanceOf(signer.address); - await token.approve(distr.address, bal) - const veDist = await distr.veDist(); - - await distr.autoNotify() - expect(await token.balanceOf(veDist)).eq(bal.div(2)); - - await distr.autoNotify() - expect(await token.balanceOf(veDist)).eq(bal); - }) -}) +// import chai from "chai"; +// import chaiAsPromised from "chai-as-promised"; +// import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +// import {BribeDistribution, MockToken,} from "../../typechain"; +// import {TimeUtils} from "../TimeUtils"; +// import {ethers} from "hardhat"; +// import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; +// +// const {expect} = chai; +// chai.use(chaiAsPromised); +// +// describe("BribeDistributorTest", function () { +// let snapshotBefore: string; +// let snapshot: string; +// let signer: SignerWithAddress; +// let signer2: SignerWithAddress; +// +// let distr: BribeDistribution; +// let token: MockToken; +// +// +// before(async function () { +// this.timeout(1200000); +// snapshotBefore = await TimeUtils.snapshot(); +// [signer, signer2] = await ethers.getSigners(); +// +// token = await DeployerUtils.deployMockToken(signer, 'TETU', 18); +// const controller = await DeployerUtils.deployMockController(signer); +// const ve = await DeployerUtils.deployVeTetu(signer, token.address, controller.address); +// +// const veDist = await DeployerUtils.deployVeDistributor( +// signer, +// controller.address, +// ve.address, +// token.address, +// ); +// +// distr = await DeployerUtils.deployContract(signer, "BribeDistribution", veDist.address, token.address) as BribeDistribution; +// }) +// +// after(async function () { +// await TimeUtils.rollback(snapshotBefore); +// }); +// +// beforeEach(async function () { +// snapshot = await TimeUtils.snapshot(); +// }); +// +// afterEach(async function () { +// await TimeUtils.rollback(snapshot); +// }); +// +// it("set new owner test", async () => { +// await expect(distr.connect(signer2).offerOwnership(signer2.address)).revertedWith('NOT_OWNER'); +// await distr.offerOwnership(signer2.address) +// await expect(distr.acceptOwnership()).revertedWith('NOT_OWNER'); +// await distr.connect(signer2).acceptOwnership() +// expect(await distr.owner()).eq(signer2.address) +// await expect(distr.offerOwnership(signer2.address)).revertedWith('NOT_OWNER'); +// }) +// +// it("manualNotify test", async () => { +// await token.approve(distr.address, 1000) +// const veDist = await distr.veDist(); +// +// await distr.manualNotify(1000, true) +// expect(await token.balanceOf(veDist)).eq(500); +// +// await distr.manualNotify(0, false) +// expect(await token.balanceOf(veDist)).eq(1000); +// }) +// +// it("autoNotify test", async () => { +// const bal = await token.balanceOf(signer.address); +// await token.approve(distr.address, bal) +// const veDist = await distr.veDist(); +// +// await distr.autoNotify() +// expect(await token.balanceOf(veDist)).eq(bal.div(2)); +// +// await distr.autoNotify() +// expect(await token.balanceOf(veDist)).eq(bal); +// }) +// }) diff --git a/test/ve/TetuEmitterTest.ts b/test/ve/TetuEmitterTest.ts index 02f2919..d7dd3ac 100644 --- a/test/ve/TetuEmitterTest.ts +++ b/test/ve/TetuEmitterTest.ts @@ -1,131 +1,131 @@ -import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import {ethers} from "hardhat"; -import chai from "chai"; -import {TimeUtils} from "../TimeUtils"; -import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; -import {MockBribe, MockBribe__factory, MockToken, MockVeDist, MockVoter, TetuEmitter} from "../../typechain"; - - -const {expect} = chai; - -describe("TetuEmitterTest", function () { - - let snapshotBefore: string; - let snapshot: string; - - let owner: SignerWithAddress; - let owner2: SignerWithAddress; - let owner3: SignerWithAddress; - - let emitter: TetuEmitter; - let veDist: MockVeDist; - let voter: MockVoter; - let tetu: MockToken; - let bribe: MockBribe; - - before(async function () { - snapshotBefore = await TimeUtils.snapshot(); - [owner, owner2, owner3] = await ethers.getSigners(); - - const controller = await DeployerUtils.deployMockController(owner); - - tetu = await DeployerUtils.deployMockToken(owner, 'TETU'); - veDist = await DeployerUtils.deployContract(owner, 'MockVeDist') as MockVeDist; - const ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - voter = await DeployerUtils.deployMockVoter(owner, ve.address); - bribe = MockBribe__factory.connect(await DeployerUtils.deployProxy(owner, 'MockBribe'), owner); - await bribe.init(controller.address); - - await controller.setVeDistributor(veDist.address); - await controller.setVoter(voter.address); - - - emitter = await DeployerUtils.deployTetuEmitter(owner, controller.address, tetu.address, bribe.address); - }); - - after(async function () { - await TimeUtils.rollback(snapshotBefore); - }); - - - beforeEach(async function () { - snapshot = await TimeUtils.snapshot(); - }); - - afterEach(async function () { - await TimeUtils.rollback(snapshot); - }); - - it("startEpoch to voter 100% test", async function () { - await expect(emitter.startEpoch(100)).revertedWith("!amount"); - await tetu.transfer(emitter.address, 100) - await emitter.startEpoch(100); - await expect(emitter.startEpoch(100)).revertedWith("too early"); - - expect(await tetu.balanceOf(voter.address)).eq(100); - expect(await bribe.epoch()).eq(1); - expect(await emitter.epoch()).eq(1); - expect(await emitter.startEpochTS()).above(0); - }); - - it("gelato Resolver test", async function () { - await tetu.transfer(emitter.address, 100) - - - expect(await emitter.isReadyToStart()).eq(true); - expect((await emitter.gelatoResolver()).canExec).eq(true); - - await emitter.startEpoch(100); - - expect(await emitter.isReadyToStart()).eq(false); - expect((await emitter.gelatoResolver()).canExec).eq(false); - }); - - it("startEpoch to ve 100% test", async function () { - await expect(emitter.connect(owner2).setToVeRatio(100)).revertedWith("!gov"); - await expect(emitter.setToVeRatio(100_001)).revertedWith("too high"); - await emitter.setToVeRatio(100_000); - await tetu.transfer(emitter.address, 100) - await emitter.startEpoch(100); - - expect(await tetu.balanceOf(veDist.address)).eq(100); - }); - - it("startEpoch twice test", async function () { - await tetu.transfer(emitter.address, 200) - await emitter.startEpoch(100); - expect(await tetu.balanceOf(voter.address)).eq(100); - - await TimeUtils.advanceBlocksOnTs(60 * 60 * 24 * 7); - - await emitter.startEpoch(100); - expect(await tetu.balanceOf(voter.address)).eq(200); - }); - - it("startEpoch with zero amount test", async function () { - await emitter.startEpoch(0); - expect(await bribe.epoch()).eq(1); - expect(await emitter.epoch()).eq(1); - expect(await emitter.startEpochTS()).above(0); - }); - - it("setMinAmountPerEpoch test", async function () { - await expect(emitter.connect(owner2).setMinAmountPerEpoch(100)).revertedWith("!gov"); - await emitter.setMinAmountPerEpoch(200); - await tetu.transfer(emitter.address, 100) - await expect(emitter.startEpoch(100)).revertedWith("!amount"); - await tetu.transfer(emitter.address, 100) - await emitter.startEpoch(200); - - expect(await tetu.balanceOf(voter.address)).eq(200); - }); - - it("changeOperator test", async function () { - await expect(emitter.connect(owner2).startEpoch(100)).revertedWith("!operator"); - await expect(emitter.connect(owner2).changeOperator(owner2.address)).revertedWith("!gov"); - await emitter.changeOperator(owner2.address); - await tetu.transfer(emitter.address, 100) - await emitter.connect(owner2).startEpoch(100); - expect(await tetu.balanceOf(voter.address)).eq(100); - }); -}); +// import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +// import {ethers} from "hardhat"; +// import chai from "chai"; +// import {TimeUtils} from "../TimeUtils"; +// import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; +// import {MockBribe, MockBribe__factory, MockToken, MockVeDist, MockVoter, TetuEmitter} from "../../typechain"; +// +// +// const {expect} = chai; +// +// describe("TetuEmitterTest", function () { +// +// let snapshotBefore: string; +// let snapshot: string; +// +// let owner: SignerWithAddress; +// let owner2: SignerWithAddress; +// let owner3: SignerWithAddress; +// +// let emitter: TetuEmitter; +// let veDist: MockVeDist; +// let voter: MockVoter; +// let tetu: MockToken; +// let bribe: MockBribe; +// +// before(async function () { +// snapshotBefore = await TimeUtils.snapshot(); +// [owner, owner2, owner3] = await ethers.getSigners(); +// +// const controller = await DeployerUtils.deployMockController(owner); +// +// tetu = await DeployerUtils.deployMockToken(owner, 'TETU'); +// veDist = await DeployerUtils.deployContract(owner, 'MockVeDist') as MockVeDist; +// const ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// voter = await DeployerUtils.deployMockVoter(owner, ve.address); +// bribe = MockBribe__factory.connect(await DeployerUtils.deployProxy(owner, 'MockBribe'), owner); +// await bribe.init(controller.address); +// +// await controller.setVeDistributor(veDist.address); +// await controller.setVoter(voter.address); +// +// +// emitter = await DeployerUtils.deployTetuEmitter(owner, controller.address, tetu.address, bribe.address); +// }); +// +// after(async function () { +// await TimeUtils.rollback(snapshotBefore); +// }); +// +// +// beforeEach(async function () { +// snapshot = await TimeUtils.snapshot(); +// }); +// +// afterEach(async function () { +// await TimeUtils.rollback(snapshot); +// }); +// +// it("startEpoch to voter 100% test", async function () { +// await expect(emitter.startEpoch(100)).revertedWith("!amount"); +// await tetu.transfer(emitter.address, 100) +// await emitter.startEpoch(100); +// await expect(emitter.startEpoch(100)).revertedWith("too early"); +// +// expect(await tetu.balanceOf(voter.address)).eq(100); +// expect(await bribe.epoch()).eq(1); +// expect(await emitter.epoch()).eq(1); +// expect(await emitter.startEpochTS()).above(0); +// }); +// +// it("gelato Resolver test", async function () { +// await tetu.transfer(emitter.address, 100) +// +// +// expect(await emitter.isReadyToStart()).eq(true); +// expect((await emitter.gelatoResolver()).canExec).eq(true); +// +// await emitter.startEpoch(100); +// +// expect(await emitter.isReadyToStart()).eq(false); +// expect((await emitter.gelatoResolver()).canExec).eq(false); +// }); +// +// it("startEpoch to ve 100% test", async function () { +// await expect(emitter.connect(owner2).setToVeRatio(100)).revertedWith("!gov"); +// await expect(emitter.setToVeRatio(100_001)).revertedWith("too high"); +// await emitter.setToVeRatio(100_000); +// await tetu.transfer(emitter.address, 100) +// await emitter.startEpoch(100); +// +// expect(await tetu.balanceOf(veDist.address)).eq(100); +// }); +// +// it("startEpoch twice test", async function () { +// await tetu.transfer(emitter.address, 200) +// await emitter.startEpoch(100); +// expect(await tetu.balanceOf(voter.address)).eq(100); +// +// await TimeUtils.advanceBlocksOnTs(60 * 60 * 24 * 7); +// +// await emitter.startEpoch(100); +// expect(await tetu.balanceOf(voter.address)).eq(200); +// }); +// +// it("startEpoch with zero amount test", async function () { +// await emitter.startEpoch(0); +// expect(await bribe.epoch()).eq(1); +// expect(await emitter.epoch()).eq(1); +// expect(await emitter.startEpochTS()).above(0); +// }); +// +// it("setMinAmountPerEpoch test", async function () { +// await expect(emitter.connect(owner2).setMinAmountPerEpoch(100)).revertedWith("!gov"); +// await emitter.setMinAmountPerEpoch(200); +// await tetu.transfer(emitter.address, 100) +// await expect(emitter.startEpoch(100)).revertedWith("!amount"); +// await tetu.transfer(emitter.address, 100) +// await emitter.startEpoch(200); +// +// expect(await tetu.balanceOf(voter.address)).eq(200); +// }); +// +// it("changeOperator test", async function () { +// await expect(emitter.connect(owner2).startEpoch(100)).revertedWith("!operator"); +// await expect(emitter.connect(owner2).changeOperator(owner2.address)).revertedWith("!gov"); +// await emitter.changeOperator(owner2.address); +// await tetu.transfer(emitter.address, 100) +// await emitter.connect(owner2).startEpoch(100); +// expect(await tetu.balanceOf(voter.address)).eq(100); +// }); +// }); diff --git a/test/ve/VeDistributorTest.ts b/test/ve/VeDistributorTest.ts index 1960fd4..3423e8d 100644 --- a/test/ve/VeDistributorTest.ts +++ b/test/ve/VeDistributorTest.ts @@ -1,322 +1,322 @@ -import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import {ethers} from "hardhat"; -import chai from "chai"; -import {formatUnits, parseUnits} from "ethers/lib/utils"; -import {ControllerMinimal, MockPawnshop, MockToken, MockVoter, Multicall, VeDistributor, VeTetu} from "../../typechain"; -import {TimeUtils} from "../TimeUtils"; -import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; -import {Misc} from "../../scripts/utils/Misc"; -import {BigNumber} from "ethers"; - -const {expect} = chai; - -const WEEK = 60 * 60 * 24 * 7; -const LOCK_PERIOD = 60 * 60 * 24 * 90; - -describe.skip("Ve distributor tests", function () { - - let snapshotBefore: string; - let snapshot: string; - - let owner: SignerWithAddress; - let owner2: SignerWithAddress; - let owner3: SignerWithAddress; - let tetu: MockToken; - let controller: ControllerMinimal; - - let ve: VeTetu; - let voter: MockVoter; - let pawnshop: MockPawnshop; - let veDist: VeDistributor; - - - before(async function () { - snapshotBefore = await TimeUtils.snapshot(); - [owner, owner2, owner3] = await ethers.getSigners(); - - tetu = await DeployerUtils.deployMockToken(owner, 'TETU', 18); - controller = await DeployerUtils.deployMockController(owner); - ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - voter = await DeployerUtils.deployMockVoter(owner, ve.address); - pawnshop = await DeployerUtils.deployContract(owner, 'MockPawnshop') as MockPawnshop; - await controller.setVoter(voter.address); - await ve.announceAction(2); - await TimeUtils.advanceBlocksOnTs(60 * 60 * 18); - await ve.whitelistTransferFor(pawnshop.address); - - veDist = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve.address, - tetu.address, - ); - - await tetu.mint(owner2.address, parseUnits('100')); - await tetu.approve(ve.address, Misc.MAX_UINT); - await tetu.connect(owner2).approve(ve.address, Misc.MAX_UINT); - await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - await ve.connect(owner2).createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - - await ve.setApprovalForAll(pawnshop.address, true); - await ve.connect(owner2).setApprovalForAll(pawnshop.address, true); - }); - - after(async function () { - await TimeUtils.rollback(snapshotBefore); - }); - - - beforeEach(async function () { - snapshot = await TimeUtils.snapshot(); - }); - - afterEach(async function () { - await TimeUtils.rollback(snapshot); - }); - - it("emergency withdraw", async function () { - await veDist.emergencyWithdraw(); - expect((await tetu.balanceOf(veDist.address)).isZero()).eq(true); - }); - - it("multi checkpointToken with empty balance test", async function () { - await tetu.transfer(veDist.address, parseUnits('10')); - await veDist.checkpoint(); - await veDist.checkpoint(); - }); - - it("adjustToDistribute test", async function () { - expect(await veDist.adjustToDistribute(100, 1, 1, 20)).eq(100); - expect(await veDist.adjustToDistribute(100, 0, 1, 20)).eq(100); - expect(await veDist.adjustToDistribute(100, 2, 1, 20)).eq(5); - }); - - it("checkpointTotalSupply dummy test", async function () { - await ve.checkpoint(); - await veDist.checkpointTotalSupply(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.checkpoint(); - await veDist.checkpointTotalSupply(); - }); - - it("adjustVeSupply test", async function () { - expect(await veDist.adjustVeSupply(100, 100, 5, 10)).eq(5); - expect(await veDist.adjustVeSupply(99, 100, 5, 10)).eq(0); - expect(await veDist.adjustVeSupply(200, 100, 5, 10)).eq(0); - expect(await veDist.adjustVeSupply(2, 1, 20, 5)).eq(15); - expect(await veDist.adjustVeSupply(3, 1, 20, 5)).eq(10); - }); - - it("claim for non exist token test", async function () { - await veDist.claim(99); - }); - - it("claim without rewards test", async function () { - await veDist.claim(1); - }); - - it("claim for early token test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address - ); - - await tetu.transfer(veDist.address, parseUnits('1')); - await veDist.checkpoint(); - - await veDist1.claim(1); - }); - - it("claimMany for early token test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address - ); - - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - - await veDist1.claimMany([1]); - }); - - it("claim for early token with delay test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address, - ); - - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await veDist1.claim(1); - await veDist1.claimMany([1]); - }); - - it("claimMany for early token with delay test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address, - ); - - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await veDist1.claimMany([1]); - }); - - it("claim with rewards test", async function () { - await ve.createLock(tetu.address, WEEK * 2, LOCK_PERIOD); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - - await tetu.transfer(veDist.address, parseUnits('1')); - await veDist.checkpoint(); - await veDist.checkpointTotalSupply(); - await veDist.claim(2); - }); - - it("claim without checkpoints after the launch should return zero", async function () { - await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - const maxUserEpoch = await ve.userPointEpoch(2) - const startTime = await veDist.startTime(); - let weekCursor = await veDist.timeCursorOf(2); - let userEpoch; - if (weekCursor.isZero()) { - userEpoch = await veDist.findTimestampUserEpoch(ve.address, 2, startTime, maxUserEpoch); - } else { - userEpoch = await veDist.userEpochOf(2); - } - if (userEpoch.isZero()) { - userEpoch = BigNumber.from(1); - } - const userPoint = await ve.userPointHistory(2, userEpoch); - if (weekCursor.isZero()) { - weekCursor = userPoint.ts.add(WEEK).sub(1).div(WEEK).mul(WEEK); - } - const lastTokenTime = await veDist.lastTokenTime(); - expect(weekCursor.gte(lastTokenTime)).eq(true); - }); - - it("claim with rewards with minimal possible amount and lock", async function () { - await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - await veDist.checkpointTotalSupply(); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - - let bal = await ve.balanceOfNFT(2) - expect(bal).above(0) - await veDist.claim(2); - expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.08')); - - // SECOND CLAIM - - await tetu.transfer(veDist.address, parseUnits('10000')) - await veDist.checkpoint(); - - await TimeUtils.advanceBlocksOnTs(123456); - - bal = await ve.balanceOfNFT(2) - await veDist.claim(2); - expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.38')); - }); - - it("claimMany on old block test", async function () { - await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); - await veDist.claimMany([1, 2, 0]); - }); - - it("timestamp test", async function () { - expect(await veDist.timestamp()).above(0); - }); - - it("claimable test", async function () { - await ve.createLock(tetu.address, parseUnits('1'), WEEK); - expect(await veDist.claimable(1)).eq(0); - }); - - it("claimMany test old", async function () { - await ve.createLock(tetu.address, parseUnits('1'), WEEK); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - - await tetu.transfer(veDist.address, parseUnits('10000')) - await veDist.checkpoint(); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - - expect(await veDist.claimable(1)).above(0); - - const bal = await ve.balanceOfNFT(1); - await veDist.claimMany([1]); - expect(await tetu.balanceOf(await tetu.signer.getAddress())).above(bal); - - expect(+formatUnits(await tetu.balanceOf(veDist.address))).lt(8000); - }); - - it("claimMany test", async function () { - expect(+formatUnits(await tetu.balanceOf(veDist.address))).eq(0); - - await TimeUtils.advanceBlocksOnTs(LOCK_PERIOD); - await tetu.transfer(veDist.address, parseUnits('10000')) - await veDist.checkpoint(); - await veDist.claimMany([1, 2]); - - console.log('ve dist bal', +formatUnits(await tetu.balanceOf(veDist.address))) - expect(+formatUnits(await tetu.balanceOf(veDist.address))).lt(1500); - }); - - it("calculateToDistribute with zero values test", async function () { - await veDist.calculateToDistribute( - 0, - 0, - 999, - { - bias: 0, - slope: 0, - ts: 0, - blk: 0, - }, - 1, - 0, - ve.address - ); - }); - - -}); +// import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +// import {ethers} from "hardhat"; +// import chai from "chai"; +// import {formatUnits, parseUnits} from "ethers/lib/utils"; +// import {ControllerMinimal, MockPawnshop, MockToken, MockVoter, Multicall, VeDistributor, VeTetu} from "../../typechain"; +// import {TimeUtils} from "../TimeUtils"; +// import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; +// import {Misc} from "../../scripts/utils/Misc"; +// import {BigNumber} from "ethers"; +// +// const {expect} = chai; +// +// const WEEK = 60 * 60 * 24 * 7; +// const LOCK_PERIOD = 60 * 60 * 24 * 90; +// +// describe.skip("Ve distributor tests", function () { +// +// let snapshotBefore: string; +// let snapshot: string; +// +// let owner: SignerWithAddress; +// let owner2: SignerWithAddress; +// let owner3: SignerWithAddress; +// let tetu: MockToken; +// let controller: ControllerMinimal; +// +// let ve: VeTetu; +// let voter: MockVoter; +// let pawnshop: MockPawnshop; +// let veDist: VeDistributor; +// +// +// before(async function () { +// snapshotBefore = await TimeUtils.snapshot(); +// [owner, owner2, owner3] = await ethers.getSigners(); +// +// tetu = await DeployerUtils.deployMockToken(owner, 'TETU', 18); +// controller = await DeployerUtils.deployMockController(owner); +// ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// voter = await DeployerUtils.deployMockVoter(owner, ve.address); +// pawnshop = await DeployerUtils.deployContract(owner, 'MockPawnshop') as MockPawnshop; +// await controller.setVoter(voter.address); +// await ve.announceAction(2); +// await TimeUtils.advanceBlocksOnTs(60 * 60 * 18); +// await ve.whitelistTransferFor(pawnshop.address); +// +// veDist = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve.address, +// tetu.address, +// ); +// +// await tetu.mint(owner2.address, parseUnits('100')); +// await tetu.approve(ve.address, Misc.MAX_UINT); +// await tetu.connect(owner2).approve(ve.address, Misc.MAX_UINT); +// await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// await ve.connect(owner2).createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// +// await ve.setApprovalForAll(pawnshop.address, true); +// await ve.connect(owner2).setApprovalForAll(pawnshop.address, true); +// }); +// +// after(async function () { +// await TimeUtils.rollback(snapshotBefore); +// }); +// +// +// beforeEach(async function () { +// snapshot = await TimeUtils.snapshot(); +// }); +// +// afterEach(async function () { +// await TimeUtils.rollback(snapshot); +// }); +// +// it("emergency withdraw", async function () { +// await veDist.emergencyWithdraw(); +// expect((await tetu.balanceOf(veDist.address)).isZero()).eq(true); +// }); +// +// it("multi checkpointToken with empty balance test", async function () { +// await tetu.transfer(veDist.address, parseUnits('10')); +// await veDist.checkpoint(); +// await veDist.checkpoint(); +// }); +// +// it("adjustToDistribute test", async function () { +// expect(await veDist.adjustToDistribute(100, 1, 1, 20)).eq(100); +// expect(await veDist.adjustToDistribute(100, 0, 1, 20)).eq(100); +// expect(await veDist.adjustToDistribute(100, 2, 1, 20)).eq(5); +// }); +// +// it("checkpointTotalSupply dummy test", async function () { +// await ve.checkpoint(); +// await veDist.checkpointTotalSupply(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await ve.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await ve.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await ve.checkpoint(); +// await veDist.checkpointTotalSupply(); +// }); +// +// it("adjustVeSupply test", async function () { +// expect(await veDist.adjustVeSupply(100, 100, 5, 10)).eq(5); +// expect(await veDist.adjustVeSupply(99, 100, 5, 10)).eq(0); +// expect(await veDist.adjustVeSupply(200, 100, 5, 10)).eq(0); +// expect(await veDist.adjustVeSupply(2, 1, 20, 5)).eq(15); +// expect(await veDist.adjustVeSupply(3, 1, 20, 5)).eq(10); +// }); +// +// it("claim for non exist token test", async function () { +// await veDist.claim(99); +// }); +// +// it("claim without rewards test", async function () { +// await veDist.claim(1); +// }); +// +// it("claim for early token test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')); +// await veDist.checkpoint(); +// +// await veDist1.claim(1); +// }); +// +// it("claimMany for early token test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// +// await veDist1.claimMany([1]); +// }); +// +// it("claim for early token with delay test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address, +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await veDist1.claim(1); +// await veDist1.claimMany([1]); +// }); +// +// it("claimMany for early token with delay test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address, +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await veDist1.claimMany([1]); +// }); +// +// it("claim with rewards test", async function () { +// await ve.createLock(tetu.address, WEEK * 2, LOCK_PERIOD); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// +// await tetu.transfer(veDist.address, parseUnits('1')); +// await veDist.checkpoint(); +// await veDist.checkpointTotalSupply(); +// await veDist.claim(2); +// }); +// +// it("claim without checkpoints after the launch should return zero", async function () { +// await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// const maxUserEpoch = await ve.userPointEpoch(2) +// const startTime = await veDist.startTime(); +// let weekCursor = await veDist.timeCursorOf(2); +// let userEpoch; +// if (weekCursor.isZero()) { +// userEpoch = await veDist.findTimestampUserEpoch(ve.address, 2, startTime, maxUserEpoch); +// } else { +// userEpoch = await veDist.userEpochOf(2); +// } +// if (userEpoch.isZero()) { +// userEpoch = BigNumber.from(1); +// } +// const userPoint = await ve.userPointHistory(2, userEpoch); +// if (weekCursor.isZero()) { +// weekCursor = userPoint.ts.add(WEEK).sub(1).div(WEEK).mul(WEEK); +// } +// const lastTokenTime = await veDist.lastTokenTime(); +// expect(weekCursor.gte(lastTokenTime)).eq(true); +// }); +// +// it("claim with rewards with minimal possible amount and lock", async function () { +// await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// await veDist.checkpointTotalSupply(); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// +// let bal = await ve.balanceOfNFT(2) +// expect(bal).above(0) +// await veDist.claim(2); +// expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.08')); +// +// // SECOND CLAIM +// +// await tetu.transfer(veDist.address, parseUnits('10000')) +// await veDist.checkpoint(); +// +// await TimeUtils.advanceBlocksOnTs(123456); +// +// bal = await ve.balanceOfNFT(2) +// await veDist.claim(2); +// expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.38')); +// }); +// +// it("claimMany on old block test", async function () { +// await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); +// await veDist.claimMany([1, 2, 0]); +// }); +// +// it("timestamp test", async function () { +// expect(await veDist.timestamp()).above(0); +// }); +// +// it("claimable test", async function () { +// await ve.createLock(tetu.address, parseUnits('1'), WEEK); +// expect(await veDist.claimable(1)).eq(0); +// }); +// +// it("claimMany test old", async function () { +// await ve.createLock(tetu.address, parseUnits('1'), WEEK); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// +// await tetu.transfer(veDist.address, parseUnits('10000')) +// await veDist.checkpoint(); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// +// expect(await veDist.claimable(1)).above(0); +// +// const bal = await ve.balanceOfNFT(1); +// await veDist.claimMany([1]); +// expect(await tetu.balanceOf(await tetu.signer.getAddress())).above(bal); +// +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).lt(8000); +// }); +// +// it("claimMany test", async function () { +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).eq(0); +// +// await TimeUtils.advanceBlocksOnTs(LOCK_PERIOD); +// await tetu.transfer(veDist.address, parseUnits('10000')) +// await veDist.checkpoint(); +// await veDist.claimMany([1, 2]); +// +// console.log('ve dist bal', +formatUnits(await tetu.balanceOf(veDist.address))) +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).lt(1500); +// }); +// +// it("calculateToDistribute with zero values test", async function () { +// await veDist.calculateToDistribute( +// 0, +// 0, +// 999, +// { +// bias: 0, +// slope: 0, +// ts: 0, +// blk: 0, +// }, +// 1, +// 0, +// ve.address +// ); +// }); +// +// +// }); diff --git a/test/ve/VeDistributorV2Test.ts b/test/ve/VeDistributorV2Test.ts index fc864e1..b660497 100644 --- a/test/ve/VeDistributorV2Test.ts +++ b/test/ve/VeDistributorV2Test.ts @@ -1,218 +1,227 @@ -import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import {ethers} from "hardhat"; -import chai from "chai"; -import {formatUnits, parseUnits} from "ethers/lib/utils"; -import {ControllerMinimal, MockToken, VeDistributorV2, VeDistributorV2__factory, VeTetu} from "../../typechain"; -import {TimeUtils} from "../TimeUtils"; -import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; -import {Misc} from "../../scripts/utils/Misc"; -import {checkTotalVeSupplyAtTS, currentEpochTS, LOCK_PERIOD, WEEK} from "../test-utils"; -import {CheckpointEventObject} from "../../typechain/ve/VeDistributorV2"; - -const {expect} = chai; - -const checkpointEvent = VeDistributorV2__factory.createInterface().getEvent('Checkpoint'); - -describe("VeDistributorV2Test", function () { - - let snapshotBefore: string; - let snapshot: string; - - let owner: SignerWithAddress; - let owner2: SignerWithAddress; - let owner3: SignerWithAddress; - let tetu: MockToken; - let controller: ControllerMinimal; - - let ve: VeTetu; - let veDist: VeDistributorV2; - - - before(async function () { - snapshotBefore = await TimeUtils.snapshot(); - [owner, owner2, owner3] = await ethers.getSigners(); - - tetu = await DeployerUtils.deployMockToken(owner, 'TETU', 18); - controller = await DeployerUtils.deployMockController(owner); - ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - veDist = await DeployerUtils.deployVeDistributorV2( - owner, - controller.address, - ve.address, - tetu.address, - ); - await controller.setVeDistributor(veDist.address); - - await tetu.mint(owner2.address, parseUnits('100')); - await tetu.approve(ve.address, Misc.MAX_UINT); - await tetu.connect(owner2).approve(ve.address, Misc.MAX_UINT); - await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - await ve.connect(owner2).createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - }); - - after(async function () { - await TimeUtils.rollback(snapshotBefore); - }); - - - beforeEach(async function () { - snapshot = await TimeUtils.snapshot(); - }); - - afterEach(async function () { - await TimeUtils.rollback(snapshot); - }); - - it("emergency withdraw", async function () { - await veDist.emergencyWithdraw(); - expect((await tetu.balanceOf(veDist.address)).isZero()).eq(true); - }); - - it("checkpointTotalSupply", async function () { - await veDist.checkpointTotalSupply(); - }); - - it("distribute and claim", async function () { - expect(await startNewEpoch(ve, veDist)).eq(false); - // need to wait for make sure everyone has powers at epoch start - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - // check pre conditions - expect((await veDist.claimable(1)).isZero()).eq(true); - expect((await veDist.claimable(2)).isZero()).eq(true); - await checkTotalVeSupplyAtTS(ve, await currentEpochTS(ve)); - console.log('precheck is fine') - - // empty claim - await veDist.claimMany([1]); - - // --- NEW EPOCH - - await tetu.transfer(veDist.address, parseUnits('100')); - expect(await startNewEpoch(ve, veDist)).eq(true); - - expect((await veDist.epoch()).toNumber()).eq(1); - - expect(+formatUnits(await veDist.claimable(1))).eq(50); - expect(+formatUnits(await veDist.claimable(2))).eq(50); - - await veDist.claimMany([1]); - await expect(veDist.claimMany([2])).revertedWith('not owner'); - await veDist.connect(owner2).claimMany([2]); - - expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); - - // --- NEW EPOCH - - expect(await startNewEpoch(ve, veDist)).eq(false); - - await tetu.transfer(veDist.address, parseUnits('100')); - expect(await startNewEpoch(ve, veDist)).eq(false); - - await TimeUtils.advanceBlocksOnTs(WEEK); - expect(await startNewEpoch(ve, veDist)).eq(true); - - expect((await veDist.epoch()).toNumber()).eq(2); - - expect(+formatUnits(await veDist.claimable(1))).eq(50); - expect(+formatUnits(await veDist.claimable(2))).eq(50); - - await veDist.claimMany([1]); - await veDist.connect(owner2).claimMany([2]); - - expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); - - // --- NEW EPOCH - - await ve.setAlwaysMaxLock(1, true); - - await TimeUtils.advanceBlocksOnTs(WEEK); - await tetu.transfer(veDist.address, parseUnits('100')); - expect(await startNewEpoch(ve, veDist)).eq(true); - - expect((await veDist.epoch()).toNumber()).eq(3); - - expect(+formatUnits(await veDist.claimable(1))).approximately(65, 5); - expect(+formatUnits(await veDist.claimable(2))).approximately(35, 5); - - await veDist.claimMany([1]); - await veDist.connect(owner2).claimMany([2]); - - expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); - - // --- NEW EPOCH - - await ve.setAlwaysMaxLock(1, false); - - await TimeUtils.advanceBlocksOnTs(WEEK * 4); - await tetu.transfer(veDist.address, parseUnits('100')); - expect(await startNewEpoch(ve, veDist)).eq(true); - - expect((await veDist.epoch()).toNumber()).eq(4); - - expect(+formatUnits(await veDist.claimable(1))).approximately(70, 5); - expect(+formatUnits(await veDist.claimable(2))).approximately(30, 5); - - await veDist.claimMany([1]); - await veDist.connect(owner2).claimMany([2]); - - expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); - - // --- NEW EPOCH - - await ve.connect(owner2).increaseAmount(tetu.address, 2, parseUnits('10')); - - await TimeUtils.advanceBlocksOnTs(WEEK); - await tetu.transfer(veDist.address, parseUnits('100')); - expect(await startNewEpoch(ve, veDist)).eq(true); - - expect((await veDist.epoch()).toNumber()).eq(5); - - expect(+formatUnits(await veDist.claimable(1))).approximately(20, 5); - expect(+formatUnits(await veDist.claimable(2))).approximately(80, 5); - - await veDist.claimMany([1]); - await veDist.connect(owner2).claimMany([2]); - - expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.000000000000001); - - }); - -}); - - -async function startNewEpoch(ve: VeTetu, veDist: VeDistributorV2): Promise { - const oldEpoch = await veDist.epoch() - - const prevEpochTs = (await veDist.epochInfos(oldEpoch)).ts.toNumber(); - console.log('prevEpochTs', prevEpochTs); - const curTs = await currentEpochTS(ve); - console.log('curTs', curTs); - - - const checkpointTx = await (await veDist.checkpoint()).wait(); - let checkpoint: CheckpointEventObject | undefined; - for (const event of checkpointTx.events ?? []) { - if (event.topics[0] !== VeDistributorV2__factory.createInterface().getEventTopic(checkpointEvent)) { - continue; - } - checkpoint = VeDistributorV2__factory.createInterface().decodeEventLog(checkpointEvent, event.data, event.topics) as unknown as CheckpointEventObject; - } - if (!checkpoint) { - return false; - } - - console.log('checkpoint epoch', checkpoint.epoch.toNumber()); - console.log('checkpoint newEpochTs', checkpoint.newEpochTs.toNumber()); - console.log('checkpoint tokenBalance', formatUnits(checkpoint.tokenBalance)); - console.log('checkpoint prevTokenBalance', formatUnits(checkpoint.prevTokenBalance)); - console.log('checkpoint tokenDiff', formatUnits(checkpoint.tokenDiff)); - console.log('checkpoint rewardsPerToken', formatUnits(checkpoint.rewardsPerToken)); - console.log('checkpoint veTotalSupply', formatUnits(checkpoint.veTotalSupply)); - - expect(curTs).eq(checkpoint.newEpochTs.toNumber()); - - await checkTotalVeSupplyAtTS(ve, curTs); - - return oldEpoch.add(1).eq(checkpoint.epoch); -} +// import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +// import {ethers} from "hardhat"; +// import chai from "chai"; +// import {formatUnits, parseUnits} from "ethers/lib/utils"; +// import {ControllerMinimal, MockToken, VeDistributorV2, VeDistributorV2__factory, VeTetu} from "../../typechain"; +// import {TimeUtils} from "../TimeUtils"; +// import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; +// import {Misc} from "../../scripts/utils/Misc"; +// import {checkTotalVeSupplyAtTS, currentEpochTS, LOCK_PERIOD, WEEK} from "../test-utils"; +// import {CheckpointEventObject} from "../../typechain/ve/VeDistributorV2"; +// +// const {expect} = chai; +// +// const checkpointEvent = VeDistributorV2__factory.createInterface().getEvent('Checkpoint'); +// +// describe("VeDistributorV2Test", function () { +// +// let snapshotBefore: string; +// let snapshot: string; +// +// let owner: SignerWithAddress; +// let owner2: SignerWithAddress; +// let owner3: SignerWithAddress; +// let tetu: MockToken; +// let controller: ControllerMinimal; +// +// let ve: VeTetu; +// let veDist: VeDistributorV2; +// +// +// before(async function () { +// snapshotBefore = await TimeUtils.snapshot(); +// [owner, owner2, owner3] = await ethers.getSigners(); +// +// tetu = await DeployerUtils.deployMockToken(owner, 'TETU', 18); +// controller = await DeployerUtils.deployMockController(owner); +// ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// veDist = await DeployerUtils.deployVeDistributorV2( +// owner, +// controller.address, +// ve.address, +// tetu.address, +// ); +// await controller.setVeDistributor(veDist.address); +// +// await tetu.mint(owner2.address, parseUnits('100')); +// await tetu.approve(ve.address, Misc.MAX_UINT); +// await tetu.connect(owner2).approve(ve.address, Misc.MAX_UINT); +// await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// await ve.connect(owner2).createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// }); +// +// after(async function () { +// await TimeUtils.rollback(snapshotBefore); +// }); +// +// +// beforeEach(async function () { +// snapshot = await TimeUtils.snapshot(); +// }); +// +// afterEach(async function () { +// await TimeUtils.rollback(snapshot); +// }); +// +// it("emergency withdraw", async function () { +// await veDist.emergencyWithdraw(); +// expect((await tetu.balanceOf(veDist.address)).isZero()).eq(true); +// }); +// +// it("checkpointTotalSupply", async function () { +// await veDist.checkpointTotalSupply(); +// }); +// +// it("distribute and claim", async function () { +// expect(await startNewEpoch(ve, veDist)).eq(false); +// // need to wait for make sure everyone has powers at epoch start +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// // check pre conditions +// expect((await veDist.claimable(1)).isZero()).eq(true); +// expect((await veDist.claimable(2)).isZero()).eq(true); +// await checkTotalVeSupplyAtTS(ve, await currentEpochTS(ve)); +// console.log('precheck is fine') +// +// // empty claim +// await veDist.claimMany([1]); +// +// // --- NEW EPOCH +// +// await tetu.transfer(veDist.address, parseUnits('100')); +// expect(await startNewEpoch(ve, veDist)).eq(true); +// +// expect((await veDist.epoch()).toNumber()).eq(1); +// +// expect(+formatUnits(await veDist.claimable(1))).eq(50); +// expect(+formatUnits(await veDist.claimable(2))).eq(50); +// +// await veDist.claimMany([1]); +// await expect(veDist.claimMany([2])).revertedWith('not owner'); +// await veDist.connect(owner2).claimMany([2]); +// +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); +// +// // --- NEW EPOCH +// +// expect(await startNewEpoch(ve, veDist)).eq(false); +// +// await tetu.transfer(veDist.address, parseUnits('100')); +// expect(await startNewEpoch(ve, veDist)).eq(false); +// +// await TimeUtils.advanceBlocksOnTs(WEEK); +// expect(await startNewEpoch(ve, veDist)).eq(true); +// +// expect((await veDist.epoch()).toNumber()).eq(2); +// +// expect(+formatUnits(await veDist.claimable(1))).eq(50); +// expect(+formatUnits(await veDist.claimable(2))).eq(50); +// +// await veDist.claimMany([1]); +// await veDist.connect(owner2).claimMany([2]); +// +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); +// +// // --- NEW EPOCH +// +// await ve.setAlwaysMaxLock(1, true); +// +// await TimeUtils.advanceBlocksOnTs(WEEK); +// await tetu.transfer(veDist.address, parseUnits('100')); +// expect(await startNewEpoch(ve, veDist)).eq(true); +// +// expect((await veDist.epoch()).toNumber()).eq(3); +// +// expect(+formatUnits(await veDist.claimable(1))).approximately(65, 5); +// expect(+formatUnits(await veDist.claimable(2))).approximately(35, 5); +// +// await veDist.claimMany([1]); +// await veDist.connect(owner2).claimMany([2]); +// +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); +// +// // --- NEW EPOCH +// +// await ve.setAlwaysMaxLock(1, false); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 4); +// await tetu.transfer(veDist.address, parseUnits('100')); +// expect(await startNewEpoch(ve, veDist)).eq(true); +// +// expect((await veDist.epoch()).toNumber()).eq(4); +// +// expect(+formatUnits(await veDist.claimable(1))).approximately(70, 5); +// expect(+formatUnits(await veDist.claimable(2))).approximately(30, 5); +// +// await veDist.claimMany([1]); +// await veDist.connect(owner2).claimMany([2]); +// +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.00000000000000001); +// +// // --- NEW EPOCH +// +// await ve.connect(owner2).increaseAmount(tetu.address, 2, parseUnits('10')); +// +// await TimeUtils.advanceBlocksOnTs(WEEK); +// await tetu.transfer(veDist.address, parseUnits('100')); +// expect(await startNewEpoch(ve, veDist)).eq(true); +// +// // ------------- test ability to claim tokens on old epochs with maxLock +// +// await expect(ve.setAlwaysMaxLock(1, true)).revertedWith('CLAIM_REWARDS'); +// +// const newId = Number(await ve.tokenId()) + 1; +// console.log('newId', newId); +// await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// const newBalance = await ve.balanceOfNFT(newId); +// console.log('newBalance', newBalance); +// +// await expect(ve.setAlwaysMaxLock(newId, true)).revertedWith('CLAIM_REWARDS'); +// +// // --------------------------------------------------------------------- +// +// expect((await veDist.epoch()).toNumber()).eq(5); +// +// expect(+formatUnits(await veDist.claimable(1))).approximately(20, 5); +// expect(+formatUnits(await veDist.claimable(2))).approximately(80, 5); +// +// await veDist.claimMany([1]); +// await veDist.connect(owner2).claimMany([2]); +// +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).approximately(0, 0.000000000000001); +// +// }); +// +// }); +// +// +// async function startNewEpoch(ve: VeTetu, veDist: VeDistributorV2): Promise { +// const oldEpoch = await veDist.epoch() +// +// +// +// const checkpointTx = await (await veDist.checkpoint()).wait(); +// let checkpoint: CheckpointEventObject | undefined; +// for (const event of checkpointTx.events ?? []) { +// if (event.topics[0] !== VeDistributorV2__factory.createInterface().getEventTopic(checkpointEvent)) { +// continue; +// } +// checkpoint = VeDistributorV2__factory.createInterface().decodeEventLog(checkpointEvent, event.data, event.topics) as unknown as CheckpointEventObject; +// } +// if (!checkpoint) { +// return false; +// } +// +// console.log('checkpoint epoch', checkpoint.epoch.toNumber()); +// console.log('checkpoint newEpochTs', checkpoint.newEpochTs.toNumber()); +// console.log('checkpoint tokenBalance', formatUnits(checkpoint.tokenBalance)); +// console.log('checkpoint prevTokenBalance', formatUnits(checkpoint.prevTokenBalance)); +// console.log('checkpoint tokenDiff', formatUnits(checkpoint.tokenDiff)); +// console.log('checkpoint rewardsPerToken', formatUnits(checkpoint.rewardsPerToken)); +// console.log('checkpoint veTotalSupply', formatUnits(checkpoint.veTotalSupply)); +// +// +// await checkTotalVeSupplyAtTS(ve, 0); +// +// return oldEpoch.add(1).eq(checkpoint.epoch); +// } diff --git a/test/ve/VeDistributorWithAlwaysMaxLockTest.ts b/test/ve/VeDistributorWithAlwaysMaxLockTest.ts index 157e6b9..33788de 100644 --- a/test/ve/VeDistributorWithAlwaysMaxLockTest.ts +++ b/test/ve/VeDistributorWithAlwaysMaxLockTest.ts @@ -1,318 +1,318 @@ -import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; -import {ethers} from "hardhat"; -import chai from "chai"; -import {formatUnits, parseUnits} from "ethers/lib/utils"; -import {ControllerMinimal, MockPawnshop, MockToken, MockVoter, VeDistributor, VeTetu} from "../../typechain"; -import {TimeUtils} from "../TimeUtils"; -import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; -import {Misc} from "../../scripts/utils/Misc"; -import {BigNumber} from "ethers"; - -const {expect} = chai; - -const WEEK = 60 * 60 * 24 * 7; -const LOCK_PERIOD = 60 * 60 * 24 * 90; - -describe.skip("VeDistributorWithAlwaysMaxLockTest", function () { - - let snapshotBefore: string; - let snapshot: string; - - let owner: SignerWithAddress; - let owner2: SignerWithAddress; - let owner3: SignerWithAddress; - let tetu: MockToken; - let controller: ControllerMinimal; - - let ve: VeTetu; - let voter: MockVoter; - let pawnshop: MockPawnshop; - let veDist: VeDistributor; - - - before(async function () { - snapshotBefore = await TimeUtils.snapshot(); - [owner, owner2, owner3] = await ethers.getSigners(); - - tetu = await DeployerUtils.deployMockToken(owner, 'TETU', 18); - controller = await DeployerUtils.deployMockController(owner); - ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - voter = await DeployerUtils.deployMockVoter(owner, ve.address); - pawnshop = await DeployerUtils.deployContract(owner, 'MockPawnshop') as MockPawnshop; - await controller.setVoter(voter.address); - await ve.announceAction(2); - await TimeUtils.advanceBlocksOnTs(60 * 60 * 18); - await ve.whitelistTransferFor(pawnshop.address); - - veDist = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve.address, - tetu.address, - ); - await controller.setVeDistributor(veDist.address); - - await tetu.mint(owner2.address, parseUnits('100')); - await tetu.approve(ve.address, Misc.MAX_UINT); - await tetu.connect(owner2).approve(ve.address, Misc.MAX_UINT); - await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - await ve.setAlwaysMaxLock(1, true); - await ve.connect(owner2).createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - // await ve.connect(owner2).setAlwaysMaxLock(2, true); - - await ve.setApprovalForAll(pawnshop.address, true); - await ve.connect(owner2).setApprovalForAll(pawnshop.address, true); - }); - - after(async function () { - await TimeUtils.rollback(snapshotBefore); - }); - - - beforeEach(async function () { - snapshot = await TimeUtils.snapshot(); - }); - - afterEach(async function () { - await TimeUtils.rollback(snapshot); - }); - - it("multi checkpointToken with empty balance test", async function () { - await tetu.transfer(veDist.address, parseUnits('10')); - await veDist.checkpoint(); - await veDist.checkpoint(); - }); - - it("adjustToDistribute test", async function () { - expect(await veDist.adjustToDistribute(100, 1, 1, 20)).eq(100); - expect(await veDist.adjustToDistribute(100, 0, 1, 20)).eq(100); - expect(await veDist.adjustToDistribute(100, 2, 1, 20)).eq(5); - }); - - it("checkpointTotalSupply dummy test", async function () { - await ve.checkpoint(); - await veDist.checkpointTotalSupply(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.checkpoint(); - await veDist.checkpointTotalSupply(); - }); - - it("adjustVeSupply test", async function () { - expect(await veDist.adjustVeSupply(100, 100, 5, 10)).eq(5); - expect(await veDist.adjustVeSupply(99, 100, 5, 10)).eq(0); - expect(await veDist.adjustVeSupply(200, 100, 5, 10)).eq(0); - expect(await veDist.adjustVeSupply(2, 1, 20, 5)).eq(15); - expect(await veDist.adjustVeSupply(3, 1, 20, 5)).eq(10); - }); - - it("claim for non exist token test", async function () { - await veDist.claim(99); - }); - - it("claim without rewards test", async function () { - await veDist.claim(1); - }); - - it("claim for early token test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address - ); - - await tetu.transfer(veDist.address, parseUnits('1')); - await veDist.checkpoint(); - - await veDist1.claim(1); - }); - - it("claimMany for early token test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address - ); - - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - - await veDist1.claimMany([1]); - }); - - it("claim for early token with delay test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address, - ); - - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await veDist1.claim(1); - await veDist1.claimMany([1]); - }); - - it("claimMany for early token with delay test", async function () { - const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); - - await tetu.approve(ve1.address, parseUnits('10000')) - await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - const veDist1 = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve1.address, - tetu.address, - ); - - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await veDist1.claimMany([1]); - }); - - it("claim with rewards test", async function () { - await ve.createLock(tetu.address, WEEK * 2, LOCK_PERIOD); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - - await tetu.transfer(veDist.address, parseUnits('1')); - await veDist.checkpoint(); - await veDist.checkpointTotalSupply(); - await veDist.claim(2); - }); - - it("claim without checkpoints after the launch should return zero", async function () { - await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); - const maxUserEpoch = await ve.userPointEpoch(2) - const startTime = await veDist.startTime(); - let weekCursor = await veDist.timeCursorOf(2); - let userEpoch; - if (weekCursor.isZero()) { - userEpoch = await veDist.findTimestampUserEpoch(ve.address, 2, startTime, maxUserEpoch); - } else { - userEpoch = await veDist.userEpochOf(2); - } - if (userEpoch.isZero()) { - userEpoch = BigNumber.from(1); - } - const userPoint = await ve.userPointHistory(2, userEpoch); - if (weekCursor.isZero()) { - weekCursor = userPoint.ts.add(WEEK).sub(1).div(WEEK).mul(WEEK); - } - const lastTokenTime = await veDist.lastTokenTime(); - expect(weekCursor.gte(lastTokenTime)).eq(true); - }); - - it("claim with rewards with minimal possible amount and lock", async function () { - await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await tetu.transfer(veDist.address, parseUnits('1')) - await veDist.checkpoint(); - await veDist.checkpointTotalSupply(); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - - let bal = await ve.balanceOfNFT(2) - expect(bal).above(0) - await veDist.claim(2); - expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.08')); - - // SECOND CLAIM - - await tetu.transfer(veDist.address, parseUnits('10000')) - await veDist.checkpoint(); - - await TimeUtils.advanceBlocksOnTs(123456); - - bal = await ve.balanceOfNFT(2) - await veDist.claim(2); - expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.38')); - }); - - it("claimMany on old block test", async function () { - await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); - await veDist.claimMany([1, 2, 0]); - }); - - it("timestamp test", async function () { - expect(await veDist.timestamp()).above(0); - }); - - it("claimable test", async function () { - await ve.createLock(tetu.address, parseUnits('1'), WEEK); - expect(await veDist.claimable(1)).eq(0); - }); - - it("claimMany test", async function () { - expect(+formatUnits(await tetu.balanceOf(veDist.address))).eq(0); - - await TimeUtils.advanceBlocksOnTs(LOCK_PERIOD); - await tetu.transfer(veDist.address, parseUnits('10000')) - await veDist.checkpoint(); - await veDist.claimMany([1, 2]); - - console.log('ve dist bal', +formatUnits(await tetu.balanceOf(veDist.address))) - expect(+formatUnits(await tetu.balanceOf(veDist.address))).lt(1500); - }); - - it("calculateToDistribute with zero values test", async function () { - await veDist.calculateToDistribute( - 0, - 0, - 999, - { - bias: 0, - slope: 0, - ts: 0, - blk: 0, - }, - 1, - 0, - ve.address - ); - }); - - -}); - - -export async function checkTotalVeSupply(ve: VeTetu) { - const total = +formatUnits(await ve.totalSupply()); - console.log('total', total) - const nftCount = (await ve.tokenId()).toNumber(); - - let sum = 0; - for (let i = 1; i <= nftCount; ++i) { - const bal = +formatUnits(await ve.balanceOfNFT(i)) - console.log('bal', i, bal) - sum += bal; - } - console.log('sum', sum) - expect(sum).approximately(total, 0.0000000000001); - console.log('total supply is fine') -} +// import {SignerWithAddress} from "@nomiclabs/hardhat-ethers/signers"; +// import {ethers} from "hardhat"; +// import chai from "chai"; +// import {formatUnits, parseUnits} from "ethers/lib/utils"; +// import {ControllerMinimal, MockPawnshop, MockToken, MockVoter, VeDistributor, VeTetu} from "../../typechain"; +// import {TimeUtils} from "../TimeUtils"; +// import {DeployerUtils} from "../../scripts/utils/DeployerUtils"; +// import {Misc} from "../../scripts/utils/Misc"; +// import {BigNumber} from "ethers"; +// +// const {expect} = chai; +// +// const WEEK = 60 * 60 * 24 * 7; +// const LOCK_PERIOD = 60 * 60 * 24 * 90; +// +// describe.skip("VeDistributorWithAlwaysMaxLockTest", function () { +// +// let snapshotBefore: string; +// let snapshot: string; +// +// let owner: SignerWithAddress; +// let owner2: SignerWithAddress; +// let owner3: SignerWithAddress; +// let tetu: MockToken; +// let controller: ControllerMinimal; +// +// let ve: VeTetu; +// let voter: MockVoter; +// let pawnshop: MockPawnshop; +// let veDist: VeDistributor; +// +// +// before(async function () { +// snapshotBefore = await TimeUtils.snapshot(); +// [owner, owner2, owner3] = await ethers.getSigners(); +// +// tetu = await DeployerUtils.deployMockToken(owner, 'TETU', 18); +// controller = await DeployerUtils.deployMockController(owner); +// ve = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// voter = await DeployerUtils.deployMockVoter(owner, ve.address); +// pawnshop = await DeployerUtils.deployContract(owner, 'MockPawnshop') as MockPawnshop; +// await controller.setVoter(voter.address); +// await ve.announceAction(2); +// await TimeUtils.advanceBlocksOnTs(60 * 60 * 18); +// await ve.whitelistTransferFor(pawnshop.address); +// +// veDist = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve.address, +// tetu.address, +// ); +// await controller.setVeDistributor(veDist.address); +// +// await tetu.mint(owner2.address, parseUnits('100')); +// await tetu.approve(ve.address, Misc.MAX_UINT); +// await tetu.connect(owner2).approve(ve.address, Misc.MAX_UINT); +// await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// await ve.setAlwaysMaxLock(1, true); +// await ve.connect(owner2).createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// // await ve.connect(owner2).setAlwaysMaxLock(2, true); +// +// await ve.setApprovalForAll(pawnshop.address, true); +// await ve.connect(owner2).setApprovalForAll(pawnshop.address, true); +// }); +// +// after(async function () { +// await TimeUtils.rollback(snapshotBefore); +// }); +// +// +// beforeEach(async function () { +// snapshot = await TimeUtils.snapshot(); +// }); +// +// afterEach(async function () { +// await TimeUtils.rollback(snapshot); +// }); +// +// it("multi checkpointToken with empty balance test", async function () { +// await tetu.transfer(veDist.address, parseUnits('10')); +// await veDist.checkpoint(); +// await veDist.checkpoint(); +// }); +// +// it("adjustToDistribute test", async function () { +// expect(await veDist.adjustToDistribute(100, 1, 1, 20)).eq(100); +// expect(await veDist.adjustToDistribute(100, 0, 1, 20)).eq(100); +// expect(await veDist.adjustToDistribute(100, 2, 1, 20)).eq(5); +// }); +// +// it("checkpointTotalSupply dummy test", async function () { +// await ve.checkpoint(); +// await veDist.checkpointTotalSupply(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await ve.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await ve.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await ve.checkpoint(); +// await veDist.checkpointTotalSupply(); +// }); +// +// it("adjustVeSupply test", async function () { +// expect(await veDist.adjustVeSupply(100, 100, 5, 10)).eq(5); +// expect(await veDist.adjustVeSupply(99, 100, 5, 10)).eq(0); +// expect(await veDist.adjustVeSupply(200, 100, 5, 10)).eq(0); +// expect(await veDist.adjustVeSupply(2, 1, 20, 5)).eq(15); +// expect(await veDist.adjustVeSupply(3, 1, 20, 5)).eq(10); +// }); +// +// it("claim for non exist token test", async function () { +// await veDist.claim(99); +// }); +// +// it("claim without rewards test", async function () { +// await veDist.claim(1); +// }); +// +// it("claim for early token test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')); +// await veDist.checkpoint(); +// +// await veDist1.claim(1); +// }); +// +// it("claimMany for early token test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// +// await veDist1.claimMany([1]); +// }); +// +// it("claim for early token with delay test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address, +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await veDist1.claim(1); +// await veDist1.claimMany([1]); +// }); +// +// it("claimMany for early token with delay test", async function () { +// const ve1 = await DeployerUtils.deployVeTetu(owner, tetu.address, controller.address); +// +// await tetu.approve(ve1.address, parseUnits('10000')) +// await ve1.createLock(tetu.address, parseUnits('1'), 60 * 60 * 24 * 14); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// const veDist1 = await DeployerUtils.deployVeDistributor( +// owner, +// controller.address, +// ve1.address, +// tetu.address, +// ); +// +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await veDist1.claimMany([1]); +// }); +// +// it("claim with rewards test", async function () { +// await ve.createLock(tetu.address, WEEK * 2, LOCK_PERIOD); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// +// await tetu.transfer(veDist.address, parseUnits('1')); +// await veDist.checkpoint(); +// await veDist.checkpointTotalSupply(); +// await veDist.claim(2); +// }); +// +// it("claim without checkpoints after the launch should return zero", async function () { +// await ve.createLock(tetu.address, parseUnits('1'), LOCK_PERIOD); +// const maxUserEpoch = await ve.userPointEpoch(2) +// const startTime = await veDist.startTime(); +// let weekCursor = await veDist.timeCursorOf(2); +// let userEpoch; +// if (weekCursor.isZero()) { +// userEpoch = await veDist.findTimestampUserEpoch(ve.address, 2, startTime, maxUserEpoch); +// } else { +// userEpoch = await veDist.userEpochOf(2); +// } +// if (userEpoch.isZero()) { +// userEpoch = BigNumber.from(1); +// } +// const userPoint = await ve.userPointHistory(2, userEpoch); +// if (weekCursor.isZero()) { +// weekCursor = userPoint.ts.add(WEEK).sub(1).div(WEEK).mul(WEEK); +// } +// const lastTokenTime = await veDist.lastTokenTime(); +// expect(weekCursor.gte(lastTokenTime)).eq(true); +// }); +// +// it("claim with rewards with minimal possible amount and lock", async function () { +// await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// await tetu.transfer(veDist.address, parseUnits('1')) +// await veDist.checkpoint(); +// await veDist.checkpointTotalSupply(); +// +// await TimeUtils.advanceBlocksOnTs(WEEK * 2); +// +// let bal = await ve.balanceOfNFT(2) +// expect(bal).above(0) +// await veDist.claim(2); +// expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.08')); +// +// // SECOND CLAIM +// +// await tetu.transfer(veDist.address, parseUnits('10000')) +// await veDist.checkpoint(); +// +// await TimeUtils.advanceBlocksOnTs(123456); +// +// bal = await ve.balanceOfNFT(2) +// await veDist.claim(2); +// expect((await tetu.balanceOf(await tetu.signer.getAddress())).sub(bal)).above(parseUnits('0.38')); +// }); +// +// it("claimMany on old block test", async function () { +// await ve.createLock(tetu.address, LOCK_PERIOD, WEEK); +// await veDist.claimMany([1, 2, 0]); +// }); +// +// it("timestamp test", async function () { +// expect(await veDist.timestamp()).above(0); +// }); +// +// it("claimable test", async function () { +// await ve.createLock(tetu.address, parseUnits('1'), WEEK); +// expect(await veDist.claimable(1)).eq(0); +// }); +// +// it("claimMany test", async function () { +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).eq(0); +// +// await TimeUtils.advanceBlocksOnTs(LOCK_PERIOD); +// await tetu.transfer(veDist.address, parseUnits('10000')) +// await veDist.checkpoint(); +// await veDist.claimMany([1, 2]); +// +// console.log('ve dist bal', +formatUnits(await tetu.balanceOf(veDist.address))) +// expect(+formatUnits(await tetu.balanceOf(veDist.address))).lt(1500); +// }); +// +// it("calculateToDistribute with zero values test", async function () { +// await veDist.calculateToDistribute( +// 0, +// 0, +// 999, +// { +// bias: 0, +// slope: 0, +// ts: 0, +// blk: 0, +// }, +// 1, +// 0, +// ve.address +// ); +// }); +// +// +// }); +// +// +// export async function checkTotalVeSupply(ve: VeTetu) { +// const total = +formatUnits(await ve.totalSupply()); +// console.log('total', total) +// const nftCount = (await ve.tokenId()).toNumber(); +// +// let sum = 0; +// for (let i = 1; i <= nftCount; ++i) { +// const bal = +formatUnits(await ve.balanceOfNFT(i)) +// console.log('bal', i, bal) +// sum += bal; +// } +// console.log('sum', sum) +// expect(sum).approximately(total, 0.0000000000001); +// console.log('total supply is fine') +// } diff --git a/test/ve/VeTetuTest.ts b/test/ve/VeTetuTest.ts index 11bd1d9..d437f35 100644 --- a/test/ve/VeTetuTest.ts +++ b/test/ve/VeTetuTest.ts @@ -50,14 +50,7 @@ describe("veTETU tests", function () { voter = await DeployerUtils.deployMockVoter(owner, ve.address); pawnshop = await DeployerUtils.deployContract(owner, 'MockPawnshop') as MockPawnshop; - const veDist = await DeployerUtils.deployVeDistributor( - owner, - controller.address, - ve.address, - tetu.address, - ); - - await controller.setVeDistributor(veDist.address); + await controller.setVoter(voter.address); await ve.announceAction(2); await TimeUtils.advanceBlocksOnTs(60 * 60 * 18); @@ -372,66 +365,16 @@ describe("veTETU tests", function () { await expect(ve.tokenURI(99)).revertedWith('TOKEN_NOT_EXIST'); }); - it("totalSupplyAt for new block revert", async function () { - await expect(ve.totalSupplyAt(Date.now() * 10)).revertedWith('WRONG_INPUT'); - }); - it("tokenUri for expired lock", async function () { await TimeUtils.advanceBlocksOnTs(60 * 60 * 24 * 365 * 5); expect(await ve.tokenURI(1)).not.eq(''); }); - it("totalSupplyAt for not exist epoch", async function () { - expect(await ve.totalSupplyAt(0)).eq(0); - }); - - it("totalSupplyAt for first epoch", async function () { - const start = (await ve.pointHistory(0)).blk; - expect(await ve.totalSupplyAt(start)).eq(0); - expect(await ve.totalSupplyAt(start.add(1))).eq(0); - }); - - it("totalSupplyAtT test", async function () { - const curBlock = await ethers.provider.getBlockNumber(); - const blockTs = await currentTS(ve); - expect(curBlock).not.eq(-1); - expect(blockTs).not.eq(-1); - const supply = +formatUnits(await ve.totalSupply()); - const supplyBlock = +formatUnits(await ve.totalSupplyAt(curBlock)); - const supplyTsNow = +formatUnits(await ve.totalSupplyAtT(blockTs)); - console.log('supply', supply); - console.log('supplyBlock', supplyBlock); - console.log('supplyTsNow', supplyTsNow); - - expect(supply).eq(supplyBlock); - expect(supplyTsNow).eq(supplyBlock); - - const supplyTs = +formatUnits(await ve.totalSupplyAtT(await currentEpochTS(ve))); - console.log('supplyTs', supplyTs); - - await checkTotalVeSupplyAtTS(ve, await currentEpochTS(ve) + WEEK) - - }); - - it("totalSupplyAt for second epoch", async function () { - const start = (await ve.pointHistory(1)).blk; - expect(await ve.totalSupplyAt(start)).not.eq(0); - expect(await ve.totalSupplyAt(start.add(1))).not.eq(0); - }); - it("checkpoint for a long period", async function () { await TimeUtils.advanceBlocksOnTs(WEEK * 10); await ve.checkpoint(); }); - it("balanceOfNFTAt with history test", async function () { - const cp0 = (await ve.userPointHistory(2, 0)); - await ve.balanceOfAtNFT(2, cp0.blk); - const cp1 = (await ve.userPointHistory(2, 1)); - await TimeUtils.advanceNBlocks(1); - await ve.balanceOfAtNFT(2, cp1.blk.add(1)); - }); - it("supportsInterface test", async function () { expect(await ve.supportsInterface('0x00000000')).is.eq(false); }); @@ -491,70 +434,6 @@ describe("veTETU tests", function () { // expect(svg).contains('88 days') }); - it("balanceOfNFTAt test", async function () { - // ve #3 - await ve.createLock(tetu.address, parseUnits('100'), LOCK_PERIOD); - const tId = 3; - - const blockTsB = await currentTS(ve); - const blockTs = await currentTS(ve); - const current = +formatUnits(await ve.balanceOfNFTAt(tId, blockTs)); - console.log('>>> current', current); - expect(current).approximately(75, 15); - const zero = +formatUnits(await ve.balanceOfNFTAt(tId, 0)); - const future = +formatUnits(await ve.balanceOfNFTAt(tId, 999_999_999_999)); - const beforeLock = +formatUnits(await ve.balanceOfNFTAt(tId, blockTsB - 1000)); - expect(zero).eq(0); - expect(future).eq(0); - expect(beforeLock).eq(0); - - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.increaseAmount(tetu.address, tId, parseUnits('1000')); - - const blockTsA = await currentTS(ve); - const beforeLockAfterIncrease = +formatUnits(await ve.balanceOfNFTAt(tId, blockTsA - 1000)); - console.log('>>> beforeLockAfterIncrease', beforeLockAfterIncrease); - expect(beforeLockAfterIncrease).approximately(75, 15); - - const currentA = +formatUnits(await ve.balanceOfNFTAt(tId, blockTsA)); - console.log('>>> currentA', currentA); - expect(currentA).approximately(700, 150); - }); - - it("balanceOfAtNFT test", async function () { - await TimeUtils.advanceNBlocks(100) - // ve #3 - await ve.createLock(tetu.address, parseUnits('100'), LOCK_PERIOD); - const tId = 3; - - const curBlockB = await ethers.provider.getBlockNumber(); - - - const curBlock = await ethers.provider.getBlockNumber(); - const current = +formatUnits(await ve.balanceOfAtNFT(tId, curBlock)); - console.log('>>> current', current); - expect(current).approximately(75, 15); - const zero = +formatUnits(await ve.balanceOfAtNFT(tId, 0)); - const future = +formatUnits(await ve.balanceOfAtNFT(tId, 999_999_999_999)); - const beforeLock = +formatUnits(await ve.balanceOfAtNFT(tId, curBlockB - 10)); - expect(zero).eq(0); - expect(future).eq(0); - expect(beforeLock).eq(0); - - await TimeUtils.advanceNBlocks(100) - await TimeUtils.advanceBlocksOnTs(WEEK * 2); - await ve.increaseAmount(tetu.address, tId, parseUnits('1000')); - - const curBlockA = await ethers.provider.getBlockNumber(); - const beforeLockAfterIncrease = +formatUnits(await ve.balanceOfAtNFT(tId, curBlockA - 10)); - console.log('>>> beforeLockAfterIncrease', beforeLockAfterIncrease); - expect(beforeLockAfterIncrease).approximately(75, 15); - - const currentA = +formatUnits(await ve.balanceOfAtNFT(tId, curBlockA)); - console.log('>>> currentA', currentA); - expect(currentA).approximately(700, 150); - }); - it("ve flesh transfer + supply checks", async function () { await pawnshop.veFlashTransfer(ve.address, 1); }); From fc4c48ec03c7b623f40286f8dce0fa589d35171a Mon Sep 17 00:00:00 2001 From: belbix <7453635@gmail.com> Date: Sat, 6 Apr 2024 14:47:52 +0300 Subject: [PATCH 2/3] remove ve historical balances fix --- contracts/infrastructure/ControllerV2.sol | 2 +- contracts/test/ControllerMinimal.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/infrastructure/ControllerV2.sol b/contracts/infrastructure/ControllerV2.sol index dc131f3..4f69d38 100644 --- a/contracts/infrastructure/ControllerV2.sol +++ b/contracts/infrastructure/ControllerV2.sol @@ -72,7 +72,7 @@ contract ControllerV2 is ControllableV3, IController { /// @dev Contract for holding assets for the Second Stage address public override investFund; /// @dev Contract for accumulate TETU rewards for veTETU and weekly distribute them. - address public override veDistributor; + address public veDistributor; /// @dev Special voter for platform attributes. address public override platformVoter; diff --git a/contracts/test/ControllerMinimal.sol b/contracts/test/ControllerMinimal.sol index efdc783..379eb64 100644 --- a/contracts/test/ControllerMinimal.sol +++ b/contracts/test/ControllerMinimal.sol @@ -14,7 +14,7 @@ contract ControllerMinimal is TetuERC165, IController { address public override liquidator; address public override forwarder; address public override investFund; - address public override veDistributor; + address public veDistributor; address public override platformVoter; address[] public override vaults; mapping(address => bool) public operators; From e4c471c793d4e0c7196a2d8124d35ba6bca8ec84 Mon Sep 17 00:00:00 2001 From: belbix <7453635@gmail.com> Date: Tue, 24 Sep 2024 13:54:33 +0300 Subject: [PATCH 3/3] bump ver for ve tetu --- contracts/ve/VeTetu.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/ve/VeTetu.sol b/contracts/ve/VeTetu.sol index 94ab44d..0c31e0c 100644 --- a/contracts/ve/VeTetu.sol +++ b/contracts/ve/VeTetu.sol @@ -54,7 +54,7 @@ contract VeTetu is ControllableV3, ReentrancyGuard, IVeTetu { // ************************************************************* /// @dev Version of this contract. Adjust manually on each code modification. - string public constant VE_VERSION = "1.3.4"; + string public constant VE_VERSION = "1.3.5"; uint internal constant WEEK = 1 weeks; uint internal constant MAX_TIME = 16 weeks; uint public constant MAX_ATTACHMENTS = 1;