diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol new file mode 100644 index 00000000..b7ef0e11 --- /dev/null +++ b/contracts/AutoBribe.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: MIT + +import "openzeppelin-contracts/contracts/access/Ownable.sol"; +import "contracts/interfaces/ITurnstile.sol"; +import "contracts/interfaces/IERC20.sol"; +import "contracts/interfaces/IVoter.sol"; +import "contracts/WrappedBribe.sol"; + +pragma solidity ^0.8.13; + +// the purpose of this contract is to allow the projects to deposit bribes that will bribe their pools for a period of time +// they will need to set up a public keeper, anyone can send the bribes +// bribes are divided evenly into the amount of weeks designated when they deposit +// each new deposit will NOT make a bribe immediately! +// calling the bribe function is public and is rewarded with a share of the bribe token +// !!!!!!!!!!!this contract handles multiple bribe tokens, and a single bribe contract!!!!!!!!! + +contract AutoBribe is Ownable { + address public constant TURNSTILE = + 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public immutable voter; + address public immutable wBribe; + + address public project; + bool public depositSealed; + bool public initialized; + uint256 public nextWeek; + address[] public bribeTokens; + mapping(address => bool) public bribeTokensDeposited; + mapping(address => uint256) public bribeTokenToWeeksLeft; + string public bribeName; + + event Deposited( + address indexed _bribeToken, + uint256 _amount, + uint256 _weeks + ); + event Bribed(uint256 indexed _timestamp, address _briber); + event EmptiedOut(uint256 indexed _timestamp, address project); + event Sealed(uint256 indexed _timestamp); + event UnSealed(uint256 indexed _timestamp); + + constructor( + address _voter, + address _wBribe, + address _team, + string memory _name, + uint256 _csrNftId + ) { + voter = _voter; + wBribe = _wBribe; + nextWeek = block.timestamp; + _transferOwnership(_team); + ITurnstile(TURNSTILE).assign(_csrNftId); + bribeName = _name; + } + + //######################################## + //###########PUBLIC FUNCTIONS############# + //######################################## + + //This public function allows anyone to send the weekly allocation to the bribe contract + //There is a small reward for calling this function + //It can only be called once a week + function bribe() public { + require(block.timestamp >= nextWeek, "already bribed this week"); + uint256 length = bribeTokens.length; + address _bribeToken; + for (uint256 i = 0; i < length; ) { + _bribeToken = bribeTokens[i]; + uint256 weeksLeft = bribeTokenToWeeksLeft[_bribeToken]; + uint256 bribeAmount = balance(_bribeToken) / weeksLeft; + uint256 gasReward = bribeAmount / 200; + _safeTransfer(_bribeToken, msg.sender, gasReward); + WrappedBribe(wBribe).notifyRewardAmount( + _bribeToken, + bribeAmount - gasReward + ); + bribeTokenToWeeksLeft[_bribeToken] = weeksLeft - 1; + unchecked { + ++i; + } + } + nextWeek = nextWeek + 604800; + emit Bribed(nextWeek, msg.sender); + } + + //This just returns the balance of bribe tokens in the contract + function balance(address _bribeToken) public view returns (uint) { + return IERC20(_bribeToken).balanceOf(address(this)); + } + + //######################################## + //########PROJECT ADMIN FUNCTIONS######### + //######################################## + + //Allows project to deposit bribe tokens and set the weeks of which they are divided up into + function deposit( + address _bribeToken, + uint256 _amount, + uint256 _weeks + ) public { + require(msg.sender == project, "only the project can bribe"); + require(_amount > 0, "Why are you depositing 0 tokens?"); + require(_weeks > 0, "You have to put at least 1 week"); + require( + IVoter(voter).isWhitelisted(_bribeToken), + "Bribe Token is not whitelisted" + ); + _safeTransferFrom(_bribeToken, msg.sender, address(this), _amount); + uint256 allowance = IERC20(_bribeToken).allowance( + address(this), + wBribe + ); + _safeApprove(_bribeToken, wBribe, allowance + _amount); + if (!bribeTokensDeposited[_bribeToken]) { + bribeTokensDeposited[_bribeToken] = true; + bribeTokens.push(_bribeToken); + } + bribeTokenToWeeksLeft[_bribeToken] += _weeks; + + emit Deposited(_bribeToken, _amount, _weeks); + } + + //Allows the project to retrieve their bribe tokens + function emptyOut() public { + require(msg.sender == project, "only project can empty out"); + require(!depositSealed, "deposit is sealed"); + uint256 length = bribeTokens.length; + uint256 amount; + + for (uint256 i = 0; i < length; ) { + address bribeToken = bribeTokens[i]; + amount = balance(bribeToken); + bribeTokenToWeeksLeft[bribeToken] = 0; + _safeTransfer(bribeToken, msg.sender, amount); + + unchecked { + ++i; + } + } + + emit EmptiedOut(block.timestamp, project); + } + + //Allows project to seal the vault making it not possible for them to withdraw their tokens + function seal() public { + require(msg.sender == project, "only project can seal"); + depositSealed = true; + + emit Sealed(block.timestamp); + } + + //Allows project to change their controlling wallet + function setProject(address _newWallet) public { + require(msg.sender == project); + project = _newWallet; + } + + //######################################## + //#######VELOCIMETER ADMIN FUNCTIONS###### + //######################################## + + //Allows Velocimeter to re allow project to withdraw their tokens + function unSeal() public onlyOwner { + depositSealed = false; + + emit UnSealed(block.timestamp); + } + + function initProject(address _newWallet) public onlyOwner { + require(!initialized, "project wallet can only be set once by team"); + if (!initialized) { + initialized = true; + } + project = _newWallet; + } + + function inCaseTokensGetStuck(address _token) external onlyOwner { + require(!bribeTokensDeposited[_token], "!bribeToken"); + uint256 amount = IERC20(_token).balanceOf(address(this)); + _safeTransfer(_token, msg.sender, amount); + } + + //######################################## + //############RECLOCK FUNCTION############ + //######################################## + + // Allows project or Velocimeter to reset the week to the current block + // This should only be called with consideration as it can allow for double bribes in a single week. + // Best use is to call it BEFORE, bribe() is called in a given week + function reclockBribeToNow() external { + require( + msg.sender == project || msg.sender == owner(), + "you can't call this" + ); + nextWeek = block.timestamp; + } + + //######################################## + //############INTERNAL FUNCTIONS########## + //######################################## + + function _safeTransfer(address token, address to, uint256 value) internal { + require(token.code.length > 0); + (bool success, bytes memory data) = token.call( + abi.encodeWithSelector(IERC20.transfer.selector, to, value) + ); + require(success && (data.length == 0 || abi.decode(data, (bool)))); + } + + function _safeTransferFrom( + address token, + address from, + address to, + uint256 value + ) internal { + require(token.code.length > 0); + (bool success, bytes memory data) = token.call( + abi.encodeWithSelector( + IERC20.transferFrom.selector, + from, + to, + value + ) + ); + require(success && (data.length == 0 || abi.decode(data, (bool)))); + } + + function _safeApprove(address token, address spender, uint value) internal { + require(token.code.length > 0); + (bool success, bytes memory data) = token.call( + abi.encodeWithSelector(IERC20.approve.selector, spender, value) + ); + require(success && (data.length == 0 || abi.decode(data, (bool)))); + } +} diff --git a/contracts/ExternalBribe.sol b/contracts/ExternalBribe.sol index 41ce2031..7debc02d 100644 --- a/contracts/ExternalBribe.sol +++ b/contracts/ExternalBribe.sol @@ -7,9 +7,11 @@ import 'contracts/interfaces/IERC20.sol'; import 'contracts/interfaces/IGauge.sol'; import 'contracts/interfaces/IVoter.sol'; import 'contracts/interfaces/IVotingEscrow.sol'; +import 'contracts/interfaces/ITurnstile.sol'; // Bribes pay out rewards for a given pool based on the votes that were received from the user (goes hand in hand with Voter.vote()) contract ExternalBribe is IBribe { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable voter; // only voter can modify balances (since it only happens on vote()) address public immutable _ve; // 天使のたまご @@ -51,7 +53,7 @@ contract ExternalBribe is IBribe { event NotifyReward(address indexed from, address indexed reward, uint epoch, uint amount); event ClaimRewards(address indexed from, address indexed reward, uint amount); - constructor(address _voter, address[] memory _allowedRewardTokens) { + constructor(address _voter, address[] memory _allowedRewardTokens, uint256 _csrNftId) { voter = _voter; _ve = IVoter(_voter)._ve(); @@ -61,6 +63,8 @@ contract ExternalBribe is IBribe { rewards.push(_allowedRewardTokens[i]); } } + + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check @@ -290,7 +294,12 @@ contract ExternalBribe is IBribe { uint adjustedTstamp = getEpochStart(block.timestamp); uint epochRewards = tokenRewardsPerEpoch[token][adjustedTstamp]; + uint256 balanceBefore = IERC20(token).balanceOf(address(this)); _safeTransferFrom(token, msg.sender, address(this), amount); + uint256 balanceAfter = IERC20(token).balanceOf(address(this)); + + amount = balanceAfter - balanceBefore; + tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount; periodFinish[token] = adjustedTstamp + DURATION; diff --git a/contracts/Flow.sol b/contracts/Flow.sol index f9c48e73..b0caab09 100644 --- a/contracts/Flow.sol +++ b/contracts/Flow.sol @@ -2,13 +2,15 @@ pragma solidity 0.8.13; import "contracts/interfaces/IFlow.sol"; +import 'contracts/interfaces/ITurnstile.sol'; contract Flow is IFlow { - + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; string public constant name = "Velocimeter"; string public constant symbol = "FLOW"; uint8 public constant decimals = 18; uint public totalSupply = 0; + uint256 public immutable csrNftId; mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; @@ -18,9 +20,11 @@ contract Flow is IFlow { event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); - constructor(address initialSupplyRecipient) { + constructor(address initialSupplyRecipient, address csrRecipient) { minter = msg.sender; - _mint(initialSupplyRecipient, 300 * 1e6 * 1e18); + _mint(initialSupplyRecipient, 82800140034502500000000000); + + csrNftId = ITurnstile(TURNSTILE).register(csrRecipient); } // No checks as its meant to be once off to set minting rights to BaseV1 Minter diff --git a/contracts/FlowConvertor.sol b/contracts/FlowConvertor.sol index 116e5460..a5cc7296 100644 --- a/contracts/FlowConvertor.sol +++ b/contracts/FlowConvertor.sol @@ -29,9 +29,8 @@ contract FlowConvertor is Ownable { address(this), amount ); - SafeERC20.safeTransferFrom( + SafeERC20.safeTransfer( IERC20(v2), - address(this), _msgSender(), amount ); @@ -48,7 +47,7 @@ contract FlowConvertor is Ownable { address(this), amount ); - SafeERC20.safeTransferFrom(IERC20(v2), address(this), _to, amount); + SafeERC20.safeTransfer(IERC20(v2), _to, amount); } /** @@ -70,4 +69,4 @@ contract FlowConvertor is Ownable { uint256 _surplus = IERC20(v2).balanceOf(address(this)); SafeERC20.safeTransfer(IERC20(v2), _to, _surplus); } -} +} \ No newline at end of file diff --git a/contracts/FlowVestor.sol b/contracts/FlowVestor.sol index 2ee2f53d..9b2a16ff 100644 --- a/contracts/FlowVestor.sol +++ b/contracts/FlowVestor.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT AND AGPL-3.0-or-later -pragma solidity ^0.8.0; +pragma solidity 0.8.13; import "openzeppelin-contracts/contracts/access/Ownable.sol"; import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; @@ -63,10 +63,8 @@ contract FlowVestor is Ownable { * Additionally, it transfers ownership to the Owner contract that needs to consequently * initiate the vesting period via {begin} after it mints the necessary amount to the contract. */ - constructor(address _admin, address _FLOW) { - require(_admin != _ZERO_ADDRESS, "Misconfiguration"); + constructor(address _FLOW) { FLOW = IERC20(_FLOW); - transferOwnership(_admin); } /* ========== VIEWS ========== */ diff --git a/contracts/Gauge.sol b/contracts/Gauge.sol index 424f2461..b4dc9d43 100644 --- a/contracts/Gauge.sol +++ b/contracts/Gauge.sol @@ -8,10 +8,11 @@ import 'contracts/interfaces/IGauge.sol'; import 'contracts/interfaces/IPair.sol'; import 'contracts/interfaces/IVoter.sol'; import 'contracts/interfaces/IVotingEscrow.sol'; +import 'contracts/interfaces/ITurnstile.sol'; // Gauges are used to incentivize pools, they emit reward tokens over 7 days for staked LP tokens contract Gauge is IGauge { - + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable stake; // the LP token that needs to be staked for rewards address public immutable _ve; // the ve token used for gauges address public immutable external_bribe; @@ -23,7 +24,8 @@ contract Gauge is IGauge { bool public isForPair; uint internal constant DURATION = 7 days; // rewards are released over 7 days - uint internal constant MAX_REWARD_TOKENS = 16; + uint internal constant PRECISION = 10 ** 18; + uint internal constant MAX_REWARD_TOKENS = 4; // default snx staking contract implementation mapping(address => uint) public rewardRate; @@ -81,7 +83,7 @@ contract Gauge is IGauge { event NotifyReward(address indexed from, address indexed reward, uint amount); event ClaimRewards(address indexed from, address indexed reward, uint amount); - constructor(address _stake, address _external_bribe, address __ve, address _voter, bool _forPair, address[] memory _allowedRewardTokens) { + constructor(address _stake, address _external_bribe, address __ve, address _voter, bool _forPair, address[] memory _allowedRewardTokens, uint256 _csrNftId) { stake = _stake; external_bribe = _external_bribe; _ve = __ve; @@ -94,6 +96,8 @@ contract Gauge is IGauge { rewards.push(_allowedRewardTokens[i]); } } + + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check @@ -284,7 +288,7 @@ contract Gauge is IGauge { if (derivedSupply == 0) { return rewardPerTokenStored[token]; } - return rewardPerTokenStored[token] + ((lastTimeRewardApplicable(token) - Math.min(lastUpdateTime[token], periodFinish[token])) * rewardRate[token] * (10**IERC20(token).decimals()) / derivedSupply); + return rewardPerTokenStored[token] + ((lastTimeRewardApplicable(token) - Math.min(lastUpdateTime[token], periodFinish[token])) * rewardRate[token] * PRECISION / derivedSupply); } function derivedBalance(address account) public view returns (uint) { @@ -326,7 +330,7 @@ contract Gauge is IGauge { function _calcRewardPerToken(address token, uint timestamp1, uint timestamp0, uint supply, uint startTimestamp) internal view returns (uint, uint) { uint endTime = Math.max(timestamp1, startTimestamp); - return (((Math.min(endTime, periodFinish[token]) - Math.min(Math.max(timestamp0, startTimestamp), periodFinish[token])) * rewardRate[token] * (10**IERC20(token).decimals()) / supply), endTime); + return (((Math.min(endTime, periodFinish[token]) - Math.min(Math.max(timestamp0, startTimestamp), periodFinish[token])) * rewardRate[token] * PRECISION / supply), endTime); } /// @dev Update stored rewardPerToken values without the last one snapshot @@ -403,13 +407,13 @@ contract Gauge is IGauge { Checkpoint memory cp1 = checkpoints[account][i+1]; (uint _rewardPerTokenStored0,) = getPriorRewardPerToken(token, cp0.timestamp); (uint _rewardPerTokenStored1,) = getPriorRewardPerToken(token, cp1.timestamp); - reward += cp0.balanceOf * (_rewardPerTokenStored1 - _rewardPerTokenStored0) / (10**IERC20(token).decimals()); + reward += cp0.balanceOf * (_rewardPerTokenStored1 - _rewardPerTokenStored0) / PRECISION; } } Checkpoint memory cp = checkpoints[account][_endIndex]; (uint _rewardPerTokenStored,) = getPriorRewardPerToken(token, cp.timestamp); - reward += cp.balanceOf * (rewardPerToken(token) - Math.max(_rewardPerTokenStored, userRewardPerTokenStored[token][account])) / (10**IERC20(token).decimals()); + reward += cp.balanceOf * (rewardPerToken(token) - Math.max(_rewardPerTokenStored, userRewardPerTokenStored[token][account])) / PRECISION; return reward; } @@ -507,13 +511,19 @@ contract Gauge is IGauge { (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true); if (block.timestamp >= periodFinish[token]) { + uint256 balanceBefore = IERC20(token).balanceOf(address(this)); _safeTransferFrom(token, msg.sender, address(this), amount); + uint256 balanceAfter = IERC20(token).balanceOf(address(this)); + amount = balanceAfter - balanceBefore; rewardRate[token] = amount / DURATION; } else { uint _remaining = periodFinish[token] - block.timestamp; uint _left = _remaining * rewardRate[token]; require(amount > _left); + uint256 balanceBefore = IERC20(token).balanceOf(address(this)); _safeTransferFrom(token, msg.sender, address(this), amount); + uint256 balanceAfter = IERC20(token).balanceOf(address(this)); + amount = balanceAfter - balanceBefore; rewardRate[token] = (amount + _left) / DURATION; } require(rewardRate[token] > 0); diff --git a/contracts/Minter.sol b/contracts/Minter.sol index 6ee5e8e2..c20ef892 100644 --- a/contracts/Minter.sol +++ b/contracts/Minter.sol @@ -8,10 +8,12 @@ import "contracts/interfaces/IRewardsDistributor.sol"; import "contracts/interfaces/IFlow.sol"; import "contracts/interfaces/IVoter.sol"; import "contracts/interfaces/IVotingEscrow.sol"; +import 'contracts/interfaces/ITurnstile.sol'; // codifies the minting rules as per ve(3,3), abstracted from the token to support any token that allows minting contract Minter is IMinter { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; uint internal constant WEEK = 86400 * 7; // allows minting once per week (reset every Thursday 00:00 UTC) uint internal constant EMISSION = 990; uint internal constant TAIL_EMISSION = 2; @@ -20,9 +22,8 @@ contract Minter is IMinter { IVoter public immutable _voter; IVotingEscrow public immutable _ve; IRewardsDistributor public immutable _rewards_distributor; - uint public weekly = 15_000_000 * 1e18; // represents a starting weekly emission of 15M FLOW (FLOW has 18 decimals) + uint public weekly = 13_000_000 * 1e18; // represents a starting weekly emission of 13M FLOW (FLOW has 18 decimals) uint public active_period; - uint internal constant LOCK = 86400 * 7 * 52 * 4; address internal initializer; address public team; @@ -32,10 +33,17 @@ contract Minter is IMinter { event Mint(address indexed sender, uint weekly, uint circulating_supply, uint circulating_emission); + struct Claim { + address claimant; + uint256 amount; + uint256 lockTime; + } + constructor( address __voter, // the voting & distribution system address __ve, // the ve(3,3) system that will be locked into - address __rewards_distributor // the distribution system that ensures users aren't diluted + address __rewards_distributor, // the distribution system that ensures users aren't diluted + uint256 _csrNftId ) { initializer = msg.sender; team = msg.sender; @@ -45,21 +53,30 @@ contract Minter is IMinter { _ve = IVotingEscrow(__ve); _rewards_distributor = IRewardsDistributor(__rewards_distributor); active_period = ((block.timestamp + (2 * WEEK)) / WEEK) * WEEK; + ITurnstile(TURNSTILE).assign(_csrNftId); } - function initialize( - address[] memory claimants, // partnerAddrs - uint[] memory amounts, // partnerAmounts + function initialMintAndLock( + Claim[] calldata claims, uint max // sum amounts / max = % ownership of top protocols, so if initial 20m is distributed, and target is 25% protocol ownership, then max - 4 x 20m = 80m ) external { - require(initializer == msg.sender); + require(initializer == msg.sender, "not initializer"); _flow.mint(address(this), max); - _flow.approve(address(_ve), type(uint).max); - for (uint i = 0; i < claimants.length; i++) { - _ve.create_lock_for(amounts[i], LOCK, claimants[i]); + _flow.approve(address(_ve), max); + uint256 length = claims.length; + for (uint i = 0; i < length;) { + _ve.create_lock_for(claims[i].amount, claims[i].lockTime, claims[i].claimant); + unchecked { + ++i; + } } + } + + function startActivePeriod() external { + require(initializer == msg.sender, "not initializer"); initializer = address(0); - active_period = ((block.timestamp) / WEEK) * WEEK; // allow minter.update_period() to mint new emissions THIS Thursday + // allow minter.update_period() to mint new emissions THIS Thursday + active_period = ((block.timestamp) / WEEK) * WEEK; } function setTeam(address _team) external { diff --git a/contracts/Pair.sol b/contracts/Pair.sol index 7f9e1ba4..943b5d24 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -5,13 +5,13 @@ import 'openzeppelin-contracts/contracts/utils/math/Math.sol'; import 'contracts/interfaces/IERC20.sol'; import 'contracts/interfaces/IPair.sol'; import 'contracts/interfaces/IPairCallee.sol'; -import 'contracts/factories/PairFactory.sol'; - +import 'contracts/interfaces/IPairFactory.sol'; import 'contracts/interfaces/IBribe.sol'; +import 'contracts/interfaces/ITurnstile.sol'; // The base pair of pools, either stable or volatile contract Pair is IPair { - + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; string public name; string public symbol; uint8 public constant decimals = 18; @@ -36,7 +36,6 @@ contract Pair is IPair { address immutable factory; address public externalBribe; address public voter; - address public immutable tank; bool public hasGauge; // Structure to capture time period obervations every 30 minutes, used for local oracles @@ -61,8 +60,8 @@ contract Pair is IPair { uint public reserve0CumulativeLast; uint public reserve1CumulativeLast; - event TankFees(address indexed token, uint amount0, address tank); - event GaugeFees(address indexed token, uint amount0, address externalBribe); + event TankFees(address indexed token, uint amount, address tank); + event GaugeFees(address indexed token, uint amount, address externalBribe); event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( @@ -78,14 +77,13 @@ contract Pair is IPair { event Transfer(address indexed from, address indexed to, uint amount); event Approval(address indexed owner, address indexed spender, uint amount); - event ExternalBribeSet(address indexed setter, address indexed externalBribe); - event HasGaugeSet(address indexed setter, bool value); + event ExternalBribeSet(address indexed externalBribe); + event HasGaugeSet(bool value); constructor() { factory = msg.sender; - voter = PairFactory(msg.sender).voter(); - tank = PairFactory(msg.sender).tank(); - (address _token0, address _token1, bool _stable) = PairFactory(msg.sender).getInitializable(); + voter = IPairFactory(msg.sender).voter(); + (address _token0, address _token1, bool _stable) = IPairFactory(msg.sender).getInitializable(); (token0, token1, stable) = (_token0, _token1, _stable); if (_stable) { name = string(abi.encodePacked("StableV1 AMM - ", IERC20(_token0).symbol(), "/", IERC20(_token1).symbol())); @@ -99,6 +97,9 @@ contract Pair is IPair { decimals1 = 10**IERC20(_token1).decimals(); observations.push(Observation(block.timestamp, 0, 0)); + + uint256 _csrNftId = IPairFactory(msg.sender).csrNftId(); + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check @@ -116,19 +117,23 @@ contract Pair is IPair { require(success && (data.length == 0 || abi.decode(data, (bool)))); } + function tank() public view returns (address) { + return IPairFactory(factory).tank(); + } + function setExternalBribe(address _externalBribe) external { require(externalBribe == address(0), 'External bribe has already been set.'); require(msg.sender == voter, 'Only voter can set external bribe'); externalBribe = _externalBribe; _safeApprove(token0, externalBribe, type(uint).max); _safeApprove(token1, externalBribe, type(uint).max); - emit ExternalBribeSet(msg.sender, _externalBribe); + emit ExternalBribeSet(_externalBribe); } function setHasGauge(bool value) external { require(msg.sender == voter, 'Only voter can set has gauge'); hasGauge = value; - emit HasGaugeSet(msg.sender, value); + emit HasGaugeSet(value); } function observationLength() external view returns (uint) { @@ -153,8 +158,9 @@ contract Pair is IPair { IBribe(externalBribe).notifyRewardAmount(token, amount); // transfer fees to exBribes emit GaugeFees(token, amount, externalBribe); } else { - _safeTransfer(token, tank, amount); // transfer the fees to tank MSig for gaugeless LPs - emit TankFees(token, amount, tank); + address _tank = tank(); + _safeTransfer(token, _tank, amount); // transfer the fees to tank MSig for gaugeless LPs + emit TankFees(token, amount, _tank); } } } @@ -300,7 +306,7 @@ contract Pair is IPair { // this low-level function should be called from a contract which performs important safety checks function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { - require(!PairFactory(factory).isPaused()); + require(!IPairFactory(factory).isPaused()); require(amount0Out > 0 || amount1Out > 0, 'IOA'); // Pair: INSUFFICIENT_OUTPUT_AMOUNT (uint _reserve0, uint _reserve1) = (reserve0, reserve1); require(amount0Out < _reserve0 && amount1Out < _reserve1, 'IL'); // Pair: INSUFFICIENT_LIQUIDITY @@ -321,8 +327,8 @@ contract Pair is IPair { require(amount0In > 0 || amount1In > 0, 'IIA'); // Pair: INSUFFICIENT_INPUT_AMOUNT { // scope for reserve{0,1}Adjusted, avoids stack too deep errors (address _token0, address _token1) = (token0, token1); - if (amount0In > 0) _sendTokenFees(token0, amount0In * PairFactory(factory).getFee(stable) / 10000); - if (amount1In > 0) _sendTokenFees(token1, amount1In * PairFactory(factory).getFee(stable) / 10000); + if (amount0In > 0) _sendTokenFees(token0, amount0In * IPairFactory(factory).getFee(stable) / 10000); + if (amount1In > 0) _sendTokenFees(token1, amount1In * IPairFactory(factory).getFee(stable) / 10000); _balance0 = IERC20(_token0).balanceOf(address(this)); // since we removed tokens, we need to reconfirm balances, can also simply use previous balance - amountIn/ 10000, but doing balanceOf again as safety check _balance1 = IERC20(_token1).balanceOf(address(this)); // The curve, either x3y+y3x for stable pools, or x*y for volatile pools @@ -379,7 +385,7 @@ contract Pair is IPair { function getAmountOut(uint amountIn, address tokenIn) external view returns (uint) { (uint _reserve0, uint _reserve1) = (reserve0, reserve1); - amountIn -= amountIn * PairFactory(factory).getFee(stable) / 10000; // remove fee from amount received + amountIn -= amountIn * IPairFactory(factory).getFee(stable) / 10000; // remove fee from amount received return _getAmountOut(amountIn, tokenIn, _reserve0, _reserve1); } diff --git a/contracts/RewardsDistributor.sol b/contracts/RewardsDistributor.sol index 3fc74bce..315248dd 100644 --- a/contracts/RewardsDistributor.sol +++ b/contracts/RewardsDistributor.sol @@ -5,6 +5,7 @@ import 'openzeppelin-contracts/contracts/utils/math/Math.sol'; import 'contracts/interfaces/IERC20.sol'; import 'contracts/interfaces/IRewardsDistributor.sol'; import 'contracts/interfaces/IVotingEscrow.sol'; +import 'contracts/interfaces/ITurnstile.sol'; /* @@ -28,6 +29,7 @@ contract RewardsDistributor is IRewardsDistributor { uint max_epoch ); + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; uint constant WEEK = 7 * 86400; uint public start_time; @@ -46,7 +48,7 @@ contract RewardsDistributor is IRewardsDistributor { address public depositor; - constructor(address _voting_escrow) { + constructor(address _voting_escrow, uint256 _csrNftId) { uint _t = block.timestamp / WEEK * WEEK; start_time = _t; last_token_time = _t; @@ -56,6 +58,7 @@ contract RewardsDistributor is IRewardsDistributor { voting_escrow = _voting_escrow; depositor = msg.sender; require(IERC20(_token).approve(_voting_escrow, type(uint).max)); + ITurnstile(TURNSTILE).assign(_csrNftId); } function timestamp() external view returns (uint) { diff --git a/contracts/Router.sol b/contracts/Router.sol index 03e3beff..4e75a4f3 100644 --- a/contracts/Router.sol +++ b/contracts/Router.sol @@ -8,6 +8,7 @@ import 'contracts/interfaces/IPair.sol'; import 'contracts/interfaces/IPairFactory.sol'; import 'contracts/interfaces/IRouter.sol'; import 'contracts/interfaces/IWETH.sol'; +import 'contracts/interfaces/ITurnstile.sol'; contract Router is IRouter { @@ -17,6 +18,7 @@ contract Router is IRouter { bool stable; } + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable factory; IWETH public immutable weth; uint internal constant MINIMUM_LIQUIDITY = 10**3; @@ -27,10 +29,11 @@ contract Router is IRouter { _; } - constructor(address _factory, address _weth) { + constructor(address _factory, address _weth, uint256 _csrNftId) { factory = _factory; pairCodeHash = IPairFactory(_factory).pairCodeHash(); weth = IWETH(_weth); + ITurnstile(TURNSTILE).assign(_csrNftId); } receive() external payable { @@ -69,7 +72,7 @@ contract Router is IRouter { } // performs chained getAmountOut calculations on any number of pairs - function getAmountOut(uint amountIn, address tokenIn, address tokenOut) public view returns (uint amount, bool stable) { + function getAmountOut(uint amountIn, address tokenIn, address tokenOut) external view returns (uint amount, bool stable) { address pair = pairFor(tokenIn, tokenOut, true); uint amountStable; uint amountVolatile; @@ -83,16 +86,6 @@ contract Router is IRouter { return amountStable > amountVolatile ? (amountStable, true) : (amountVolatile, false); } - //@override - //getAmountOut : bool stable - //Gets exact output for specific pair-type(S|V) - function getAmountOut(uint amountIn, address tokenIn, address tokenOut, bool stable) public view returns (uint amount) { - address pair = pairFor(tokenIn, tokenOut, stable); - if (IPairFactory(factory).isPair(pair)) { - amount = IPair(pair).getAmountOut(amountIn, tokenIn); - } - } - // performs chained getAmountOut calculations on any number of pairs function getAmountsOut(uint amountIn, route[] memory routes) public view returns (uint[] memory amounts) { require(routes.length >= 1, 'Router: INVALID_PATH'); @@ -430,129 +423,4 @@ contract Router is IRouter { token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } - - // Experimental Extension [eth.guru/solidly/Router02] - - // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens)**** - function removeLiquidityETHSupportingFeeOnTransferTokens( - address token, - bool stable, - uint liquidity, - uint amountTokenMin, - uint amountETHMin, - address to, - uint deadline - ) public ensure(deadline) returns (uint amountToken, uint amountETH) { - (amountToken, amountETH) = removeLiquidity( - token, - address(weth), - stable, - liquidity, - amountTokenMin, - amountETHMin, - address(this), - deadline - ); - _safeTransfer(token, to, IERC20(token).balanceOf(address(this))); - weth.withdraw(amountETH); - _safeTransferETH(to, amountETH); - } - function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( - address token, - bool stable, - uint liquidity, - uint amountTokenMin, - uint amountETHMin, - address to, - uint deadline, - bool approveMax, uint8 v, bytes32 r, bytes32 s - ) external returns (uint amountToken, uint amountETH) { - address pair = pairFor(token, address(weth), stable); - uint value = approveMax ? type(uint).max : liquidity; - IPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); - (amountToken, amountETH) = removeLiquidityETHSupportingFeeOnTransferTokens( - token, stable, liquidity, amountTokenMin, amountETHMin, to, deadline - ); - } - // **** SWAP (supporting fee-on-transfer tokens) **** - // requires the initial amount to have already been sent to the first pair - function _swapSupportingFeeOnTransferTokens(route[] memory routes, address _to) internal virtual { - for (uint i; i < routes.length; i++) { - (address input, address output, bool stable) = (routes[i].from, routes[i].to, routes[i].stable); - (address token0,) = sortTokens(input, output); - IPair pair = IPair(pairFor(routes[i].from, routes[i].to, routes[i].stable)); - uint amountInput; - uint amountOutput; - { // scope to avoid stack too deep errors - (uint reserve0, uint reserve1,) = pair.getReserves(); - (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0); - amountInput = IERC20(input).balanceOf(address(pair)) - reserveInput; - amountOutput = pair.getAmountOut(amountInput, input); - } - (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0)); - address to = i < routes.length - 1 ? pairFor(routes[i+1].from, routes[i+1].to, routes[i+1].stable) : _to; - pair.swap(amount0Out, amount1Out, to, new bytes(0)); - } - } - function swapExactTokensForTokensSupportingFeeOnTransferTokens( - uint amountIn, - uint amountOutMin, - route[] calldata routes, - address to, - uint deadline - ) external ensure(deadline) { - _safeTransferFrom( - routes[0].from, - msg.sender, - pairFor(routes[0].from, routes[0].to, routes[0].stable), - amountIn - ); - uint balanceBefore = IERC20(routes[routes.length - 1].to).balanceOf(to); - _swapSupportingFeeOnTransferTokens(routes, to); - require( - IERC20(routes[routes.length - 1].to).balanceOf(to) - balanceBefore >= amountOutMin, - 'Router: INSUFFICIENT_OUTPUT_AMOUNT' - ); - } - function swapExactETHForTokensSupportingFeeOnTransferTokens( - uint amountOutMin, - route[] calldata routes, - address to, - uint deadline - ) - external - payable - ensure(deadline) - { - require(routes[0].from == address(weth), 'Router: INVALID_PATH'); - uint amountIn = msg.value; - weth.deposit{value: amountIn}(); - assert(weth.transfer(pairFor(routes[0].from, routes[0].to, routes[0].stable), amountIn)); - uint balanceBefore = IERC20(routes[routes.length - 1].to).balanceOf(to); - _swapSupportingFeeOnTransferTokens(routes, to); - require( - IERC20(routes[routes.length - 1].to).balanceOf(to) - balanceBefore >= amountOutMin, - 'Router: INSUFFICIENT_OUTPUT_AMOUNT' - ); - } - function swapExactTokensForETHSupportingFeeOnTransferTokens( - uint amountIn, - uint amountOutMin, - route[] calldata routes, - address to, - uint deadline - ) - external - ensure(deadline) - { - require(routes[routes.length - 1].to == address(weth), 'Router: INVALID_PATH'); - _safeTransferFrom( - routes[0].from, msg.sender, pairFor(routes[0].from, routes[0].to, routes[0].stable), amountIn - ); - _swapSupportingFeeOnTransferTokens(routes, address(this)); - uint amountOut = IERC20(address(weth)).balanceOf(address(this)); - require(amountOut >= amountOutMin, 'Router: INSUFFICIENT_OUTPUT_AMOUNT'); - weth.withdraw(amountOut); - _safeTransferETH(to, amountOut); - } } diff --git a/contracts/VeloGovernor.sol b/contracts/VeloGovernor.sol index faa0804f..3cdec942 100644 --- a/contracts/VeloGovernor.sol +++ b/contracts/VeloGovernor.sol @@ -8,6 +8,7 @@ import {L2Governor} from "contracts/governance/L2Governor.sol"; import {L2GovernorCountingSimple} from "contracts/governance/L2GovernorCountingSimple.sol"; import {L2GovernorVotes} from "contracts/governance/L2GovernorVotes.sol"; import {L2GovernorVotesQuorumFraction} from "contracts/governance/L2GovernorVotesQuorumFraction.sol"; +import 'contracts/interfaces/ITurnstile.sol'; contract VeloGovernor is L2Governor, @@ -15,17 +16,19 @@ contract VeloGovernor is L2GovernorVotes, L2GovernorVotesQuorumFraction { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public team; uint256 public constant MAX_PROPOSAL_NUMERATOR = 50; // max 5% uint256 public constant PROPOSAL_DENOMINATOR = 1000; uint256 public proposalNumerator = 2; // start at 0.02% - constructor(IVotes _ve) + constructor(IVotes _ve, uint256 _csrNftId) L2Governor("Velodrome Governor") L2GovernorVotes(_ve) L2GovernorVotesQuorumFraction(4) // 4% { team = msg.sender; + ITurnstile(TURNSTILE).assign(_csrNftId); } function votingDelay() public pure override(IGovernor) returns (uint256) { diff --git a/contracts/VelodromeLibrary.sol b/contracts/VelocimeterLibrary.sol similarity index 99% rename from contracts/VelodromeLibrary.sol rename to contracts/VelocimeterLibrary.sol index 9682faa5..2b38a774 100644 --- a/contracts/VelodromeLibrary.sol +++ b/contracts/VelocimeterLibrary.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.13; import "contracts/interfaces/IPair.sol"; import "contracts/interfaces/IRouter.sol"; -contract VelodromeLibrary { +contract VelocimeterLibrary { IRouter internal immutable router; constructor(address _router) { @@ -101,5 +101,5 @@ contract VelodromeLibrary { return x * y; // xy >= k } } - + } diff --git a/contracts/Voter.sol b/contracts/Voter.sol index 7716e2a3..02adb259 100644 --- a/contracts/Voter.sol +++ b/contracts/Voter.sol @@ -12,11 +12,11 @@ import 'contracts/interfaces/IPair.sol'; import 'contracts/interfaces/IPairFactory.sol'; import 'contracts/interfaces/IVoter.sol'; import 'contracts/interfaces/IVotingEscrow.sol'; - +import 'contracts/interfaces/ITurnstile.sol'; import 'contracts/interfaces/IWrappedExternalBribeFactory.sol'; contract Voter is IVoter { - + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable _ve; // the ve token that governs these contracts address public immutable factory; // the PairFactory address internal immutable base; @@ -56,7 +56,7 @@ contract Voter is IVoter { event Detach(address indexed owner, address indexed gauge, uint tokenId); event Whitelisted(address indexed whitelister, address indexed token); - constructor(address __ve, address _factory, address _gauges, address _bribes, address _wrappedExternalBribeFactory) { + constructor(address __ve, address _factory, address _gauges, address _bribes, address _wrappedExternalBribeFactory, uint256 _csrNftId) { _ve = __ve; factory = _factory; base = IVotingEscrow(__ve).token(); @@ -66,6 +66,7 @@ contract Voter is IVoter { minter = msg.sender; governor = msg.sender; emergencyCouncil = msg.sender; + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check @@ -79,7 +80,7 @@ contract Voter is IVoter { } modifier onlyNewEpoch(uint _tokenId) { - // ensure new epoch since last vote + // ensure new epoch since last vote require((block.timestamp / DURATION) * DURATION > lastVoted[_tokenId], "TOKEN_ALREADY_VOTED_THIS_EPOCH"); _; } @@ -98,7 +99,7 @@ contract Voter is IVoter { } function setEmergencyCouncil(address _council) public { - require(msg.sender == emergencyCouncil); + require(msg.sender == governor); emergencyCouncil = _council; } @@ -241,8 +242,10 @@ contract Voter is IVoter { isAlive[_gauge] = true; _updateFor(_gauge); pools.push(_pool); - IPair(_pool).setHasGauge(true); - IPair(_pool).setExternalBribe(_wxbribe); + if (isPair) { + IPair(_pool).setHasGauge(true); + IPair(_pool).setExternalBribe(_wxbribe); + } emit GaugeCreated(_gauge, msg.sender, _external_bribe, _wxbribe, _pool); return _gauge; } diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol index 66eff883..81d43185 100644 --- a/contracts/VotingEscrow.sol +++ b/contracts/VotingEscrow.sol @@ -7,6 +7,7 @@ import {IERC721Receiver} from "openzeppelin-contracts/contracts/token/ERC721/IER import {IERC20} from "contracts/interfaces/IERC20.sol"; import {IVeArtProxy} from "contracts/interfaces/IVeArtProxy.sol"; import {IVotingEscrow} from "contracts/interfaces/IVotingEscrow.sol"; +import 'contracts/interfaces/ITurnstile.sol'; /// @title Voting Escrow /// @notice veNFT implementation that escrows ERC-20 tokens in the form of an ERC-721 NFT @@ -63,7 +64,8 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ - + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public immutable owner; address public immutable token; address public voter; address public team; @@ -87,12 +89,13 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { uint internal tokenId; /// @notice Contract constructor - /// @param token_addr `VELO` token address - constructor(address token_addr, address art_proxy) { + /// @param token_addr `FLOW` token address + constructor(address token_addr, address art_proxy, address _owner, uint256 _csrNftId) { token = token_addr; voter = msg.sender; team = msg.sender; artProxy = art_proxy; + owner = _owner; point_history[0].blk = block.number; point_history[0].ts = block.timestamp; @@ -101,6 +104,8 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { supportedInterfaces[ERC721_INTERFACE_ID] = true; supportedInterfaces[ERC721_METADATA_INTERFACE_ID] = true; + ITurnstile(TURNSTILE).assign(_csrNftId); + // mint-ish emit Transfer(address(0), address(this), tokenId); // burn-ish @@ -220,18 +225,18 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { /// @param _approved Address to be approved for the given NFT ID. /// @param _tokenId ID of the token to be approved. function approve(address _approved, uint _tokenId) public { - address owner = idToOwner[_tokenId]; + address tokenOwner = idToOwner[_tokenId]; // Throws if `_tokenId` is not a valid NFT - require(owner != address(0)); + require(tokenOwner != address(0)); // Throws if `_approved` is the current owner - require(_approved != owner); + require(_approved != tokenOwner); // Check requirements bool senderIsOwner = (idToOwner[_tokenId] == msg.sender); - bool senderIsApprovedForAll = (ownerToOperators[owner])[msg.sender]; + bool senderIsApprovedForAll = (ownerToOperators[tokenOwner])[msg.sender]; require(senderIsOwner || senderIsApprovedForAll); // Set the approval idToApprovals[_tokenId] = _approved; - emit Approval(owner, _approved, _tokenId); + emit Approval(tokenOwner, _approved, _tokenId); } /// @dev Enables or disables approval for a third party ("operator") to manage all of @@ -264,10 +269,10 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { /// @param _tokenId uint ID of the token to be transferred /// @return bool whether the msg.sender is approved for the given token ID, is an operator of the owner, or is the owner of the token function _isApprovedOrOwner(address _spender, uint _tokenId) internal view returns (bool) { - address owner = idToOwner[_tokenId]; - bool spenderIsOwner = owner == _spender; + address tokenOwner = idToOwner[_tokenId]; + bool spenderIsOwner = tokenOwner == _spender; bool spenderIsApproved = _spender == idToApprovals[_tokenId]; - bool spenderIsApprovedForAll = (ownerToOperators[owner])[_spender]; + bool spenderIsApprovedForAll = (ownerToOperators[tokenOwner])[_spender]; return spenderIsOwner || spenderIsApproved || spenderIsApprovedForAll; } @@ -500,15 +505,15 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { function _burn(uint _tokenId) internal { require(_isApprovedOrOwner(msg.sender, _tokenId), "caller is not owner nor approved"); - address owner = ownerOf(_tokenId); + address tokenOwner = ownerOf(_tokenId); // Clear approval approve(address(0), _tokenId); // checkpoint for gov - _moveTokenDelegates(delegates(owner), address(0), _tokenId); + _moveTokenDelegates(delegates(tokenOwner), address(0), _tokenId); // Remove token _removeTokenFrom(msg.sender, _tokenId); - emit Transfer(owner, address(0), _tokenId); + emit Transfer(tokenOwner, address(0), _tokenId); } /*////////////////////////////////////////////////////////////// @@ -1260,7 +1265,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { } function _moveAllDelegates( - address owner, + address tokenOwner, address srcRep, address dstRep ) internal { @@ -1275,10 +1280,10 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { uint[] storage srcRepNew = checkpoints[srcRep][ nextSrcRepNum ].tokenIds; - // All the same except what owner owns + // All the same except what tokenOwner owns for (uint i = 0; i < srcRepOld.length; i++) { uint tId = srcRepOld[i]; - if (idToOwner[tId] != owner) { + if (idToOwner[tId] != tokenOwner) { srcRepNew.push(tId); } } @@ -1295,7 +1300,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { uint[] storage dstRepNew = checkpoints[dstRep][ nextDstRepNum ].tokenIds; - uint ownerTokenCount = ownerToNFTokenCount[owner]; + uint ownerTokenCount = ownerToNFTokenCount[tokenOwner]; require( dstRepOld.length + ownerTokenCount <= MAX_DELEGATES, "dstRep would have too many tokenIds" @@ -1307,7 +1312,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { } // Plus all that's owned for (uint i = 0; i < ownerTokenCount; i++) { - uint tId = ownerToNFTokenIdList[owner][i]; + uint tId = ownerToNFTokenIdList[tokenOwner][i]; dstRepNew.push(tId); } diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol new file mode 100644 index 00000000..7014876b --- /dev/null +++ b/contracts/WrappedBribe.sol @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +import 'openzeppelin-contracts/contracts/utils/math/Math.sol'; +import 'contracts/ExternalBribe.sol'; +import 'contracts/interfaces/IERC20.sol'; +import 'contracts/interfaces/IGauge.sol'; +import 'contracts/interfaces/ITurnstile.sol'; +import 'contracts/interfaces/IVoter.sol'; +import 'contracts/interfaces/IVotingEscrow.sol'; + +// Bribes pay out rewards for a given pool based on the votes that were received from the user (goes hand in hand with Voter.vote()) +contract WrappedBribe { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public immutable voter; + address public immutable _ve; + ExternalBribe public underlying_bribe; + + uint internal constant DURATION = 7 days; // rewards are released over the voting period + uint internal constant MAX_REWARD_TOKENS = 16; + + mapping(address => mapping(uint => uint)) public tokenRewardsPerEpoch; + mapping(address => uint) public periodFinish; + mapping(address => uint) public lastUpdated; + mapping(address => mapping(uint => uint)) public lastEarn; + + address[] public rewards; + mapping(address => bool) public isReward; + mapping(address => uint) public tokenRewardBalance; + + /// @notice A checkpoint for marking balance + struct RewardCheckpoint { + uint timestamp; + uint balance; + } + + event NotifyReward(address indexed from, address indexed reward, uint epoch, uint amount); + event ClaimRewards(address indexed from, address indexed reward, uint amount); + event HandleLeftOverRewards(address indexed reward, uint originalEpoch, uint updatedEpoch, uint amount); + + constructor(address _voter, address _old_bribe, uint256 _csrNftId) { + voter = _voter; + _ve = IVoter(_voter)._ve(); + underlying_bribe = ExternalBribe(_old_bribe); + + for (uint i; i < underlying_bribe.rewardsListLength(); i++) { + address underlying_reward = underlying_bribe.rewards(i); + if (underlying_reward != address(0)) { + isReward[underlying_reward] = true; + rewards.push(underlying_reward); + } + } + + ITurnstile(TURNSTILE).assign(_csrNftId); + } + + // simple re-entrancy check + uint internal _unlocked = 1; + modifier lock() { + require(_unlocked == 1); + _unlocked = 2; + _; + _unlocked = 1; + } + + function _bribeStart(uint timestamp) internal pure returns (uint) { + return timestamp - (timestamp % (7 days)); + } + + function getEpochStart(uint timestamp) public pure returns (uint) { + uint bribeStart = _bribeStart(timestamp); + uint bribeEnd = bribeStart + DURATION; + return timestamp < bribeEnd ? bribeStart : bribeStart + 7 days; + } + + function rewardsListLength() external view returns (uint) { + return rewards.length; + } + + // returns the last time the reward was modified or periodFinish if the reward has ended + function lastTimeRewardApplicable(address token) public view returns (uint) { + return Math.min(block.timestamp, periodFinish[token]); + } + + // allows a user to claim rewards for a given token + function getReward(uint tokenId, address[] memory tokens) external lock { + require(IVotingEscrow(_ve).isApprovedOrOwner(msg.sender, tokenId)); + + uint256 balanceBefore; + + for (uint i = 0; i < tokens.length; i++) { + uint _reward = earned(tokens[i], tokenId); + lastEarn[tokens[i]][tokenId] = block.timestamp; + if (_reward > 0) { + balanceBefore = IERC20(tokens[i]).balanceOf(address(this)); + _safeTransfer(tokens[i], msg.sender, _reward); + tokenRewardBalance[tokens[i]] -= balanceBefore - IERC20(tokens[i]).balanceOf(address(this)); + } + + emit ClaimRewards(msg.sender, tokens[i], _reward); + } + } + + // used by Voter to allow batched reward claims + function getRewardForOwner(uint tokenId, address[] memory tokens) external lock { + require(msg.sender == voter); + address _owner = IVotingEscrow(_ve).ownerOf(tokenId); + + uint256 balanceBefore; + + for (uint i = 0; i < tokens.length; i++) { + uint _reward = earned(tokens[i], tokenId); + lastEarn[tokens[i]][tokenId] = block.timestamp; + if (_reward > 0) { + balanceBefore = IERC20(tokens[i]).balanceOf(address(this)); + _safeTransfer(tokens[i], _owner, _reward); + tokenRewardBalance[tokens[i]] -= balanceBefore - IERC20(tokens[i]).balanceOf(address(this)); + } + + emit ClaimRewards(_owner, tokens[i], _reward); + } + } + + function earned(address token, uint tokenId) public view returns (uint) { + if (underlying_bribe.numCheckpoints(tokenId) == 0) { + return 0; + } + + uint reward = 0; + uint _ts = 0; + uint _bal = 0; + uint _supply = 1; + uint _index = 0; + uint _currTs = _bribeStart(lastEarn[token][tokenId]); // take epoch last claimed in as starting point + + _index = underlying_bribe.getPriorBalanceIndex(tokenId, _currTs); + (_ts, _bal) = underlying_bribe.checkpoints(tokenId,_index); + // accounts for case where lastEarn is before first checkpoint + _currTs = Math.max(_currTs, _bribeStart(_ts)); + + // get epochs between current epoch and first checkpoint in same epoch as last claim + uint numEpochs = (_bribeStart(block.timestamp) - _currTs) / DURATION; + + if (numEpochs > 0) { + for (uint256 i = 0; i < numEpochs; i++) { + // get index of last checkpoint in this epoch + _index = underlying_bribe.getPriorBalanceIndex(tokenId, _currTs + DURATION); + // get checkpoint in this epoch + (_ts, _bal) = underlying_bribe.checkpoints(tokenId,_index); + // get supply of last checkpoint in this epoch + (, _supply) = underlying_bribe.supplyCheckpoints(underlying_bribe.getPriorSupplyIndex(_currTs + DURATION)); + if (_supply != 0) { + reward += _bal * tokenRewardsPerEpoch[token][_currTs] / _supply; + } + _currTs += DURATION; + } + } + + return reward; + } + + function left(address token) external view returns (uint) { + uint adjustedTstamp = getEpochStart(block.timestamp); + return tokenRewardsPerEpoch[token][adjustedTstamp]; + } + + function notifyRewardAmount(address token, uint amount) external lock { + require(amount > 0); + if (!isReward[token]) { + require(IVoter(voter).isWhitelisted(token), "bribe tokens must be whitelisted"); + require(rewards.length < MAX_REWARD_TOKENS, "too many rewards tokens"); + } + // bribes kick in at the start of next bribe period + uint adjustedTstamp = getEpochStart(block.timestamp); + uint epochRewards = tokenRewardsPerEpoch[token][adjustedTstamp]; + + uint256 balanceBefore = IERC20(token).balanceOf(address(this)); + _safeTransferFrom(token, msg.sender, address(this), amount); + uint256 balanceAfter = IERC20(token).balanceOf(address(this)); + + amount = balanceAfter - balanceBefore; + + tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount; + tokenRewardBalance[token] += amount; + + periodFinish[token] = adjustedTstamp + DURATION; + + if (!isReward[token]) { + isReward[token] = true; + rewards.push(token); + } + + emit NotifyReward(msg.sender, token, adjustedTstamp, amount); + } + + function updateRewardAmount(address[] memory tokens) external lock { + uint256 length = tokens.length; + uint256 adjustedTstamp = getEpochStart(block.timestamp); + + uint256 rewardBalance; + uint256 difference; + + for (uint256 i = 0; i < length;) { + rewardBalance = tokenRewardBalance[tokens[i]]; + difference = IERC20(tokens[i]).balanceOf(address(this)) - rewardBalance; + + if (difference != 0) { + tokenRewardsPerEpoch[tokens[i]][adjustedTstamp] += difference; + tokenRewardBalance[tokens[i]] = rewardBalance + difference; + + periodFinish[tokens[i]] = adjustedTstamp + DURATION; + lastUpdated[tokens[i]] = block.timestamp; + + emit NotifyReward(msg.sender, tokens[i], adjustedTstamp, difference); + } + + unchecked { + ++i; + } + } + } + + // This is an external function that can only be called by teams to handle unclaimed rewards due to zero vote + function handleLeftOverRewards(uint epochTimestamp, address[] memory tokens) external { + require(msg.sender == IVotingEscrow(_ve).team(), "only team"); + + // require that supply of that epoch to be ZERO + uint epochStart = getEpochStart(epochTimestamp); + (uint _ts, uint _supply) = underlying_bribe.supplyCheckpoints(underlying_bribe.getPriorSupplyIndex(epochStart + DURATION)); + if (epochStart + DURATION > _bribeStart(_ts)) { + require(_supply == 0, "this epoch has votes"); + } + + // do sth like notifyRewardAmount + uint length = tokens.length; + for (uint i = 0; i < length;) { + // check bribe amount + uint previousEpochRewards = tokenRewardsPerEpoch[tokens[i]][epochStart]; + require(previousEpochRewards != 0, "no bribes for this epoch"); + + // get timestamp of current epoch + uint adjustedTstamp = getEpochStart(block.timestamp); + + // get notified reward of current epoch + uint currentEpochRewards = tokenRewardsPerEpoch[tokens[i]][adjustedTstamp]; + + // add previous unclaimed rewards to current epoch + tokenRewardsPerEpoch[tokens[i]][adjustedTstamp] = currentEpochRewards + previousEpochRewards; + + // remove token rewards from previous epoch + tokenRewardsPerEpoch[tokens[i]][epochStart] = 0; + + // amend period finish + periodFinish[tokens[i]] = adjustedTstamp + DURATION; + + emit HandleLeftOverRewards(tokens[i], epochStart, adjustedTstamp, previousEpochRewards); + + unchecked { + ++i; + } + } + } + + function swapOutRewardToken(uint i, address oldToken, address newToken) external { + require(msg.sender == IVotingEscrow(_ve).team(), 'only team'); + require(rewards[i] == oldToken); + isReward[oldToken] = false; + isReward[newToken] = true; + rewards[i] = newToken; + } + + function _safeTransfer(address token, address to, uint256 value) internal { + require(token.code.length > 0); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool)))); + } + + function _safeTransferFrom(address token, address from, address to, uint256 value) internal { + require(token.code.length > 0); + (bool success, bytes memory data) = + token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); + require(success && (data.length == 0 || abi.decode(data, (bool)))); + } +} diff --git a/contracts/WrappedExternalBribe.sol b/contracts/WrappedExternalBribe.sol index d44d4ea5..823ad629 100644 --- a/contracts/WrappedExternalBribe.sol +++ b/contracts/WrappedExternalBribe.sol @@ -7,9 +7,11 @@ import 'contracts/interfaces/IERC20.sol'; import 'contracts/interfaces/IGauge.sol'; import 'contracts/interfaces/IVoter.sol'; import 'contracts/interfaces/IVotingEscrow.sol'; +import 'contracts/interfaces/ITurnstile.sol'; // Bribes pay out rewards for a given pool based on the votes that were received from the user (goes hand in hand with Voter.vote()) contract WrappedExternalBribe { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable voter; address public immutable _ve; ExternalBribe public underlying_bribe; @@ -33,7 +35,7 @@ contract WrappedExternalBribe { event NotifyReward(address indexed from, address indexed reward, uint epoch, uint amount); event ClaimRewards(address indexed from, address indexed reward, uint amount); - constructor(address _voter, address _old_bribe) { + constructor(address _voter, address _old_bribe, uint256 _csrNftId) { voter = _voter; _ve = IVoter(_voter)._ve(); underlying_bribe = ExternalBribe(_old_bribe); @@ -45,6 +47,8 @@ contract WrappedExternalBribe { rewards.push(underlying_reward); } } + + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check @@ -161,7 +165,12 @@ contract WrappedExternalBribe { uint adjustedTstamp = getEpochStart(block.timestamp); uint epochRewards = tokenRewardsPerEpoch[token][adjustedTstamp]; + uint256 balanceBefore = IERC20(token).balanceOf(address(this)); _safeTransferFrom(token, msg.sender, address(this), amount); + uint256 balanceAfter = IERC20(token).balanceOf(address(this)); + + amount = balanceAfter - balanceBefore; + tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount; periodFinish[token] = adjustedTstamp + DURATION; diff --git a/contracts/factories/AutoBribeFactory.sol b/contracts/factories/AutoBribeFactory.sol new file mode 100644 index 00000000..56360e5c --- /dev/null +++ b/contracts/factories/AutoBribeFactory.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +import {AutoBribe} from "contracts/AutoBribe.sol"; +import "contracts/interfaces/ITurnstile.sol"; + +contract AutoBribeFactory { + address public constant TURNSTILE = + 0xEcf044C5B4b867CFda001101c617eCd347095B44; + uint256 public immutable csrNftId; + address public immutable team; + address public immutable voter; + address public immutable wBribeFactory; + + constructor(address _voter, address _team, address _wBribeFactory, uint256 _csrNftId) { + voter = _voter; + team = _team; + wBribeFactory = _wBribeFactory; + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; + } + + function createAutoBribe( + address wbribe, + string memory name + ) external returns (address auto_bribe) { + require(wbribe != address(0), "Wrapped bribe not yet created"); + auto_bribe = address(new AutoBribe(voter, wbribe, team, name, csrNftId)); + } +} diff --git a/contracts/factories/BribeFactory.sol b/contracts/factories/BribeFactory.sol index b945c859..3dcf0e01 100644 --- a/contracts/factories/BribeFactory.sol +++ b/contracts/factories/BribeFactory.sol @@ -3,12 +3,20 @@ pragma solidity 0.8.13; import "contracts/interfaces/IBribeFactory.sol"; import 'contracts/ExternalBribe.sol'; +import 'contracts/interfaces/ITurnstile.sol'; contract BribeFactory is IBribeFactory { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public last_external_bribe; + uint256 public immutable csrNftId; + + constructor(uint256 _csrNftId) { + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; + } function createExternalBribe(address[] memory allowedRewards) external returns (address) { - last_external_bribe = address(new ExternalBribe(msg.sender, allowedRewards)); + last_external_bribe = address(new ExternalBribe(msg.sender, allowedRewards, csrNftId)); return last_external_bribe; } } diff --git a/contracts/factories/GaugeFactory.sol b/contracts/factories/GaugeFactory.sol index 5e8ba6f0..8ad157a8 100644 --- a/contracts/factories/GaugeFactory.sol +++ b/contracts/factories/GaugeFactory.sol @@ -3,12 +3,19 @@ pragma solidity 0.8.13; import 'contracts/interfaces/IGaugeFactory.sol'; import 'contracts/Gauge.sol'; +import 'contracts/interfaces/ITurnstile.sol'; contract GaugeFactory is IGaugeFactory { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public last_gauge; + uint256 public immutable csrNftId; + constructor(uint256 _csrNftId) { + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; + } function createGauge(address _pool, address _external_bribe, address _ve, bool isPair, address[] memory allowedRewards) external returns (address) { - last_gauge = address(new Gauge(_pool, _external_bribe, _ve, msg.sender, isPair, allowedRewards)); + last_gauge = address(new Gauge(_pool, _external_bribe, _ve, msg.sender, isPair, allowedRewards, csrNftId)); return last_gauge; } } diff --git a/contracts/factories/PairFactory.sol b/contracts/factories/PairFactory.sol index 06b12892..9a9f595b 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -3,20 +3,16 @@ pragma solidity 0.8.13; import 'contracts/interfaces/IPairFactory.sol'; import 'contracts/Pair.sol'; +import 'contracts/interfaces/ITurnstile.sol'; +import "openzeppelin-contracts/contracts/access/Ownable.sol"; -contract PairFactory is IPairFactory { - +contract PairFactory is IPairFactory, Ownable { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; bool public isPaused; - address public pauser; - address public pendingPauser; - uint256 public stableFee; uint256 public volatileFee; uint256 public constant MAX_FEE = 50; // 0.5% - address public feeManager; - address public pendingFeeManager; address public voter; - address public team; address public tank; address public deployer; @@ -28,43 +24,32 @@ contract PairFactory is IPairFactory { address internal _temp1; bool internal _temp; + uint256 public immutable csrNftId; + event PairCreated(address indexed token0, address indexed token1, bool stable, address pair, uint); - event TeamSet(address indexed setter, address indexed team); event VoterSet(address indexed setter, address indexed voter); event TankSet(address indexed setter, address indexed tank); - event PauserSet(address indexed setter, address indexed pauser); - event PauserAccepted(address indexed previous, address indexed current); event Paused(address indexed pauser, bool paused); - event FeeManagerSet(address indexed setter, address indexed feeManager); - event FeeManagerAccepted(address indexed previous, address indexed current); event FeeSet(address indexed setter, bool stable, uint256 fee); - constructor() { - pauser = msg.sender; - isPaused = false; - feeManager = msg.sender; + constructor(uint256 _csrNftId) { stableFee = 3; // 0.03% volatileFee = 25; // 0.25% deployer = msg.sender; - } - - function setTeam(address _team) external { - require(team == address(0), 'The team has already been set.'); - require(msg.sender == deployer, 'Not authorised to set team.'); // might need to set this to deployer?? or just make it - team = _team; - emit TeamSet(msg.sender, _team); + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; } function setVoter(address _voter) external { require(voter == address(0), 'The voter has already been set.'); - require(msg.sender == deployer, 'Not authorised to set voter.'); // have to make sure that this can be set to the voter addres during init script + // have to make sure that this can be set to the voter address during init script + require(msg.sender == deployer, 'Not authorised to set voter.'); voter = _voter; emit VoterSet(msg.sender, _voter); } - function setTank(address _tank) external { - require(msg.sender == deployer || msg.sender == team, 'Not authorised to set tank.'); // this should be updateable to team but adding deployer so that init script can run.. + function setTank(address _tank) external onlyOwner { tank = _tank; emit TankSet(msg.sender, _tank); } @@ -73,40 +58,12 @@ contract PairFactory is IPairFactory { return allPairs.length; } - function setPauser(address _pauser) external { - require(msg.sender == pauser); - pendingPauser = _pauser; - emit PauserSet(msg.sender, _pauser); - } - - function acceptPauser() external { - require(msg.sender == pendingPauser); - address prevPauser = pauser; - pauser = pendingPauser; - emit PauserAccepted(prevPauser, msg.sender); - } - - function setPause(bool _state) external { - require(msg.sender == pauser); + function setPause(bool _state) external onlyOwner { isPaused = _state; emit Paused(msg.sender, _state); } - function setFeeManager(address _feeManager) external { - require(msg.sender == feeManager, 'not fee manager'); - pendingFeeManager = _feeManager; - emit FeeManagerSet(msg.sender, _feeManager); - } - - function acceptFeeManager() external { - require(msg.sender == pendingFeeManager, 'not pending fee manager'); - address prevFeeManager = feeManager; - feeManager = pendingFeeManager; - emit FeeManagerAccepted(prevFeeManager, msg.sender); - } - - function setFee(bool _stable, uint256 _fee) external { - require(msg.sender == feeManager, 'not fee manager'); + function setFee(bool _stable, uint256 _fee) external onlyOwner { require(_fee <= MAX_FEE, 'fee too high'); if (_stable) { stableFee = _fee; diff --git a/contracts/factories/WrappedBribeFactory.sol b/contracts/factories/WrappedBribeFactory.sol new file mode 100644 index 00000000..e1cfdb18 --- /dev/null +++ b/contracts/factories/WrappedBribeFactory.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +import {WrappedBribe} from 'contracts/WrappedBribe.sol'; +import 'contracts/interfaces/ITurnstile.sol'; + +contract WrappedBribeFactory { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + uint256 public immutable csrNftId; + address public immutable voter; + mapping(address => address) public oldBribeToNew; + address public last_bribe; + + constructor(address _voter, uint256 _csrNftId) { + voter = _voter; + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; + } + + function createBribe(address existing_bribe) external returns (address) { + require( + oldBribeToNew[existing_bribe] == address(0), + "Wrapped bribe already created" + ); + last_bribe = address(new WrappedBribe(voter, existing_bribe, csrNftId)); + oldBribeToNew[existing_bribe] = last_bribe; + return last_bribe; + } +} diff --git a/contracts/factories/WrappedExternalBribeFactory.sol b/contracts/factories/WrappedExternalBribeFactory.sol index 1e4aad81..09b0d5ea 100644 --- a/contracts/factories/WrappedExternalBribeFactory.sol +++ b/contracts/factories/WrappedExternalBribeFactory.sol @@ -2,20 +2,28 @@ pragma solidity 0.8.13; import {WrappedExternalBribe} from 'contracts/WrappedExternalBribe.sol'; +import 'contracts/interfaces/ITurnstile.sol'; contract WrappedExternalBribeFactory { + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + uint256 public immutable csrNftId; address public voter; mapping(address => address) public oldBribeToNew; address public last_bribe; event VoterSet(address indexed setter, address indexed voter); + constructor(uint256 _csrNftId) { + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; + } + function createBribe(address existing_bribe) external returns (address) { require( oldBribeToNew[existing_bribe] == address(0), "Wrapped bribe already created" ); - last_bribe = address(new WrappedExternalBribe(voter, existing_bribe)); + last_bribe = address(new WrappedExternalBribe(voter, existing_bribe, csrNftId)); oldBribeToNew[existing_bribe] = last_bribe; return last_bribe; } diff --git a/contracts/interfaces/IPairFactory.sol b/contracts/interfaces/IPairFactory.sol index f943725a..0ed7eb3e 100644 --- a/contracts/interfaces/IPairFactory.sol +++ b/contracts/interfaces/IPairFactory.sol @@ -3,7 +3,13 @@ pragma solidity 0.8.13; interface IPairFactory { function allPairsLength() external view returns (uint); function isPair(address pair) external view returns (bool); + function isPaused() external view returns (bool); function pairCodeHash() external pure returns (bytes32); + function getFee(bool _stable) external view returns (uint256); function getPair(address tokenA, address token, bool stable) external view returns (address); + function getInitializable() external view returns (address, address, bool); function createPair(address tokenA, address tokenB, bool stable) external returns (address pair); + function voter() external view returns (address); + function tank() external view returns (address); + function csrNftId() external view returns (uint256); } diff --git a/contracts/interfaces/ITurnstile.sol b/contracts/interfaces/ITurnstile.sol new file mode 100644 index 00000000..87a1eb73 --- /dev/null +++ b/contracts/interfaces/ITurnstile.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity 0.8.13; + +interface ITurnstile { + function register(address) external returns(uint256); + function assign(uint256) external returns(uint256); +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 05d19884..ccfd719a 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -25,11 +25,14 @@ const remappings = fs const config: HardhatUserConfig = { networks: { hardhat: { + chainId: 7700, initialBaseFeePerGas: 0, forking: { - url: `https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, - blockNumber: 16051852 - } + url: "https://canto.neobase.one", + }, + accounts: [ + { privateKey: process.env.PRIVATE_KEY || '', balance: "999999999999999999999999999999999999" }, + ] }, opera: { url: "https://rpc.fantom.network", diff --git a/lib/ds-test b/lib/ds-test new file mode 160000 index 00000000..e282159d --- /dev/null +++ b/lib/ds-test @@ -0,0 +1 @@ +Subproject commit e282159d5170298eb2455a6c05280ab5a73a4ef0 diff --git a/scripts/DeployWrappedBribeFactory.s.sol b/scripts/DeployWrappedBribeFactory.s.sol new file mode 100644 index 00000000..267669b1 --- /dev/null +++ b/scripts/DeployWrappedBribeFactory.s.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +// Scripting tool +import {Script} from "../lib/forge-std/src/Script.sol"; + +import {Flow} from "../contracts/Flow.sol"; +import {WrappedBribeFactory} from "../contracts/factories/WrappedBribeFactory.sol"; + +contract DeployWrappedBribeFactory is Script { + // token addresses + address private constant FLOW = 0xB5b060055F0d1eF5174329913ef861bC3aDdF029; // TODO + address private constant VOTER = 0x8e3525Dbc8356c08d2d55F3ACb6416b5979D3389; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + uint256 csrNftId = Flow(FLOW).csrNftId(); + // Wrapped external bribe factory + WrappedBribeFactory wrappedBribeFactory = new WrappedBribeFactory( + VOTER, + csrNftId + ); + + vm.stopBroadcast(); + } +} diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol new file mode 100644 index 00000000..7184fdee --- /dev/null +++ b/scripts/Deployment.s.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +// Scripting tool +import {Script} from "../lib/forge-std/src/Script.sol"; + +import {Flow} from "../contracts/Flow.sol"; +import {GaugeFactory} from "../contracts/factories/GaugeFactory.sol"; +import {BribeFactory} from "../contracts/factories/BribeFactory.sol"; +import {PairFactory} from "../contracts/factories/PairFactory.sol"; +import {WrappedExternalBribeFactory} from "../contracts/factories/WrappedExternalBribeFactory.sol"; +import {Router} from "../contracts/Router.sol"; +import {VelocimeterLibrary} from "../contracts/VelocimeterLibrary.sol"; +import {VeArtProxy} from "../contracts/VeArtProxy.sol"; +import {VotingEscrow} from "../contracts/VotingEscrow.sol"; +import {RewardsDistributor} from "../contracts/RewardsDistributor.sol"; +import {Voter} from "../contracts/Voter.sol"; +import {Minter} from "../contracts/Minter.sol"; + +contract Deployment is Script { + // token addresses + address private constant WCANTO = 0x826551890Dc65655a0Aceca109aB11AbDbD7a07B; + + // privileged accounts + // TODO: reset DEPLOYER_EOA + address private constant DEPLOYER_EOA = 0xD93142ED5B85FcA4550153088750005759CE8318; + address private constant COUNCIL = 0x06b16991B53632C2362267579AE7C4863c72fDb8; + address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; + address private constant GOVERNOR = 0x06b16991B53632C2362267579AE7C4863c72fDb8; + address private constant TANK = 0x0A868fd1523a1ef58Db1F2D135219F0e30CBf7FB; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + // Flow token + Flow flow = new Flow({initialSupplyRecipient: DEPLOYER_EOA, csrRecipient: TEAM_MULTI_SIG}); + uint256 csrNftId = flow.csrNftId(); + + // Gauge factory + GaugeFactory gaugeFactory = new GaugeFactory(csrNftId); + + // Bribe factory + BribeFactory bribeFactory = new BribeFactory(csrNftId); + + // Pair factory + PairFactory pairFactory = new PairFactory(csrNftId); + + // Router + Router router = new Router(address(pairFactory), WCANTO, csrNftId); + + // VelocimeterLibrary + new VelocimeterLibrary(address(router)); + + // VeArtProxy + VeArtProxy veArtProxy = new VeArtProxy(); + + // VotingEscrow + VotingEscrow votingEscrow = new VotingEscrow(address(flow), address(veArtProxy), TEAM_MULTI_SIG, csrNftId); + + // RewardsDistributor + RewardsDistributor rewardsDistributor = new RewardsDistributor(address(votingEscrow), csrNftId); + + // Wrapped external bribe factory + WrappedExternalBribeFactory wrappedExternalBribeFactory = new WrappedExternalBribeFactory(csrNftId); + + // Voter + Voter voter = new Voter( + address(votingEscrow), + address(pairFactory), + address(gaugeFactory), + address(bribeFactory), + address(wrappedExternalBribeFactory), + csrNftId + ); + + // Set voter + wrappedExternalBribeFactory.setVoter(address(voter)); + votingEscrow.setVoter(address(voter)); + pairFactory.setVoter(address(voter)); + + // Minter + Minter minter = new Minter( + address(voter), + address(votingEscrow), + address(rewardsDistributor), + csrNftId + ); + + // Set flow minter to contract + flow.setMinter(address(minter)); + + // Set pair factory pauser and tank + pairFactory.setTank(TANK); + + // Set voting escrow's art proxy + votingEscrow.setArtProxy(address(veArtProxy)); + + // Set minter and voting escrow's team + votingEscrow.setTeam(TEAM_MULTI_SIG); + minter.setTeam(TEAM_MULTI_SIG); + + // Transfer pairfactory ownership to MSIG (team) + pairFactory.transferOwnership(TEAM_MULTI_SIG); + + // Set voter's emergency council + voter.setEmergencyCouncil(TEAM_MULTI_SIG); + + // Set voter's governor + voter.setGovernor(TEAM_MULTI_SIG); + + // Set rewards distributor's depositor to minter contract + rewardsDistributor.setDepositor(address(minter)); + + // Initialize tokens for voter + address[] memory whitelistedTokens = new address[](19); + whitelistedTokens[0] = address(flow); + whitelistedTokens[1] = 0x4e71A2E537B7f9D9413D3991D37958c0b5e1e503; // NOTE + whitelistedTokens[2] = 0x80b5a32E4F032B2a058b4F29EC95EEfEEB87aDcd; // USDC + whitelistedTokens[3] = 0x5db67696C3c088DfBf588d3dd849f44266ff0ffa; // CRE + whitelistedTokens[4] = WCANTO; + whitelistedTokens[5] = 0xecEEEfCEE421D8062EF8d6b4D814efe4dc898265; // ATOM + whitelistedTokens[6] = 0x1D54EcB8583Ca25895c512A8308389fFD581F9c9; // INJ + whitelistedTokens[7] = 0x3452e23F9c4cC62c70B7ADAd699B264AF3549C19; // CMDX + whitelistedTokens[8] = 0xC5e00D3b04563950941f7137B5AfA3a534F0D6d6; // KAVA + whitelistedTokens[9] = 0x5aD523d94Efb56C400941eb6F34393b84c75ba39; // AKT + whitelistedTokens[10] = 0x0CE35b0D42608Ca54Eb7bcc8044f7087C18E7717; // OSMO + whitelistedTokens[11] = 0x7264610A66EcA758A8ce95CF11Ff5741E1fd0455; // cINU + whitelistedTokens[12] = 0xc03345448969Dd8C00e9E4A85d2d9722d093aF8E; // GRAV + whitelistedTokens[13] = 0xFA3C22C069B9556A4B2f7EcE1Ee3B467909f4864; // SOMM + whitelistedTokens[14] = 0x38D11B40D2173009aDB245b869e90525950aE345; // cBONK + whitelistedTokens[15] = 0x5FD55A1B9FC24967C4dB09C513C3BA0DFa7FF687; // ETH + whitelistedTokens[16] = 0xd567B3d7B8FE3C79a1AD8dA978812cfC4Fa05e75; // USDT + whitelistedTokens[17] = 0x74ccbe53F77b08632ce0CB91D3A545bF6B8E0979; // fBOMB + voter.initialize(whitelistedTokens, address(minter)); + + vm.stopBroadcast(); + } +} diff --git a/scripts/FlowConvertorDeployment.s.sol b/scripts/FlowConvertorDeployment.s.sol new file mode 100644 index 00000000..b8891caa --- /dev/null +++ b/scripts/FlowConvertorDeployment.s.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +// Scripting tool +import {Script} from "../lib/forge-std/src/Script.sol"; +import {IFlow} from "../contracts/interfaces/IFlow.sol"; +import {FlowConvertor} from "../contracts/FlowConvertor.sol"; + +contract FlowConvertorDeployment is Script { + address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; + // TODO: Fill the address + address private constant FLOW = 0x78e489523291581205Ea3fA16a69689EcA79757A; + uint256 private constant FIFTY_MILLION = 50e24; // 50e24 == 50e6 (50m) ** 1e18 (decimals) + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + FlowConvertor flowConvertor = new FlowConvertor({_v1: 0x2Baec546a92cA3469f71b7A091f7dF61e5569889, _v2: FLOW}); + + flowConvertor.transferOwnership(TEAM_MULTI_SIG); + + IFlow(FLOW).transfer(address(flowConvertor), FIFTY_MILLION); + + vm.stopBroadcast(); + } +} diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol new file mode 100644 index 00000000..f932b3c8 --- /dev/null +++ b/scripts/InitialMintAndLock.s.sol @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +// Scripting tool +import {Script} from "../lib/forge-std/src/Script.sol"; + +import {Minter} from "../contracts/Minter.sol"; + +contract InitialMintAndLock is Script { + address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; + + // address to receive veNFT to be distributed to partners in the future + address private constant FLOW_VOTER_EOA = 0xcC06464C7bbCF81417c08563dA2E1847c22b703a; + address private constant ASSET_EOA = 0x1bAe1083CF4125eD5dEeb778985C1Effac0ecC06; + + // team member addresses + address private constant DUNKS = 0x069e85D4F1010DD961897dC8C095FBB5FF297434; + address private constant T0RB1K = 0x0b776552c1Aef1Dc33005DD25AcDA22493b6615d; + address private constant CEAZOR = 0x06b16991B53632C2362267579AE7C4863c72fDb8; + address private constant MOTTO = 0x78e801136F77805239A7F533521A7a5570F572C8; + address private constant COOLIE = 0x03B88DacB7c21B54cEfEcC297D981E5b721A9dF1; + + // token amounts + uint256 private constant ONE_MILLION = 1e24; // 1e24 == 1e6 (1m) ** 1e18 (decimals) + uint256 private constant TWO_MILLION = 2e24; // 2e24 == 1e6 (1m) ** 1e18 (decimals) + uint256 private constant THREE_MILLION = 3e24; // 3e24 == 1e6 (1m) ** 1e18 (decimals) + uint256 private constant FOUR_MILLION = 4e24; // 4e24 == 1e6 (1m) ** 1e18 (decimals) + + // time + uint256 private constant ONE_YEAR = 31_536_000; + uint256 private constant TWO_YEARS = 63_072_000; + uint256 private constant FOUR_YEARS = 126_144_000; + + Minter private minter; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + // TODO: Fill address after mainnet deploy + minter = Minter(address(0)); + + // Mint tokens and lock for veNFT + + // 1. Mint to Flow voter EOA + _batchInitialMintAndLock({ + owner: FLOW_VOTER_EOA, + numberOfVotingEscrow: 5, + amountPerVotingEscrow: ONE_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: FLOW_VOTER_EOA, + numberOfVotingEscrow: 6, + amountPerVotingEscrow: TWO_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: FLOW_VOTER_EOA, + numberOfVotingEscrow: 2, + amountPerVotingEscrow: THREE_MILLION, + lockTime: FOUR_YEARS + }); + + // 2. Mint to team members + _batchInitialMintAndLock({ + owner: DUNKS, + numberOfVotingEscrow: 1, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: DUNKS, + numberOfVotingEscrow: 1, + amountPerVotingEscrow: TWO_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: T0RB1K, + numberOfVotingEscrow: 3, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: CEAZOR, + numberOfVotingEscrow: 3, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: MOTTO, + numberOfVotingEscrow: 3, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: COOLIE, + numberOfVotingEscrow: 3, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); + + // 3. Mint for future partners + _batchInitialMintAndLock({ + owner: ASSET_EOA, + numberOfVotingEscrow: 4, + amountPerVotingEscrow: THREE_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: TEAM_MULTI_SIG, + numberOfVotingEscrow: 18, + amountPerVotingEscrow: THREE_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: ASSET_EOA, + numberOfVotingEscrow: 4, + amountPerVotingEscrow: TWO_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: TEAM_MULTI_SIG, + numberOfVotingEscrow: 14, + amountPerVotingEscrow: TWO_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: TEAM_MULTI_SIG, + numberOfVotingEscrow: 15, + amountPerVotingEscrow: ONE_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: ASSET_EOA, + numberOfVotingEscrow: 5, + amountPerVotingEscrow: ONE_MILLION, + lockTime: TWO_YEARS + }); + + _batchInitialMintAndLock({ + owner: ASSET_EOA, + numberOfVotingEscrow: 5, + amountPerVotingEscrow: ONE_MILLION, + lockTime: ONE_YEAR + }); + // Mint for current partners and presale + _singleInitialMintAndLock(0x69224dbA1D77bfe6eA99409aB595d04631D95C22, 1205636240970620000000000); + _singleInitialMintAndLock(0x69224dbA1D77bfe6eA99409aB595d04631D95C22, 1201854505093560000000000); + _singleInitialMintAndLock(0x69224dbA1D77bfe6eA99409aB595d04631D95C22, 1207527108909160000000000); + _singleInitialMintAndLock(0x69224dbA1D77bfe6eA99409aB595d04631D95C22, 1207527108909160000000000); + _singleInitialMintAndLock(0x69224dbA1D77bfe6eA99409aB595d04631D95C22, 1207527108909160000000000); + _singleInitialMintAndLock(0xCFFC6e659DF622e2d41c7A879C76E6d33F37925E, 1207527108909160000000000); + _singleInitialMintAndLock(0xF09d213EE8a8B159C884b276b86E08E26B3bfF75, 5000000000000000000000000); + _singleInitialMintAndLock(0x50149b01f19c2D4A403B1FE4469c117a5cEdb4fc, 1006272590757630000000000); + + // Mint for snapshot recipients, quants already 1.2x + _singleInitialMintAndLock(0xd0cC9738866cd82B237A14c92ac60577602d6c18, 1200000000000000000); + _singleInitialMintAndLock(0x38dAEa6f17E4308b0Da9647dB9ca6D84a3A7E195, 24000000000000000000000); + _singleInitialMintAndLock(0xaA970e6bD6E187492f8327e514c9E8c36c81f11E, 24000000000000000000000); + _singleInitialMintAndLock(0xa66e216b038d0F4121bf9A218dABbf4759375f5E, 1200000000000000000000); + _singleInitialMintAndLock(0xC9eebecb1d0AfF4fb2B9978516E075A33639892C, 1025088000000000000000); + _singleInitialMintAndLock(0xe9335fabfB4536bE78D539D759a29e1AFE7455A6, 3508800000000000000000); + _singleInitialMintAndLock(0x37FC9Dc092E8a30A63A1567C9ac9738A7D4A08ed, 1200000000000000000000); + _singleInitialMintAndLock(0x0496cbAD3B943cc246Aa793AB069bFC5516961Ef, 1200000000000000000000); + _singleInitialMintAndLock(0xaA970e6bD6E187492f8327e514c9E8c36c81f11E, 12000000000000000000000); + _singleInitialMintAndLock(0x3aE6a0e8Ec1Edd305553686387dC85Ff8D16AC51, 1014000000000000000000); + _singleInitialMintAndLock(0xED20BC9f8BE737572d7e40237023C7A8FEA3449e, 61044000000000000000); + _singleInitialMintAndLock(0x6c7286c5AB525ccD92c134c0dCDfDdfcA018B048, 600000000000000000000); + _singleInitialMintAndLock(0x5Be66f4095f89BD18aBE4aE9d2acD5021EC433Bc, 900000000000000000000); + _singleInitialMintAndLock(0xB1fC41Cbad16caFDfC2ED196c7fe515DfB6a1577, 3762240000000000000000); + _singleInitialMintAndLock(0x2Ba838E42126aC349D01c3D1FAc85a36266151a4, 36000000000000000000); + _singleInitialMintAndLock(0x609470c2f08FF626078bA64Ceb905d73b155089d, 840000000000000000000); + _singleInitialMintAndLock(0x947D9bcDc2C34Df8587630CAf45b2a2bf07c88cB, 6000000000000000000000); + _singleInitialMintAndLock(0x82619EDe0ac5d964a0711613cFf5446ED3fF85Dc, 1200000000000000000); + _singleInitialMintAndLock(0x707c4603FB72996FF95AB91f571516aFC0F3Fe1b, 70608000000000000000); + _singleInitialMintAndLock(0x7E3b6f966f3666F77813db84DD352173749D24d8, 600000000000000000000); + _singleInitialMintAndLock(0x037B21279931E628b11b4507b9F7870B15dE1C17, 787824000000000000000); + _singleInitialMintAndLock(0x3C2d6d7144241F1F1203c29C124585e55B58975E, 240000000000000000000); + _singleInitialMintAndLock(0x3C2d6d7144241F1F1203c29C124585e55B58975E, 240000000000000000000); + _singleInitialMintAndLock(0xc742a9458c4Cc6f6498007ffC81266Cd3a3f578A, 28800000000000000000); + _singleInitialMintAndLock(0x891C16d225e4Fd30d0874Bf2E139B0c11a459a07, 1351200000000000000000); + _singleInitialMintAndLock(0x5FE1521173F553084eD21e5CbeDE7233b5fE1AA7, 120000000000000000000); + _singleInitialMintAndLock(0x540A6992368aA24dd6baD1DB8BF4982e6183Caf3, 892536000000000000000); + _singleInitialMintAndLock(0x20cE0C0f284219f4E0B68804a8333A782461674c, 30000000000000000000); + _singleInitialMintAndLock(0x41a6ac7f4e4DBfFEB934f95F1Db58B68C76Dc4dF, 43788000000000000000); + _singleInitialMintAndLock(0x9665B6F0CF162792851A902E452248B16F2f4b5A, 1692540023765800000000); + _singleInitialMintAndLock(0x9665B6F0CF162792851A902E452248B16F2f4b5A, 978720000000000000000); + _singleInitialMintAndLock(0x02706C602c59F86Cc2EbD9aE662a25987A7C7986, 198000000000000000000); + _singleInitialMintAndLock(0x5FE1521173F553084eD21e5CbeDE7233b5fE1AA7, 480000000000000000000); + _singleInitialMintAndLock(0x15Eb585735334Db4B0B75919e5990E6391863B39, 34800000000000000000); + _singleInitialMintAndLock(0x96FCa82BB2ce4c5A700a14581412366CC05dd6fA, 3600000000000000000000); + _singleInitialMintAndLock(0xb00d51d3992BC412f783D0e21EDcf952Ce651D91, 1824000000000000000); + _singleInitialMintAndLock(0x56BbBDD8d9e939EC047E3a61907a4caF4d90d231, 4645200000000000000000); + _singleInitialMintAndLock(0x274949b0dB377742A46074f75749E953A8da45A7, 5545200000000000000000); + _singleInitialMintAndLock(0xDc43D0c0497FBf3BB3cf43dcAFaCe9c116d5dd21, 120000000000000000000); + _singleInitialMintAndLock(0xAf79312EB821871208ac76A80c8E282f8796964e, 768000000000000000000); + _singleInitialMintAndLock(0xe4ec13946CE37ae7b3EA6AAC315B486DAD7766F2, 774000000000000000000); + _singleInitialMintAndLock(0xB3dDC2A5B4EbDb7640191906Bd4195E23e17142c, 1800000000000000000000); + _singleInitialMintAndLock(0xb0FabE3bCAC50F065DBF68C0B271118DDC005402, 24000000000000000000000); + _singleInitialMintAndLock(0x6fE4aceD57AE0b50D14229F3d40617C8b7d2F2E1, 2230332000000000000000); + _singleInitialMintAndLock(0xd264bC31A13D962c22967f02e44DAdD8Bbf25232, 240000000000000000000); + _singleInitialMintAndLock(0xbFB5458071867Bc00985BC6c13EE400327Ac5F97, 60000000000000000000); + _singleInitialMintAndLock(0x56F662AADe12e5aB99C4dcb037d1274d0d5dcb94, 29897047241334700000000); + _singleInitialMintAndLock(0x3a390b018fc3425d06FB84DCcdD140481A960939, 2452800000000000000000); + _singleInitialMintAndLock(0xCb59280EB3983a4221263343EF184D2D0189De17, 158400000000000000000); + _singleInitialMintAndLock(0x0d7BbDb6d0D82E896ECB8ED8Bc33aaBd20dE0dA9, 3506400000000000000000); + _singleInitialMintAndLock(0x2ed284077cc25A3f400DAEA79714Ac4A5AC474aC, 613200000000000000000); + _singleInitialMintAndLock(0x14989473630F117Dd5583B946B9B4733CD305e57, 6741600000000000000000); + _singleInitialMintAndLock(0x6f5a8A35fb10EEcEF9128f407a0fe67B898556CF, 12554198211802100000000); + _singleInitialMintAndLock(0x812B9c3Ea2c49beC95D0Bcda4Db39513baaee261, 1789008000000000000000); + _singleInitialMintAndLock(0x80bb0D87DCe1a94329586Ce9C7d39692bBf44af6, 1200000000000000000000); + _singleInitialMintAndLock(0x80bb0D87DCe1a94329586Ce9C7d39692bBf44af6, 120000000000000000000); + _singleInitialMintAndLock(0x30B5a6e6f54507E0DEE280923234204B6A82664A, 195492000000000000000); + _singleInitialMintAndLock(0x2e0692A3d9097931E9b7ba47035C8EA4A388f747, 7044000000000000000000); + _singleInitialMintAndLock(0x57702217d1cDbf4DF7110ABD91832216310B4062, 1200000000000000000000); + _singleInitialMintAndLock(0x09bAc567D73E8BC701a900D14C90c06644eA0156, 885600000000000000000); + _singleInitialMintAndLock(0x4A228f14d2130E8E4636418B52aAF3D6b4E887D3, 4382400000000000000000); + _singleInitialMintAndLock(0xd8b87A01980eB792e3BC030bDEc42Db2b9B5CBfc, 241200000000000000000); + _singleInitialMintAndLock(0x25217b4A6138350350A2ce1f97A6B0111bbFdB56, 1200000000000000000000); + _singleInitialMintAndLock(0x973872cA85cD7175b02FE24701438174901ED751, 1560000000000000000000); + _singleInitialMintAndLock(0xB0720A40d6335dF0aC90fF9e4b755217632Ca78C, 1488000000000000000000); + _singleInitialMintAndLock(0x3AA6605d87f611E43aD0a64740d6BeF9b80FCD2C, 6000000000000000000000); + _singleInitialMintAndLock(0x135Cc51c0b07a8f70256e8DF398e6B916b402444, 360000000000000000000); + _singleInitialMintAndLock(0x945a873B0E08a361458141f637031490cA01b9c1, 576000000000000000000); + _singleInitialMintAndLock(0x464F6392E68Bc6093354E5bf12692e37F5e4113e, 1200000000000000000000); + _singleInitialMintAndLock(0x1C86E98A4CC451db8A502f31c14327D2B7CEC123, 339532320000000000000); + _singleInitialMintAndLock(0x17114903eB90909D3058dAE24D583E5970030FFb, 5400000000000000000000); + _singleInitialMintAndLock(0x17114903eB90909D3058dAE24D583E5970030FFb, 3829200000000000000000); + _singleInitialMintAndLock(0xe12D731750E222eC53b001E00d978901B134CFC9, 332400000000000000000); + _singleInitialMintAndLock(0x801612E860e40612cfbbdEF0133A2Fb6938f2f73, 48000000000000000000); + _singleInitialMintAndLock(0xe12D731750E222eC53b001E00d978901B134CFC9, 2145600000000000000000); + _singleInitialMintAndLock(0xE7A1C621Ed75EC40fe4c86605e60d2851287D14D, 146400000000000000000); + _singleInitialMintAndLock(0xD1A0B66835D830e9ada42eEf436f3AA8005b20B5, 1896000000000000000000); + _singleInitialMintAndLock(0x7Cb552152e2b28F9f6911c51B69B0d8D1FADafe1, 96000000000000000000); + _singleInitialMintAndLock(0x249A49d3201C1B92a1029Aab1BC76a6Ca8f5FFf0, 248400000000000000000); + _singleInitialMintAndLock(0xc27FD9D5113dE19EA89D0265Be9FD93F35f052c8, 2341200000000000000000); + _singleInitialMintAndLock(0xf6301E682769A8b3ECdCe94b2419ba40A958D17e, 3085080000000000000000); + _singleInitialMintAndLock(0xfe5a2B6Cf60e8A5c06a87c999E7944421653e0f3, 240000000000000000000); + _singleInitialMintAndLock(0x0D0d6625F9A0B3370b4b69393E59fdD4d077BB38, 784800000000000000000); + _singleInitialMintAndLock(0xbC82A7232c1f043e4cc608e0eC1510Cf50E28f64, 108000000000000000000); + _singleInitialMintAndLock(0x35128c4263aA0213c59A897Fd31d8C837E8B71C8, 120000000000000000000); + _singleInitialMintAndLock(0x7Cb552152e2b28F9f6911c51B69B0d8D1FADafe1, 12000000000000000000); + _singleInitialMintAndLock(0xDE0187458364Eb836D5bF563721efD1ED14B9673, 240000000000000000000); + _singleInitialMintAndLock(0x0a3043F9d2b1c6cCfc492EB59Af5156F378c57BD, 1200000000000000000); + _singleInitialMintAndLock(0xAE886e2A6AA00e98C0C7b1e4885f94a2dB720690, 6240696000000000000000); + _singleInitialMintAndLock(0x5fA275BA9F04BDC906084478Dbf41CBE29388C5d, 112800000000000000000); + _singleInitialMintAndLock(0x97294B51BF128E6988c7747E0696Ed7F7CfEe993, 1856040000000000000000); + _singleInitialMintAndLock(0x945a873B0E08a361458141f637031490cA01b9c1, 805200000000000000000); + _singleInitialMintAndLock(0x865D7eb5db37cc02ec209DD778f4e3851a421A20, 329760000000000000000); + _singleInitialMintAndLock(0x97c98D6ab8DBbfe6ba464BD7a849d376DA1bB540, 180000000000000000000); + _singleInitialMintAndLock(0x55e1490a1878D0B61811726e2cB96560022E764c, 86880000000000000000); + _singleInitialMintAndLock(0x97Db0E57b1C315a08cc889Ed405ADB100D7F137d, 1327116000000000000000); + _singleInitialMintAndLock(0xc45D05CDc809d20c7B14959E8cd4a1199E3e966F, 1419144000000000000000); + _singleInitialMintAndLock(0xEfce38f31Ebeb9637E85D3487595261FDf6ebeEb, 174600000000000000000); + _singleInitialMintAndLock(0x5A1a3dff949225E39767Ca981218756DB47C7d8c, 60000000000000000000); + _singleInitialMintAndLock(0xd286a9bB11d2165915E3bf6D1c79aadEBe30f605, 90900000000000000000); + _singleInitialMintAndLock(0xBd1E1Cc9613B510d1669D1e79Fd0115C70a4C7be, 480000000000000000000); + _singleInitialMintAndLock(0xBd1E1Cc9613B510d1669D1e79Fd0115C70a4C7be, 547200000000000000000); + _singleInitialMintAndLock(0xC438E5d32f9381b59072b9a0c730Cbac41575A4E, 6000000000000000000000); + _singleInitialMintAndLock(0x1E480827489E3eA19f82EF213b67200A76C0DF58, 360000000000000000000); + _singleInitialMintAndLock(0x0D69BF20A4A00cbebC569E4beF27a78DcB4C0880, 240000000000000000000); + _singleInitialMintAndLock(0x1E480827489E3eA19f82EF213b67200A76C0DF58, 1492800000000000000000); + _singleInitialMintAndLock(0x908E8E8084d660f8f9054AA8Ad1B31380d04B08F, 85572000000000000000); + _singleInitialMintAndLock(0xdDb3e886D78F180A0B435741901cE091cdd0a848, 1862400000000000000000); + _singleInitialMintAndLock(0x90F15E09B8Fb5BC080B968170C638920Db3A3446, 120000000000000000000000); + _singleInitialMintAndLock(0xbC82A7232c1f043e4cc608e0eC1510Cf50E28f64, 217200000000000000000); + _singleInitialMintAndLock(0x56E30aF541D4d54b96770Ecc1a9113F02FEe3bf1, 18917688000000000000000); + _singleInitialMintAndLock(0x20cE0C0f284219f4E0B68804a8333A782461674c, 30000000000000000000); + _singleInitialMintAndLock(0xd7F1BfBfA430FFEE78511E37772cAdaFF63A9A23, 1200000000000000000); + _singleInitialMintAndLock(0xCba1A275e2D858EcffaF7a87F606f74B719a8A93, 300000000000000000000000); + _singleInitialMintAndLock(0x4A401Ee7Fef089CD20D183fE2510d7BD38294728, 241200000000000000000); + _singleInitialMintAndLock(0xFe36AacBCF5677a4A04288764C16acb4220894b9, 1200000000000000000000); + _singleInitialMintAndLock(0x707c4603FB72996FF95AB91f571516aFC0F3Fe1b, 61398000000000000000); + _singleInitialMintAndLock(0xAA1742ab92c694934b97Ab9F557E565Bd2217BFf, 120000000000000000000); + _singleInitialMintAndLock(0xE524D29daf6D7CDEaaaF07Fa1aa7732a45f330B3, 1080000000000000000000); + _singleInitialMintAndLock(0x8E07Ab8Fc9E5F2613b17a5E5069673d522D0207a, 120000000000000000000); + _singleInitialMintAndLock(0x9DEB607b7E92096df55b02aA563e82F612fD0DEf, 1670256000000000000000); + _singleInitialMintAndLock(0x7798Ba9512B5A684C12e31518923Ea4221A41Fb9, 1712160000000000000000); + _singleInitialMintAndLock(0x868CBfd33ec93B451c510125E4D9f1AB1E42fcD2, 1680396000000000000000); + _singleInitialMintAndLock(0xAB63953B631336bD204fdcF126e2a010A47b1A36, 780000000000000000000); + _singleInitialMintAndLock(0x7074E05C39b41EDd1C16478856b5de54B3ac67D6, 1200000000000000000); + _singleInitialMintAndLock(0x479dE30A1E7e53657C437a6d36ae6389B290B5Fb, 3600000000000000000000); + _singleInitialMintAndLock(0xb8920e475E32B807cE51e0eF823fE070D7D96e8C, 528000000000000000000); + _singleInitialMintAndLock(0xb0916C38861dCeef1A62A77887e573861FFb5d63, 27600000000000000000); + _singleInitialMintAndLock(0x707c4603FB72996FF95AB91f571516aFC0F3Fe1b, 27634800000000000000); + _singleInitialMintAndLock(0xDEb3994785Bfc8863e808df0E0C43C9C0058d7c9, 571440000000000000000); + _singleInitialMintAndLock(0x4CE69fd760AD0c07490178f9a47863Dc0358cCCD, 600000000000000000000); + _singleInitialMintAndLock(0x6F106e0ef498a594CCE8280976822fA3798A35cb, 2429760000000000000000); + _singleInitialMintAndLock(0x9b25235ee2e5564F50810E03eA5F91976A8EE6fA, 4705200000000000000000); + _singleInitialMintAndLock(0xEFa9bEbE299dE7AcAECa6876E1E4f5508eEeF2db, 7200000000000000000); + _singleInitialMintAndLock(0x5fA275BA9F04BDC906084478Dbf41CBE29388C5d, 120000000000000000000); + _singleInitialMintAndLock(0x5fA275BA9F04BDC906084478Dbf41CBE29388C5d, 62400000000000000000); + _singleInitialMintAndLock(0xC9eebecb1d0AfF4fb2B9978516E075A33639892C, 1200000000000000000000); + _singleInitialMintAndLock(0x865D7eb5db37cc02ec209DD778f4e3851a421A20, 364800000000000000000); + _singleInitialMintAndLock(0xd0441C0B63f6c97D56e9490B3fdd1c45F89D3678, 5806800000000000000000); + _singleInitialMintAndLock(0xb0916C38861dCeef1A62A77887e573861FFb5d63, 14400000000000000000); + _singleInitialMintAndLock(0xbA00D84Ddbc8cAe67C5800a52496E47A8CaFcd27, 21493200000000000000000); + _singleInitialMintAndLock(0xD40846A19fdC9c8255DCcD18BcBB261BDBF5e4db, 338040000000000000000); + _singleInitialMintAndLock(0xFe36AacBCF5677a4A04288764C16acb4220894b9, 1200000000000000000000); + _singleInitialMintAndLock(0x4c890Dc20f7D99D0135396A08d07d1518a45a1DD, 1200000000000000000); + _singleInitialMintAndLock(0xbA00D84Ddbc8cAe67C5800a52496E47A8CaFcd27, 19147200000000000000000); + _singleInitialMintAndLock(0xD40846A19fdC9c8255DCcD18BcBB261BDBF5e4db, 2815200000000000000000); + _singleInitialMintAndLock(0x5fA275BA9F04BDC906084478Dbf41CBE29388C5d, 122400000000000000000); + _singleInitialMintAndLock(0xD40846A19fdC9c8255DCcD18BcBB261BDBF5e4db, 978000000000000000000); + _singleInitialMintAndLock(0x9505F160A9a74ad532d674De4F200484e0049b43, 1489680000000000000000); + _singleInitialMintAndLock(0x9505F160A9a74ad532d674De4F200484e0049b43, 1489680000000000000000); + _singleInitialMintAndLock(0xb6fB12999a09eFfdbcC6F60776331eacCc42E539, 60000000000000000000000); + _singleInitialMintAndLock(0xb6fB12999a09eFfdbcC6F60776331eacCc42E539, 60000000000000000000000); + _singleInitialMintAndLock(0x0a3043F9d2b1c6cCfc492EB59Af5156F378c57BD, 14164800000000000000000); + _singleInitialMintAndLock(0xD26eA7412FB75D5E4c8c9F3EE7b1dfFf64440eE8, 31200000000000000000); + _singleInitialMintAndLock(0xDE0187458364Eb836D5bF563721efD1ED14B9673, 6000000000000000000); + _singleInitialMintAndLock(0x859Fc918Cf1322686FeC52A30E4A9eA388DF876D, 12000000000000000000); + _singleInitialMintAndLock(0xe9bCCEd88099FC4aacF78b7c43307E758E1a5382, 1200000000000000000000); + _singleInitialMintAndLock(0x7206BC81E2C52441EEFfE120118aC880f4528dDA, 3049200000000000000000); + _singleInitialMintAndLock(0x1448D297420799a0dEB4bE0C270E8ec310c8E8dD, 4800000000000000000); + _singleInitialMintAndLock(0x75592081D5FC1c38d2da8098dfE535CaDBe39425, 12000000000000000000); + _singleInitialMintAndLock(0x9105F56F58A9cDB0e2DFb8696197CFAF3E45b9F0, 2904000000000000000); + _singleInitialMintAndLock(0x8DE3c3891268502F77DB7E876d727257DEc0F852, 40380000000000000000); + _singleInitialMintAndLock(0x5D8A52e816b7A29789C32dD21A034caDDd2bC750, 60000000000000000000); + _singleInitialMintAndLock(0x7074E05C39b41EDd1C16478856b5de54B3ac67D6, 1200000000000000000); + _singleInitialMintAndLock(0xD016cCF7B485D658E063d2E7CB3Afef94Bf79548, 6000000000000000000); + _singleInitialMintAndLock(0x7A8B83DaC270463895233Bb3932A799c12919f27, 4200000000000000000); + _singleInitialMintAndLock(0xDE0187458364Eb836D5bF563721efD1ED14B9673, 337200000000000000000); + _singleInitialMintAndLock(0xdDb3e886D78F180A0B435741901cE091cdd0a848, 165264000000000000000); + _singleInitialMintAndLock(0x0b776552c1Aef1Dc33005DD25AcDA22493b6615d, 1200120000000000000000); + _singleInitialMintAndLock(0x9BDbdb4A8f7f816C87a67F5281484ED902C6b942, 1800000000000000000); + _singleInitialMintAndLock(0xf4E2152c622260A1f1f8E8B8c4C3C5065165Ce55, 118800000000000000000); + _singleInitialMintAndLock(0xd204Bc46046FC0Cd3f074fF9B3Be7b5C59f0a150, 3475464000000000000000); + _singleInitialMintAndLock(0xD7bb2EeE591CE19A54636600936eAB8a40f5a65C, 9600000000000000000); + _singleInitialMintAndLock(0xEb0CeB1F89D1dd01bDFD2Ff9e145271d8FEEfB00, 192000000000000000000); + _singleInitialMintAndLock(0x686Bd59caE3e78107515E87B2895cCBe27fb7D0A, 1800000000000000000000); + _singleInitialMintAndLock(0xb245A959A3D2608e248239638a240c5FCFE20596, 856800000000000000000); + _singleInitialMintAndLock(0xdDb3e886D78F180A0B435741901cE091cdd0a848, 246396000000000000000); + _singleInitialMintAndLock(0x4A80f927126eC56c1E6773805fFa03A04216b293, 28406400000000000000000); + _singleInitialMintAndLock(0xB1e22281E1BC8Ab83Da1CB138e24aCB004B5a4ca, 3600000000000000000000); + _singleInitialMintAndLock(0x84A51c92a653dc0e6AE11C9D873C55Ee7Af62106, 2113200000000000000); + _singleInitialMintAndLock(0x84A51c92a653dc0e6AE11C9D873C55Ee7Af62106, 2110800000000000000000); + _singleInitialMintAndLock(0x3bE2a617a86DD49Bc8893ca04CEa2e5F444F9c12, 717600000000000000000); + + // set initializer to 0 so we can no longer mint more + minter.startActivePeriod(); + + vm.stopBroadcast(); + } + + function _singleInitialMintAndLock(address owner, uint256 amount) private { + Minter.Claim[] memory claim = new Minter.Claim[](1); + claim[0] = Minter.Claim({claimant: owner, amount: amount, lockTime: FOUR_YEARS}); + minter.initialMintAndLock(claim, amount); + } + + function _batchInitialMintAndLock( + address owner, + uint256 numberOfVotingEscrow, + uint256 amountPerVotingEscrow, + uint256 lockTime + ) private { + Minter.Claim[] memory claim = new Minter.Claim[](numberOfVotingEscrow); + for (uint256 i; i < numberOfVotingEscrow; i++) { + claim[i] = Minter.Claim({claimant: owner, amount: amountPerVotingEscrow, lockTime: lockTime}); + } + minter.initialMintAndLock(claim, amountPerVotingEscrow * numberOfVotingEscrow); + } +} diff --git a/scripts/TeamMemberVesting.s.sol b/scripts/TeamMemberVesting.s.sol new file mode 100644 index 00000000..f68b100a --- /dev/null +++ b/scripts/TeamMemberVesting.s.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +// Scripting tool +import {Script} from "../lib/forge-std/src/Script.sol"; + +import {FlowVestor} from "../contracts/FlowVestor.sol"; +import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; + +contract TeamMemberVesting is Script { + address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; + // TODO: reset DEPLOYER_EOA + address private constant DEPLOYER_EOA = 0xD93142ED5B85FcA4550153088750005759CE8318; + // team member addresses + address private constant T0RB1K = 0x0b776552c1Aef1Dc33005DD25AcDA22493b6615d; + address private constant MOTTO = 0x78e801136F77805239A7F533521A7a5570F572C8; + address private constant COOLIE = 0x03B88DacB7c21B54cEfEcC297D981E5b721A9dF1; + + // TODO: Fill the address + address private constant FLOW = 0x78e489523291581205Ea3fA16a69689EcA79757A; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + FlowVestor flowVestor = new FlowVestor(FLOW); + + IERC20(FLOW).approve(address(flowVestor), 4_500_000e18); + flowVestor.vestFor(T0RB1K, 2_000_000e18); + flowVestor.vestFor(MOTTO, 2_000_000e18); + flowVestor.vestFor(COOLIE, 500_000e18); + + flowVestor.transferOwnership(TEAM_MULTI_SIG); + + uint256 looseTokens = IERC20(FLOW).balanceOf(DEPLOYER_EOA); + IERC20(FLOW).transfer(TEAM_MULTI_SIG, looseTokens); + + vm.stopBroadcast(); + } +} diff --git a/scripts/VeNFTSnapshot.s.sol b/scripts/VeNFTSnapshot.s.sol new file mode 100644 index 00000000..f993121c --- /dev/null +++ b/scripts/VeNFTSnapshot.s.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +// Scripting tool +import "forge-std/console2.sol"; +import {Script} from "../lib/forge-std/src/Script.sol"; + +import {VotingEscrow} from "../contracts/VotingEscrow.sol"; + +contract VeNFTSnapshot is Script { + function run() external view { + VotingEscrow votingEscrow = VotingEscrow(0x990efF367C6c4aece43c1E98099061c897730F27); + // From https://alto.build/collections/0x990eff367c6c4aece43c1e98099061c897730f27 + uint256 currentTokenId = 0; + uint256 maxTokenId = 267; + while (currentTokenId <= maxTokenId) { + address owner = votingEscrow.ownerOf(currentTokenId); + + if (owner != address(0)) { + (int128 lockAmount,) = votingEscrow.locked(currentTokenId); + + console2.log("Token ID: "); + console2.log(currentTokenId); + console2.log("Owner: "); + console2.log(owner); + console2.log("Locked amount: "); + console2.log(lockAmount); + } + + currentTokenId++; + } + } +} diff --git a/tasks/deploy/constants/optimismConfig.ts b/tasks/deploy/constants/optimismConfig.ts deleted file mode 100644 index 8eb91894..00000000 --- a/tasks/deploy/constants/optimismConfig.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { ethers } from "ethers"; - -const TOKEN_DECIMALS = ethers.BigNumber.from("10").pow( - ethers.BigNumber.from("18") -); -const MILLION = ethers.BigNumber.from("10").pow(ethers.BigNumber.from("6")); - -const FOUR_MILLION = ethers.BigNumber.from("4") - .mul(MILLION) - .mul(TOKEN_DECIMALS); -const TEN_MILLION = ethers.BigNumber.from("10") - .mul(MILLION) - .mul(TOKEN_DECIMALS); -const TWENTY_MILLION = ethers.BigNumber.from("20") - .mul(MILLION) - .mul(TOKEN_DECIMALS); -const PARTNER_MAX = ethers.BigNumber.from("78") - .mul(MILLION) - .mul(TOKEN_DECIMALS); - -const TEAM_MULTISIG = "0xb074ec6c37659525EEf2Fb44478077901F878012"; -const TEAM_EOA = "0xe247340f06FCB7eb904F16a48C548221375b5b96"; - -const optimismConfig = { - // Chain const - lzChainId: 11, - lzEndpoint: "0x3c2269811836af69497E5F486A85D7316753cf62", - - // Tokens - WETH: "0x4200000000000000000000000000000000000006", - USDC: "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", - - // Addresses - teamEOA: TEAM_EOA, - teamMultisig: TEAM_MULTISIG, - emergencyCouncil: "0xcC2D01030eC2cd187346F70bFc483F24488C32E8", - - merkleRoot: - "0xbb99a09fb3b8499385659e82a8da93596dd07082fe86981ec06c83181dee489f", - tokenWhitelist: [ - "0x4200000000000000000000000000000000000042", // OP - "0x4200000000000000000000000000000000000006", // WETH - "0x7F5c764cBc14f9669B88837ca1490cCa17c31607", // USDC - "0x2E3D870790dC77A83DD1d18184Acc7439A53f475", // FRAX - "0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1", // DAI - "0x8c6f28f2F1A3C87F0f938b96d27520d9751ec8d9", // sUSD - "0x217D47011b23BB961eB6D93cA9945B7501a5BB11", // THALES - "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb", // LYRA - "0x67CCEA5bb16181E7b4109c9c2143c24a1c2205Be", // FXS - "0x9e1028F5F1D5eDE59748FFceE5532509976840E0", // PERP - "0x8700dAec35aF8Ff88c16BdF0418774CB3D7599B4", // SNX - "0xCB8FA9a76b8e203D8C3797bF438d8FB81Ea3326A", // alUSD - "0x3E29D3A9316dAB217754d13b28646B76607c5f04", // alETH - "0x8aE125E8653821E851F12A49F7765db9a9ce7384", // DOLA - "0x10010078a54396F62c96dF8532dc2B4847d47ED3", // HND - // "", // BTRFLY -- N/A - // "", // pxVELO -- N/A - "0xc40F949F8a4e094D1b49a23ea9241D289B7b2819", // LUSD - // "", // wstETH -- N/A - // "", // HOP -- N/A - ], - partnerAddrs: [ - TEAM_EOA, // VELO - "0x4a84675512949f81EBFEAAcC6C00D03eDd329de5", // OP - TEAM_EOA, // SNX -- custodied - "0xa283139017a2f5BAdE8d8e25412C600055D318F8", // INV - "0xDcf664d0f76E99eaA2DBD569474d0E75dC899FCD", // PERP - "0x489863b61C625a15C74FB4C21486baCb4A3937AB", // THALES - "0x641f26c67A5D0829Ae61019131093B6a7c7d18a3", // HND - "0xC224bf25Dcc99236F00843c7D8C4194abE8AA94a", // ALCX - "0xB6DACAE4eF97b4817d54df8e005269f509f803f9", // LYRA - TEAM_EOA, // MKR -- custodied - TEAM_EOA, // HOP -- custodied - "0x0dF840dCbf1229262A4125C1fc559bd338eC9491", // FRAX - "0x2E33A660742e813aD948fB9f7d682FE461E5fbf3", // BTRFLY - "0xd2D4e9024D8C90aB52032a9F1e0d92D4cE20191B", // LUSD - ], - partnerAmts: [ - TEN_MILLION, - TWENTY_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - FOUR_MILLION, - ], - partnerMax: PARTNER_MAX, -}; - -export default optimismConfig; diff --git a/tasks/deploy/op.ts b/tasks/deploy/op.ts index cb11ded2..b16c9f2c 100644 --- a/tasks/deploy/op.ts +++ b/tasks/deploy/op.ts @@ -1,6 +1,5 @@ import { task } from "hardhat/config"; -import optimismConfig from "./constants/optimismConfig"; import testOptimismConfig from "./constants/testOptimismConfig"; task("deploy:op", "Deploys Optimism contracts").setAction(async function ( @@ -9,7 +8,7 @@ task("deploy:op", "Deploys Optimism contracts").setAction(async function ( ) { const mainnet = false; - const OP_CONFIG = mainnet ? optimismConfig : testOptimismConfig; + const OP_CONFIG = testOptimismConfig; // Load const [ @@ -31,7 +30,7 @@ task("deploy:op", "Deploys Optimism contracts").setAction(async function ( ethers.getContractFactory("BribeFactory"), ethers.getContractFactory("PairFactory"), ethers.getContractFactory("Router"), - ethers.getContractFactory("VelodromeLibrary"), + ethers.getContractFactory("VelocimeterLibrary"), ethers.getContractFactory("VeArtProxy"), ethers.getContractFactory("VotingEscrow"), ethers.getContractFactory("RewardsDistributor"), @@ -63,7 +62,7 @@ task("deploy:op", "Deploys Optimism contracts").setAction(async function ( const library = await Library.deploy(router.address); await library.deployed(); - console.log("VelodromeLibrary deployed to: ", library.address); + console.log("VelocimeterLibrary deployed to: ", library.address); console.log("Args: ", router.address, "\n"); const artProxy = await VeArtProxy.deploy(); @@ -120,9 +119,6 @@ task("deploy:op", "Deploys Optimism contracts").setAction(async function ( await flow.setMinter(minter.address); console.log("Minter set"); - await pairFactory.setPauser(OP_CONFIG.teamMultisig); - console.log("Pauser set"); - await escrow.setVoter(voter.address); console.log("Voter set"); @@ -147,13 +143,15 @@ task("deploy:op", "Deploys Optimism contracts").setAction(async function ( await voter.initialize(tokenWhitelist, minter.address); console.log("Whitelist set"); - // Initial veVELO distro - await minter.initialize( + // Initial veFLOW distro + await minter.initialMintAndLock( OP_CONFIG.partnerAddrs, OP_CONFIG.partnerAmts, OP_CONFIG.partnerMax ); - console.log("veVELO distributed"); + await minter.startActivePeriod(); + console.log("veFLOW distributed"); + await minter.setTeam(OP_CONFIG.teamMultisig) console.log("Team set for minter"); diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol new file mode 100644 index 00000000..775e2e8b --- /dev/null +++ b/test/AutoBribe.t.sol @@ -0,0 +1,335 @@ +pragma solidity 0.8.13; + +import "./BaseTest.sol"; +import "contracts/AutoBribe.sol"; +import "contracts/WrappedBribe.sol"; +import "contracts/factories/WrappedBribeFactory.sol"; +import "contracts/factories/WrappedExternalBribeFactory.sol"; +import "forge-std/console2.sol"; + +contract AutoBribeTest is BaseTest { + VotingEscrow escrow; + GaugeFactory gaugeFactory; + BribeFactory bribeFactory; + WrappedBribeFactory wbribeFactory; + WrappedExternalBribeFactory wxbribeFactory; + Voter voter; + RewardsDistributor distributor; + Minter minter; + Gauge gauge; + ExternalBribe xbribe; + WrappedBribe wbribe; + AutoBribe autoBribe; + Gauge gauge2; + ExternalBribe xbribe2; + WrappedBribe wbribe2; + AutoBribe autoBribe2; + + function setUp() public { + vm.warp(block.timestamp + 1 weeks); // put some initial time in + + deployOwners(); + deployCoins(); + mintStables(); + uint256[] memory amounts = new uint256[](3); + amounts[0] = 2e25; + amounts[1] = 1e25; + amounts[2] = 1e25; + mintFlow(owners, amounts); + mintLR(owners, amounts); + mintWETH(owners, amounts); + VeArtProxy artProxy = new VeArtProxy(); + escrow = new VotingEscrow( + address(FLOW), + address(artProxy), + owners[0], + csrNftId + ); + deployPairFactoryAndRouter(); + + // deployVoter() + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter( + address(escrow), + address(factory), + address(gaugeFactory), + address(bribeFactory), + address(wxbribeFactory), + csrNftId + ); + wbribeFactory = new WrappedBribeFactory(address(voter), csrNftId); + + escrow.setVoter(address(voter)); + factory.setVoter(address(voter)); + wxbribeFactory.setVoter(address(voter)); + deployPairWithOwner(address(owner)); + + // deployMinter() + distributor = new RewardsDistributor(address(escrow), csrNftId); + minter = new Minter( + address(voter), + address(escrow), + address(distributor), + csrNftId + ); + distributor.setDepositor(address(minter)); + FLOW.setMinter(address(minter)); + address[] memory tokens = new address[](5); + tokens[0] = address(USDC); + tokens[1] = address(FRAX); + tokens[2] = address(DAI); + tokens[3] = address(FLOW); + tokens[4] = address(LR); + voter.initialize(tokens, address(minter)); + + // USDC - FRAX stable + gauge = Gauge(voter.createGauge(address(pair))); + xbribe = ExternalBribe(gauge.external_bribe()); + wbribe = WrappedBribe(wbribeFactory.createBribe(address(xbribe))); + autoBribe = new AutoBribe( + address(voter), + address(wbribe), + address(owner), + "AUTO", + csrNftId + ); + + vm.startPrank(address(owner)); + autoBribe.initProject(address(owner2)); + vm.stopPrank(); + } + + function testSetUpCorrectly() public { + assertEq(autoBribe.owner(), address(owner)); + assertEq(autoBribe.project(), address(owner2)); + assertEq(autoBribe.wBribe(), address(wbribe)); + } + + function testCanDepositAndBribeEveryWeek( + uint256 depositAmountLR, + uint256 depositAmountFLOW, + uint256 depositWeeks + ) public { + vm.assume( + depositAmountLR > depositWeeks && + depositAmountLR <= 1e25 && + depositAmountFLOW > depositWeeks && + depositAmountFLOW <= 1e25 && + depositWeeks > 0 && + depositWeeks < 52 + ); + + vm.warp(block.timestamp + 1 weeks / 2); + + // Project deposit tokens + vm.startPrank(address(owner2)); + LR.approve(address(autoBribe), depositAmountLR); + autoBribe.deposit(address(LR), depositAmountLR, depositWeeks); + + FLOW.approve(address(autoBribe), depositAmountFLOW); + autoBribe.deposit(address(FLOW), depositAmountFLOW, depositWeeks); + vm.stopPrank(); + + uint256 balanceBeforeLR = LR.balanceOf(address(this)); + uint256 balanceBeforeFLOW = FLOW.balanceOf(address(this)); + + for (uint256 i = 0; i < depositWeeks - 1; ) { + autoBribe.bribe(); + vm.warp(block.timestamp + 1 weeks); + + unchecked { + ++i; + } + } + + assertGt(LR.balanceOf(address(autoBribe)), 0); + assertGt(FLOW.balanceOf(address(autoBribe)), 0); + + autoBribe.bribe(); + vm.warp(block.timestamp + 1 weeks); + + assertEq(LR.balanceOf(address(autoBribe)), 0); + assertEq(FLOW.balanceOf(address(autoBribe)), 0); + assertEq( + LR.balanceOf(address(wbribe)) + + LR.balanceOf(address(this)) - + balanceBeforeLR, + depositAmountLR + ); + assertEq( + FLOW.balanceOf(address(wbribe)) + + FLOW.balanceOf(address(this)) - + balanceBeforeFLOW, + depositAmountFLOW + ); + } + + function testCannotDepositNonWhitelistedTokens() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // Project deposit tokens + vm.startPrank(address(owner2)); + LR.approve(address(autoBribe), type(uint256).max); + vm.expectRevert("Bribe Token is not whitelisted"); + autoBribe.deposit(address(WETH), 1e18, 2); + vm.stopPrank(); + } + + function testRedeposit( + uint256 depositAmountLR, + uint256 depositWeeks + ) public { + vm.assume( + depositAmountLR > depositWeeks && + depositAmountLR <= 1e24 && + depositWeeks > 0 && + depositWeeks < 52 + ); + + vm.warp(block.timestamp + 1 weeks / 2); + + // Project deposit tokens + vm.startPrank(address(owner2)); + LR.approve(address(autoBribe), type(uint256).max); + autoBribe.deposit(address(LR), depositAmountLR, depositWeeks); + vm.stopPrank(); + + uint256 balanceBeforeLR = LR.balanceOf(address(this)); + + autoBribe.bribe(); + vm.warp(block.timestamp + 1 weeks); + + vm.startPrank(address(owner2)); + LR.approve(address(autoBribe), depositAmountLR); + autoBribe.deposit(address(LR), depositAmountLR, depositWeeks); + vm.stopPrank(); + + for (uint256 i = 0; i < depositWeeks * 2 - 2; ) { + autoBribe.bribe(); + vm.warp(block.timestamp + 1 weeks); + + unchecked { + ++i; + } + } + + assertGt(LR.balanceOf(address(autoBribe)), 0); + + autoBribe.bribe(); + vm.warp(block.timestamp + 1 weeks); + + assertEq(LR.balanceOf(address(autoBribe)), 0); + assertEq( + LR.balanceOf(address(wbribe)) + + LR.balanceOf(address(this)) - + balanceBeforeLR, + depositAmountLR * 2 + ); + } + + function testCannotBribeTwice( + uint256 depositAmountLR, + uint256 depositWeeks + ) public { + vm.assume( + depositAmountLR > depositWeeks && + depositAmountLR <= 1e25 && + depositWeeks > 0 && + depositWeeks < 52 + ); + + vm.warp(block.timestamp + 1 weeks / 2); + + // Project deposit tokens + vm.startPrank(address(owner2)); + LR.approve(address(autoBribe), depositAmountLR); + autoBribe.deposit(address(LR), depositAmountLR, depositWeeks); + vm.stopPrank(); + + autoBribe.bribe(); + + vm.expectRevert("already bribed this week"); + autoBribe.bribe(); + } + + function testEmptyOut( + uint256 depositAmountLR, + uint256 depositAmountFLOW, + uint256 depositWeeks + ) public { + vm.assume( + depositAmountLR > depositWeeks && + depositAmountLR <= 1e25 && + depositAmountFLOW > depositWeeks && + depositAmountFLOW <= 1e25 && + depositWeeks > 0 && + depositWeeks < 52 + ); + + vm.warp(block.timestamp + 1 weeks / 2); + + // Project deposit tokens + vm.startPrank(address(owner2)); + LR.approve(address(autoBribe), depositAmountLR); + autoBribe.deposit(address(LR), depositAmountLR, depositWeeks); + + FLOW.approve(address(autoBribe), depositAmountFLOW); + autoBribe.deposit(address(FLOW), depositAmountFLOW, depositWeeks); + + autoBribe.seal(); + vm.stopPrank(); + + vm.expectRevert("only project can empty out"); + autoBribe.emptyOut(); + + vm.startPrank(address(owner2)); + vm.expectRevert("deposit is sealed"); + autoBribe.emptyOut(); + vm.stopPrank(); + + vm.startPrank(address(owner)); + autoBribe.unSeal(); + vm.stopPrank(); + + uint256 balanceBeforeLR = LR.balanceOf(address(owner2)); + uint256 balanceBeforeFLOW = FLOW.balanceOf(address(owner2)); + + vm.startPrank(address(owner2)); + autoBribe.emptyOut(); + vm.stopPrank(); + + assertEq(autoBribe.bribeTokenToWeeksLeft(address(LR)), 0); + assertEq(autoBribe.bribeTokenToWeeksLeft(address(FLOW)), 0); + + assertEq(LR.balanceOf(address(autoBribe)), 0); + assertEq(FLOW.balanceOf(address(autoBribe)), 0); + + assertEq( + LR.balanceOf(address(owner2)) - balanceBeforeLR, + depositAmountLR + ); + assertEq( + FLOW.balanceOf(address(owner2)) - balanceBeforeFLOW, + depositAmountFLOW + ); + } + + function testTeamCannotInitProjectTwice() public { + vm.startPrank(address(owner)); + vm.expectRevert("project wallet can only be set once by team"); + autoBribe.initProject(address(owner2)); + vm.stopPrank(); + } + + function testProjectSetProjectTwice() public { + vm.startPrank(address(owner2)); + autoBribe.setProject(address(owner3)); + vm.stopPrank(); + + vm.startPrank(address(owner3)); + autoBribe.setProject(address(0x10)); + vm.stopPrank(); + } +} diff --git a/test/BaseTest.sol b/test/BaseTest.sol index f2f5fc5d..4c56cc76 100644 --- a/test/BaseTest.sol +++ b/test/BaseTest.sol @@ -14,7 +14,7 @@ import "contracts/Pair.sol"; import "contracts/RewardsDistributor.sol"; import "contracts/Router.sol"; import "contracts/Flow.sol"; -import "contracts/VelodromeLibrary.sol"; +import "contracts/VelocimeterLibrary.sol"; import "contracts/Voter.sol"; import "contracts/VeArtProxy.sol"; import "contracts/VotingEscrow.sol"; @@ -34,7 +34,11 @@ abstract contract BaseTest is Test, TestOwner { uint256 constant TOKEN_100M = 1e26; // 1e8 = 100M tokens with 18 decimals uint256 constant TOKEN_10B = 1e28; // 1e10 = 10B tokens with 18 decimals uint256 constant PAIR_1 = 1e9; + uint256 constant private ONE_DAY = 86400; + uint256 constant internal ONE_WEEK = ONE_DAY * 7; + uint256 constant internal FOUR_YEARS = 4 * 365 * ONE_DAY; + uint256 csrNftId; TestOwner owner; TestOwner owner2; TestOwner owner3; @@ -43,13 +47,12 @@ abstract contract BaseTest is Test, TestOwner { MockERC20 FRAX; MockERC20 DAI; TestWETH WETH; // Mock WETH token - Flow VELO; - MockERC20 WEVE; + Flow FLOW; MockERC20 LR; // late reward TestToken stake; PairFactory factory; Router router; - VelodromeLibrary lib; + VelocimeterLibrary lib; Pair pair; Pair pair2; Pair pair3; @@ -68,8 +71,8 @@ abstract contract BaseTest is Test, TestOwner { USDC = new MockERC20("USDC", "USDC", 6); FRAX = new MockERC20("FRAX", "FRAX", 18); DAI = new MockERC20("DAI", "DAI", 18); - VELO = new Flow(msg.sender); - WEVE = new MockERC20("WEVE", "WEVE", 18); + FLOW = new Flow(msg.sender, msg.sender); + csrNftId = FLOW.csrNftId(); LR = new MockERC20("LR", "LR", 18); WETH = new TestWETH(); stake = new TestToken("stake", "stake", 18, address(owner)); @@ -85,7 +88,7 @@ abstract contract BaseTest is Test, TestOwner { function mintFlow(address[] memory _accounts, uint256[] memory _amounts) public { for (uint256 i = 0; i < _amounts.length; i++) { - VELO.mint(_accounts[i], _amounts[i]); + FLOW.mint(_accounts[i], _amounts[i]); } } @@ -114,16 +117,15 @@ abstract contract BaseTest is Test, TestOwner { } function deployPairFactoryAndRouter() public { - factory = new PairFactory(); + factory = new PairFactory(csrNftId); assertEq(factory.allPairsLength(), 0); factory.setFee(true, 1); // set fee back to 0.01% for old tests factory.setFee(false, 1); - factory.setTeam(address(msg.sender)); // set team factory.setTank(address(msg.sender)); // set tank - router = new Router(address(factory), address(WETH)); + router = new Router(address(factory), address(WETH), csrNftId); assertEq(router.factory(), address(factory)); - lib = new VelodromeLibrary(address(router)); + lib = new VelocimeterLibrary(address(router)); } function deployPairWithOwner(address _owner) public { diff --git a/test/ExternalBribes.t.sol b/test/ExternalBribes.t.sol index 7191a5fb..b42b9986 100644 --- a/test/ExternalBribes.t.sol +++ b/test/ExternalBribes.t.sol @@ -27,14 +27,14 @@ contract ExternalBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); deployPairFactoryAndRouter(); // deployVoter() - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -42,32 +42,32 @@ contract ExternalBribesTest is BaseTest { factory.setVoter(address(voter)); deployPairWithOwner(address(owner)); - distributor = new RewardsDistributor(address(escrow)); - minter = new Minter(address(voter), address(escrow), address(distributor)); + distributor = new RewardsDistributor(address(escrow), csrNftId); + minter = new Minter(address(voter), address(escrow), address(distributor), csrNftId); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); address[] memory tokens = new address[](5); tokens[0] = address(USDC); tokens[1] = address(FRAX); tokens[2] = address(DAI); - tokens[3] = address(VELO); + tokens[3] = address(FLOW); tokens[4] = address(LR); voter.initialize(tokens, address(minter)); - address[] memory claimants = new address[](0); - uint[] memory amounts1 = new uint[](0); - minter.initialize(claimants, amounts1, 0); + Minter.Claim[] memory claims = new Minter.Claim[](0); + minter.initialMintAndLock(claims, 0); + minter.startActivePeriod(); // USDC - FRAX stable gauge = Gauge(voter.createGauge(address(pair))); xbribe = ExternalBribe(gauge.external_bribe()); // ve - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.startPrank(address(owner2)); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(block.timestamp + 1); vm.stopPrank(); } diff --git a/test/FlowConvertor.t.sol b/test/FlowConvertor.t.sol new file mode 100644 index 00000000..7b770b9d --- /dev/null +++ b/test/FlowConvertor.t.sol @@ -0,0 +1,50 @@ +pragma solidity 0.8.13; + +import "forge-std/Test.sol"; +import {Flow} from "../contracts/Flow.sol"; +import {FlowConvertor} from "../contracts/FlowConvertor.sol"; +import {IFlow} from "../contracts/interfaces/IFlow.sol"; + +contract FlowConvertorTest is Test { + address private constant FLOW_V1 = 0x2Baec546a92cA3469f71b7A091f7dF61e5569889; + address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; + + address private constant INITIAL_SUPPLY_RECIPIENT = address(1); + address private constant REDEEMER = address(2); + uint256 private constant FLOW_V1_BALANCE = 1_000e18; + Flow private flow; + FlowConvertor private flowConvertor; + + function setUp() public { + vm.createSelectFork("https://mainnode.plexnode.org:8545"); + + flow = new Flow({initialSupplyRecipient: INITIAL_SUPPLY_RECIPIENT, csrRecipient: TEAM_MULTI_SIG}); + flowConvertor = new FlowConvertor({_v1: FLOW_V1, _v2: address(flow)}); + + vm.prank(INITIAL_SUPPLY_RECIPIENT); + flow.transfer(address(flowConvertor), 50e24); + + deal(FLOW_V1, REDEEMER, FLOW_V1_BALANCE); + } + + function testRedeem() public { + vm.startPrank(REDEEMER); + IFlow(FLOW_V1).approve(address(flowConvertor), FLOW_V1_BALANCE); + flowConvertor.redeem(FLOW_V1_BALANCE); + vm.stopPrank(); + + assertEq(flow.balanceOf(REDEEMER), FLOW_V1_BALANCE); + assertEq(IFlow(FLOW_V1).balanceOf(REDEEMER), 0); + } + + function testRedeemTo() public { + vm.startPrank(REDEEMER); + IFlow(FLOW_V1).approve(address(flowConvertor), FLOW_V1_BALANCE); + address customRecipient = address(3); + flowConvertor.redeemTo(customRecipient, FLOW_V1_BALANCE); + vm.stopPrank(); + + assertEq(flow.balanceOf(customRecipient), FLOW_V1_BALANCE); + assertEq(IFlow(FLOW_V1).balanceOf(REDEEMER), 0); + } +} diff --git a/test/Imbalance.t.sol b/test/Imbalance.t.sol index cc00ee4c..68a4a427 100644 --- a/test/Imbalance.t.sol +++ b/test/Imbalance.t.sol @@ -19,26 +19,26 @@ contract ImbalanceTest is BaseTest { amounts[0] = 1e25; mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); } function createLock() public { deployBaseCoins(); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(1); assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); } function votingEscrowMerge() public { createLock(); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); assertGt(escrow.balanceOfNFT(2), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), 2 * TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), 2 * TOKEN_1); escrow.merge(2, 1); assertGt(escrow.balanceOfNFT(1), 1990039602248405587); assertEq(escrow.balanceOfNFT(2), 0); @@ -79,17 +79,17 @@ contract ImbalanceTest is BaseTest { } function deployVoter() public { - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); wxbribeFactory.setVoter(address(voter)); factory.setVoter(address(voter)); address[] memory tokens = new address[](4); tokens[0] = address(USDC); tokens[1] = address(FRAX); tokens[2] = address(DAI); - tokens[3] = address(VELO); + tokens[3] = address(FLOW); voter.initialize(tokens, address(owner)); assertEq(voter.length(), 0); @@ -97,7 +97,7 @@ contract ImbalanceTest is BaseTest { function deployPairFactoryGauge() public { routerAddLiquidity(); - VELO.approve(address(gaugeFactory), 5 * TOKEN_100K); + FLOW.approve(address(gaugeFactory), 5 * TOKEN_100K); voter.createGauge(address(pair3)); assertFalse(voter.gauges(address(pair3)) == address(0)); diff --git a/test/KillGauges.t.sol b/test/KillGauges.t.sol index 1fc3ee28..e38fda57 100644 --- a/test/KillGauges.t.sol +++ b/test/KillGauges.t.sol @@ -25,23 +25,24 @@ contract KillGaugesTest is BaseTest { amounts[2] = 1e25; mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); - VELO.approve(address(escrow), 100 * TOKEN_1); - escrow.create_lock(100 * TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), 100 * TOKEN_1); + escrow.create_lock(100 * TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); deployPairFactoryAndRouter(); - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); voter = new Voter( address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), - address(wxbribeFactory) + address(wxbribeFactory), + csrNftId ); escrow.setVoter(address(voter)); @@ -49,24 +50,24 @@ contract KillGaugesTest is BaseTest { factory.setVoter(address(voter)); deployPairWithOwner(address(owner)); - distributor = new RewardsDistributor(address(escrow)); + distributor = new RewardsDistributor(address(escrow), csrNftId); - minter = new Minter(address(voter), address(escrow), address(distributor)); + minter = new Minter(address(voter), address(escrow), address(distributor), csrNftId); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); address[] memory tokens = new address[](4); tokens[0] = address(USDC); tokens[1] = address(FRAX); tokens[2] = address(DAI); - tokens[3] = address(VELO); + tokens[3] = address(FLOW); voter.initialize(tokens, address(minter)); - VELO.approve(address(gaugeFactory), 15 * TOKEN_100K); + FLOW.approve(address(gaugeFactory), 15 * TOKEN_100K); voter.createGauge(address(pair)); voter.createGauge(address(pair2)); - staking = new TestStakingRewards(address(pair), address(VELO)); - staking2 = new TestStakingRewards(address(pair2), address(VELO)); + staking = new TestStakingRewards(address(pair), address(FLOW)); + staking2 = new TestStakingRewards(address(pair2), address(FLOW)); address gaugeAddress = voter.gauges(address(pair)); gauge = Gauge(gaugeAddress); @@ -127,12 +128,12 @@ contract KillGaugesTest is BaseTest { } function testKilledGaugeCanUpdateButGoesToZero() public { - vm.warp(block.timestamp + 86400 * 7 * 2); + vm.warp(block.timestamp + ONE_WEEK * 2); vm.roll(block.number + 1); minter.update_period(); voter.updateGauge(address(gauge)); uint256 claimable = voter.claimable(address(gauge)); - VELO.approve(address(staking), claimable); + FLOW.approve(address(staking), claimable); staking.notifyRewardAmount(claimable); address[] memory gauges = new address[](1); gauges[0] = address(gauge); @@ -145,12 +146,12 @@ contract KillGaugesTest is BaseTest { } function testKilledGaugeCanDistributeButGoesToZero() public { - vm.warp(block.timestamp + 86400 * 7 * 2); + vm.warp(block.timestamp + ONE_WEEK * 2); vm.roll(block.number + 1); minter.update_period(); voter.updateGauge(address(gauge)); uint256 claimable = voter.claimable(address(gauge)); - VELO.approve(address(staking), claimable); + FLOW.approve(address(staking), claimable); staking.notifyRewardAmount(claimable); address[] memory gauges = new address[](1); gauges[0] = address(gauge); @@ -162,7 +163,7 @@ contract KillGaugesTest is BaseTest { } function testCanStillDistroAllWithKilledGauge() public { - vm.warp(block.timestamp + 86400 * 7 * 2); + vm.warp(block.timestamp + ONE_WEEK * 2); vm.roll(block.number + 1); minter.update_period(); voter.updateGauge(address(gauge)); @@ -170,11 +171,11 @@ contract KillGaugesTest is BaseTest { uint256 claimable = voter.claimable(address(gauge)); console2.log(claimable); - VELO.approve(address(staking), claimable); + FLOW.approve(address(staking), claimable); staking.notifyRewardAmount(claimable); uint256 claimable2 = voter.claimable(address(gauge2)); - VELO.approve(address(staking), claimable2); + FLOW.approve(address(staking), claimable2); staking.notifyRewardAmount(claimable2); address[] memory gauges = new address[](2); diff --git a/test/LPRewards.t.sol b/test/LPRewards.t.sol index d1ddc7e9..68962566 100644 --- a/test/LPRewards.t.sol +++ b/test/LPRewards.t.sol @@ -20,18 +20,18 @@ contract LPRewardsTest is BaseTest { amounts[1] = TOKEN_1M; mintFlow(owners, amounts); - // give owner1 veVELO + // give owner1 veFLOW VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); - VELO.approve(address(escrow), TOKEN_1M); - escrow.create_lock(TOKEN_1M, 4 * 365 * 86400); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); + FLOW.approve(address(escrow), TOKEN_1M); + escrow.create_lock(TOKEN_1M, FOUR_YEARS); deployPairFactoryAndRouter(); - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); wxbribeFactory.setVoter(address(voter)); factory.setVoter(address(voter)); deployPairWithOwner(address(owner)); @@ -40,7 +40,7 @@ contract LPRewardsTest is BaseTest { tokens[0] = address(USDC); tokens[1] = address(FRAX); tokens[2] = address(DAI); - tokens[3] = address(VELO); + tokens[3] = address(FLOW); voter.initialize(tokens, address(owner)); escrow.setVoter(address(voter)); } @@ -72,7 +72,7 @@ contract LPRewardsTest is BaseTest { vm.roll(block.number + 1); address[] memory rewards = new address[](1); - rewards[0] = address(VELO); + rewards[0] = address(FLOW); // check derived balance is the same assertEq(gauge.derivedBalance(address(owner)), gauge.derivedBalance(address(owner2))); diff --git a/test/Minter.t.sol b/test/Minter.t.sol index fa96fd6b..07060a63 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -23,41 +23,41 @@ contract MinterTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); - factory = new PairFactory(); - router = new Router(address(factory), address(owner)); - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); + factory = new PairFactory(csrNftId); + router = new Router(address(factory), address(owner), csrNftId); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); wxbribeFactory.setVoter(address(voter)); factory.setVoter(address(voter)); address[] memory tokens = new address[](2); tokens[0] = address(FRAX); - tokens[1] = address(VELO); + tokens[1] = address(FLOW); voter.initialize(tokens, address(owner)); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); - distributor = new RewardsDistributor(address(escrow)); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); + distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); - minter = new Minter(address(voter), address(escrow), address(distributor)); + minter = new Minter(address(voter), address(escrow), address(distributor), csrNftId); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); - VELO.approve(address(router), TOKEN_1); + FLOW.approve(address(router), TOKEN_1); FRAX.approve(address(router), TOKEN_1); - router.addLiquidity(address(FRAX), address(VELO), false, TOKEN_1, TOKEN_1, 0, 0, address(owner), block.timestamp); + router.addLiquidity(address(FRAX), address(FLOW), false, TOKEN_1, TOKEN_1, 0, 0, address(owner), block.timestamp); - address pair = router.pairFor(address(FRAX), address(VELO), false); + address pair = router.pairFor(address(FRAX), address(FLOW), false); - VELO.approve(address(voter), 5 * TOKEN_100K); + FLOW.approve(address(voter), 5 * TOKEN_100K); voter.createGauge(pair); vm.roll(block.number + 1); // fwd 1 block because escrow.balanceOfNFT() returns 0 in same block assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); address[] memory pools = new address[](1); pools[0] = pair; @@ -69,67 +69,92 @@ contract MinterTest is BaseTest { function initializeVotingEscrow() public { deployBase(); - address[] memory claimants = new address[](1); - claimants[0] = address(owner); - uint256[] memory amounts = new uint256[](1); - amounts[0] = TOKEN_1M; - minter.initialize(claimants, amounts, 2e25); + Minter.Claim[] memory claims = new Minter.Claim[](1); + claims[0] = Minter.Claim({ + claimant: address(owner), + amount: TOKEN_1M, + lockTime: FOUR_YEARS + }); + minter.initialMintAndLock(claims, 2e25); + minter.startActivePeriod(); + assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); vm.roll(block.number + 1); - assertEq(VELO.balanceOf(address(minter)), 19 * TOKEN_1M); + assertEq(FLOW.balanceOf(address(minter)), 19 * TOKEN_1M); } function testMinterWeeklyDistribute() public { initializeVotingEscrow(); minter.update_period(); - assertEq(minter.weekly(), 15 * TOKEN_1M); // 15M - vm.warp(block.timestamp + 86400 * 7); - vm.roll(block.number + 1); + assertEq(minter.weekly(), 13 * TOKEN_1M); // 13M + + _elapseOneWeek(); + minter.update_period(); assertEq(distributor.claimable(1), 0); - assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift - vm.warp(block.timestamp + 86400 * 7); - vm.roll(block.number + 1); + assertLt(minter.weekly(), 13 * TOKEN_1M); // <13M for week shift + + _elapseOneWeek(); + minter.update_period(); uint256 claimable = distributor.claimable(1); - assertGt(claimable, 128115516517529); + /** + * This has been updated from 128115516517529 to + * 4276543748717 because originally in VELO the + * constructor mints 0 tokens, but now we are minting + * an initial supply instead of using the initialMint + * function. + */ + + assertGt(claimable, 4276543748717); + distributor.claim(1); assertEq(distributor.claimable(1), 0); uint256 weekly = minter.weekly(); + console2.log(weekly); console2.log(minter.calculate_growth(weekly)); - console2.log(VELO.totalSupply()); + console2.log(FLOW.totalSupply()); console2.log(escrow.totalSupply()); - vm.warp(block.timestamp + 86400 * 7); - vm.roll(block.number + 1); + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim(1); - vm.warp(block.timestamp + 86400 * 7); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); uint256[] memory tokenIds = new uint256[](1); tokenIds[0] = 1; distributor.claim_many(tokenIds); - vm.warp(block.timestamp + 86400 * 7); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim(1); - vm.warp(block.timestamp + 86400 * 7); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim_many(tokenIds); - vm.warp(block.timestamp + 86400 * 7); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim(1); } + + function _elapseOneWeek() private { + vm.warp(block.timestamp + ONE_WEEK); + vm.roll(block.number + 1); + } } diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index c7fe97a7..daa2fc46 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -25,43 +25,45 @@ contract MinterTeamEmissions is BaseTest { mintFlow(owners, amountsVelo); team = new TestOwner(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); - factory = new PairFactory(); - router = new Router(address(factory), address(owner)); - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); + factory = new PairFactory(csrNftId); + router = new Router(address(factory), address(owner), csrNftId); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); voter = new Voter( address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), - address(wxbribeFactory) + address(wxbribeFactory), + csrNftId ); wxbribeFactory.setVoter(address(voter)); factory.setVoter(address(voter)); address[] memory tokens = new address[](2); tokens[0] = address(FRAX); - tokens[1] = address(VELO); + tokens[1] = address(FLOW); voter.initialize(tokens, address(owner)); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); - distributor = new RewardsDistributor(address(escrow)); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); + distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); minter = new Minter( address(voter), address(escrow), - address(distributor) + address(distributor), + csrNftId ); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); - VELO.approve(address(router), TOKEN_1); + FLOW.approve(address(router), TOKEN_1); FRAX.approve(address(router), TOKEN_1); router.addLiquidity( address(FRAX), - address(VELO), + address(FLOW), false, TOKEN_1, TOKEN_1, @@ -71,13 +73,13 @@ contract MinterTeamEmissions is BaseTest { block.timestamp ); - address pair = router.pairFor(address(FRAX), address(VELO), false); + address pair = router.pairFor(address(FRAX), address(FLOW), false); - VELO.approve(address(voter), 5 * TOKEN_100K); + FLOW.approve(address(voter), 5 * TOKEN_100K); voter.createGauge(pair); vm.roll(block.number + 1); // fwd 1 block because escrow.balanceOfNFT() returns 0 in same block assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); address[] memory pools = new address[](1); pools[0] = pair; @@ -85,27 +87,31 @@ contract MinterTeamEmissions is BaseTest { weights[0] = 5000; voter.vote(1, pools, weights); - address[] memory claimants = new address[](1); - claimants[0] = address(owner); - uint256[] memory amountsToMint = new uint256[](1); - amountsToMint[0] = TOKEN_1M; - minter.initialize(claimants, amountsToMint, 15 * TOKEN_1M); + Minter.Claim[] memory claims = new Minter.Claim[](1); + claims[0] = Minter.Claim({ + claimant: address(owner), + amount: TOKEN_1M, + lockTime: FOUR_YEARS + }); + minter.initialMintAndLock(claims, 13 * TOKEN_1M); + minter.startActivePeriod(); + assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); vm.roll(block.number + 1); - assertEq(VELO.balanceOf(address(minter)), 14 * TOKEN_1M); + assertEq(FLOW.balanceOf(address(minter)), 12 * TOKEN_1M); - uint256 before = VELO.balanceOf(address(owner)); + uint256 before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 1 - uint256 after_ = VELO.balanceOf(address(owner)); - assertEq(minter.weekly(), 15 * TOKEN_1M); + uint256 after_ = FLOW.balanceOf(address(owner)); + assertEq(minter.weekly(), 13 * TOKEN_1M); assertEq(after_ - before, 0); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); - before = VELO.balanceOf(address(owner)); + before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 2 - after_ = VELO.balanceOf(address(owner)); - assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift + after_ = FLOW.balanceOf(address(owner)); + assertLt(minter.weekly(), 13 * TOKEN_1M); // <13M for week shift } function testChangeTeam() public { @@ -129,35 +135,35 @@ contract MinterTeamEmissions is BaseTest { owner.setTeam(address(minter), address(team)); team.acceptTeam(address(minter)); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); - uint256 beforeTeamSupply = VELO.balanceOf(address(team)); + uint256 beforeTeamSupply = FLOW.balanceOf(address(team)); uint256 weekly = minter.weekly_emission(); uint256 growth = minter.calculate_growth(weekly); minter.update_period(); // new period - uint256 afterTeamSupply = VELO.balanceOf(address(team)); + uint256 afterTeamSupply = FLOW.balanceOf(address(team)); uint256 newTeamVelo = afterTeamSupply - beforeTeamSupply; assertEq(((weekly + growth + newTeamVelo) * 30) / 1000, newTeamVelo); // check 3% of new emissions to team - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); - beforeTeamSupply = VELO.balanceOf(address(team)); + beforeTeamSupply = FLOW.balanceOf(address(team)); weekly = minter.weekly_emission(); growth = minter.calculate_growth(weekly); minter.update_period(); // new period - afterTeamSupply = VELO.balanceOf(address(team)); + afterTeamSupply = FLOW.balanceOf(address(team)); newTeamVelo = afterTeamSupply - beforeTeamSupply; assertEq(((weekly + growth + newTeamVelo) * 30) / 1000, newTeamVelo); // check 3% of new emissions to team - // rate is right even when VELO is sent to Minter contract - vm.warp(block.timestamp + 86400 * 7); + // rate is right even when FLOW is sent to Minter contract + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); - owner2.transfer(address(VELO), address(minter), 1e25); - beforeTeamSupply = VELO.balanceOf(address(team)); + owner2.transfer(address(FLOW), address(minter), 1e25); + beforeTeamSupply = FLOW.balanceOf(address(team)); weekly = minter.weekly_emission(); growth = minter.calculate_growth(weekly); minter.update_period(); // new period - afterTeamSupply = VELO.balanceOf(address(team)); + afterTeamSupply = FLOW.balanceOf(address(team)); newTeamVelo = afterTeamSupply - beforeTeamSupply; assertEq(((weekly + growth + newTeamVelo) * 30) / 1000, newTeamVelo); // check 3% of new emissions to team } @@ -177,13 +183,13 @@ contract MinterTeamEmissions is BaseTest { // new rate in bounds team.setTeamEmissions(address(minter), 50); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); - uint256 beforeTeamSupply = VELO.balanceOf(address(team)); + uint256 beforeTeamSupply = FLOW.balanceOf(address(team)); uint256 weekly = minter.weekly_emission(); uint256 growth = minter.calculate_growth(weekly); minter.update_period(); // new period - uint256 afterTeamSupply = VELO.balanceOf(address(team)); + uint256 afterTeamSupply = FLOW.balanceOf(address(team)); uint256 newTeamVelo = afterTeamSupply - beforeTeamSupply; assertEq(((weekly + growth + newTeamVelo) * 50) / 1000, newTeamVelo); // check 5% of new emissions to team } diff --git a/test/NFTVote.t.sol b/test/NFTVote.t.sol index 2b032673..4e599df2 100644 --- a/test/NFTVote.t.sol +++ b/test/NFTVote.t.sol @@ -19,22 +19,23 @@ contract NFTVoteTest is BaseTest { function setUp() public { deployCoins(); + deployOwners(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); gov = new TestL2Governance(escrow); // test variable to vote on flag = new FlagCondition(); flag.transferOwnership(address(gov)); - VELO.mint(address(this), 1e21); + FLOW.mint(address(this), 1e21); vm.roll(block.number + 1); } function testLockAndPropose() public { uint256 fourYears = 4 * 365 * 24 * 3600; - VELO.approve(address(escrow), 1e21); + FLOW.approve(address(escrow), 1e21); escrow.create_lock(1e21, fourYears); uint256 quorum = gov.quorum(block.timestamp); uint256 numVotes = gov.getVotes(address(this), block.timestamp); diff --git a/test/Oracle.t.sol b/test/Oracle.t.sol index 5e554e50..4e87b6a1 100644 --- a/test/Oracle.t.sol +++ b/test/Oracle.t.sol @@ -13,7 +13,7 @@ contract OracleTest is BaseTest { uint256[] memory amounts = new uint256[](1); amounts[0] = 1e25; mintFlow(owners, amounts); - escrow = VotingEscrow(address(VELO)); + escrow = VotingEscrow(address(FLOW)); } function confirmTokensForFraxUsdc() public { diff --git a/test/Pair.t.sol b/test/Pair.t.sol index dd08b2f0..4cc73ac4 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -31,28 +31,28 @@ contract PairTest is BaseTest { mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); } function createLock() public { deployPairCoins(); - VELO.approve(address(escrow), 5e17); - escrow.create_lock(5e17, 4 * 365 * 86400); + FLOW.approve(address(escrow), 5e17); + escrow.create_lock(5e17, FOUR_YEARS); vm.roll(block.number + 1); // fwd 1 block because escrow.balanceOfNFT() returns 0 in same block assertGt(escrow.balanceOfNFT(1), 495063075414519385); - assertEq(VELO.balanceOf(address(escrow)), 5e17); + assertEq(FLOW.balanceOf(address(escrow)), 5e17); } function increaseLock() public { createLock(); - VELO.approve(address(escrow), 5e17); + FLOW.approve(address(escrow), 5e17); escrow.increase_amount(1, 5e17); vm.expectRevert(abi.encodePacked('Can only increase lock duration')); - escrow.increase_unlock_time(1, 4 * 365 * 86400); + escrow.increase_unlock_time(1, FOUR_YEARS); assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); } function votingEscrowViews() public { @@ -63,7 +63,7 @@ contract PairTest is BaseTest { assertEq(escrow.totalSupplyAt(block_), escrow.totalSupply()); assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); } function stealNFT() public { @@ -80,10 +80,10 @@ contract PairTest is BaseTest { function votingEscrowMerge() public { stealNFT(); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); assertGt(escrow.balanceOfNFT(2), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), 2 * TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), 2 * TOKEN_1); console2.log(escrow.totalSupply()); escrow.merge(2, 1); console2.log(escrow.totalSupply()); @@ -92,10 +92,10 @@ contract PairTest is BaseTest { (int256 id, uint256 amount) = escrow.locked(2); assertEq(amount, 0); assertEq(escrow.ownerOf(2), address(0)); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); assertGt(escrow.balanceOfNFT(3), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), 3 * TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), 3 * TOKEN_1); console2.log(escrow.totalSupply()); escrow.merge(3, 1); console2.log(escrow.totalSupply()); @@ -244,10 +244,10 @@ contract PairTest is BaseTest { } function deployVoter() public { - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -258,16 +258,16 @@ contract PairTest is BaseTest { function deployMinter() public { routerAddLiquidity(); - distributor = new RewardsDistributor(address(escrow)); + distributor = new RewardsDistributor(address(escrow), csrNftId); - minter = new Minter(address(voter), address(escrow), address(distributor)); + minter = new Minter(address(voter), address(escrow), address(distributor), csrNftId); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); address[] memory tokens = new address[](5); tokens[0] = address(USDC); tokens[1] = address(FRAX); tokens[2] = address(DAI); - tokens[3] = address(VELO); + tokens[3] = address(FLOW); tokens[4] = address(LR); voter.initialize(tokens, address(minter)); } @@ -275,13 +275,13 @@ contract PairTest is BaseTest { function deployPairFactoryGauge() public { deployMinter(); - VELO.approve(address(gaugeFactory), 15 * TOKEN_100K); + FLOW.approve(address(gaugeFactory), 15 * TOKEN_100K); voter.createGauge(address(pair)); voter.createGauge(address(pair2)); voter.createGauge(address(pair3)); assertFalse(voter.gauges(address(pair)) == address(0)); - staking = new TestStakingRewards(address(pair), address(VELO)); + staking = new TestStakingRewards(address(pair), address(FLOW)); address gaugeAddress = voter.gauges(address(pair)); address xBribeAddress = voter.external_bribes(gaugeAddress); @@ -354,17 +354,17 @@ contract PairTest is BaseTest { function addGaugeAndBribeRewards() public { withdrawGaugeStake(); - VELO.approve(address(gauge), PAIR_1); - VELO.approve(address(xbribe), PAIR_1); - VELO.approve(address(staking), PAIR_1); + FLOW.approve(address(gauge), PAIR_1); + FLOW.approve(address(xbribe), PAIR_1); + FLOW.approve(address(staking), PAIR_1); - gauge.notifyRewardAmount(address(VELO), PAIR_1); - xbribe.notifyRewardAmount(address(VELO), PAIR_1); + gauge.notifyRewardAmount(address(FLOW), PAIR_1); + xbribe.notifyRewardAmount(address(FLOW), PAIR_1); staking.notifyRewardAmount(PAIR_1); - assertEq(gauge.rewardRate(address(VELO)), 1653); + assertEq(gauge.rewardRate(address(FLOW)), 1653); // no reward rate, all or nothing - // assertEq(xbribe.rewardRate(address(VELO)), 1653); + // assertEq(xbribe.rewardRate(address(FLOW)), 1653); assertEq(staking.rewardRate(), 1653); } @@ -399,11 +399,11 @@ contract PairTest is BaseTest { function createLock2() public { voterPokeSelf(); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(block.timestamp + 1); assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), 4 * TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), 4 * TOKEN_1); } function voteHacking() public { @@ -495,7 +495,7 @@ contract PairTest is BaseTest { function gaugeDistributeBasedOnVoting() public { gaugePokeHacking3(); - VELO.approve(address(voter), PAIR_1); + FLOW.approve(address(voter), PAIR_1); voter.notifyRewardAmount(PAIR_1); voter.updateAll(); voter.distro(); @@ -505,7 +505,7 @@ contract PairTest is BaseTest { gaugeDistributeBasedOnVoting(); address[] memory rewards = new address[](1); - rewards[0] = address(VELO); + rewards[0] = address(FLOW); xbribe.getReward(1, rewards); vm.warp(block.timestamp + 691200); vm.roll(block.number + 1); @@ -591,17 +591,22 @@ contract PairTest is BaseTest { console2.log(distributor.last_token_time()); console2.log(distributor.timestamp()); - address[] memory claimants = new address[](1); - claimants[0] = address(owner); - uint256[] memory amounts = new uint256[](1); - amounts[0] = TOKEN_1; - minter.initialize(claimants, amounts, TOKEN_1); + + Minter.Claim[] memory claims = new Minter.Claim[](1); + claims[0] = Minter.Claim({ + claimant: address(owner), + amount: TOKEN_1, + lockTime: FOUR_YEARS + }); + minter.initialMintAndLock(claims, TOKEN_1); + minter.startActivePeriod(); + minter.update_period(); voter.updateGauge(address(gauge)); - console2.log(VELO.balanceOf(address(distributor))); + console2.log(FLOW.balanceOf(address(distributor))); console2.log(distributor.claimable(1)); uint256 claimable = voter.claimable(address(gauge)); - VELO.approve(address(staking), claimable); + FLOW.approve(address(staking), claimable); staking.notifyRewardAmount(claimable); voter.distro(); vm.warp(block.timestamp + 1800); @@ -621,25 +626,25 @@ contract PairTest is BaseTest { gauge.deposit(PAIR_1, 0); staking.getReward(); vm.warp(block.timestamp + 1); - uint256 before = VELO.balanceOf(address(owner)); + uint256 before = FLOW.balanceOf(address(owner)); vm.warp(block.timestamp + 1); - gauge.batchRewardPerToken(address(VELO), 200); + gauge.batchRewardPerToken(address(FLOW), 200); vm.warp(block.timestamp + 1); - gauge.batchRewardPerToken(address(VELO), 200); + gauge.batchRewardPerToken(address(FLOW), 200); vm.warp(block.timestamp + 1); - gauge.batchRewardPerToken(address(VELO), 200); + gauge.batchRewardPerToken(address(FLOW), 200); vm.warp(block.timestamp + 1); - gauge.batchRewardPerToken(address(VELO), 200); + gauge.batchRewardPerToken(address(FLOW), 200); vm.warp(block.timestamp + 1); - gauge.batchRewardPerToken(address(VELO), 200); + gauge.batchRewardPerToken(address(FLOW), 200); vm.warp(block.timestamp + 1); - uint256 earned = gauge.earned(address(VELO), address(owner)); + uint256 earned = gauge.earned(address(FLOW), address(owner)); address[] memory rewards = new address[](1); - rewards[0] = address(VELO); + rewards[0] = address(FLOW); vm.warp(block.timestamp + 1); gauge.getReward(address(owner), rewards); vm.warp(block.timestamp + 1); - uint256 after_ = VELO.balanceOf(address(owner)); + uint256 after_ = FLOW.balanceOf(address(owner)); uint256 received = after_ - before; gauge.withdraw(gauge.balanceOf(address(owner))); @@ -676,7 +681,7 @@ contract PairTest is BaseTest { gaugeClaimRewards(); address[] memory rewards = new address[](1); - rewards[0] = address(VELO); + rewards[0] = address(FLOW); pair.approve(address(gauge), PAIR_1); gauge.deposit(PAIR_1, 1); gauge.getReward(address(owner), rewards); @@ -723,7 +728,7 @@ contract PairTest is BaseTest { voter.claimFees(bribes_, rewards, 1); uint256 supply = escrow.totalSupply(); assertGt(supply, 0); - vm.warp(block.timestamp + 4*365*86400); + vm.warp(block.timestamp + FOUR_YEARS); vm.roll(block.number + 1); assertEq(escrow.balanceOfNFT(1), 0); assertEq(escrow.totalSupply(), 0); @@ -755,16 +760,16 @@ contract PairTest is BaseTest { owner3.approve(address(pair), address(gauge), PAIR_1); owner3.deposit(address(gauge), PAIR_1, 0); owner3.withdrawGauge(address(gauge), gauge.balanceOf(address(owner3))); - gauge.batchRewardPerToken(address(VELO), 200); + gauge.batchRewardPerToken(address(FLOW), 200); owner3.approve(address(pair), address(gauge), PAIR_1); owner3.deposit(address(gauge), PAIR_1, 0); - gauge.batchRewardPerToken(address(VELO), 200); - gauge.batchRewardPerToken(address(VELO), 200); - gauge.batchRewardPerToken(address(VELO), 200); - gauge.batchRewardPerToken(address(VELO), 200); + gauge.batchRewardPerToken(address(FLOW), 200); + gauge.batchRewardPerToken(address(FLOW), 200); + gauge.batchRewardPerToken(address(FLOW), 200); + gauge.batchRewardPerToken(address(FLOW), 200); address[] memory rewards = new address[](1); - rewards[0] = address(VELO); + rewards[0] = address(FLOW); owner3.getGaugeReward(address(gauge), address(owner3), rewards); owner3.withdrawGauge(address(gauge), gauge.balanceOf(address(owner3))); owner3.approve(address(pair), address(gauge), PAIR_1); @@ -787,12 +792,12 @@ contract PairTest is BaseTest { function minterMint2() public { gaugeClaimRewardsOwner3(); - vm.warp(block.timestamp + 86400 * 7 * 2); + vm.warp(block.timestamp + ONE_WEEK * 2); vm.roll(block.number + 1); minter.update_period(); voter.updateGauge(address(gauge)); uint256 claimable = voter.claimable(address(gauge)); - VELO.approve(address(staking), claimable); + FLOW.approve(address(staking), claimable); staking.notifyRewardAmount(claimable); address[] memory gauges = new address[](1); gauges[0] = address(gauge); @@ -800,30 +805,30 @@ contract PairTest is BaseTest { voter.distro(); address[][] memory tokens = new address[][](1); address[] memory token = new address[](1); - token[0] = address(VELO); + token[0] = address(FLOW); tokens[0] = token; voter.claimRewards(gauges, tokens); - assertEq(gauge.rewardRate(address(VELO)), staking.rewardRate()); - console2.log(gauge.rewardPerTokenStored(address(VELO))); + assertEq(gauge.rewardRate(address(FLOW)), staking.rewardRate()); + console2.log(gauge.rewardPerTokenStored(address(FLOW))); } function gaugeClaimRewardsOwner3NextCycle() public { minterMint2(); owner3.withdrawGauge(address(gauge), gauge.balanceOf(address(owner3))); - console2.log(gauge.rewardPerTokenStored(address(VELO))); + console2.log(gauge.rewardPerTokenStored(address(FLOW))); owner3.approve(address(pair), address(gauge), PAIR_1); owner3.deposit(address(gauge), PAIR_1, 0); - uint256 before = VELO.balanceOf(address(owner3)); + uint256 before = FLOW.balanceOf(address(owner3)); vm.warp(block.timestamp + 1); - // uint256 earned = gauge.earned(address(VELO), address(owner3)); + // uint256 earned = gauge.earned(address(FLOW), address(owner3)); address[] memory rewards = new address[](1); - rewards[0] = address(VELO); + rewards[0] = address(FLOW); owner3.getGaugeReward(address(gauge), address(owner3), rewards); - uint256 after_ = VELO.balanceOf(address(owner3)); + uint256 after_ = FLOW.balanceOf(address(owner3)); uint256 received = after_ - before; assertGt(received, 0); - console2.log(gauge.rewardPerTokenStored(address(VELO))); + console2.log(gauge.rewardPerTokenStored(address(FLOW))); owner3.withdrawGauge(address(gauge), gauge.balanceOf(address(owner))); owner3.approve(address(pair), address(gauge), PAIR_1); @@ -857,8 +862,8 @@ contract PairTest is BaseTest { pair.approve(address(gauge), PAIR_1); gauge.deposit(PAIR_1, 0); - VELO.approve(address(gauge), VELO.balanceOf(address(owner))); - gauge.notifyRewardAmount(address(VELO), VELO.balanceOf(address(owner))); + FLOW.approve(address(gauge), FLOW.balanceOf(address(owner))); + gauge.notifyRewardAmount(address(FLOW), FLOW.balanceOf(address(owner))); vm.warp(block.timestamp + 604800); vm.roll(block.number + 1); diff --git a/test/Staking.t.sol b/test/Staking.t.sol index 63339835..c62645ee 100644 --- a/test/Staking.t.sol +++ b/test/Staking.t.sol @@ -21,42 +21,42 @@ contract StakingTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); mintStake(owners, amounts); - escrow = new TestVotingEscrow(address(VELO)); + escrow = new TestVotingEscrow(address(FLOW)); voter = new TestVoter(); } function createLock() public { deployBaseCoins(); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); } function createLock2() public { createLock(); - owner2.approve(address(VELO), address(escrow), TOKEN_1); - owner2.create_lock(address(escrow), TOKEN_1, 4 * 365 * 86400); + owner2.approve(address(FLOW), address(escrow), TOKEN_1); + owner2.create_lock(address(escrow), TOKEN_1, FOUR_YEARS); } function createLock3() public { createLock2(); - owner3.approve(address(VELO), address(escrow), TOKEN_1); - owner3.create_lock(address(escrow), TOKEN_1, 4 * 365 * 86400); + owner3.approve(address(FLOW), address(escrow), TOKEN_1); + owner3.create_lock(address(escrow), TOKEN_1, FOUR_YEARS); } function deployFactory() public { createLock3(); - gaugeFactory = new GaugeFactory(); + gaugeFactory = new GaugeFactory(csrNftId); address[] memory allowedRewards = new address[](1); vm.prank(address(voter)); gaugeFactory.createGauge(address(stake), address(owner), address(escrow), false, allowedRewards); address gaugeAddr = gaugeFactory.last_gauge(); gauge = Gauge(gaugeAddr); - staking = new TestStakingRewards(address(stake), address(VELO)); + staking = new TestStakingRewards(address(stake), address(FLOW)); } function depositEmpty() public { @@ -67,7 +67,7 @@ contract StakingTest is BaseTest { staking.stake(1e21); gauge.deposit(1e21, 1); - assertEq(gauge.earned(address(VELO), address(owner)), staking.earned(address(owner))); + assertEq(gauge.earned(address(FLOW), address(owner)), staking.earned(address(owner))); } function depositEmpty2() public { @@ -78,7 +78,7 @@ contract StakingTest is BaseTest { owner2.stakeStake(address(staking), 1e21); owner2.deposit(address(gauge), 1e21, 2); - assertEq(gauge.earned(address(VELO), address(owner2)), staking.earned(address(owner2))); + assertEq(gauge.earned(address(FLOW), address(owner2)), staking.earned(address(owner2))); } function depositEmpty3() public { @@ -89,27 +89,27 @@ contract StakingTest is BaseTest { owner3.stakeStake(address(staking), 1e21); owner3.deposit(address(gauge), 1e21, 3); - assertEq(gauge.earned(address(VELO), address(owner3)), staking.earned(address(owner3))); + assertEq(gauge.earned(address(FLOW), address(owner3)), staking.earned(address(owner3))); } function notifyRewardsAndCompare() public { depositEmpty3(); - VELO.approve(address(staking), TOKEN_1M); - VELO.approve(address(gauge), TOKEN_1M); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + FLOW.approve(address(staking), TOKEN_1M); + FLOW.approve(address(gauge), TOKEN_1M); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.notifyRewardAmount(TOKEN_1M); - gauge.notifyRewardAmount(address(VELO), TOKEN_1M); + gauge.notifyRewardAmount(address(FLOW), TOKEN_1M); vm.warp(block.timestamp + 1800); vm.roll(block.number + 1); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); - VELO.approve(address(staking), TOKEN_1M); - VELO.approve(address(gauge), TOKEN_1M); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); + FLOW.approve(address(staking), TOKEN_1M); + FLOW.approve(address(gauge), TOKEN_1M); staking.notifyRewardAmount(TOKEN_1M); - gauge.notifyRewardAmount(address(VELO), TOKEN_1M); + gauge.notifyRewardAmount(address(FLOW), TOKEN_1M); vm.warp(block.timestamp + 1800); vm.roll(block.number + 1); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); } function notifyReward2AndCompare() public { @@ -133,38 +133,38 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); vm.warp(block.timestamp + 1800); vm.roll(block.number + 1); staking.withdraw(1e21); @@ -173,8 +173,8 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); vm.warp(block.timestamp + 604800); vm.roll(block.number + 1); staking.withdraw(1e21); @@ -183,8 +183,8 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); } function notifyRewardsAndCompareOwner2() public { @@ -278,32 +278,32 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); vm.warp(block.timestamp + 1800); vm.roll(block.number + 1); staking.withdraw(1e21); @@ -312,8 +312,8 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); vm.warp(block.timestamp + 604800); vm.roll(block.number + 1); staking.withdraw(1e21); @@ -322,29 +322,29 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); } function notifyRewardsAndCompareSet2() public { depositAndWithdrawWithoutRewards(); - VELO.approve(address(staking), TOKEN_1M); - VELO.approve(address(gauge), TOKEN_1M); + FLOW.approve(address(staking), TOKEN_1M); + FLOW.approve(address(gauge), TOKEN_1M); staking.notifyRewardAmount(TOKEN_1M); - gauge.notifyRewardAmount(address(VELO), TOKEN_1M); + gauge.notifyRewardAmount(address(FLOW), TOKEN_1M); vm.warp(block.timestamp + 1800); vm.roll(block.number + 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); - VELO.approve(address(staking), TOKEN_1M); - VELO.approve(address(gauge), TOKEN_1M); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); + FLOW.approve(address(staking), TOKEN_1M); + FLOW.approve(address(gauge), TOKEN_1M); staking.notifyRewardAmount(TOKEN_1M); - gauge.notifyRewardAmount(address(VELO), TOKEN_1M); + gauge.notifyRewardAmount(address(FLOW), TOKEN_1M); vm.warp(block.timestamp + 1800); vm.roll(block.number + 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); assertEq(gauge.derivedSupply(), staking.totalSupply()); } @@ -370,32 +370,32 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); staking.withdraw(1e21); gauge.withdraw(1e21); stake.approve(address(staking), 1e21); stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); vm.warp(block.timestamp + 1800); vm.roll(block.number + 1); staking.withdraw(1e21); @@ -404,16 +404,16 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); - // uint256 sb = VELO.balanceOf(address(owner)); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); + // uint256 sb = FLOW.balanceOf(address(owner)); staking.getReward(); - // uint256 sa = VELO.balanceOf(address(owner)); - // uint256 gb = VELO.balanceOf(address(owner)); + // uint256 sa = FLOW.balanceOf(address(owner)); + // uint256 gb = FLOW.balanceOf(address(owner)); address[] memory tokens = new address[](1); - tokens[0] = address(VELO); + tokens[0] = address(FLOW); gauge.getReward(address(owner), tokens); - // uint256 ga = VELO.balanceOf(address(owner)); + // uint256 ga = FLOW.balanceOf(address(owner)); vm.warp(block.timestamp + 604800); vm.roll(block.number + 1); staking.withdraw(1e21); @@ -422,8 +422,8 @@ contract StakingTest is BaseTest { stake.approve(address(gauge), 1e21); staking.stake(1e21); gauge.deposit(1e21, 1); - gauge.batchRewardPerToken(address(VELO), 200); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + gauge.batchRewardPerToken(address(FLOW), 200); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); assertGt(staking.rewardPerTokenStored(), 1330355346300364281191); } @@ -464,7 +464,7 @@ contract StakingTest is BaseTest { owner2.deposit(address(gauge), 1e21, 2); owner2.getStakeReward(address(staking)); address[] memory tokens = new address[](1); - tokens[0] = address(VELO); + tokens[0] = address(FLOW); owner2.getGaugeReward(address(gauge), address(owner2), tokens); vm.warp(block.timestamp + 604800); vm.roll(block.number + 1); @@ -474,7 +474,7 @@ contract StakingTest is BaseTest { owner2.approve(address(stake), address(gauge), 1e21); owner2.stakeStake(address(staking), 1e21); owner2.deposit(address(gauge), 1e21, 2); - assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(VELO))); + assertEq(staking.rewardPerTokenStored(), gauge.rewardPerTokenStored(address(FLOW))); assertGt(staking.rewardPerTokenStored(), 1330355346300364281191); } diff --git a/test/VeloGovernor.t.sol b/test/VeloGovernor.t.sol index 55e9d874..1c59d744 100644 --- a/test/VeloGovernor.t.sol +++ b/test/VeloGovernor.t.sol @@ -25,25 +25,25 @@ contract VeloGovernorTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); - VELO.approve(address(escrow), 97 * TOKEN_1); - escrow.create_lock(97 * TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), 97 * TOKEN_1); + escrow.create_lock(97 * TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); // owner2 owns less than quorum, 3% vm.startPrank(address(owner2)); - VELO.approve(address(escrow), 3 * TOKEN_1); - escrow.create_lock(3 * TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), 3 * TOKEN_1); + escrow.create_lock(3 * TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); vm.stopPrank(); deployPairFactoryAndRouter(); - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -53,21 +53,21 @@ contract VeloGovernorTest is BaseTest { FRAX.approve(address(router), TOKEN_100K); router.addLiquidity(address(FRAX), address(USDC), true, TOKEN_100K, USDC_100K, TOKEN_100K, USDC_100K, address(owner), block.timestamp); - distributor = new RewardsDistributor(address(escrow)); + distributor = new RewardsDistributor(address(escrow), csrNftId); - minter = new Minter(address(voter), address(escrow), address(distributor)); + minter = new Minter(address(voter), address(escrow), address(distributor), csrNftId); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); address address1 = factory.getPair(address(FRAX), address(USDC), true); pair = Pair(address1); - VELO.approve(address(gaugeFactory), 15 * TOKEN_100K); + FLOW.approve(address(gaugeFactory), 15 * TOKEN_100K); voter.createGauge(address(pair)); address gaugeAddress = voter.gauges(address(pair)); gauge = Gauge(gaugeAddress); - governor = new VeloGovernor(escrow); + governor = new VeloGovernor(escrow, csrNftId); voter.setGovernor(address(governor)); } @@ -96,8 +96,8 @@ contract VeloGovernorTest is BaseTest { function testVeVeloMergesAutoDelegates() public { // owner2 + owner3 > quorum vm.startPrank(address(owner3)); - VELO.approve(address(escrow), 3 * TOKEN_1); - escrow.create_lock(3 * TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), 3 * TOKEN_1); + escrow.create_lock(3 * TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); uint256 pre2 = escrow.getVotes(address(owner2)); uint256 pre3 = escrow.getVotes(address(owner3)); @@ -115,7 +115,7 @@ contract VeloGovernorTest is BaseTest { assertApproxEqAbs( pre2 + pre3, post2, - 4 * 365 * 86400 // merge rounds down time lock + FOUR_YEARS // merge rounds down time lock ); } diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index 297a652e..19606959 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -25,18 +25,19 @@ contract VeloVotingTest is BaseTest { mintFlow(owners, amountsVelo); team = new TestOwner(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); - factory = new PairFactory(); - router = new Router(address(factory), address(owner)); - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); + factory = new PairFactory(csrNftId); + router = new Router(address(factory), address(owner), csrNftId); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); voter = new Voter( address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), - address(wxbribeFactory) + address(wxbribeFactory), + csrNftId ); wxbribeFactory.setVoter(address(voter)); @@ -44,26 +45,27 @@ contract VeloVotingTest is BaseTest { address[] memory tokens = new address[](2); tokens[0] = address(FRAX); - tokens[1] = address(VELO); + tokens[1] = address(FLOW); voter.initialize(tokens, address(owner)); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); - distributor = new RewardsDistributor(address(escrow)); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); + distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); minter = new Minter( address(voter), address(escrow), - address(distributor) + address(distributor), + csrNftId ); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); - VELO.approve(address(router), TOKEN_1); + FLOW.approve(address(router), TOKEN_1); FRAX.approve(address(router), TOKEN_1); router.addLiquidity( address(FRAX), - address(VELO), + address(FLOW), false, TOKEN_1, TOKEN_1, @@ -73,13 +75,13 @@ contract VeloVotingTest is BaseTest { block.timestamp ); - address pair = router.pairFor(address(FRAX), address(VELO), false); + address pair = router.pairFor(address(FRAX), address(FLOW), false); - VELO.approve(address(voter), 5 * TOKEN_100K); + FLOW.approve(address(voter), 5 * TOKEN_100K); voter.createGauge(pair); vm.roll(block.number + 1); // fwd 1 block because escrow.balanceOfNFT() returns 0 in same block assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); address[] memory pools = new address[](1); pools[0] = pair; @@ -87,27 +89,31 @@ contract VeloVotingTest is BaseTest { weights[0] = 5000; voter.vote(1, pools, weights); - address[] memory claimants = new address[](1); - claimants[0] = address(owner); - uint256[] memory amountsToMint = new uint256[](1); - amountsToMint[0] = TOKEN_1M; - minter.initialize(claimants, amountsToMint, 15 * TOKEN_1M); + Minter.Claim[] memory claims = new Minter.Claim[](1); + claims[0] = Minter.Claim({ + claimant: address(owner), + amount: TOKEN_1M, + lockTime: FOUR_YEARS + }); + minter.initialMintAndLock(claims, 13 * TOKEN_1M); + minter.startActivePeriod(); + assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); vm.roll(block.number + 1); - assertEq(VELO.balanceOf(address(minter)), 14 * TOKEN_1M); + assertEq(FLOW.balanceOf(address(minter)), 12 * TOKEN_1M); - uint256 before = VELO.balanceOf(address(owner)); + uint256 before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 1 - uint256 after_ = VELO.balanceOf(address(owner)); - assertEq(minter.weekly(), 15 * TOKEN_1M); + uint256 after_ = FLOW.balanceOf(address(owner)); + assertEq(minter.weekly(), 13 * TOKEN_1M); assertEq(after_ - before, 0); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); - before = VELO.balanceOf(address(owner)); + before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 2 - after_ = VELO.balanceOf(address(owner)); - assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift + after_ = FLOW.balanceOf(address(owner)); + assertLt(minter.weekly(), 13 * TOKEN_1M); // <13m for week shift } // Note: _vote and _reset are not included in one-vote-per-epoch diff --git a/test/VotingEscrow.t.sol b/test/VotingEscrow.t.sol index e8d29123..e60e43ff 100644 --- a/test/VotingEscrow.t.sol +++ b/test/VotingEscrow.t.sol @@ -15,11 +15,11 @@ contract VotingEscrowTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); } function testCreateLock() public { - VELO.approve(address(escrow), 1e21); + FLOW.approve(address(escrow), 1e21); uint256 lockDuration = 7 * 24 * 3600; // 1 week // Balance should be zero before and 1 after creating the lock @@ -30,7 +30,7 @@ contract VotingEscrowTest is BaseTest { } function testCreateLockOutsideAllowedZones() public { - VELO.approve(address(escrow), 1e21); + FLOW.approve(address(escrow), 1e21); uint256 oneWeek = 7 * 24 * 3600; uint256 fourYears = 4 * 365 * 24 * 3600; vm.expectRevert(abi.encodePacked('Voting lock can be 4 years max')); @@ -38,7 +38,7 @@ contract VotingEscrowTest is BaseTest { } function testWithdraw() public { - VELO.approve(address(escrow), 1e21); + FLOW.approve(address(escrow), 1e21); uint256 lockDuration = 7 * 24 * 3600; // 1 week escrow.create_lock(1e21, lockDuration); @@ -51,7 +51,7 @@ contract VotingEscrowTest is BaseTest { vm.roll(block.number + 1); // mine the next block escrow.withdraw(tokenId); - assertEq(VELO.balanceOf(address(owner)), 1e21); + assertEq(FLOW.balanceOf(address(owner)), 1e21); // Check that the NFT is burnt assertEq(escrow.balanceOfNFT(tokenId), 0); assertEq(escrow.ownerOf(tokenId), address(0)); @@ -61,7 +61,7 @@ contract VotingEscrowTest is BaseTest { // tokenURI should not work for non-existent token ids vm.expectRevert(abi.encodePacked("Query for nonexistent token")); escrow.tokenURI(999); - VELO.approve(address(escrow), 1e21); + FLOW.approve(address(escrow), 1e21); uint256 lockDuration = 7 * 24 * 3600; // 1 week escrow.create_lock(1e21, lockDuration); diff --git a/test/WashTrade.t.sol b/test/WashTrade.t.sol index c8895ac9..0893e80c 100644 --- a/test/WashTrade.t.sol +++ b/test/WashTrade.t.sol @@ -22,27 +22,27 @@ contract WashTradeTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); } function createLock() public { deployBaseCoins(); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); // fwd 1 block because escrow.balanceOfNFT() returns 0 in same block assertGt(escrow.balanceOfNFT(1), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); } function votingEscrowMerge() public { createLock(); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); assertGt(escrow.balanceOfNFT(2), 995063075414519385); - assertEq(VELO.balanceOf(address(escrow)), 2 * TOKEN_1); + assertEq(FLOW.balanceOf(address(escrow)), 2 * TOKEN_1); escrow.merge(2, 1); assertGt(escrow.balanceOfNFT(1), 1990039602248405587); assertEq(escrow.balanceOfNFT(2), 0); @@ -82,10 +82,10 @@ contract WashTradeTest is BaseTest { } function deployVoter() public { - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); wxbribeFactory.setVoter(address(voter)); factory.setVoter(address(voter)); @@ -93,7 +93,7 @@ contract WashTradeTest is BaseTest { tokens[0] = address(USDC); tokens[1] = address(FRAX); tokens[2] = address(DAI); - tokens[3] = address(VELO); + tokens[3] = address(FLOW); voter.initialize(tokens, address(owner)); assertEq(voter.length(), 0); @@ -102,7 +102,7 @@ contract WashTradeTest is BaseTest { function deployPairFactoryGauge() public { routerAddLiquidity(); - VELO.approve(address(gaugeFactory), 5 * TOKEN_100K); + FLOW.approve(address(gaugeFactory), 5 * TOKEN_100K); voter.createGauge(address(pair3)); assertFalse(voter.gauges(address(pair3)) == address(0)); diff --git a/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol new file mode 100644 index 00000000..4d54f252 --- /dev/null +++ b/test/WrappedBribes.t.sol @@ -0,0 +1,703 @@ +pragma solidity 0.8.13; + +import './BaseTest.sol'; +import "contracts/WrappedBribe.sol"; +import "contracts/factories/WrappedBribeFactory.sol"; +import "forge-std/console2.sol"; + +contract WrappedBribesTest is BaseTest { + VotingEscrow escrow; + GaugeFactory gaugeFactory; + BribeFactory bribeFactory; + WrappedBribeFactory wxbribeFactory; + Voter voter; + RewardsDistributor distributor; + Minter minter; + Gauge gauge; + ExternalBribe xbribe; + WrappedBribe wxbribe; + Gauge gauge2; + ExternalBribe xbribe2; + WrappedBribe wxbribe2; + + function setUp() public { + vm.warp(block.timestamp + 1 weeks); // put some initial time in + + deployOwners(); + deployCoins(); + mintStables(); + uint256[] memory amounts = new uint256[](3); + amounts[0] = 2e25; + amounts[1] = 1e25; + amounts[2] = 1e25; + mintFlow(owners, amounts); + mintLR(owners, amounts); + VeArtProxy artProxy = new VeArtProxy(); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); + deployPairFactoryAndRouter(); + + // deployVoter() + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); + wxbribeFactory = new WrappedBribeFactory(address(voter), csrNftId); + + escrow.setVoter(address(voter)); + factory.setVoter(address(voter)); + deployPairWithOwner(address(owner)); + + // deployMinter() + distributor = new RewardsDistributor(address(escrow), csrNftId); + minter = new Minter(address(voter), address(escrow), address(distributor), csrNftId); + distributor.setDepositor(address(minter)); + FLOW.setMinter(address(minter)); + address[] memory tokens = new address[](5); + tokens[0] = address(USDC); + tokens[1] = address(FRAX); + tokens[2] = address(DAI); + tokens[3] = address(FLOW); + tokens[4] = address(LR); + voter.initialize(tokens, address(minter)); + + Minter.Claim[] memory claims = new Minter.Claim[](0); + minter.initialMintAndLock(claims, 0); + minter.startActivePeriod(); + + // USDC - FRAX stable + gauge = Gauge(voter.createGauge(address(pair))); + xbribe = ExternalBribe(gauge.external_bribe()); + wxbribe = WrappedBribe(wxbribeFactory.oldBribeToNew(address(xbribe))); + + + // USDC - FRAX stable + gauge2 = Gauge(voter.createGauge(address(pair2))); + xbribe2 = ExternalBribe(gauge2.external_bribe()); + wxbribe2 = WrappedBribe(wxbribeFactory.oldBribeToNew(address(xbribe2))); + + // ve + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); + vm.startPrank(address(owner2)); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); + vm.warp(block.timestamp + 1); + vm.stopPrank(); + + vm.startPrank(address(owner3)); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); + vm.warp(block.timestamp + 1); + vm.stopPrank(); + } + + function testOldBribesAreBroken() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(xbribe), TOKEN_1); + xbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // fwd half a week + vm.warp(block.timestamp + 1 weeks / 2); + + uint256 pre = LR.balanceOf(address(owner)); + uint256 earned = xbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1 / 2); + + // rewards + address[] memory rewards = new address[](1); + rewards[0] = address(LR); + + vm.startPrank(address(voter)); + // once + xbribe.getRewardForOwner(1, rewards); + // twice + xbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post = LR.balanceOf(address(owner)); + assertEq(post - pre, TOKEN_1); + } + + function testWrappedBribesCanClaimOnlyOnce() public { + // Epoch 0 + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // fwd half a week + // Epoch flip + // Epoch 1 starts + vm.warp(block.timestamp + 1 weeks / 2); + + uint256 pre = LR.balanceOf(address(owner)); + console2.log(""); + console2.log("Epoch 1: BEFORE checking 1 in bribe"); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1 / 2); + + // rewards + address[] memory rewards = new address[](1); + rewards[0] = address(LR); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1 / 2); + + // Middle of Epoch 1 + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe2), TOKEN_1); + wxbribe2.notifyRewardAmount(address(LR), TOKEN_1); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // vote + address[] memory pools2 = new address[](1); + pools2[0] = address(pair2); + uint256[] memory weights2 = new uint256[](1); + weights2[0] = 10000; + voter.vote(1, pools2, weights2); + + + vm.startPrank(address(owner2)); + voter.vote(2, pools2, weights2); + vm.stopPrank(); + + + vm.startPrank(address(owner3)); + voter.vote(3, pools, weights); + vm.stopPrank(); + + // fwd half a week + // Epoch flip + // Epoch 2 starts + vm.warp(block.timestamp + 1 weeks / 2); + + uint256 pre2 = LR.balanceOf(address(owner)); + console2.log(""); + console2.log("Epoch 2: BEFORE checking 1 in bribe2"); + uint256 earned2 = wxbribe2.earned(address(LR), 1); + assertEq(earned2, TOKEN_1 / 2); + + console2.log(""); + console2.log("Epoch 2: BEFORE checking 1 in bribe1"); + earned = wxbribe.earned(address(LR), 1); + assertEq(earned, 0); + + // rewards + address[] memory rewards2 = new address[](1); + rewards2[0] = address(LR); + + vm.startPrank(address(voter)); + // once + wxbribe2.getRewardForOwner(1, rewards2); + uint256 post2 = LR.balanceOf(address(owner)); + // twice + wxbribe2.getRewardForOwner(1, rewards2); + vm.stopPrank(); + + uint256 post_post2 = LR.balanceOf(address(owner)); + assertEq(post_post2, post2); + assertEq(post_post2 - pre2, TOKEN_1 / 2); + + continueEpoch2(); + } + + function continueEpoch2() public { + // Middle of epoch 2 + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + + vm.startPrank(address(owner3)); + voter.vote(3, pools, weights); + vm.stopPrank(); + + epoch3(); + } + + function epoch3() public { + // fwd half a week + // Epoch flip + // Epoch 3 starts + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + + vm.startPrank(address(owner3)); + voter.vote(3, pools, weights); + vm.stopPrank(); + + // not claiming epoch 3 bribes for NFT 3 + epoch4(); + } + + function epoch4() public { + // fwd a week + // Epoch flip + // Epoch 4 + vm.warp(block.timestamp + 1 weeks); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + + voter.vote(1, pools, weights); + + vm.startPrank(address(owner3)); + voter.reset(3); + vm.stopPrank(); + + // Middle of epoch 4 + vm.warp(block.timestamp + 1 weeks / 2); + + console2.log(""); + console2.log("Epoch 4: BEFORE checking 1"); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, 0); // Existing bug: this is >0 + console2.log(""); + console2.log("Epoch 4: BEFORE checking 2"); + earned = wxbribe.earned(address(LR), 2); + assertEq(earned, TOKEN_1 / 2); + console2.log(""); + console2.log("Epoch 4: BEFORE checking 3"); + earned = wxbribe.earned(address(LR), 3); + assertEq(earned, TOKEN_1 * 3); + + epoch5(); + } + + function epoch5() public { + // fwd half a week + // Epoch flip + // Epoch 5 + vm.warp(block.timestamp + 1 weeks / 2); + + uint256 pre = LR.balanceOf(address(owner)); + console2.log(""); + console2.log("Epoch 5: BEFORE checking 1"); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1); + // rewards + address[] memory rewards = new address[](1); + rewards[0] = address(LR); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1); + } + + function testWrappedBribesCanClaimOnlyOnceArray() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // fwd half a week + vm.warp(block.timestamp + 1 weeks / 2); + + uint256 pre = LR.balanceOf(address(owner)); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1 / 2); + + // rewards + address[] memory rewards = new address[](2); + rewards[0] = address(LR); + rewards[1] = address(LR); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1 / 2); + } + + function testBribesCanClaimLeftOverRewardAfterBeingHandled() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // fwd half a week + uint epochTimestamp = block.timestamp; + vm.warp(block.timestamp + 1 weeks / 2); + + // rewards + address[] memory rewards = new address[](1); + rewards[0] = address(LR); + + wxbribe.handleLeftOverRewards(epochTimestamp, rewards); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // fwd a week + vm.warp(block.timestamp + 1 weeks); + + uint256 pre = LR.balanceOf(address(owner)); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1 / 2); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1 / 2); + } + + function testBribesCanClaimLeftOverRewardAfterBeingHandledPlusAddingMoreBribes() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // fwd half a week + uint epochTimestamp = block.timestamp; + vm.warp(block.timestamp + 1 weeks / 2); + + // add more bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // rewards + address[] memory rewards = new address[](1); + rewards[0] = address(LR); + + wxbribe.handleLeftOverRewards(epochTimestamp, rewards); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // fwd a week + vm.warp(block.timestamp + 1 weeks); + + uint256 pre = LR.balanceOf(address(owner)); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1); + } + + function testBribesCanClaimLeftOverRewardAfterBeingHandledAfterSeveralEpochs() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // fwd half a week + uint epochTimestamp = block.timestamp; + vm.warp(block.timestamp + 1 weeks / 2); + + // add more bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // rewards + address[] memory rewards = new address[](1); + rewards[0] = address(LR); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // fwd a week + vm.warp(block.timestamp + 3 weeks); + + wxbribe.handleLeftOverRewards(epochTimestamp, rewards); + + vm.warp(block.timestamp + 1 weeks); + + uint256 pre = LR.balanceOf(address(owner)); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1); + } + + function testCanUpdateRewardAmountWithBalanceDiscrepancy() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // transfer LR tokens to wxbribe + LR.transfer(address(wxbribe), TOKEN_1); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // try to get reward for owner + address[] memory tokens = new address[](1); + tokens[0] = address(LR); + + uint256 balance1 = LR.balanceOf(address(owner)); + uint256 pre_pre_earned = wxbribe.earned(address(LR), 1); + assertEq(pre_pre_earned, 0); + vm.startPrank(address(voter)); + wxbribe.getRewardForOwner(1, tokens); + vm.stopPrank(); + + uint256 balance2 = LR.balanceOf(address(owner)); + assertEq(balance2 - balance1, 0); + uint256 pre_earned = wxbribe.earned(address(LR), 1); + assertEq(pre_earned, 0); + + // update reward amount before epoch flip + wxbribe.updateRewardAmount(tokens); + + // fwd half a week + vm.warp(block.timestamp + 1 weeks / 2); + + uint256 pre = LR.balanceOf(address(owner)); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1 / 2); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, tokens); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, tokens); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1 / 2); + } + + function testCannotUpdateRewardAmountWithoutBalanceDiscrepancy() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + uint256 actualBalance1 = LR.balanceOf(address(wxbribe)); + assertEq(actualBalance1, TOKEN_1); + + uint256 accountBalance1 = wxbribe.tokenRewardBalance(address(LR)); + assertEq(accountBalance1, TOKEN_1); + + // try to update reward amount + address[] memory tokens = new address[](1); + tokens[0] = address(LR); + wxbribe.updateRewardAmount(tokens); + + uint256 actualBalance2 = LR.balanceOf(address(wxbribe)); + assertEq(actualBalance2, TOKEN_1); + + uint256 accountBalance2 = wxbribe.tokenRewardBalance(address(LR)); + assertEq(accountBalance2, TOKEN_1); + } + + function testCanUpdateRewardAmountCorrectlyAfterClaiming() public { + vm.warp(block.timestamp + 1 weeks / 2); + + // create a bribe + LR.approve(address(wxbribe), TOKEN_1); + wxbribe.notifyRewardAmount(address(LR), TOKEN_1); + + // transfer LR token to wxbribe + LR.transfer(address(wxbribe), TOKEN_1); + + // vote + address[] memory pools = new address[](1); + pools[0] = address(pair); + uint256[] memory weights = new uint256[](1); + weights[0] = 10000; + voter.vote(1, pools, weights); + + vm.startPrank(address(owner2)); + voter.vote(2, pools, weights); + vm.stopPrank(); + + // fwd half a week + vm.warp(block.timestamp + 1 weeks / 2); + + uint256 pre = LR.balanceOf(address(owner)); + uint256 earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1 / 2); + + // rewards + address[] memory rewards = new address[](1); + rewards[0] = address(LR); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + uint256 post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + uint256 post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1 / 2); + + uint256 accountBalance1 = wxbribe.tokenRewardBalance(address(LR)); + + // update reward amount before epoch flip + wxbribe.updateRewardAmount(rewards); + + uint256 accountBalance2 = wxbribe.tokenRewardBalance(address(LR)); + assertEq(accountBalance2 - accountBalance1, TOKEN_1); + + // epoch flip + vm.warp(block.timestamp + 1 weeks); + + pre = LR.balanceOf(address(owner)); + earned = wxbribe.earned(address(LR), 1); + assertEq(earned, TOKEN_1 / 2); + + vm.startPrank(address(voter)); + // once + wxbribe.getRewardForOwner(1, rewards); + post = LR.balanceOf(address(owner)); + // twice + wxbribe.getRewardForOwner(1, rewards); + vm.stopPrank(); + + post_post = LR.balanceOf(address(owner)); + assertEq(post_post, post); + assertEq(post_post - pre, TOKEN_1 / 2); + } +} \ No newline at end of file diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index 0c3c0a3f..28dceb4b 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -1,6 +1,6 @@ pragma solidity 0.8.13; -import './BaseTest.sol'; +import "./BaseTest.sol"; import "contracts/WrappedExternalBribe.sol"; import "contracts/factories/WrappedExternalBribeFactory.sol"; @@ -29,14 +29,14 @@ contract WrappedExternalBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); deployPairFactoryAndRouter(); // deployVoter() - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedExternalBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + gaugeFactory = new GaugeFactory(csrNftId); + bribeFactory = new BribeFactory(csrNftId); + wxbribeFactory = new WrappedExternalBribeFactory(csrNftId); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -44,33 +44,35 @@ contract WrappedExternalBribesTest is BaseTest { deployPairWithOwner(address(owner)); // deployMinter() - distributor = new RewardsDistributor(address(escrow)); - minter = new Minter(address(voter), address(escrow), address(distributor)); + distributor = new RewardsDistributor(address(escrow), csrNftId); + minter = new Minter(address(voter), address(escrow), address(distributor), csrNftId); distributor.setDepositor(address(minter)); - VELO.setMinter(address(minter)); + FLOW.setMinter(address(minter)); address[] memory tokens = new address[](5); tokens[0] = address(USDC); tokens[1] = address(FRAX); tokens[2] = address(DAI); - tokens[3] = address(VELO); + tokens[3] = address(FLOW); tokens[4] = address(LR); voter.initialize(tokens, address(minter)); - address[] memory claimants = new address[](0); - uint[] memory amounts1 = new uint[](0); - minter.initialize(claimants, amounts1, 0); + Minter.Claim[] memory claims = new Minter.Claim[](0); + minter.initialMintAndLock(claims, 0); + minter.startActivePeriod(); // USDC - FRAX stable gauge = Gauge(voter.createGauge(address(pair))); xbribe = ExternalBribe(gauge.external_bribe()); - wxbribe = WrappedExternalBribe(wxbribeFactory.oldBribeToNew(address(xbribe))); + wxbribe = WrappedExternalBribe( + wxbribeFactory.oldBribeToNew(address(xbribe)) + ); // ve - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.startPrank(address(owner2)); - VELO.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + FLOW.approve(address(escrow), TOKEN_1); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(block.timestamp + 1); vm.stopPrank(); } @@ -199,4 +201,4 @@ contract WrappedExternalBribesTest is BaseTest { assertEq(post_post, post); assertEq(post_post - pre, TOKEN_1 / 2); } -} \ No newline at end of file +} diff --git a/test/utils/TestOwner.sol b/test/utils/TestOwner.sol index 7f3ce4ec..50296da7 100644 --- a/test/utils/TestOwner.sol +++ b/test/utils/TestOwner.sol @@ -4,6 +4,7 @@ import "solmate/test/utils/mocks/MockERC20.sol"; import "contracts/Gauge.sol"; import "contracts/Minter.sol"; import "contracts/Pair.sol"; +import "contracts/factories/PairFactory.sol"; import "contracts/Router.sol"; import "contracts/Flow.sol"; import "contracts/VotingEscrow.sol"; @@ -39,14 +40,6 @@ contract TestOwner { PairFactory //////////////////////////////////////////////////////////////*/ - function setFeeManager(address _factory, address _feeManager) public { - PairFactory(_factory).setFeeManager(_feeManager); - } - - function acceptFeeManager(address _factory) public { - PairFactory(_factory).acceptFeeManager(); - } - function setFee(address _factory, bool _stable, uint256 _fee) public { PairFactory(_factory).setFee(_stable, _fee); } diff --git a/test/utils/TestVoter.sol b/test/utils/TestVoter.sol index 14819702..6a33d926 100644 --- a/test/utils/TestVoter.sol +++ b/test/utils/TestVoter.sol @@ -20,10 +20,10 @@ contract TestVoter { } function distribute(address _gauge) external { - + } - function isWhitelisted(address token) public returns (bool) { + function isWhitelisted(address) public pure returns (bool) { return true; } }