From 8d5f7eaa360e86bb277b7d270d30472fa040096f Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 4 Mar 2023 21:31:24 +0800 Subject: [PATCH 001/119] feat: add canto csr --- contracts/ExternalBribe.sol | 6 +- contracts/Flow.sol | 7 +- contracts/FlowConvertor.sol | 73 ------- contracts/FlowVestor.sol | 189 ------------------ contracts/Gauge.sol | 7 +- contracts/Minter.sol | 6 +- contracts/Pair.sol | 6 +- contracts/RewardsDistributor.sol | 5 +- contracts/Router.sol | 142 +------------ contracts/VeloGovernor.sol | 5 +- contracts/Voter.sol | 7 +- contracts/VotingEscrow.sol | 6 +- contracts/WrappedExternalBribe.sol | 6 +- contracts/factories/BribeFactory.sol | 10 +- contracts/factories/GaugeFactory.sol | 9 +- contracts/factories/PairFactory.sol | 11 +- .../factories/WrappedExternalBribeFactory.sol | 10 +- contracts/interfaces/ITurnstile.sol | 7 + test/BaseTest.sol | 8 +- test/ExternalBribes.t.sol | 14 +- test/Imbalance.t.sol | 10 +- test/KillGauges.t.sol | 15 +- test/LPRewards.t.sol | 10 +- test/Minter.t.sol | 18 +- test/MinterTeamEmissions.t.sol | 20 +- test/NFTVote.t.sol | 2 +- test/Pair.t.sol | 14 +- test/Staking.t.sol | 2 +- test/VeloGovernor.t.sol | 16 +- test/VeloVoting.t.sol | 20 +- test/VotingEscrow.t.sol | 2 +- test/WashTrade.t.sol | 10 +- test/WrappedExternalBribes.t.sol | 14 +- 33 files changed, 183 insertions(+), 504 deletions(-) delete mode 100644 contracts/FlowConvertor.sol delete mode 100644 contracts/FlowVestor.sol create mode 100644 contracts/interfaces/ITurnstile.sol diff --git a/contracts/ExternalBribe.sol b/contracts/ExternalBribe.sol index 41ce2031..a5ecc6d0 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 diff --git a/contracts/Flow.sol b/contracts/Flow.sol index f9c48e73..6a52ba1e 100644 --- a/contracts/Flow.sol +++ b/contracts/Flow.sol @@ -2,13 +2,14 @@ pragma solidity 0.8.13; import "contracts/interfaces/IFlow.sol"; +import 'contracts/interfaces/ITurnstile.sol'; contract Flow is IFlow { - string public constant name = "Velocimeter"; string public constant symbol = "FLOW"; uint8 public constant decimals = 18; uint public totalSupply = 0; + uint256 public csrNftId; mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; @@ -18,9 +19,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); + + csrNftId = ITurnstile(0xEcf044C5B4b867CFda001101c617eCd347095B44).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 deleted file mode 100644 index 116e5460..00000000 --- a/contracts/FlowConvertor.sol +++ /dev/null @@ -1,73 +0,0 @@ -pragma solidity 0.8.13; - -import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; -import "openzeppelin-contracts/contracts/access/Ownable.sol"; - -/** - * @dev This contract allow users to convert one token to another. - * It requires both tokens to have valid contract addresses. - * It requires that it is filled up first with liquid v2 tokens., they dont need to be exact. - * Any tokens that get sent here accidently can be sent back out, except v1 token. - */ -contract FlowConvertor is Ownable { - address public immutable v1; - address public immutable v2; - - constructor(address _v1, address _v2) { - v1 = _v1; - v2 = _v2; - } - - /** - * @dev Transfers ERC20 v1 from user to contract, and Transfer ERC20 v2 to user, 1 to 1. - */ - function redeem(uint256 amount) public { - require(amount > 0, "you dont have and v1 tokens"); - SafeERC20.safeTransferFrom( - IERC20(v1), - _msgSender(), - address(this), - amount - ); - SafeERC20.safeTransferFrom( - IERC20(v2), - address(this), - _msgSender(), - amount - ); - } - - /** - * @dev Transfers ERC20 v1 from user to contract, and Transfer ERC20 v2 to an address specified, 1 to 1. - */ - function redeemTo(address _to, uint256 amount) public { - require(amount > 0, "you dont have and v1 tokens"); - SafeERC20.safeTransferFrom( - IERC20(v1), - _msgSender(), - address(this), - amount - ); - SafeERC20.safeTransferFrom(IERC20(v2), address(this), _to, amount); - } - - /** - * @dev Allows owner to clean out the contract of ANY tokens including v2, but not v1 - */ - function inCaseTokensGetStuck( - address _token, - address _to, - uint256 _amount - ) public onlyOwner { - require(_token != address(v1), "these tkns are essentially burnt"); - SafeERC20.safeTransfer(IERC20(_token), _to, _amount); - } - - /** - * @dev Allows owner sweep out all the remaining v2 tokens. - */ - function sweepV2(address _to) public onlyOwner { - uint256 _surplus = IERC20(v2).balanceOf(address(this)); - SafeERC20.safeTransfer(IERC20(v2), _to, _surplus); - } -} diff --git a/contracts/FlowVestor.sol b/contracts/FlowVestor.sol deleted file mode 100644 index 2ee2f53d..00000000 --- a/contracts/FlowVestor.sol +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: MIT AND AGPL-3.0-or-later -pragma solidity ^0.8.0; - -import "openzeppelin-contracts/contracts/access/Ownable.sol"; -import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; - -// Inspired by https://github.com/vetherasset/vader-protocol-v2/blob/main/contracts/tokens/vesting/LinearVesting.sol -/** - * @dev Implementation of the Linear Vesting - * - * The straightforward vesting contract that gradually releases a - * fixed supply of tokens to multiple vest parties over a 1 year - * window. - * - * The token expects the {begin} hook to be invoked the moment - * it is supplied with the necessary amount of tokens to vest - */ -contract FlowVestor is Ownable { - address public revokeTo; - /* ========== CONSTANTS ========== */ - - address internal constant _ZERO_ADDRESS = address(0); - - uint256 internal constant _ONE_YEAR = 365 days; - - /* ========== FLOW ALLOCATION ========== */ - - // The FLOW token - IERC20 public immutable FLOW; - - /* ========== VESTING ========== */ - - // Vesting Duration - uint256 public constant VESTING_DURATION = 1 * _ONE_YEAR; - - /* ========== STRUCTS ========== */ - - // Struct of a vesting member, tight-packed to 256-bits - struct Vester { - uint192 amount; - uint64 lastClaim; - uint128 start; - uint128 end; - } - - /* ========== EVENTS ========== */ - - event RevokeToUpdated(address oldAddress, address newAddress); - event VestingCreated(address user, uint256 amount); - event VestingCancelled(address user, uint256 amount); - event Vested(address indexed from, uint256 amount); - - /* ========== STATE VARIABLES ========== */ - - // The status of each vesting member (Vester) - mapping(address => Vester) public vest; - - /* ========== CONSTRUCTOR ========== */ - - /** - * @dev Initializes the FLOW token address - * - * 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"); - FLOW = IERC20(_FLOW); - transferOwnership(_admin); - } - - /* ========== VIEWS ========== */ - - /** - * @dev Returns the amount a user can claim at a given point in time. - * - * Requirements: - * - the vesting period has started - */ - function getClaim(address _vester) - external - view - returns (uint256 vestedAmount) - { - Vester memory vester = vest[_vester]; - return - _getClaim( - vester.amount, - vester.lastClaim, - vester.start, - vester.end - ); - } - - /* ========== MUTATIVE FUNCTIONS ========== */ - - /** - * @dev Allows a user to claim their pending vesting amount of the vested claim - * - * Emits a {Vested} event indicating the user who claimed their vested tokens - * as well as the amount that was vested. - * - * Requirements: - * - * - the vesting period has started - * - the caller must have a non-zero vested amount - */ - function claim() external returns (uint256 vestedAmount) { - Vester memory vester = vest[msg.sender]; - - require(vester.start != 0, "Not Started"); - - require(vester.start < block.timestamp, "Not Started Yet"); - - vestedAmount = _getClaim( - vester.amount, - vester.lastClaim, - vester.start, - vester.end - ); - - require(vestedAmount != 0, "Nothing to claim"); - - vester.amount -= uint192(vestedAmount); - vester.lastClaim = uint64(block.timestamp); - - vest[msg.sender] = vester; - - emit Vested(msg.sender, vestedAmount); - - FLOW.transfer(msg.sender, vestedAmount); - } - - /* ========== RESTRICTED FUNCTIONS ========== */ - - /** - * @dev Adds a new vesting schedule to the contract. - * - * Requirements: - * - Only {owner} can call. - */ - function vestFor(address user, uint256 amount) external onlyOwner { - require(amount <= type(uint192).max, "Amount Overflows uint192"); - require(vest[user].amount == 0, "Already a vester"); - vest[user] = Vester( - uint192(amount), - 0, - uint128(block.timestamp), - uint128(block.timestamp + VESTING_DURATION) - ); - FLOW.transferFrom(msg.sender, address(this), amount); - - emit VestingCreated(user, amount); - } - - function cancelVest(address user) external onlyOwner { - require(revokeTo != address(0), "0 revoke to address"); - uint256 amount = vest[user].amount; - require(amount > 0, "Not a vester"); - require( - FLOW.balanceOf(address(this)) >= amount, - "Insufficient FLOW balance" - ); - delete vest[user]; - FLOW.transfer(revokeTo, amount); - - emit VestingCancelled(user, amount); - } - - function setRevokeTo(address _revokeTo) external onlyOwner { - require(_revokeTo != address(0), "0 address"); - emit RevokeToUpdated(revokeTo, _revokeTo); - revokeTo = _revokeTo; - } - - /* ========== PRIVATE FUNCTIONS ========== */ - - function _getClaim( - uint256 amount, - uint256 lastClaim, - uint256 _start, - uint256 _end - ) private view returns (uint256) { - if (block.timestamp >= _end) return amount; - if (lastClaim == 0) lastClaim = _start; - - return (amount * (block.timestamp - lastClaim)) / (_end - lastClaim); - } -} diff --git a/contracts/Gauge.sol b/contracts/Gauge.sol index 424f2461..b11d7804 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; @@ -81,7 +82,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 +95,8 @@ contract Gauge is IGauge { rewards.push(_allowedRewardTokens[i]); } } + + ITurnstile(turnstile).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/Minter.sol b/contracts/Minter.sol index 6ee5e8e2..2ac0a410 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; @@ -35,7 +37,8 @@ contract Minter is IMinter { 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,6 +48,7 @@ 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( diff --git a/contracts/Pair.sol b/contracts/Pair.sol index 7f9e1ba4..ee5c5999 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -8,10 +8,11 @@ import 'contracts/interfaces/IPairCallee.sol'; import 'contracts/factories/PairFactory.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; @@ -81,7 +82,7 @@ contract Pair is IPair { event ExternalBribeSet(address indexed setter, address indexed externalBribe); event HasGaugeSet(address indexed setter, bool value); - constructor() { + constructor(uint256 _csrNftId) { factory = msg.sender; voter = PairFactory(msg.sender).voter(); tank = PairFactory(msg.sender).tank(); @@ -99,6 +100,7 @@ contract Pair is IPair { decimals1 = 10**IERC20(_token1).decimals(); observations.push(Observation(block.timestamp, 0, 0)); + ITurnstile(turnstile).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/RewardsDistributor.sol b/contracts/RewardsDistributor.sol index 3fc74bce..351a8eac 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..8515fd5c 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..8a832a56 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/Voter.sol b/contracts/Voter.sol index 7716e2a3..f24b6766 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 diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol index 66eff883..8d8bd5f4 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,6 +64,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ + address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable token; address public voter; @@ -88,7 +90,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { /// @notice Contract constructor /// @param token_addr `VELO` token address - constructor(address token_addr, address art_proxy) { + constructor(address token_addr, address art_proxy, uint256 _csrNftId) { token = token_addr; voter = msg.sender; team = msg.sender; @@ -101,6 +103,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 diff --git a/contracts/WrappedExternalBribe.sol b/contracts/WrappedExternalBribe.sol index d44d4ea5..fc6d91a6 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 diff --git a/contracts/factories/BribeFactory.sol b/contracts/factories/BribeFactory.sol index b945c859..53c46210 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..bc839b47 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..b5f4e124 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -3,9 +3,10 @@ pragma solidity 0.8.13; import 'contracts/interfaces/IPairFactory.sol'; import 'contracts/Pair.sol'; +import 'contracts/interfaces/ITurnstile.sol'; contract PairFactory is IPairFactory { - + address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; bool public isPaused; address public pauser; address public pendingPauser; @@ -28,6 +29,8 @@ 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); @@ -40,13 +43,15 @@ contract PairFactory is IPairFactory { event FeeSet(address indexed setter, bool stable, uint256 fee); - constructor() { + constructor(uint256 _csrNftId) { pauser = msg.sender; isPaused = false; feeManager = msg.sender; stableFee = 3; // 0.03% volatileFee = 25; // 0.25% deployer = msg.sender; + ITurnstile(turnstile).assign(_csrNftId); + csrNftId = _csrNftId; } function setTeam(address _team) external { @@ -135,7 +140,7 @@ contract PairFactory is IPairFactory { require(getPair[token0][token1][stable] == address(0), 'PE'); // Pair: PAIR_EXISTS - single check is sufficient bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); // notice salt includes stable as well, 3 parameters (_temp0, _temp1, _temp) = (token0, token1, stable); - pair = address(new Pair{salt:salt}()); + pair = address(new Pair{salt:salt}(csrNftId)); getPair[token0][token1][stable] = pair; getPair[token1][token0][stable] = pair; // populate mapping in the reverse direction allPairs.push(pair); diff --git a/contracts/factories/WrappedExternalBribeFactory.sol b/contracts/factories/WrappedExternalBribeFactory.sol index 1e4aad81..9ceaf569 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; address public voter; mapping(address => address) public oldBribeToNew; address public last_bribe; + uint256 public immutable csrNftId; 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/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/test/BaseTest.sol b/test/BaseTest.sol index f2f5fc5d..5c0c7f83 100644 --- a/test/BaseTest.sol +++ b/test/BaseTest.sol @@ -35,6 +35,7 @@ abstract contract BaseTest is Test, TestOwner { uint256 constant TOKEN_10B = 1e28; // 1e10 = 10B tokens with 18 decimals uint256 constant PAIR_1 = 1e9; + uint256 csrNftId; TestOwner owner; TestOwner owner2; TestOwner owner3; @@ -68,7 +69,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); + VELO = new Flow(msg.sender, msg.sender); + csrNftId = VELO.csrNftId(); WEVE = new MockERC20("WEVE", "WEVE", 18); LR = new MockERC20("LR", "LR", 18); WETH = new TestWETH(); @@ -114,14 +116,14 @@ 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)); } diff --git a/test/ExternalBribes.t.sol b/test/ExternalBribes.t.sol index 7191a5fb..7af877c1 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(VELO), address(artProxy), 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,8 +42,8 @@ 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)); address[] memory tokens = new address[](5); diff --git a/test/Imbalance.t.sol b/test/Imbalance.t.sol index cc00ee4c..20c5530d 100644 --- a/test/Imbalance.t.sol +++ b/test/Imbalance.t.sol @@ -19,7 +19,7 @@ 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(VELO), address(artProxy), csrNftId); } function createLock() public { @@ -79,10 +79,10 @@ 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); diff --git a/test/KillGauges.t.sol b/test/KillGauges.t.sol index 1fc3ee28..49975bd1 100644 --- a/test/KillGauges.t.sol +++ b/test/KillGauges.t.sol @@ -25,7 +25,7 @@ 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(VELO), address(artProxy), csrNftId); VELO.approve(address(escrow), 100 * TOKEN_1); escrow.create_lock(100 * TOKEN_1, 4 * 365 * 86400); @@ -33,15 +33,16 @@ contract KillGaugesTest is BaseTest { 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,9 +50,9 @@ 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)); address[] memory tokens = new address[](4); diff --git a/test/LPRewards.t.sol b/test/LPRewards.t.sol index d1ddc7e9..f0a16650 100644 --- a/test/LPRewards.t.sol +++ b/test/LPRewards.t.sol @@ -22,16 +22,16 @@ contract LPRewardsTest is BaseTest { // give owner1 veVELO VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); VELO.approve(address(escrow), TOKEN_1M); escrow.create_lock(TOKEN_1M, 4 * 365 * 86400); 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)); diff --git a/test/Minter.t.sol b/test/Minter.t.sol index fa96fd6b..6cc15b3d 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -23,13 +23,13 @@ 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(VELO), address(artProxy), 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)); @@ -40,10 +40,10 @@ contract MinterTest is BaseTest { voter.initialize(tokens, address(owner)); VELO.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); - distributor = new RewardsDistributor(address(escrow)); + 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)); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index c7fe97a7..1c87c8b4 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -25,18 +25,19 @@ 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(VELO), address(artProxy), 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)); @@ -46,13 +47,14 @@ contract MinterTeamEmissions is BaseTest { voter.initialize(tokens, address(owner)); VELO.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); - distributor = new RewardsDistributor(address(escrow)); + 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)); diff --git a/test/NFTVote.t.sol b/test/NFTVote.t.sol index 2b032673..d542f969 100644 --- a/test/NFTVote.t.sol +++ b/test/NFTVote.t.sol @@ -21,7 +21,7 @@ contract NFTVoteTest is BaseTest { deployCoins(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); gov = new TestL2Governance(escrow); // test variable to vote on diff --git a/test/Pair.t.sol b/test/Pair.t.sol index dd08b2f0..6b2690fb 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -31,7 +31,7 @@ contract PairTest is BaseTest { mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); } function createLock() public { @@ -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,9 +258,9 @@ 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)); address[] memory tokens = new address[](5); diff --git a/test/Staking.t.sol b/test/Staking.t.sol index 63339835..83dd055f 100644 --- a/test/Staking.t.sol +++ b/test/Staking.t.sol @@ -49,7 +49,7 @@ contract StakingTest is BaseTest { 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); diff --git a/test/VeloGovernor.t.sol b/test/VeloGovernor.t.sol index 55e9d874..cb08d18b 100644 --- a/test/VeloGovernor.t.sol +++ b/test/VeloGovernor.t.sol @@ -25,7 +25,7 @@ contract VeloGovernorTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); VELO.approve(address(escrow), 97 * TOKEN_1); escrow.create_lock(97 * TOKEN_1, 4 * 365 * 86400); @@ -40,10 +40,10 @@ contract VeloGovernorTest is BaseTest { 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,9 +53,9 @@ 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)); @@ -67,7 +67,7 @@ contract VeloGovernorTest is BaseTest { address gaugeAddress = voter.gauges(address(pair)); gauge = Gauge(gaugeAddress); - governor = new VeloGovernor(escrow); + governor = new VeloGovernor(escrow, csrNftId); voter.setGovernor(address(governor)); } diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index 297a652e..ef77fdcb 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(VELO), address(artProxy), 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)); @@ -48,13 +49,14 @@ contract VeloVotingTest is BaseTest { voter.initialize(tokens, address(owner)); VELO.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); - distributor = new RewardsDistributor(address(escrow)); + 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)); diff --git a/test/VotingEscrow.t.sol b/test/VotingEscrow.t.sol index e8d29123..951b9c27 100644 --- a/test/VotingEscrow.t.sol +++ b/test/VotingEscrow.t.sol @@ -15,7 +15,7 @@ contract VotingEscrowTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); } function testCreateLock() public { diff --git a/test/WashTrade.t.sol b/test/WashTrade.t.sol index c8895ac9..b834746f 100644 --- a/test/WashTrade.t.sol +++ b/test/WashTrade.t.sol @@ -22,7 +22,7 @@ contract WashTradeTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy)); + escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); } function createLock() public { @@ -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)); diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index 0c3c0a3f..b8f5b45a 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.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(VELO), address(artProxy), 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,8 +44,8 @@ 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)); address[] memory tokens = new address[](5); From 3d5501e34e62afe2fdac827cfa19f0387c1b58e3 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 4 Mar 2023 21:42:53 +0800 Subject: [PATCH 002/119] feat: add owner in voting escrow --- contracts/VotingEscrow.sol | 5 +++-- test/ExternalBribes.t.sol | 2 +- test/Imbalance.t.sol | 2 +- test/KillGauges.t.sol | 2 +- test/LPRewards.t.sol | 2 +- test/Minter.t.sol | 2 +- test/MinterTeamEmissions.t.sol | 2 +- test/NFTVote.t.sol | 2 +- test/Pair.t.sol | 2 +- test/VeloGovernor.t.sol | 2 +- test/VeloVoting.t.sol | 2 +- test/VotingEscrow.t.sol | 2 +- test/WashTrade.t.sol | 2 +- test/WrappedExternalBribes.t.sol | 2 +- 14 files changed, 16 insertions(+), 15 deletions(-) diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol index 8d8bd5f4..03f2acc3 100644 --- a/contracts/VotingEscrow.sol +++ b/contracts/VotingEscrow.sol @@ -65,7 +65,7 @@ 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; @@ -90,11 +90,12 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { /// @notice Contract constructor /// @param token_addr `VELO` token address - constructor(address token_addr, address art_proxy, uint256 _csrNftId) { + 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; diff --git a/test/ExternalBribes.t.sol b/test/ExternalBribes.t.sol index 7af877c1..853811b2 100644 --- a/test/ExternalBribes.t.sol +++ b/test/ExternalBribes.t.sol @@ -27,7 +27,7 @@ contract ExternalBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); deployPairFactoryAndRouter(); // deployVoter() diff --git a/test/Imbalance.t.sol b/test/Imbalance.t.sol index 20c5530d..9465f70f 100644 --- a/test/Imbalance.t.sol +++ b/test/Imbalance.t.sol @@ -19,7 +19,7 @@ contract ImbalanceTest is BaseTest { amounts[0] = 1e25; mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); } function createLock() public { diff --git a/test/KillGauges.t.sol b/test/KillGauges.t.sol index 49975bd1..44fab70d 100644 --- a/test/KillGauges.t.sol +++ b/test/KillGauges.t.sol @@ -25,7 +25,7 @@ contract KillGaugesTest is BaseTest { amounts[2] = 1e25; mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); VELO.approve(address(escrow), 100 * TOKEN_1); escrow.create_lock(100 * TOKEN_1, 4 * 365 * 86400); diff --git a/test/LPRewards.t.sol b/test/LPRewards.t.sol index f0a16650..7e4d3d76 100644 --- a/test/LPRewards.t.sol +++ b/test/LPRewards.t.sol @@ -22,7 +22,7 @@ contract LPRewardsTest is BaseTest { // give owner1 veVELO VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); VELO.approve(address(escrow), TOKEN_1M); escrow.create_lock(TOKEN_1M, 4 * 365 * 86400); diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 6cc15b3d..1208430f 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -23,7 +23,7 @@ contract MinterTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); factory = new PairFactory(csrNftId); router = new Router(address(factory), address(owner), csrNftId); gaugeFactory = new GaugeFactory(csrNftId); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 1c87c8b4..456db44e 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -25,7 +25,7 @@ contract MinterTeamEmissions is BaseTest { mintFlow(owners, amountsVelo); team = new TestOwner(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); factory = new PairFactory(csrNftId); router = new Router(address(factory), address(owner), csrNftId); gaugeFactory = new GaugeFactory(csrNftId); diff --git a/test/NFTVote.t.sol b/test/NFTVote.t.sol index d542f969..b0282ad1 100644 --- a/test/NFTVote.t.sol +++ b/test/NFTVote.t.sol @@ -21,7 +21,7 @@ contract NFTVoteTest is BaseTest { deployCoins(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); gov = new TestL2Governance(escrow); // test variable to vote on diff --git a/test/Pair.t.sol b/test/Pair.t.sol index 6b2690fb..00c89f3e 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -31,7 +31,7 @@ contract PairTest is BaseTest { mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); } function createLock() public { diff --git a/test/VeloGovernor.t.sol b/test/VeloGovernor.t.sol index cb08d18b..9b28cb5d 100644 --- a/test/VeloGovernor.t.sol +++ b/test/VeloGovernor.t.sol @@ -25,7 +25,7 @@ contract VeloGovernorTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); VELO.approve(address(escrow), 97 * TOKEN_1); escrow.create_lock(97 * TOKEN_1, 4 * 365 * 86400); diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index ef77fdcb..40b9cec4 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -25,7 +25,7 @@ contract VeloVotingTest is BaseTest { mintFlow(owners, amountsVelo); team = new TestOwner(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); factory = new PairFactory(csrNftId); router = new Router(address(factory), address(owner), csrNftId); gaugeFactory = new GaugeFactory(csrNftId); diff --git a/test/VotingEscrow.t.sol b/test/VotingEscrow.t.sol index 951b9c27..a18daac0 100644 --- a/test/VotingEscrow.t.sol +++ b/test/VotingEscrow.t.sol @@ -15,7 +15,7 @@ contract VotingEscrowTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); } function testCreateLock() public { diff --git a/test/WashTrade.t.sol b/test/WashTrade.t.sol index b834746f..d42d5ef6 100644 --- a/test/WashTrade.t.sol +++ b/test/WashTrade.t.sol @@ -22,7 +22,7 @@ contract WashTradeTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); } function createLock() public { diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index b8f5b45a..b35eec8f 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -29,7 +29,7 @@ contract WrappedExternalBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), csrNftId); + escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); deployPairFactoryAndRouter(); // deployVoter() From 3ec589e838cec58c242a36a5b6955024bc4e1228 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 4 Mar 2023 21:51:24 +0800 Subject: [PATCH 003/119] fix: fix failed tests --- test/NFTVote.t.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/test/NFTVote.t.sol b/test/NFTVote.t.sol index b0282ad1..5b8cf07c 100644 --- a/test/NFTVote.t.sol +++ b/test/NFTVote.t.sol @@ -18,6 +18,7 @@ contract NFTVoteTest is BaseTest { FlagCondition flag; function setUp() public { + deployOwners(); deployCoins(); VeArtProxy artProxy = new VeArtProxy(); From 67fe09ac2509f417e5b9ea52a31e2b3aa5e2274a Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 13:53:41 +0000 Subject: [PATCH 004/119] refactor: Rename VELO to FLOW and fixed a test --- contracts/VotingEscrow.sol | 2 +- tasks/deploy/constants/optimismConfig.ts | 4 +- tasks/deploy/op.ts | 4 +- test/BaseTest.sol | 8 +- test/ExternalBribes.t.sol | 10 +- test/Imbalance.t.sol | 14 +-- test/KillGauges.t.sol | 22 ++-- test/LPRewards.t.sol | 10 +- test/Minter.t.sol | 22 ++-- test/MinterTeamEmissions.t.sol | 48 +++---- test/NFTVote.t.sol | 7 +- test/Oracle.t.sol | 2 +- test/Pair.t.sol | 110 ++++++++-------- test/Staking.t.sol | 152 +++++++++++------------ test/VeloGovernor.t.sol | 12 +- test/VeloVoting.t.sol | 28 ++--- test/VotingEscrow.t.sol | 12 +- test/WashTrade.t.sol | 14 +-- test/WrappedExternalBribes.t.sol | 41 ++++-- 19 files changed, 271 insertions(+), 251 deletions(-) diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol index 03f2acc3..596b1cf8 100644 --- a/contracts/VotingEscrow.sol +++ b/contracts/VotingEscrow.sol @@ -89,7 +89,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { uint internal tokenId; /// @notice Contract constructor - /// @param token_addr `VELO` token address + /// @param token_addr `FLOW` token address constructor(address token_addr, address art_proxy, address _owner, uint256 _csrNftId) { token = token_addr; voter = msg.sender; diff --git a/tasks/deploy/constants/optimismConfig.ts b/tasks/deploy/constants/optimismConfig.ts index 8eb91894..f25a4c4d 100644 --- a/tasks/deploy/constants/optimismConfig.ts +++ b/tasks/deploy/constants/optimismConfig.ts @@ -54,13 +54,13 @@ const optimismConfig = { "0x8aE125E8653821E851F12A49F7765db9a9ce7384", // DOLA "0x10010078a54396F62c96dF8532dc2B4847d47ED3", // HND // "", // BTRFLY -- N/A - // "", // pxVELO -- N/A + // "", // pxFLOW -- N/A "0xc40F949F8a4e094D1b49a23ea9241D289B7b2819", // LUSD // "", // wstETH -- N/A // "", // HOP -- N/A ], partnerAddrs: [ - TEAM_EOA, // VELO + TEAM_EOA, // FLOW "0x4a84675512949f81EBFEAAcC6C00D03eDd329de5", // OP TEAM_EOA, // SNX -- custodied "0xa283139017a2f5BAdE8d8e25412C600055D318F8", // INV diff --git a/tasks/deploy/op.ts b/tasks/deploy/op.ts index cb11ded2..9e7993c3 100644 --- a/tasks/deploy/op.ts +++ b/tasks/deploy/op.ts @@ -147,13 +147,13 @@ task("deploy:op", "Deploys Optimism contracts").setAction(async function ( await voter.initialize(tokenWhitelist, minter.address); console.log("Whitelist set"); - // Initial veVELO distro + // Initial veFLOW distro await minter.initialize( OP_CONFIG.partnerAddrs, OP_CONFIG.partnerAmts, OP_CONFIG.partnerMax ); - console.log("veVELO distributed"); + console.log("veFLOW distributed"); await minter.setTeam(OP_CONFIG.teamMultisig) console.log("Team set for minter"); diff --git a/test/BaseTest.sol b/test/BaseTest.sol index 5c0c7f83..074e6f07 100644 --- a/test/BaseTest.sol +++ b/test/BaseTest.sol @@ -44,7 +44,7 @@ abstract contract BaseTest is Test, TestOwner { MockERC20 FRAX; MockERC20 DAI; TestWETH WETH; // Mock WETH token - Flow VELO; + Flow FLOW; MockERC20 WEVE; MockERC20 LR; // late reward TestToken stake; @@ -69,8 +69,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, msg.sender); - csrNftId = VELO.csrNftId(); + FLOW = new Flow(msg.sender, msg.sender); + csrNftId = FLOW.csrNftId(); WEVE = new MockERC20("WEVE", "WEVE", 18); LR = new MockERC20("LR", "LR", 18); WETH = new TestWETH(); @@ -87,7 +87,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]); } } diff --git a/test/ExternalBribes.t.sol b/test/ExternalBribes.t.sol index 853811b2..387662f9 100644 --- a/test/ExternalBribes.t.sol +++ b/test/ExternalBribes.t.sol @@ -27,7 +27,7 @@ contract ExternalBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); deployPairFactoryAndRouter(); // deployVoter() @@ -45,12 +45,12 @@ contract ExternalBribesTest is BaseTest { 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)); @@ -63,10 +63,10 @@ contract ExternalBribesTest is BaseTest { xbribe = ExternalBribe(gauge.external_bribe()); // ve - VELO.approve(address(escrow), TOKEN_1); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); vm.startPrank(address(owner2)); - VELO.approve(address(escrow), TOKEN_1); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); vm.warp(block.timestamp + 1); vm.stopPrank(); diff --git a/test/Imbalance.t.sol b/test/Imbalance.t.sol index 9465f70f..04db8f60 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), owners[0], csrNftId); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); } function createLock() public { deployBaseCoins(); - VELO.approve(address(escrow), TOKEN_1); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); 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); @@ -89,7 +89,7 @@ contract ImbalanceTest 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); @@ -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 44fab70d..9ce5344b 100644 --- a/test/KillGauges.t.sol +++ b/test/KillGauges.t.sol @@ -25,9 +25,9 @@ contract KillGaugesTest is BaseTest { amounts[2] = 1e25; mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); - VELO.approve(address(escrow), 100 * TOKEN_1); + FLOW.approve(address(escrow), 100 * TOKEN_1); escrow.create_lock(100 * TOKEN_1, 4 * 365 * 86400); vm.roll(block.number + 1); @@ -54,20 +54,20 @@ contract KillGaugesTest is BaseTest { 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); @@ -133,7 +133,7 @@ contract KillGaugesTest is BaseTest { 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); @@ -151,7 +151,7 @@ contract KillGaugesTest is BaseTest { 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); @@ -171,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 7e4d3d76..7b653831 100644 --- a/test/LPRewards.t.sol +++ b/test/LPRewards.t.sol @@ -20,10 +20,10 @@ 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), owners[0], csrNftId); - VELO.approve(address(escrow), TOKEN_1M); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); + FLOW.approve(address(escrow), TOKEN_1M); escrow.create_lock(TOKEN_1M, 4 * 365 * 86400); deployPairFactoryAndRouter(); @@ -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 1208430f..0375c053 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -23,7 +23,7 @@ contract MinterTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + 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); @@ -36,28 +36,28 @@ contract MinterTest 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); 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; @@ -77,7 +77,7 @@ contract MinterTest is BaseTest { 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 { @@ -101,7 +101,7 @@ contract MinterTest is BaseTest { 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); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 456db44e..0a820959 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -25,7 +25,7 @@ contract MinterTeamEmissions is BaseTest { mintFlow(owners, amountsVelo); team = new TestOwner(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + 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); @@ -43,9 +43,9 @@ contract MinterTeamEmissions is BaseTest { 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); @@ -57,13 +57,13 @@ contract MinterTeamEmissions is BaseTest { 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 +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; @@ -95,18 +95,18 @@ contract MinterTeamEmissions is BaseTest { 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)), 14 * 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)); + uint256 after_ = FLOW.balanceOf(address(owner)); assertEq(minter.weekly(), 15 * TOKEN_1M); assertEq(after_ - before, 0); vm.warp(block.timestamp + 86400 * 7); 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)); + after_ = FLOW.balanceOf(address(owner)); assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift } @@ -133,33 +133,33 @@ contract MinterTeamEmissions is BaseTest { vm.warp(block.timestamp + 86400 * 7); 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.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 + // rate is right even when FLOW is sent to Minter contract vm.warp(block.timestamp + 86400 * 7); 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 } @@ -181,11 +181,11 @@ contract MinterTeamEmissions is BaseTest { vm.warp(block.timestamp + 86400 * 7); 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 5b8cf07c..45d68040 100644 --- a/test/NFTVote.t.sol +++ b/test/NFTVote.t.sol @@ -20,22 +20,23 @@ contract NFTVoteTest is BaseTest { function setUp() public { deployOwners(); deployCoins(); + deployOwners(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + 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 00c89f3e..50d3bab5 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), owners[0], csrNftId); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); } function createLock() public { deployPairCoins(); - VELO.approve(address(escrow), 5e17); + FLOW.approve(address(escrow), 5e17); escrow.create_lock(5e17, 4 * 365 * 86400); 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); 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); 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()); @@ -262,12 +262,12 @@ contract PairTest is BaseTest { 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); 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); @@ -598,10 +598,10 @@ contract PairTest is BaseTest { minter.initialize(claimants, amounts, TOKEN_1); 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 +621,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 +676,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); @@ -755,16 +755,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); @@ -792,7 +792,7 @@ contract PairTest is BaseTest { 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 +800,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 +857,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 83dd055f..064dfdc3 100644 --- a/test/Staking.t.sol +++ b/test/Staking.t.sol @@ -21,28 +21,28 @@ 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); } function createLock2() public { createLock(); - owner2.approve(address(VELO), address(escrow), TOKEN_1); + owner2.approve(address(FLOW), address(escrow), TOKEN_1); owner2.create_lock(address(escrow), TOKEN_1, 4 * 365 * 86400); } function createLock3() public { createLock2(); - owner3.approve(address(VELO), address(escrow), TOKEN_1); + owner3.approve(address(FLOW), address(escrow), TOKEN_1); owner3.create_lock(address(escrow), TOKEN_1, 4 * 365 * 86400); } @@ -56,7 +56,7 @@ contract StakingTest is BaseTest { 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 9b28cb5d..ce646720 100644 --- a/test/VeloGovernor.t.sol +++ b/test/VeloGovernor.t.sol @@ -25,15 +25,15 @@ contract VeloGovernorTest is BaseTest { mintFlow(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); - VELO.approve(address(escrow), 97 * TOKEN_1); + FLOW.approve(address(escrow), 97 * TOKEN_1); escrow.create_lock(97 * TOKEN_1, 4 * 365 * 86400); vm.roll(block.number + 1); // owner2 owns less than quorum, 3% vm.startPrank(address(owner2)); - VELO.approve(address(escrow), 3 * TOKEN_1); + FLOW.approve(address(escrow), 3 * TOKEN_1); escrow.create_lock(3 * TOKEN_1, 4 * 365 * 86400); vm.roll(block.number + 1); vm.stopPrank(); @@ -57,12 +57,12 @@ contract VeloGovernorTest is BaseTest { 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); @@ -96,7 +96,7 @@ contract VeloGovernorTest is BaseTest { function testVeVeloMergesAutoDelegates() public { // owner2 + owner3 > quorum vm.startPrank(address(owner3)); - VELO.approve(address(escrow), 3 * TOKEN_1); + FLOW.approve(address(escrow), 3 * TOKEN_1); escrow.create_lock(3 * TOKEN_1, 4 * 365 * 86400); vm.roll(block.number + 1); uint256 pre2 = escrow.getVotes(address(owner2)); diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index 40b9cec4..3c29af1a 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -25,7 +25,7 @@ contract VeloVotingTest is BaseTest { mintFlow(owners, amountsVelo); team = new TestOwner(); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + 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); @@ -45,9 +45,9 @@ 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); @@ -59,13 +59,13 @@ contract VeloVotingTest is BaseTest { 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, @@ -75,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; @@ -97,18 +97,18 @@ contract VeloVotingTest is BaseTest { 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)), 14 * 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)); + uint256 after_ = FLOW.balanceOf(address(owner)); assertEq(minter.weekly(), 15 * TOKEN_1M); assertEq(after_ - before, 0); vm.warp(block.timestamp + 86400 * 7); 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)); + after_ = FLOW.balanceOf(address(owner)); assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift } diff --git a/test/VotingEscrow.t.sol b/test/VotingEscrow.t.sol index a18daac0..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), owners[0], csrNftId); + 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 d42d5ef6..daf88f37 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), owners[0], csrNftId); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); } function createLock() public { deployBaseCoins(); - VELO.approve(address(escrow), TOKEN_1); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); 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); @@ -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/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index b35eec8f..d569c158 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,26 @@ contract WrappedExternalBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(VELO), address(artProxy), owners[0], csrNftId); + 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); + voter = new Voter( + address(escrow), + address(factory), + address(gaugeFactory), + address(bribeFactory), + address(wxbribeFactory), + csrNftId + ); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -45,31 +57,38 @@ contract WrappedExternalBribesTest is BaseTest { // deployMinter() distributor = new RewardsDistributor(address(escrow), csrNftId); - minter = new Minter(address(voter), address(escrow), address(distributor), 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); + uint256[] memory amounts1 = new uint256[](0); minter.initialize(claimants, amounts1, 0); // 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); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); vm.startPrank(address(owner2)); - VELO.approve(address(escrow), TOKEN_1); + FLOW.approve(address(escrow), TOKEN_1); escrow.create_lock(TOKEN_1, 4 * 365 * 86400); vm.warp(block.timestamp + 1); vm.stopPrank(); @@ -199,4 +218,4 @@ contract WrappedExternalBribesTest is BaseTest { assertEq(post_post, post); assertEq(post_post - pre, TOKEN_1 / 2); } -} \ No newline at end of file +} From 5f60d42e76f2a7931c0a9fdf14392d4100a1034d Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:03:36 +0000 Subject: [PATCH 005/119] refactor: Rename VelodromeLibrary to VelocimeterLibrary --- contracts/{VelodromeLibrary.sol => VelocimeterLibrary.sol} | 4 ++-- tasks/deploy/op.ts | 4 ++-- test/BaseTest.sol | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) rename contracts/{VelodromeLibrary.sol => VelocimeterLibrary.sol} (99%) 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/tasks/deploy/op.ts b/tasks/deploy/op.ts index 9e7993c3..4843d3fe 100644 --- a/tasks/deploy/op.ts +++ b/tasks/deploy/op.ts @@ -31,7 +31,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 +63,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(); diff --git a/test/BaseTest.sol b/test/BaseTest.sol index 074e6f07..a458b103 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"; @@ -50,7 +50,7 @@ abstract contract BaseTest is Test, TestOwner { TestToken stake; PairFactory factory; Router router; - VelodromeLibrary lib; + VelocimeterLibrary lib; Pair pair; Pair pair2; Pair pair3; @@ -125,7 +125,7 @@ abstract contract BaseTest is Test, TestOwner { 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 { From def0eeb17f4fdae28fab4151e40289cc3930eecb Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:12:03 +0000 Subject: [PATCH 006/119] test: Extract 4 years as a constant --- test/BaseTest.sol | 1 + test/ExternalBribes.t.sol | 4 ++-- test/Imbalance.t.sol | 4 ++-- test/KillGauges.t.sol | 2 +- test/LPRewards.t.sol | 2 +- test/Minter.t.sol | 2 +- test/MinterTeamEmissions.t.sol | 2 +- test/Pair.t.sol | 12 ++++++------ test/Staking.t.sol | 6 +++--- test/VeloGovernor.t.sol | 8 ++++---- test/VeloVoting.t.sol | 2 +- test/WashTrade.t.sol | 4 ++-- test/WrappedExternalBribes.t.sol | 4 ++-- 13 files changed, 27 insertions(+), 26 deletions(-) diff --git a/test/BaseTest.sol b/test/BaseTest.sol index a458b103..dbdf1dc7 100644 --- a/test/BaseTest.sol +++ b/test/BaseTest.sol @@ -34,6 +34,7 @@ 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 internal FOUR_YEARS = 4 * 365 * 86400; uint256 csrNftId; TestOwner owner; diff --git a/test/ExternalBribes.t.sol b/test/ExternalBribes.t.sol index 387662f9..f7b93283 100644 --- a/test/ExternalBribes.t.sol +++ b/test/ExternalBribes.t.sol @@ -64,10 +64,10 @@ contract ExternalBribesTest is BaseTest { // ve FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.startPrank(address(owner2)); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(block.timestamp + 1); vm.stopPrank(); } diff --git a/test/Imbalance.t.sol b/test/Imbalance.t.sol index 04db8f60..68a4a427 100644 --- a/test/Imbalance.t.sol +++ b/test/Imbalance.t.sol @@ -26,7 +26,7 @@ contract ImbalanceTest is BaseTest { deployBaseCoins(); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(1); assertGt(escrow.balanceOfNFT(1), 995063075414519385); assertEq(FLOW.balanceOf(address(escrow)), TOKEN_1); @@ -36,7 +36,7 @@ contract ImbalanceTest is BaseTest { createLock(); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); assertGt(escrow.balanceOfNFT(2), 995063075414519385); assertEq(FLOW.balanceOf(address(escrow)), 2 * TOKEN_1); escrow.merge(2, 1); diff --git a/test/KillGauges.t.sol b/test/KillGauges.t.sol index 9ce5344b..32a21687 100644 --- a/test/KillGauges.t.sol +++ b/test/KillGauges.t.sol @@ -28,7 +28,7 @@ contract KillGaugesTest is BaseTest { escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); FLOW.approve(address(escrow), 100 * TOKEN_1); - escrow.create_lock(100 * TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(100 * TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); deployPairFactoryAndRouter(); diff --git a/test/LPRewards.t.sol b/test/LPRewards.t.sol index 7b653831..68962566 100644 --- a/test/LPRewards.t.sol +++ b/test/LPRewards.t.sol @@ -24,7 +24,7 @@ contract LPRewardsTest is BaseTest { VeArtProxy artProxy = new VeArtProxy(); escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); FLOW.approve(address(escrow), TOKEN_1M); - escrow.create_lock(TOKEN_1M, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1M, FOUR_YEARS); deployPairFactoryAndRouter(); diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 0375c053..ec25985d 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -39,7 +39,7 @@ contract MinterTest is BaseTest { tokens[1] = address(FLOW); voter.initialize(tokens, address(owner)); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 0a820959..8aeb3946 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -46,7 +46,7 @@ contract MinterTeamEmissions is BaseTest { tokens[1] = address(FLOW); voter.initialize(tokens, address(owner)); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); diff --git a/test/Pair.t.sol b/test/Pair.t.sol index 50d3bab5..0552fe05 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -38,7 +38,7 @@ contract PairTest is BaseTest { deployPairCoins(); FLOW.approve(address(escrow), 5e17); - escrow.create_lock(5e17, 4 * 365 * 86400); + 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(FLOW.balanceOf(address(escrow)), 5e17); @@ -50,7 +50,7 @@ contract PairTest is BaseTest { 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(FLOW.balanceOf(address(escrow)), TOKEN_1); } @@ -81,7 +81,7 @@ contract PairTest is BaseTest { stealNFT(); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); assertGt(escrow.balanceOfNFT(2), 995063075414519385); assertEq(FLOW.balanceOf(address(escrow)), 2 * TOKEN_1); console2.log(escrow.totalSupply()); @@ -93,7 +93,7 @@ contract PairTest is BaseTest { assertEq(amount, 0); assertEq(escrow.ownerOf(2), address(0)); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); assertGt(escrow.balanceOfNFT(3), 995063075414519385); assertEq(FLOW.balanceOf(address(escrow)), 3 * TOKEN_1); console2.log(escrow.totalSupply()); @@ -400,7 +400,7 @@ contract PairTest is BaseTest { voterPokeSelf(); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(block.timestamp + 1); assertGt(escrow.balanceOfNFT(1), 995063075414519385); assertEq(FLOW.balanceOf(address(escrow)), 4 * TOKEN_1); @@ -723,7 +723,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); diff --git a/test/Staking.t.sol b/test/Staking.t.sol index 064dfdc3..c62645ee 100644 --- a/test/Staking.t.sol +++ b/test/Staking.t.sol @@ -29,21 +29,21 @@ contract StakingTest is BaseTest { deployBaseCoins(); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); } function createLock2() public { createLock(); owner2.approve(address(FLOW), address(escrow), TOKEN_1); - owner2.create_lock(address(escrow), TOKEN_1, 4 * 365 * 86400); + owner2.create_lock(address(escrow), TOKEN_1, FOUR_YEARS); } function createLock3() public { createLock2(); owner3.approve(address(FLOW), address(escrow), TOKEN_1); - owner3.create_lock(address(escrow), TOKEN_1, 4 * 365 * 86400); + owner3.create_lock(address(escrow), TOKEN_1, FOUR_YEARS); } function deployFactory() public { diff --git a/test/VeloGovernor.t.sol b/test/VeloGovernor.t.sol index ce646720..1c59d744 100644 --- a/test/VeloGovernor.t.sol +++ b/test/VeloGovernor.t.sol @@ -28,13 +28,13 @@ contract VeloGovernorTest is BaseTest { escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); FLOW.approve(address(escrow), 97 * TOKEN_1); - escrow.create_lock(97 * TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(97 * TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); // owner2 owns less than quorum, 3% vm.startPrank(address(owner2)); FLOW.approve(address(escrow), 3 * TOKEN_1); - escrow.create_lock(3 * TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(3 * TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); vm.stopPrank(); @@ -97,7 +97,7 @@ contract VeloGovernorTest is BaseTest { // owner2 + owner3 > quorum vm.startPrank(address(owner3)); FLOW.approve(address(escrow), 3 * TOKEN_1); - escrow.create_lock(3 * TOKEN_1, 4 * 365 * 86400); + 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 3c29af1a..65e70e9e 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -48,7 +48,7 @@ contract VeloVotingTest is BaseTest { tokens[1] = address(FLOW); voter.initialize(tokens, address(owner)); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); distributor = new RewardsDistributor(address(escrow), csrNftId); escrow.setVoter(address(voter)); diff --git a/test/WashTrade.t.sol b/test/WashTrade.t.sol index daf88f37..0893e80c 100644 --- a/test/WashTrade.t.sol +++ b/test/WashTrade.t.sol @@ -29,7 +29,7 @@ contract WashTradeTest is BaseTest { deployBaseCoins(); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + 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(FLOW.balanceOf(address(escrow)), TOKEN_1); @@ -39,7 +39,7 @@ contract WashTradeTest is BaseTest { createLock(); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.roll(block.number + 1); assertGt(escrow.balanceOfNFT(2), 995063075414519385); assertEq(FLOW.balanceOf(address(escrow)), 2 * TOKEN_1); diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index d569c158..02bd3d39 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -86,10 +86,10 @@ contract WrappedExternalBribesTest is BaseTest { // ve FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.startPrank(address(owner2)); FLOW.approve(address(escrow), TOKEN_1); - escrow.create_lock(TOKEN_1, 4 * 365 * 86400); + escrow.create_lock(TOKEN_1, FOUR_YEARS); vm.warp(block.timestamp + 1); vm.stopPrank(); } From e2a66949b3be742729138f404e66cff8aabc22d2 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:13:27 +0000 Subject: [PATCH 007/119] test: Extract 1 week as a constant --- test/BaseTest.sol | 4 +++- test/KillGauges.t.sol | 6 +++--- test/Minter.t.sol | 14 +++++++------- test/MinterTeamEmissions.t.sol | 10 +++++----- test/Pair.t.sol | 2 +- test/VeloVoting.t.sol | 2 +- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/test/BaseTest.sol b/test/BaseTest.sol index dbdf1dc7..95d023de 100644 --- a/test/BaseTest.sol +++ b/test/BaseTest.sol @@ -34,7 +34,9 @@ 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 internal FOUR_YEARS = 4 * 365 * 86400; + 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; diff --git a/test/KillGauges.t.sol b/test/KillGauges.t.sol index 32a21687..e38fda57 100644 --- a/test/KillGauges.t.sol +++ b/test/KillGauges.t.sol @@ -128,7 +128,7 @@ 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)); @@ -146,7 +146,7 @@ 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)); @@ -163,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)); diff --git a/test/Minter.t.sol b/test/Minter.t.sol index ec25985d..0cf11ac8 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -85,12 +85,12 @@ contract MinterTest is BaseTest { minter.update_period(); assertEq(minter.weekly(), 15 * TOKEN_1M); // 15M - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); 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.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); minter.update_period(); uint256 claimable = distributor.claimable(1); @@ -104,29 +104,29 @@ contract MinterTest is BaseTest { console2.log(FLOW.totalSupply()); console2.log(escrow.totalSupply()); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim(1); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); 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.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim(1); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim_many(tokenIds); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); minter.update_period(); console2.log(distributor.claimable(1)); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 8aeb3946..3db2c980 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -102,7 +102,7 @@ contract MinterTeamEmissions is BaseTest { uint256 after_ = FLOW.balanceOf(address(owner)); assertEq(minter.weekly(), 15 * TOKEN_1M); assertEq(after_ - before, 0); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 2 @@ -131,7 +131,7 @@ 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 = FLOW.balanceOf(address(team)); uint256 weekly = minter.weekly_emission(); @@ -141,7 +141,7 @@ contract MinterTeamEmissions is BaseTest { 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 = FLOW.balanceOf(address(team)); weekly = minter.weekly_emission(); @@ -152,7 +152,7 @@ contract MinterTeamEmissions is BaseTest { assertEq(((weekly + growth + newTeamVelo) * 30) / 1000, newTeamVelo); // check 3% of new emissions to team // rate is right even when FLOW is sent to Minter contract - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); owner2.transfer(address(FLOW), address(minter), 1e25); beforeTeamSupply = FLOW.balanceOf(address(team)); @@ -179,7 +179,7 @@ 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 = FLOW.balanceOf(address(team)); uint256 weekly = minter.weekly_emission(); diff --git a/test/Pair.t.sol b/test/Pair.t.sol index 0552fe05..3b172db3 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -787,7 +787,7 @@ 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)); diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index 65e70e9e..641337e5 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -104,7 +104,7 @@ contract VeloVotingTest is BaseTest { uint256 after_ = FLOW.balanceOf(address(owner)); assertEq(minter.weekly(), 15 * TOKEN_1M); assertEq(after_ - before, 0); - vm.warp(block.timestamp + 86400 * 7); + vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 2 From ef1cb387f888045c303589a5777cedf3af4e67cc Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:23:46 +0000 Subject: [PATCH 008/119] fix: Variable shadowing --- contracts/VotingEscrow.sol | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol index 596b1cf8..d083cc36 100644 --- a/contracts/VotingEscrow.sol +++ b/contracts/VotingEscrow.sol @@ -225,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 @@ -269,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; } @@ -505,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); } /*////////////////////////////////////////////////////////////// @@ -1265,7 +1265,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { } function _moveAllDelegates( - address owner, + address tokenOwner, address srcRep, address dstRep ) internal { @@ -1280,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); } } @@ -1300,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" @@ -1312,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); } From c88d38592d75bd1bad7ebf5c04dfeb579920181b Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:26:50 +0000 Subject: [PATCH 009/119] test: Restrict mutability --- test/utils/TestVoter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils/TestVoter.sol b/test/utils/TestVoter.sol index 14819702..7c8b5a24 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 token) public pure returns (bool) { return true; } } From c3ecebfe8b0a78a5d46cc45dce2cbe99c2c8cdf2 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:27:37 +0000 Subject: [PATCH 010/119] fix: Unused functiona arg --- test/utils/TestVoter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/TestVoter.sol b/test/utils/TestVoter.sol index 7c8b5a24..6a33d926 100644 --- a/test/utils/TestVoter.sol +++ b/test/utils/TestVoter.sol @@ -23,7 +23,7 @@ contract TestVoter { } - function isWhitelisted(address token) public pure returns (bool) { + function isWhitelisted(address) public pure returns (bool) { return true; } } From 940e7586baf3ca4eb328c8182b4c093bb22907b1 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:28:02 +0000 Subject: [PATCH 011/119] fix: Unused local var --- contracts/Router.sol | 125 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/contracts/Router.sol b/contracts/Router.sol index 8515fd5c..3f466d35 100644 --- a/contracts/Router.sol +++ b/contracts/Router.sol @@ -423,4 +423,129 @@ 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,) = (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,) = 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); + } } From 532e533e385d8bd5e743c82865f41d01694d6065 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:38:14 +0000 Subject: [PATCH 012/119] fix: set hasGauge/external bribe does not work if _pool is not pair --- contracts/Voter.sol | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contracts/Voter.sol b/contracts/Voter.sol index f24b6766..70b19557 100644 --- a/contracts/Voter.sol +++ b/contracts/Voter.sol @@ -80,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"); _; } @@ -242,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; } From b5bf68a97253ab238f16df28a824b3ceaf09d7ad Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:40:57 +0000 Subject: [PATCH 013/119] fix: Voter cannot change in Pair, so no need to emit setter --- contracts/Pair.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/Pair.sol b/contracts/Pair.sol index ee5c5999..5ebd627a 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -79,8 +79,8 @@ 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(uint256 _csrNftId) { factory = msg.sender; @@ -124,13 +124,13 @@ contract Pair is IPair { 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) { From 36aaad63842bb159fe7e3c8c2a2b1a09e478c3e5 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:44:49 +0000 Subject: [PATCH 014/119] fix: Failing testMinterWeeklyDistribute --- test/Minter.t.sol | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 0cf11ac8..324ca908 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -85,51 +85,64 @@ contract MinterTest is BaseTest { minter.update_period(); assertEq(minter.weekly(), 15 * TOKEN_1M); // 15M - vm.warp(block.timestamp + ONE_WEEK); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); assertEq(distributor.claimable(1), 0); assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift - vm.warp(block.timestamp + ONE_WEEK); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); uint256 claimable = distributor.claimable(1); assertGt(claimable, 128115516517529); + distributor.claim(1); assertEq(distributor.claimable(1), 0); uint256 weekly = minter.weekly(); + console2.log(weekly); console2.log(minter.calculate_growth(weekly)); console2.log(FLOW.totalSupply()); console2.log(escrow.totalSupply()); - vm.warp(block.timestamp + ONE_WEEK); - vm.roll(block.number + 1); + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim(1); - vm.warp(block.timestamp + ONE_WEEK); - 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 + ONE_WEEK); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim(1); - vm.warp(block.timestamp + ONE_WEEK); - vm.roll(block.number + 1); + + _elapseOneWeek(); + minter.update_period(); console2.log(distributor.claimable(1)); distributor.claim_many(tokenIds); - vm.warp(block.timestamp + ONE_WEEK); - 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); + } } From 932d329576f6680dafe29302bd18f28f8aee38a1 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 14:57:26 +0000 Subject: [PATCH 015/119] build: forge install ds-test --- lib/ds-test | 1 + 1 file changed, 1 insertion(+) create mode 160000 lib/ds-test 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 From 64e20c0c36d1fbb629bbcb73ccfc2d65d1b47aa5 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 15:22:13 +0000 Subject: [PATCH 016/119] fix: Failing testMinterWeeklyDistribute --- test/Minter.t.sol | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 324ca908..8bde3241 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -96,7 +96,15 @@ contract MinterTest is BaseTest { minter.update_period(); uint256 claimable = distributor.claimable(1); - assertGt(claimable, 128115516517529); + /** + * This has been updated from 128115516517529 to + * 197073360700 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, 197073360700); distributor.claim(1); assertEq(distributor.claimable(1), 0); From 8aab7c7591a5f0ebb9da6ae48df8a07702f7a8ef Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 15:47:15 +0000 Subject: [PATCH 017/119] test: Remove WEVE --- test/BaseTest.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/BaseTest.sol b/test/BaseTest.sol index 95d023de..9928a2b6 100644 --- a/test/BaseTest.sol +++ b/test/BaseTest.sol @@ -48,7 +48,6 @@ abstract contract BaseTest is Test, TestOwner { MockERC20 DAI; TestWETH WETH; // Mock WETH token Flow FLOW; - MockERC20 WEVE; MockERC20 LR; // late reward TestToken stake; PairFactory factory; @@ -74,7 +73,6 @@ abstract contract BaseTest is Test, TestOwner { DAI = new MockERC20("DAI", "DAI", 18); FLOW = new Flow(msg.sender, msg.sender); csrNftId = FLOW.csrNftId(); - WEVE = new MockERC20("WEVE", "WEVE", 18); LR = new MockERC20("LR", "LR", 18); WETH = new TestWETH(); stake = new TestToken("stake", "stake", 18, address(owner)); From 9ba916434d47a80b0355d782a09b60f44df862a0 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 16:09:01 +0000 Subject: [PATCH 018/119] build: Canto deployment script --- scripts/Deployment.s.sol | 205 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 scripts/Deployment.s.sol diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol new file mode 100644 index 00000000..49001dc6 --- /dev/null +++ b/scripts/Deployment.s.sol @@ -0,0 +1,205 @@ +// 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 + address private constant COUNCIL = 0x06b16991b53632c2362267579ae7c4863c72fdb8; + address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; + address private constant GOVERNOR = 0x06b16991b53632c2362267579ae7c4863c72fdb8; + address private constant TANK = 0x0A868fd1523a1ef58Db1F2D135219F0e30CBf7FB; + + // address to receive veNFT to be distributed to partners in the future + address private constant FLOW_VOTER_EOA = 0xcC06464C7bbCF81417c08563dA2E1847c22b703a; + + // 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 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; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + // Flow token + Flow flow = new Flow({initialSupplyRecipient: address(this)}); + + // Gauge factory + GaugeFactory gaugeFactory = new GaugeFactory(); + + // Bribe factory + BribeFactory bribeFactory = new BribeFactory(); + + // Pair factory + PairFactory pairFactory = new PairFactory(); + + // Router + Router router = new Router(address(pairFactory), WCANTO); + + // VelocimeterLibrary + VelocimeterLibrary velocimeterLib = new VelocimeterLibrary(address(router)); + + // VeArtProxy + VeArtProxy veArtProxy = new VeArtProxy(); + + // VotingEscrow + VotingEscrow votingEscrow = new VotingEscrow(address(flow), address(veArtProxy), TEAM_MULTI_SIG); + + // RewardsDistributor + RewardsDistributor rewardsDistributor = new RewardsDistributor(address(votingEscrow)); + + // Wrapped external bribe factory + WrappedExternalBribeFactory wrappedExternalBribeFactory = new WrappedExternalBribeFactory(); + + // Voter + Voter voter = new Voter( + address(votingEscrow), + address(pairFactory), + address(gaugeFactory), + address(bribeFactory), + address(wrappedExternalBribeFactory) + ); + + // 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) + ); + // TODO: Minter.initialize, Minter.setTeam + + // Set flow minter to contract + flow.setMinter(address(minter)); + + // Set pair factory pauser + pairFactory.setPauser(TEAM_MULTI_SIG); + + // Set voting escrow's voter + votingEscrow.setVoter(address(voter)); + + // Set minter and voting escrow's team + votingEscrow.setTeam(TEAM_MULTI_SIG); + minter.setTeam(TEAM_MULTI_SIG); + + // Set voter's governor + voter.setGovernor(TEAM_MULTI_SIG); + + // Set voter's emergency council + voter.setEmergencyCouncil(TEAM_MULTI_SIG); + + // Set rewards distributor's depositor to minter contract + rewardsDistributor.setDepositor(address(minter)); + + // Initialize tokens for voter + // TODO: Get all the whitelisted tokens + address[] memory whitelistedTokens = new address[](2); + whitelistedTokens[0] = address(flow); + voter.initialize(whitelistedTokens, address(minter)); + + // Mint tokens and lock for veNFT + address[] memory claimants = new claimants[](); + uint256[] memory amounts = new amounts[](); + + // 1. Mint to Flow voter EOA + claimants[0] = FLOW_VOTER_EOA; + claimants[1] = FLOW_VOTER_EOA; + claimants[2] = FLOW_VOTER_EOA; + claimants[3] = FLOW_VOTER_EOA; + claimants[4] = FLOW_VOTER_EOA; + claimants[5] = FLOW_VOTER_EOA; + claimants[6] = FLOW_VOTER_EOA; + claimants[7] = FLOW_VOTER_EOA; + claimants[8] = FLOW_VOTER_EOA; + claimants[9] = FLOW_VOTER_EOA; + claimants[10] = FLOW_VOTER_EOA; + claimants[11] = FLOW_VOTER_EOA; + claimants[12] = FLOW_VOTER_EOA; + + amounts[0] = ONE_MILLION; + amounts[1] = ONE_MILLION; + amounts[2] = ONE_MILLION; + amounts[3] = ONE_MILLION; + amounts[4] = ONE_MILLION; + amounts[5] = TWO_MILLION; + amounts[6] = TWO_MILLION; + amounts[7] = TWO_MILLION; + amounts[8] = TWO_MILLION; + amounts[9] = TWO_MILLION; + amounts[10] = FOUR_MILLION; + amounts[11] = FOUR_MILLION; + amounts[12] = FOUR_MILLION; + + // 2. Mint to team members + claimants[13] = DUNKS; + claimants[14] = T0RB1K; + claimants[15] = T0RB1K; + claimants[16] = T0RB1K; + claimants[17] = CEAZOR; + claimants[18] = CEAZOR; + claimants[19] = CEAZOR; + claimants[20] = MOTTO; + claimants[21] = MOTTO; + claimants[22] = MOTTO; + claimants[22] = COOLIE; + claimants[23] = COOLIE; + claimants[24] = COOLIE; + + amounts[13] = FOUR_MILLION; + amounts[14] = FOUR_MILLION; + amounts[15] = FOUR_MILLION; + amounts[16] = FOUR_MILLION; + amounts[17] = FOUR_MILLION; + amounts[18] = FOUR_MILLION; + amounts[19] = FOUR_MILLION; + amounts[20] = FOUR_MILLION; + amounts[21] = FOUR_MILLION; + amounts[22] = FOUR_MILLION; + amounts[22] = FOUR_MILLION; + amounts[23] = FOUR_MILLION; + amounts[24] = FOUR_MILLION; + + minter.initialize( + claimants, + amounts, + max + ); + + vm.stopBroadcast(); + } +} From 4ceede9c4773a9d4c32ff0bb39b81b25974d06ce Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 17:08:06 +0000 Subject: [PATCH 019/119] refactor: Minter.initialize Claim struct --- contracts/Minter.sol | 17 +++++++++++++---- test/ExternalBribes.t.sol | 5 ++--- test/Minter.t.sol | 13 ++++++++----- test/MinterTeamEmissions.t.sol | 13 ++++++++----- test/Pair.t.sol | 14 +++++++++----- test/VeloVoting.t.sol | 13 ++++++++----- test/WrappedExternalBribes.t.sol | 5 ++--- 7 files changed, 50 insertions(+), 30 deletions(-) diff --git a/contracts/Minter.sol b/contracts/Minter.sol index 2ac0a410..e7671539 100644 --- a/contracts/Minter.sol +++ b/contracts/Minter.sol @@ -34,6 +34,12 @@ 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 @@ -52,15 +58,18 @@ contract Minter is IMinter { } function initialize( - address[] memory claimants, // partnerAddrs - uint[] memory amounts, // partnerAmounts + 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); _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]); + 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; + } } initializer = address(0); active_period = ((block.timestamp) / WEEK) * WEEK; // allow minter.update_period() to mint new emissions THIS Thursday diff --git a/test/ExternalBribes.t.sol b/test/ExternalBribes.t.sol index f7b93283..060a2aa5 100644 --- a/test/ExternalBribes.t.sol +++ b/test/ExternalBribes.t.sol @@ -54,9 +54,8 @@ contract ExternalBribesTest is BaseTest { 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.initialize(claims, 0); // USDC - FRAX stable gauge = Gauge(voter.createGauge(address(pair))); diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 8bde3241..854ee0fc 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -69,11 +69,14 @@ 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: 86400 * 7 * 52 * 4 + }); + minter.initialize(claims, 2e25); + assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); vm.roll(block.number + 1); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 3db2c980..61188127 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -87,11 +87,14 @@ 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: 86400 * 7 * 52 * 4 + }); + minter.initialize(claims, 15 * TOKEN_1M); + assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); vm.roll(block.number + 1); diff --git a/test/Pair.t.sol b/test/Pair.t.sol index 3b172db3..4a5b1f9f 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -591,11 +591,15 @@ 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: 86400 * 7 * 52 * 4 + }); + minter.initialize(claims, TOKEN_1); + minter.update_period(); voter.updateGauge(address(gauge)); console2.log(FLOW.balanceOf(address(distributor))); diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index 641337e5..ccc71cd8 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -89,11 +89,14 @@ 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: 86400 * 7 * 52 * 4 + }); + minter.initialize(claims, 15 * TOKEN_1M); + assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); vm.roll(block.number + 1); diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index 02bd3d39..0330695a 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -73,9 +73,8 @@ contract WrappedExternalBribesTest is BaseTest { tokens[4] = address(LR); voter.initialize(tokens, address(minter)); - address[] memory claimants = new address[](0); - uint256[] memory amounts1 = new uint256[](0); - minter.initialize(claimants, amounts1, 0); + Minter.Claim[] memory claims = new Minter.Claim[](0); + minter.initialize(claims, 0); // USDC - FRAX stable gauge = Gauge(voter.createGauge(address(pair))); From 2999f9bc10630a6051b1b62360050f267fb5ddb7 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 17:12:11 +0000 Subject: [PATCH 020/119] build: Mint initialize in deployment --- scripts/Deployment.s.sol | 117 ++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 49001dc6..fde99433 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -29,6 +29,7 @@ contract Deployment is Script { // 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; @@ -133,66 +134,70 @@ contract Deployment is Script { voter.initialize(whitelistedTokens, address(minter)); // Mint tokens and lock for veNFT - address[] memory claimants = new claimants[](); - uint256[] memory amounts = new amounts[](); + Minter.Claim[] memory claims = new Minter.Claim[](30); // 1. Mint to Flow voter EOA - claimants[0] = FLOW_VOTER_EOA; - claimants[1] = FLOW_VOTER_EOA; - claimants[2] = FLOW_VOTER_EOA; - claimants[3] = FLOW_VOTER_EOA; - claimants[4] = FLOW_VOTER_EOA; - claimants[5] = FLOW_VOTER_EOA; - claimants[6] = FLOW_VOTER_EOA; - claimants[7] = FLOW_VOTER_EOA; - claimants[8] = FLOW_VOTER_EOA; - claimants[9] = FLOW_VOTER_EOA; - claimants[10] = FLOW_VOTER_EOA; - claimants[11] = FLOW_VOTER_EOA; - claimants[12] = FLOW_VOTER_EOA; - - amounts[0] = ONE_MILLION; - amounts[1] = ONE_MILLION; - amounts[2] = ONE_MILLION; - amounts[3] = ONE_MILLION; - amounts[4] = ONE_MILLION; - amounts[5] = TWO_MILLION; - amounts[6] = TWO_MILLION; - amounts[7] = TWO_MILLION; - amounts[8] = TWO_MILLION; - amounts[9] = TWO_MILLION; - amounts[10] = FOUR_MILLION; - amounts[11] = FOUR_MILLION; - amounts[12] = FOUR_MILLION; + for (uint256 i = 0; i <= 4; i++) { + claims[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: ONE_MILLION, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 5; i <= 9; i++) { + claims[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: TWO_MILLION, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 10; i <= 12; i++) { + claims[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } // 2. Mint to team members - claimants[13] = DUNKS; - claimants[14] = T0RB1K; - claimants[15] = T0RB1K; - claimants[16] = T0RB1K; - claimants[17] = CEAZOR; - claimants[18] = CEAZOR; - claimants[19] = CEAZOR; - claimants[20] = MOTTO; - claimants[21] = MOTTO; - claimants[22] = MOTTO; - claimants[22] = COOLIE; - claimants[23] = COOLIE; - claimants[24] = COOLIE; - - amounts[13] = FOUR_MILLION; - amounts[14] = FOUR_MILLION; - amounts[15] = FOUR_MILLION; - amounts[16] = FOUR_MILLION; - amounts[17] = FOUR_MILLION; - amounts[18] = FOUR_MILLION; - amounts[19] = FOUR_MILLION; - amounts[20] = FOUR_MILLION; - amounts[21] = FOUR_MILLION; - amounts[22] = FOUR_MILLION; - amounts[22] = FOUR_MILLION; - amounts[23] = FOUR_MILLION; - amounts[24] = FOUR_MILLION; + claims[13] = Minter.Claim({claimant: DUNKS, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + + for (uint256 i = 14; i <= 16; i++) { + claims[i] = Minter.Claim({claimant: T0RB1K, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 17; i <= 19; i++) { + claims[i] = Minter.Claim({claimant: CEAZOR, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 20; i <= 22; i++) { + claims[i] = Minter.Claim({claimant: MOTTO, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 23; i <= 25; i++) { + claims[i] = Minter.Claim({claimant: COOLIE, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + + // 3. Mint to snapshotted veNFT holders + + // 4. Mint for future partners + for (uint256 i = 26; i <= 28; i++) { + claims[i] = Minter.Claim({amount: FOUR_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 29; i <= 42; i++) { + claims[i] = Minter.Claim({amount: FOUR_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 43; i <= 45; i++) { + claims[i] = Minter.Claim({amount: TWO_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 46; i <= 60; i++) { + claims[i] = Minter.Claim({amount: TWO_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 61; i <= 76; i++) { + claims[i] = Minter.Claim({amount: ONE_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + } + + for (uint256 i = 77; i <= 81; i++) { + claims[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: TWO_YEARS}); + } + + for (uint256 i = 82; i <= 86; i++) { + claims[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: ONE_YEAR}); + } minter.initialize( claimants, From a046d81539636064021f636d2f4f6549c73d9e80 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 18:37:10 +0000 Subject: [PATCH 021/119] build: Script to get veNFT snapshot --- scripts/VeNFTSnapshot.s.sol | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 scripts/VeNFTSnapshot.s.sol 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++; + } + } +} From 486b6216dff224ff3f705796401cd227f4e19519 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:18:12 +0000 Subject: [PATCH 022/119] feat: Allow minter multiple mint and lock --- contracts/Minter.sol | 11 ++++++++--- scripts/Deployment.s.sol | 1 + tasks/deploy/op.ts | 4 +++- test/ExternalBribes.t.sol | 3 ++- test/Minter.t.sol | 3 ++- test/MinterTeamEmissions.t.sol | 3 ++- test/Pair.t.sol | 3 ++- test/VeloVoting.t.sol | 3 ++- test/WrappedExternalBribes.t.sol | 3 ++- 9 files changed, 24 insertions(+), 10 deletions(-) diff --git a/contracts/Minter.sol b/contracts/Minter.sol index e7671539..15750549 100644 --- a/contracts/Minter.sol +++ b/contracts/Minter.sol @@ -57,11 +57,11 @@ contract Minter is IMinter { ITurnstile(turnstile).assign(_csrNftId); } - function initialize( + 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); uint256 length = claims.length; @@ -71,8 +71,13 @@ contract Minter is IMinter { ++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/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index fde99433..754f16c8 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -204,6 +204,7 @@ contract Deployment is Script { amounts, max ); + minter.startActivePeriod(); vm.stopBroadcast(); } diff --git a/tasks/deploy/op.ts b/tasks/deploy/op.ts index 4843d3fe..488c0867 100644 --- a/tasks/deploy/op.ts +++ b/tasks/deploy/op.ts @@ -148,13 +148,15 @@ task("deploy:op", "Deploys Optimism contracts").setAction(async function ( console.log("Whitelist set"); // Initial veFLOW distro - await minter.initialize( + await minter.initialMintAndLock( OP_CONFIG.partnerAddrs, OP_CONFIG.partnerAmts, OP_CONFIG.partnerMax ); + await minter.startActivePeriod(); console.log("veFLOW distributed"); + await minter.setTeam(OP_CONFIG.teamMultisig) console.log("Team set for minter"); diff --git a/test/ExternalBribes.t.sol b/test/ExternalBribes.t.sol index 060a2aa5..b42b9986 100644 --- a/test/ExternalBribes.t.sol +++ b/test/ExternalBribes.t.sol @@ -55,7 +55,8 @@ contract ExternalBribesTest is BaseTest { voter.initialize(tokens, address(minter)); Minter.Claim[] memory claims = new Minter.Claim[](0); - minter.initialize(claims, 0); + minter.initialMintAndLock(claims, 0); + minter.startActivePeriod(); // USDC - FRAX stable gauge = Gauge(voter.createGauge(address(pair))); diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 854ee0fc..1ab85958 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -75,7 +75,8 @@ contract MinterTest is BaseTest { amount: TOKEN_1M, lockTime: 86400 * 7 * 52 * 4 }); - minter.initialize(claims, 2e25); + minter.initialMintAndLock(claims, 2e25); + minter.startActivePeriod(); assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 61188127..794a836c 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -93,7 +93,8 @@ contract MinterTeamEmissions is BaseTest { amount: TOKEN_1M, lockTime: 86400 * 7 * 52 * 4 }); - minter.initialize(claims, 15 * TOKEN_1M); + minter.initialMintAndLock(claims, 15 * TOKEN_1M); + minter.startActivePeriod(); assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); diff --git a/test/Pair.t.sol b/test/Pair.t.sol index 4a5b1f9f..0e5af918 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -598,7 +598,8 @@ contract PairTest is BaseTest { amount: TOKEN_1, lockTime: 86400 * 7 * 52 * 4 }); - minter.initialize(claims, TOKEN_1); + minter.initialMintAndLock(claims, TOKEN_1); + minter.startActivePeriod(); minter.update_period(); voter.updateGauge(address(gauge)); diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index ccc71cd8..1a3d2f81 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -95,7 +95,8 @@ contract VeloVotingTest is BaseTest { amount: TOKEN_1M, lockTime: 86400 * 7 * 52 * 4 }); - minter.initialize(claims, 15 * TOKEN_1M); + minter.initialMintAndLock(claims, 15 * TOKEN_1M); + minter.startActivePeriod(); assertEq(escrow.ownerOf(2), address(owner)); assertEq(escrow.ownerOf(3), address(0)); diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index 0330695a..9f6acba8 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -74,7 +74,8 @@ contract WrappedExternalBribesTest is BaseTest { voter.initialize(tokens, address(minter)); Minter.Claim[] memory claims = new Minter.Claim[](0); - minter.initialize(claims, 0); + minter.initialMintAndLock(claims, 0); + minter.startActivePeriod(); // USDC - FRAX stable gauge = Gauge(voter.createGauge(address(pair))); From f591d128602c0e6cc0b1177021d536f7cab98a80 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:31:46 +0000 Subject: [PATCH 023/119] build: Split batch mint tokens + veNFTs --- contracts/Minter.sol | 2 +- scripts/Deployment.s.sol | 94 +++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/contracts/Minter.sol b/contracts/Minter.sol index 15750549..efc3ed5b 100644 --- a/contracts/Minter.sol +++ b/contracts/Minter.sol @@ -63,7 +63,7 @@ contract Minter is IMinter { ) external { require(initializer == msg.sender, "not initializer"); _flow.mint(address(this), max); - _flow.approve(address(_ve), type(uint).max); + _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); diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 754f16c8..805ef56a 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -134,76 +134,100 @@ contract Deployment is Script { voter.initialize(whitelistedTokens, address(minter)); // Mint tokens and lock for veNFT - Minter.Claim[] memory claims = new Minter.Claim[](30); // 1. Mint to Flow voter EOA - for (uint256 i = 0; i <= 4; i++) { - claims[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: ONE_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory flowVoterEOAClaim1 = new Minter.Claim[](4); + for (uint256 i; i < flowVoterEOAClaim1.length; i++) { + flowVoterEOAClaim1[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: ONE_MILLION, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(flowVoterEOAClaim1, ONE_MILLION * 5); - for (uint256 i = 5; i <= 9; i++) { - claims[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: TWO_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory flowVoterEOAClaim2 = new Minter.Claim[](5); + for (uint256 i; i < flowVoterEOAClaim2.length; i++) { + flowVoterEOAClaim2[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: TWO_MILLION, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(flowVoterEOAClaim2, TWO_MILLION * 5); - for (uint256 i = 10; i <= 12; i++) { - claims[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory flowVoterEOAClaim3 = new Minter.Claim[](3); + for (uint256 i; i < flowVoterEOAClaim3.length; i++) { + flowVoterEOAClaim3[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(flowVoterEOAClaim3, FOUR_MILLION * 3); // 2. Mint to team members - claims[13] = Minter.Claim({claimant: DUNKS, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory dunksClaim = new Minter.Claim[](1); + dunksClaim[0] = Minter.Claim({claimant: DUNKS, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + minter.initialMintAndLock(dunksClaim, FOUR_MILLION); - for (uint256 i = 14; i <= 16; i++) { - claims[i] = Minter.Claim({claimant: T0RB1K, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory t0rb1kClaim = new Minter.Claim[](3); + for (uint256 i; i < t0rb1kClaim.length; i++) { + t0rb1kClaim[i] = Minter.Claim({claimant: T0RB1K, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(t0rb1kClaim, FOUR_MILLION * 3); - for (uint256 i = 17; i <= 19; i++) { - claims[i] = Minter.Claim({claimant: CEAZOR, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory ceazorClaim = new Minter.Claim[](3); + for (uint256 i; i < ceazorClaim.length; i++) { + ceazorClaim[i] = Minter.Claim({claimant: CEAZOR, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(ceazorClaim, FOUR_MILLION * 3); - for (uint256 i = 20; i <= 22; i++) { - claims[i] = Minter.Claim({claimant: MOTTO, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory mottoClaim = new Minter.Claim[](3); + for (uint256 i; i < mottoClaim.length; i++) { + mottoClaim[i] = Minter.Claim({claimant: MOTTO, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(mottoClaim, FOUR_MILLION * 3); - for (uint256 i = 23; i <= 25; i++) { - claims[i] = Minter.Claim({claimant: COOLIE, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + Minter.Claim[] memory coolieClaim = new Minter.Claim[](3); + for (uint256 i; i < coolieClaim.length; i++) { + coolieClaim[i] = Minter.Claim({claimant: COOLIE, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(coolieClaim, FOUR_MILLION * 3); // 3. Mint to snapshotted veNFT holders // 4. Mint for future partners - for (uint256 i = 26; i <= 28; i++) { - claims[i] = Minter.Claim({amount: FOUR_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); + Minter.Claim[] memory assetEOAClaim1 = new Minter.Claim[](3); + for (uint256 i; i < assetEOAClaim1.length; i++) { + assetEOAClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(assetEOAClaim1, FOUR_MILLION * 3); - for (uint256 i = 29; i <= 42; i++) { - claims[i] = Minter.Claim({amount: FOUR_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + Minter.Claim[] memory multiSigClaim1 = new Minter.Claim[](14); + for (uint256 i; i < multiSigClaim1.length; i++) { + multiSigClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(multiSigClaim1, FOUR_MILLION * 14); - for (uint256 i = 43; i <= 45; i++) { - claims[i] = Minter.Claim({amount: TWO_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); + Minter.Claim[] memory assetEOAClaim2 = new Minter.Claim[](3); + for (uint256 i; i < assetEOAClaim2.length; i++) { + assetEOAClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(assetEOAClaim1, TWO_MILLION * 3); - for (uint256 i = 46; i <= 60; i++) { - claims[i] = Minter.Claim({amount: TWO_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + Minter.Claim[] memory multiSigClaim2 = new Minter.Claim[](15); + for (uint256 i; i < multiSigClaim2.length; i++) { + multiSigClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(multiSigClaim2, TWO_MILLION * 15); - for (uint256 i = 61; i <= 76; i++) { - claims[i] = Minter.Claim({amount: ONE_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + Minter.Claim[] memory multiSigClaim3 = new Minter.Claim[](16); + for (uint256 i; i < multiSigClaim3.length; i++) { + multiSigClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); } + minter.initialMintAndLock(multiSigClaim3, ONE_MILLION * 16); - for (uint256 i = 77; i <= 81; i++) { - claims[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: TWO_YEARS}); + Minter.Claim[] memory assetEOAClaim3 = new Minter.Claim[](5); + for (uint256 i; i < assetEOAClaim3.length; i++) { + assetEOAClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: TWO_YEARS}); } + minter.initialMintAndLock(assetEOAClaim3, ONE_MILLION * 5); - for (uint256 i = 82; i <= 86; i++) { - claims[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: ONE_YEAR}); + Minter.Claim[] memory assetEOAClaim4 = new Minter.Claim[](5); + for (uint256 i; i < assetEOAClaim4.length; i++) { + assetEOAClaim4[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: ONE_YEAR}); } + minter.initialMintAndLock(assetEOAClaim4, ONE_MILLION * 5); - minter.initialize( - claimants, - amounts, - max - ); minter.startActivePeriod(); vm.stopBroadcast(); From e51e16484732e373488de0f25b3eda9424748a2e Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:38:45 +0000 Subject: [PATCH 024/119] build: Migrate mint script --- scripts/Deployment.s.sol | 118 -------------------------- scripts/InitialMintAndLock.s.sol | 141 +++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 118 deletions(-) create mode 100644 scripts/InitialMintAndLock.s.sol diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 805ef56a..e2b9da2f 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -27,27 +27,6 @@ contract Deployment is Script { address private constant GOVERNOR = 0x06b16991b53632c2362267579ae7c4863c72fdb8; address private constant TANK = 0x0A868fd1523a1ef58Db1F2D135219F0e30CBf7FB; - // 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 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; - function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); @@ -133,103 +112,6 @@ contract Deployment is Script { whitelistedTokens[0] = address(flow); voter.initialize(whitelistedTokens, address(minter)); - // Mint tokens and lock for veNFT - - // 1. Mint to Flow voter EOA - Minter.Claim[] memory flowVoterEOAClaim1 = new Minter.Claim[](4); - for (uint256 i; i < flowVoterEOAClaim1.length; i++) { - flowVoterEOAClaim1[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: ONE_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(flowVoterEOAClaim1, ONE_MILLION * 5); - - Minter.Claim[] memory flowVoterEOAClaim2 = new Minter.Claim[](5); - for (uint256 i; i < flowVoterEOAClaim2.length; i++) { - flowVoterEOAClaim2[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: TWO_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(flowVoterEOAClaim2, TWO_MILLION * 5); - - Minter.Claim[] memory flowVoterEOAClaim3 = new Minter.Claim[](3); - for (uint256 i; i < flowVoterEOAClaim3.length; i++) { - flowVoterEOAClaim3[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(flowVoterEOAClaim3, FOUR_MILLION * 3); - - // 2. Mint to team members - Minter.Claim[] memory dunksClaim = new Minter.Claim[](1); - dunksClaim[0] = Minter.Claim({claimant: DUNKS, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - minter.initialMintAndLock(dunksClaim, FOUR_MILLION); - - Minter.Claim[] memory t0rb1kClaim = new Minter.Claim[](3); - for (uint256 i; i < t0rb1kClaim.length; i++) { - t0rb1kClaim[i] = Minter.Claim({claimant: T0RB1K, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(t0rb1kClaim, FOUR_MILLION * 3); - - Minter.Claim[] memory ceazorClaim = new Minter.Claim[](3); - for (uint256 i; i < ceazorClaim.length; i++) { - ceazorClaim[i] = Minter.Claim({claimant: CEAZOR, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(ceazorClaim, FOUR_MILLION * 3); - - Minter.Claim[] memory mottoClaim = new Minter.Claim[](3); - for (uint256 i; i < mottoClaim.length; i++) { - mottoClaim[i] = Minter.Claim({claimant: MOTTO, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(mottoClaim, FOUR_MILLION * 3); - - Minter.Claim[] memory coolieClaim = new Minter.Claim[](3); - for (uint256 i; i < coolieClaim.length; i++) { - coolieClaim[i] = Minter.Claim({claimant: COOLIE, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(coolieClaim, FOUR_MILLION * 3); - - // 3. Mint to snapshotted veNFT holders - - // 4. Mint for future partners - Minter.Claim[] memory assetEOAClaim1 = new Minter.Claim[](3); - for (uint256 i; i < assetEOAClaim1.length; i++) { - assetEOAClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(assetEOAClaim1, FOUR_MILLION * 3); - - Minter.Claim[] memory multiSigClaim1 = new Minter.Claim[](14); - for (uint256 i; i < multiSigClaim1.length; i++) { - multiSigClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(multiSigClaim1, FOUR_MILLION * 14); - - Minter.Claim[] memory assetEOAClaim2 = new Minter.Claim[](3); - for (uint256 i; i < assetEOAClaim2.length; i++) { - assetEOAClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(assetEOAClaim1, TWO_MILLION * 3); - - Minter.Claim[] memory multiSigClaim2 = new Minter.Claim[](15); - for (uint256 i; i < multiSigClaim2.length; i++) { - multiSigClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(multiSigClaim2, TWO_MILLION * 15); - - Minter.Claim[] memory multiSigClaim3 = new Minter.Claim[](16); - for (uint256 i; i < multiSigClaim3.length; i++) { - multiSigClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(multiSigClaim3, ONE_MILLION * 16); - - Minter.Claim[] memory assetEOAClaim3 = new Minter.Claim[](5); - for (uint256 i; i < assetEOAClaim3.length; i++) { - assetEOAClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: TWO_YEARS}); - } - minter.initialMintAndLock(assetEOAClaim3, ONE_MILLION * 5); - - Minter.Claim[] memory assetEOAClaim4 = new Minter.Claim[](5); - for (uint256 i; i < assetEOAClaim4.length; i++) { - assetEOAClaim4[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: ONE_YEAR}); - } - minter.initialMintAndLock(assetEOAClaim4, ONE_MILLION * 5); - - minter.startActivePeriod(); - vm.stopBroadcast(); } } diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol new file mode 100644 index 00000000..5f84963d --- /dev/null +++ b/scripts/InitialMintAndLock.s.sol @@ -0,0 +1,141 @@ +// 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 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; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + // TODO: Fill address after mainnet deploy + Minter minter = Minter(address(0)); + + // Mint tokens and lock for veNFT + + // 1. Mint to Flow voter EOA + Minter.Claim[] memory flowVoterEOAClaim1 = new Minter.Claim[](5); + for (uint256 i; i < flowVoterEOAClaim1.length; i++) { + flowVoterEOAClaim1[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: ONE_MILLION, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(flowVoterEOAClaim1, ONE_MILLION * flowVoterEOAClaim1.length); + + Minter.Claim[] memory flowVoterEOAClaim2 = new Minter.Claim[](5); + for (uint256 i; i < flowVoterEOAClaim2.length; i++) { + flowVoterEOAClaim2[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: TWO_MILLION, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(flowVoterEOAClaim2, TWO_MILLION * flowVoterEOAClaim2.length); + + Minter.Claim[] memory flowVoterEOAClaim3 = new Minter.Claim[](3); + for (uint256 i; i < flowVoterEOAClaim3.length; i++) { + flowVoterEOAClaim3[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(flowVoterEOAClaim3, FOUR_MILLION * flowVoterEOAClaim3.length); + + // 2. Mint to team members + Minter.Claim[] memory dunksClaim = new Minter.Claim[](1); + dunksClaim[0] = Minter.Claim({claimant: DUNKS, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + minter.initialMintAndLock(dunksClaim, FOUR_MILLION); + + Minter.Claim[] memory t0rb1kClaim = new Minter.Claim[](3); + for (uint256 i; i < t0rb1kClaim.length; i++) { + t0rb1kClaim[i] = Minter.Claim({claimant: T0RB1K, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(t0rb1kClaim, FOUR_MILLION * t0rb1kClaim.length); + + Minter.Claim[] memory ceazorClaim = new Minter.Claim[](3); + for (uint256 i; i < ceazorClaim.length; i++) { + ceazorClaim[i] = Minter.Claim({claimant: CEAZOR, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(ceazorClaim, FOUR_MILLION * ceazorClaim.length); + + Minter.Claim[] memory mottoClaim = new Minter.Claim[](3); + for (uint256 i; i < mottoClaim.length; i++) { + mottoClaim[i] = Minter.Claim({claimant: MOTTO, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(mottoClaim, FOUR_MILLION * mottoClaim.length); + + Minter.Claim[] memory coolieClaim = new Minter.Claim[](3); + for (uint256 i; i < coolieClaim.length; i++) { + coolieClaim[i] = Minter.Claim({claimant: COOLIE, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(coolieClaim, FOUR_MILLION * coolieClaim.length); + + // 3. TODO: Mint to snapshotted veNFT holders + + // 4. Mint for future partners + Minter.Claim[] memory assetEOAClaim1 = new Minter.Claim[](3); + for (uint256 i; i < assetEOAClaim1.length; i++) { + assetEOAClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(assetEOAClaim1, FOUR_MILLION * assetEOAClaim1.length); + + Minter.Claim[] memory multiSigClaim1 = new Minter.Claim[](13); + for (uint256 i; i < multiSigClaim1.length; i++) { + multiSigClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(multiSigClaim1, FOUR_MILLION * multiSigClaim1.length); + + Minter.Claim[] memory assetEOAClaim2 = new Minter.Claim[](3); + for (uint256 i; i < assetEOAClaim2.length; i++) { + assetEOAClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(assetEOAClaim1, TWO_MILLION * assetEOAClaim2.length); + + Minter.Claim[] memory multiSigClaim2 = new Minter.Claim[](15); + for (uint256 i; i < multiSigClaim2.length; i++) { + multiSigClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(multiSigClaim2, TWO_MILLION * multiSigClaim2.length); + + Minter.Claim[] memory multiSigClaim3 = new Minter.Claim[](16); + for (uint256 i; i < multiSigClaim3.length; i++) { + multiSigClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); + } + minter.initialMintAndLock(multiSigClaim3, ONE_MILLION * multiSigClaim3.length); + + Minter.Claim[] memory assetEOAClaim3 = new Minter.Claim[](5); + for (uint256 i; i < assetEOAClaim3.length; i++) { + assetEOAClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: TWO_YEARS}); + } + minter.initialMintAndLock(assetEOAClaim3, ONE_MILLION * assetEOAClaim3.length); + + Minter.Claim[] memory assetEOAClaim4 = new Minter.Claim[](5); + for (uint256 i; i < assetEOAClaim4.length; i++) { + assetEOAClaim4[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: ONE_YEAR}); + } + minter.initialMintAndLock(assetEOAClaim4, ONE_MILLION * assetEOAClaim4.length); + + // set initializer to 0 so we can no longer mint more + minter.startActivePeriod(); + + vm.stopBroadcast(); + } +} From 972527feab945b4d7ca1f2d84f52e7ccfcb88ec7 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:44:19 +0000 Subject: [PATCH 025/119] build: Update initial weekly emission to 13m --- contracts/Minter.sol | 2 +- test/Minter.t.sol | 8 ++++---- test/MinterTeamEmissions.t.sol | 8 ++++---- test/VeloVoting.t.sol | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/contracts/Minter.sol b/contracts/Minter.sol index efc3ed5b..59632e8c 100644 --- a/contracts/Minter.sol +++ b/contracts/Minter.sol @@ -22,7 +22,7 @@ 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; diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 1ab85958..a51905cc 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -88,13 +88,13 @@ contract MinterTest is BaseTest { initializeVotingEscrow(); minter.update_period(); - assertEq(minter.weekly(), 15 * TOKEN_1M); // 15M + 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 + assertLt(minter.weekly(), 13 * TOKEN_1M); // <13M for week shift _elapseOneWeek(); @@ -102,13 +102,13 @@ contract MinterTest is BaseTest { uint256 claimable = distributor.claimable(1); /** * This has been updated from 128115516517529 to - * 197073360700 because originally in VELO the + * 170796912607 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, 197073360700); + assertGt(claimable, 170796912607); distributor.claim(1); assertEq(distributor.claimable(1), 0); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 794a836c..17410d2f 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -93,25 +93,25 @@ contract MinterTeamEmissions is BaseTest { amount: TOKEN_1M, lockTime: 86400 * 7 * 52 * 4 }); - minter.initialMintAndLock(claims, 15 * TOKEN_1M); + 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(FLOW.balanceOf(address(minter)), 14 * TOKEN_1M); + assertEq(FLOW.balanceOf(address(minter)), 12 * TOKEN_1M); uint256 before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 1 uint256 after_ = FLOW.balanceOf(address(owner)); - assertEq(minter.weekly(), 15 * TOKEN_1M); + assertEq(minter.weekly(), 13 * TOKEN_1M); assertEq(after_ - before, 0); vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 2 after_ = FLOW.balanceOf(address(owner)); - assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift + assertLt(minter.weekly(), 13 * TOKEN_1M); // <13M for week shift } function testChangeTeam() public { diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index 1a3d2f81..d5d88512 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -95,25 +95,25 @@ contract VeloVotingTest is BaseTest { amount: TOKEN_1M, lockTime: 86400 * 7 * 52 * 4 }); - minter.initialMintAndLock(claims, 15 * TOKEN_1M); + 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(FLOW.balanceOf(address(minter)), 14 * TOKEN_1M); + assertEq(FLOW.balanceOf(address(minter)), 12 * TOKEN_1M); uint256 before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 1 uint256 after_ = FLOW.balanceOf(address(owner)); - assertEq(minter.weekly(), 15 * TOKEN_1M); + assertEq(minter.weekly(), 13 * TOKEN_1M); assertEq(after_ - before, 0); vm.warp(block.timestamp + ONE_WEEK); vm.roll(block.number + 1); before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 2 after_ = FLOW.balanceOf(address(owner)); - assertLt(minter.weekly(), 15 * TOKEN_1M); // <15M for week shift + assertLt(minter.weekly(), 13 * TOKEN_1M); // <13m for week shift } // Note: _vote and _reset are not included in one-vote-per-epoch From d47024e2f9d8c15c1ba6b2cc0a73899e56d4aac3 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:52:52 +0000 Subject: [PATCH 026/119] build: Team member vesting --- contracts/FlowVestor.sol | 189 ++++++++++++++++++++++++++++++++ scripts/TeamMemberVesting.s.sol | 40 +++++++ 2 files changed, 229 insertions(+) create mode 100644 contracts/FlowVestor.sol create mode 100644 scripts/TeamMemberVesting.s.sol diff --git a/contracts/FlowVestor.sol b/contracts/FlowVestor.sol new file mode 100644 index 00000000..8c835ba2 --- /dev/null +++ b/contracts/FlowVestor.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT AND AGPL-3.0-or-later +pragma solidity 0.8.13; + +import "openzeppelin-contracts/contracts/access/Ownable.sol"; +import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; + +// Inspired by https://github.com/vetherasset/vader-protocol-v2/blob/main/contracts/tokens/vesting/LinearVesting.sol +/** + * @dev Implementation of the Linear Vesting + * + * The straightforward vesting contract that gradually releases a + * fixed supply of tokens to multiple vest parties over a 1 year + * window. + * + * The token expects the {begin} hook to be invoked the moment + * it is supplied with the necessary amount of tokens to vest + */ +contract FlowVestor is Ownable { + address public revokeTo; + /* ========== CONSTANTS ========== */ + + address internal constant _ZERO_ADDRESS = address(0); + + uint256 internal constant _ONE_YEAR = 365 days; + + /* ========== FLOW ALLOCATION ========== */ + + // The FLOW token + IERC20 public immutable FLOW; + + /* ========== VESTING ========== */ + + // Vesting Duration + uint256 public constant VESTING_DURATION = 1 * _ONE_YEAR; + + /* ========== STRUCTS ========== */ + + // Struct of a vesting member, tight-packed to 256-bits + struct Vester { + uint192 amount; + uint64 lastClaim; + uint128 start; + uint128 end; + } + + /* ========== EVENTS ========== */ + + event RevokeToUpdated(address oldAddress, address newAddress); + event VestingCreated(address user, uint256 amount); + event VestingCancelled(address user, uint256 amount); + event Vested(address indexed from, uint256 amount); + + /* ========== STATE VARIABLES ========== */ + + // The status of each vesting member (Vester) + mapping(address => Vester) public vest; + + /* ========== CONSTRUCTOR ========== */ + + /** + * @dev Initializes the FLOW token address + * + * 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"); + FLOW = IERC20(_FLOW); + transferOwnership(_admin); + } + + /* ========== VIEWS ========== */ + + /** + * @dev Returns the amount a user can claim at a given point in time. + * + * Requirements: + * - the vesting period has started + */ + function getClaim(address _vester) + external + view + returns (uint256 vestedAmount) + { + Vester memory vester = vest[_vester]; + return + _getClaim( + vester.amount, + vester.lastClaim, + vester.start, + vester.end + ); + } + + /* ========== MUTATIVE FUNCTIONS ========== */ + + /** + * @dev Allows a user to claim their pending vesting amount of the vested claim + * + * Emits a {Vested} event indicating the user who claimed their vested tokens + * as well as the amount that was vested. + * + * Requirements: + * + * - the vesting period has started + * - the caller must have a non-zero vested amount + */ + function claim() external returns (uint256 vestedAmount) { + Vester memory vester = vest[msg.sender]; + + require(vester.start != 0, "Not Started"); + + require(vester.start < block.timestamp, "Not Started Yet"); + + vestedAmount = _getClaim( + vester.amount, + vester.lastClaim, + vester.start, + vester.end + ); + + require(vestedAmount != 0, "Nothing to claim"); + + vester.amount -= uint192(vestedAmount); + vester.lastClaim = uint64(block.timestamp); + + vest[msg.sender] = vester; + + emit Vested(msg.sender, vestedAmount); + + FLOW.transfer(msg.sender, vestedAmount); + } + + /* ========== RESTRICTED FUNCTIONS ========== */ + + /** + * @dev Adds a new vesting schedule to the contract. + * + * Requirements: + * - Only {owner} can call. + */ + function vestFor(address user, uint256 amount) external onlyOwner { + require(amount <= type(uint192).max, "Amount Overflows uint192"); + require(vest[user].amount == 0, "Already a vester"); + vest[user] = Vester( + uint192(amount), + 0, + uint128(block.timestamp), + uint128(block.timestamp + VESTING_DURATION) + ); + FLOW.transferFrom(msg.sender, address(this), amount); + + emit VestingCreated(user, amount); + } + + function cancelVest(address user) external onlyOwner { + require(revokeTo != address(0), "0 revoke to address"); + uint256 amount = vest[user].amount; + require(amount > 0, "Not a vester"); + require( + FLOW.balanceOf(address(this)) >= amount, + "Insufficient FLOW balance" + ); + delete vest[user]; + FLOW.transfer(revokeTo, amount); + + emit VestingCancelled(user, amount); + } + + function setRevokeTo(address _revokeTo) external onlyOwner { + require(_revokeTo != address(0), "0 address"); + emit RevokeToUpdated(revokeTo, _revokeTo); + revokeTo = _revokeTo; + } + + /* ========== PRIVATE FUNCTIONS ========== */ + + function _getClaim( + uint256 amount, + uint256 lastClaim, + uint256 _start, + uint256 _end + ) private view returns (uint256) { + if (block.timestamp >= _end) return amount; + if (lastClaim == 0) lastClaim = _start; + + return (amount * (block.timestamp - lastClaim)) / (_end - lastClaim); + } +} diff --git a/scripts/TeamMemberVesting.s.sol b/scripts/TeamMemberVesting.s.sol new file mode 100644 index 00000000..c0f53855 --- /dev/null +++ b/scripts/TeamMemberVesting.s.sol @@ -0,0 +1,40 @@ +// 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; + + // team member addresses + address private constant T0RB1K = 0x0b776552c1aef1dc33005dd25acda22493b6615d; + address private constant MOTTO = 0x78e801136f77805239a7f533521a7a5570f572c8; + address private constant COOLIE = 0x03b88dacb7c21b54cefecc297d981e5b721a9df1; + + address private constant ADMIN = 0xBC3043983276887f6b6F164Df33646479C9b1653; + // TODO: Fill the address + address private constant FLOW = 0x0000000000000000000000000000000000000000; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + FlowVestor flowVestor = new FlowVestor(ADMIN, 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); + + IERC20(FLOW).transfer(TEAM_MULTI_SIG, 2_500_000e18); + + vm.stopBroadcast(); + } +} From 6e549b4c2c53c2ce4737eaa8836f7766942e3cd7 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:57:02 +0000 Subject: [PATCH 027/119] build: Flow convertor deployment --- scripts/FlowConvertorDeployment.s.sol | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 scripts/FlowConvertorDeployment.s.sol diff --git a/scripts/FlowConvertorDeployment.s.sol b/scripts/FlowConvertorDeployment.s.sol new file mode 100644 index 00000000..0f70373c --- /dev/null +++ b/scripts/FlowConvertorDeployment.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +// Scripting tool +import {Script} from "../lib/forge-std/src/Script.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 = 0x0000000000000000000000000000000000000000; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(deployerPrivateKey); + + FlowVestor flowConvertor = new flowConvertor({_v1: 0x2baec546a92ca3469f71b7a091f7df61e5569889, _v2: FLOW}); + + flowVestor.transferOwnership(TEAM_MULTI_SIG); + + IERC20(FLOW).transfer(address(flowConvertor), 55_000_000e18); + + vm.stopBroadcast(); + } +} From 3f93bf05ab5d6eca08faedcfaa601b3d1793601c Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:58:05 +0000 Subject: [PATCH 028/119] chore: Remove TODO --- scripts/Deployment.s.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index e2b9da2f..abed6278 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -82,7 +82,6 @@ contract Deployment is Script { address(votingEscrow), address(rewardsDistributor) ); - // TODO: Minter.initialize, Minter.setTeam // Set flow minter to contract flow.setMinter(address(minter)); From a832177941631372e887de14bd655310dadf0265 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 19:58:47 +0000 Subject: [PATCH 029/119] build: PairFactory set tank --- scripts/Deployment.s.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index abed6278..bb6fbae6 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -86,8 +86,9 @@ contract Deployment is Script { // Set flow minter to contract flow.setMinter(address(minter)); - // Set pair factory pauser + // Set pair factory pauser and tank pairFactory.setPauser(TEAM_MULTI_SIG); + pairFactory.setTank(TANK); // Set voting escrow's voter votingEscrow.setVoter(address(voter)); From 997ba1c6d31a723995df632f7af401bf867e3e62 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 20:00:18 +0000 Subject: [PATCH 030/119] build: Voting escrod set ve art proxy --- scripts/Deployment.s.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index bb6fbae6..a1fd1041 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -90,8 +90,9 @@ contract Deployment is Script { pairFactory.setPauser(TEAM_MULTI_SIG); pairFactory.setTank(TANK); - // Set voting escrow's voter + // Set voting escrow's voter and art proxy votingEscrow.setVoter(address(voter)); + votingEscrow.setArtProxy(address(veArtProxy)); // Set minter and voting escrow's team votingEscrow.setTeam(TEAM_MULTI_SIG); From b26ed3a97fa0781e95661ce9b4b846e23763a7ff Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 20:02:28 +0000 Subject: [PATCH 031/119] build: Pair factory set X --- scripts/Deployment.s.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index a1fd1041..568bd32c 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -97,6 +97,10 @@ contract Deployment is Script { // Set minter and voting escrow's team votingEscrow.setTeam(TEAM_MULTI_SIG); minter.setTeam(TEAM_MULTI_SIG); + pairFactory.setTeam(TEAM_MULTI_SIG); + + // Set fee manager + pairFactory.setFeeManager(TEAM_MULTI_SIG); // Set voter's governor voter.setGovernor(TEAM_MULTI_SIG); From de2bd568ffa9543ba541efecd2d369b6914f4ca1 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 20:09:36 +0000 Subject: [PATCH 032/119] chore: Initial liquid supply should be 82m --- contracts/Flow.sol | 2 +- test/Minter.t.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/Flow.sol b/contracts/Flow.sol index 6a52ba1e..46e5844c 100644 --- a/contracts/Flow.sol +++ b/contracts/Flow.sol @@ -21,7 +21,7 @@ contract Flow is IFlow { constructor(address initialSupplyRecipient, address csrRecipient) { minter = msg.sender; - _mint(initialSupplyRecipient, 300 * 1e6 * 1e18); + _mint(initialSupplyRecipient, 82 * 1e6 * 1e18); csrNftId = ITurnstile(0xEcf044C5B4b867CFda001101c617eCd347095B44).register(csrRecipient); } diff --git a/test/Minter.t.sol b/test/Minter.t.sol index a51905cc..50b7e618 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -102,13 +102,13 @@ contract MinterTest is BaseTest { uint256 claimable = distributor.claimable(1); /** * This has been updated from 128115516517529 to - * 170796912607 because originally in VELO the + * 4368856374421 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, 170796912607); + assertGt(claimable, 4368856374421); distributor.claim(1); assertEq(distributor.claimable(1), 0); From a3ec0ef87182b0bc6862297d7e58dd2ab80f6008 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 22:44:00 +0000 Subject: [PATCH 033/119] build: Update whitelisted tokens --- scripts/Deployment.s.sol | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 568bd32c..66e12eef 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -112,9 +112,26 @@ contract Deployment is Script { rewardsDistributor.setDepositor(address(minter)); // Initialize tokens for voter - // TODO: Get all the whitelisted tokens - address[] memory whitelistedTokens = new address[](2); + 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] = 0xe832c073b1b665e21150ac70fa7c798d9926ccf1; // WAIT + whitelistedTokens[12] = 0x7264610a66eca758a8ce95cf11ff5741e1fd0455; // cINU + whitelistedTokens[13] = 0xc03345448969dd8c00e9e4a85d2d9722d093af8e; // GRAV + whitelistedTokens[14] = 0xfa3c22c069b9556a4b2f7ece1ee3b467909f4864; // SOMM + whitelistedTokens[15] = 0x38d11b40d2173009adb245b869e90525950ae345; // cBONK + whitelistedTokens[16] = 0x5FD55A1B9FC24967C4dB09C513C3BA0DFa7FF687; // ETH + whitelistedTokens[17] = 0xd567B3d7B8FE3C79a1AD8dA978812cfC4Fa05e75; // USDT + whitelistedTokens[18] = 0x74ccbe53F77b08632ce0CB91D3A545bF6B8E0979; // fBOMB voter.initialize(whitelistedTokens, address(minter)); vm.stopBroadcast(); From 8eb3213a04bf39e43c871e1a5fee3e8dbbfce13b Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 22:55:21 +0000 Subject: [PATCH 034/119] build: Include snapshotted veNFT holders --- scripts/InitialMintAndLock.s.sol | 193 ++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 1 deletion(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 5f84963d..81d6224f 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -30,13 +30,15 @@ contract InitialMintAndLock is Script { 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 = Minter(address(0)); + minter = Minter(address(0)); // Mint tokens and lock for veNFT @@ -133,9 +135,198 @@ contract InitialMintAndLock is Script { } minter.initialMintAndLock(assetEOAClaim4, ONE_MILLION * assetEOAClaim4.length); + _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 _singleInitialAndLock(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); + } } From a7d3a1c730bdcbe6c67308cf1020e1d18efc54dd Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 23:02:24 +0000 Subject: [PATCH 035/119] refactor: Move batch mint to function --- scripts/InitialMintAndLock.s.sol | 206 ++++++++++++++++++------------- 1 file changed, 117 insertions(+), 89 deletions(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 81d6224f..dc5bd4f8 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -43,97 +43,112 @@ contract InitialMintAndLock is Script { // Mint tokens and lock for veNFT // 1. Mint to Flow voter EOA - Minter.Claim[] memory flowVoterEOAClaim1 = new Minter.Claim[](5); - for (uint256 i; i < flowVoterEOAClaim1.length; i++) { - flowVoterEOAClaim1[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: ONE_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(flowVoterEOAClaim1, ONE_MILLION * flowVoterEOAClaim1.length); - - Minter.Claim[] memory flowVoterEOAClaim2 = new Minter.Claim[](5); - for (uint256 i; i < flowVoterEOAClaim2.length; i++) { - flowVoterEOAClaim2[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: TWO_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(flowVoterEOAClaim2, TWO_MILLION * flowVoterEOAClaim2.length); - - Minter.Claim[] memory flowVoterEOAClaim3 = new Minter.Claim[](3); - for (uint256 i; i < flowVoterEOAClaim3.length; i++) { - flowVoterEOAClaim3[i] = Minter.Claim({claimant: FLOW_VOTER_EOA, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(flowVoterEOAClaim3, FOUR_MILLION * flowVoterEOAClaim3.length); + _batchInitialMintAndLock({ + owner: FLOW_VOTER_EOA, + numberOfVotingEscrow: 5, + amountPerVotingEscrow: ONE_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: FLOW_VOTER_EOA, + numberOfVotingEscrow: 5, + amountPerVotingEscrow: TWO_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: FLOW_VOTER_EOA, + numberOfVotingEscrow: 3, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); // 2. Mint to team members - Minter.Claim[] memory dunksClaim = new Minter.Claim[](1); - dunksClaim[0] = Minter.Claim({claimant: DUNKS, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - minter.initialMintAndLock(dunksClaim, FOUR_MILLION); - - Minter.Claim[] memory t0rb1kClaim = new Minter.Claim[](3); - for (uint256 i; i < t0rb1kClaim.length; i++) { - t0rb1kClaim[i] = Minter.Claim({claimant: T0RB1K, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(t0rb1kClaim, FOUR_MILLION * t0rb1kClaim.length); - - Minter.Claim[] memory ceazorClaim = new Minter.Claim[](3); - for (uint256 i; i < ceazorClaim.length; i++) { - ceazorClaim[i] = Minter.Claim({claimant: CEAZOR, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(ceazorClaim, FOUR_MILLION * ceazorClaim.length); - - Minter.Claim[] memory mottoClaim = new Minter.Claim[](3); - for (uint256 i; i < mottoClaim.length; i++) { - mottoClaim[i] = Minter.Claim({claimant: MOTTO, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(mottoClaim, FOUR_MILLION * mottoClaim.length); - - Minter.Claim[] memory coolieClaim = new Minter.Claim[](3); - for (uint256 i; i < coolieClaim.length; i++) { - coolieClaim[i] = Minter.Claim({claimant: COOLIE, amount: FOUR_MILLION, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(coolieClaim, FOUR_MILLION * coolieClaim.length); - - // 3. TODO: Mint to snapshotted veNFT holders - - // 4. Mint for future partners - Minter.Claim[] memory assetEOAClaim1 = new Minter.Claim[](3); - for (uint256 i; i < assetEOAClaim1.length; i++) { - assetEOAClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(assetEOAClaim1, FOUR_MILLION * assetEOAClaim1.length); - - Minter.Claim[] memory multiSigClaim1 = new Minter.Claim[](13); - for (uint256 i; i < multiSigClaim1.length; i++) { - multiSigClaim1[i] = Minter.Claim({amount: FOUR_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(multiSigClaim1, FOUR_MILLION * multiSigClaim1.length); - - Minter.Claim[] memory assetEOAClaim2 = new Minter.Claim[](3); - for (uint256 i; i < assetEOAClaim2.length; i++) { - assetEOAClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: ASSET_EOA, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(assetEOAClaim1, TWO_MILLION * assetEOAClaim2.length); - - Minter.Claim[] memory multiSigClaim2 = new Minter.Claim[](15); - for (uint256 i; i < multiSigClaim2.length; i++) { - multiSigClaim2[i] = Minter.Claim({amount: TWO_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(multiSigClaim2, TWO_MILLION * multiSigClaim2.length); - - Minter.Claim[] memory multiSigClaim3 = new Minter.Claim[](16); - for (uint256 i; i < multiSigClaim3.length; i++) { - multiSigClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: TEAM_MULTI_SIG, lockTime: FOUR_YEARS}); - } - minter.initialMintAndLock(multiSigClaim3, ONE_MILLION * multiSigClaim3.length); - - Minter.Claim[] memory assetEOAClaim3 = new Minter.Claim[](5); - for (uint256 i; i < assetEOAClaim3.length; i++) { - assetEOAClaim3[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: TWO_YEARS}); - } - minter.initialMintAndLock(assetEOAClaim3, ONE_MILLION * assetEOAClaim3.length); - - Minter.Claim[] memory assetEOAClaim4 = new Minter.Claim[](5); - for (uint256 i; i < assetEOAClaim4.length; i++) { - assetEOAClaim4[i] = Minter.Claim({amount: ONE_MILLION, claimant: ASSET_EOA, lockTime: ONE_YEAR}); - } - minter.initialMintAndLock(assetEOAClaim4, ONE_MILLION * assetEOAClaim4.length); + _batchInitialMintAndLock({ + owner: DUNKS, + numberOfVotingEscrow: 1, + amountPerVotingEscrow: FOUR_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: 3, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: TEAM_MULTI_SIG, + numberOfVotingEscrow: 13, + amountPerVotingEscrow: FOUR_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: TEAM_MULTI_SIG, + numberOfVotingEscrow: 3, + amountPerVotingEscrow: TWO_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: TEAM_MULTI_SIG, + numberOfVotingEscrow: 15, + amountPerVotingEscrow: TWO_MILLION, + lockTime: FOUR_YEARS + }); + + _batchInitialMintAndLock({ + owner: TEAM_MULTI_SIG, + numberOfVotingEscrow: 16, + 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_YEARS + }); _singleInitialMintAndLock(0xd0cC9738866cd82B237A14c92ac60577602d6c18, 1200000000000000000); _singleInitialMintAndLock(0x38dAEa6f17E4308b0Da9647dB9ca6D84a3A7E195, 24000000000000000000000); @@ -329,4 +344,17 @@ contract InitialMintAndLock is Script { 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); + } } From 4122ae5d315c7355aef2e0b03ad21b15b7e96a0a Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 4 Mar 2023 21:31:24 +0800 Subject: [PATCH 036/119] feat: add canto csr --- test/Minter.t.sol | 2 +- test/VeloVoting.t.sol | 2 +- test/WrappedExternalBribes.t.sol | 23 +++-------------------- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 50b7e618..3867a118 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -102,7 +102,7 @@ contract MinterTest is BaseTest { uint256 claimable = distributor.claimable(1); /** * This has been updated from 128115516517529 to - * 4368856374421 because originally in VELO the + * 4368856374421 because originally in FLOW the * constructor mints 0 tokens, but now we are minting * an initial supply instead of using the initialMint * function. diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index d5d88512..2927906d 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -113,7 +113,7 @@ contract VeloVotingTest is BaseTest { before = FLOW.balanceOf(address(owner)); minter.update_period(); // initial period week 2 after_ = FLOW.balanceOf(address(owner)); - assertLt(minter.weekly(), 13 * TOKEN_1M); // <13m for week shift + 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/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index 9f6acba8..28dceb4b 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -29,26 +29,14 @@ contract WrappedExternalBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow( - address(FLOW), - address(artProxy), - owners[0], - csrNftId - ); + 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 - ); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -57,12 +45,7 @@ contract WrappedExternalBribesTest is BaseTest { // deployMinter() distributor = new RewardsDistributor(address(escrow), csrNftId); - minter = new Minter( - address(voter), - address(escrow), - address(distributor), - 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); From 8e341eea4b4fc8476eb6efca62f79875e587ea87 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 5 Mar 2023 13:16:20 +0800 Subject: [PATCH 037/119] chore: add initial mint for dunks --- scripts/InitialMintAndLock.s.sol | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index dc5bd4f8..15baf23d 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -72,6 +72,13 @@ contract InitialMintAndLock is Script { lockTime: FOUR_YEARS }); + _batchInitialMintAndLock({ + owner: DUNKS, + numberOfVotingEscrow: 1, + amountPerVotingEscrow: ONE_MILLION, + lockTime: FOUR_YEARS + }); + _batchInitialMintAndLock({ owner: T0RB1K, numberOfVotingEscrow: 3, From 0168f87e2f972bc96c411c78d842c2f08667f02f Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 5 Mar 2023 13:16:44 +0800 Subject: [PATCH 038/119] chore: change multi sig claim veNFT from 13 to 14 --- scripts/InitialMintAndLock.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 15baf23d..51c61531 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -117,7 +117,7 @@ contract InitialMintAndLock is Script { _batchInitialMintAndLock({ owner: TEAM_MULTI_SIG, - numberOfVotingEscrow: 13, + numberOfVotingEscrow: 14, amountPerVotingEscrow: FOUR_MILLION, lockTime: FOUR_YEARS }); From a9855b883a9bc858c027b59820c8347fd3f67e70 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 5 Mar 2023 13:17:00 +0800 Subject: [PATCH 039/119] chore: change asset eoa initial mint from 5 to 4 --- scripts/InitialMintAndLock.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 51c61531..00c0232e 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -145,7 +145,7 @@ contract InitialMintAndLock is Script { _batchInitialMintAndLock({ owner: ASSET_EOA, - numberOfVotingEscrow: 5, + numberOfVotingEscrow: 4, amountPerVotingEscrow: ONE_MILLION, lockTime: TWO_YEARS }); From c9d326beea29c3da7d379721461073657ba1cb87 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 5 Mar 2023 13:56:06 +0800 Subject: [PATCH 040/119] fix: add csr related code to deployment script --- scripts/Deployment.s.sol | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 66e12eef..4b0d2d41 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -33,19 +33,20 @@ contract Deployment is Script { vm.startBroadcast(deployerPrivateKey); // Flow token - Flow flow = new Flow({initialSupplyRecipient: address(this)}); + Flow flow = new Flow({initialSupplyRecipient: address(this), csrRecipient: TEAM_MULTI_SIG}); + uint256 csrNftId = flow.csrNftId(); // Gauge factory - GaugeFactory gaugeFactory = new GaugeFactory(); + GaugeFactory gaugeFactory = new GaugeFactory(csrNftId); // Bribe factory - BribeFactory bribeFactory = new BribeFactory(); + BribeFactory bribeFactory = new BribeFactory(csrNftId); // Pair factory - PairFactory pairFactory = new PairFactory(); + PairFactory pairFactory = new PairFactory(csrNftId); // Router - Router router = new Router(address(pairFactory), WCANTO); + Router router = new Router(address(pairFactory), WCANTO, csrNftId); // VelocimeterLibrary VelocimeterLibrary velocimeterLib = new VelocimeterLibrary(address(router)); @@ -54,13 +55,13 @@ contract Deployment is Script { VeArtProxy veArtProxy = new VeArtProxy(); // VotingEscrow - VotingEscrow votingEscrow = new VotingEscrow(address(flow), address(veArtProxy), TEAM_MULTI_SIG); + VotingEscrow votingEscrow = new VotingEscrow(address(flow), address(veArtProxy), TEAM_MULTI_SIG, csrNftId); // RewardsDistributor - RewardsDistributor rewardsDistributor = new RewardsDistributor(address(votingEscrow)); + RewardsDistributor rewardsDistributor = new RewardsDistributor(address(votingEscrow), csrNftId); // Wrapped external bribe factory - WrappedExternalBribeFactory wrappedExternalBribeFactory = new WrappedExternalBribeFactory(); + WrappedExternalBribeFactory wrappedExternalBribeFactory = new WrappedExternalBribeFactory(csrNftId); // Voter Voter voter = new Voter( @@ -68,7 +69,8 @@ contract Deployment is Script { address(pairFactory), address(gaugeFactory), address(bribeFactory), - address(wrappedExternalBribeFactory) + address(wrappedExternalBribeFactory), + csrNftId ); // Set voter @@ -80,7 +82,8 @@ contract Deployment is Script { Minter minter = new Minter( address(voter), address(votingEscrow), - address(rewardsDistributor) + address(rewardsDistributor), + csrNftId ); // Set flow minter to contract From f0629dbdc876a48c1e614429e208b8e523e33e4c Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 5 Mar 2023 13:57:12 +0800 Subject: [PATCH 041/119] fix: remove duplicated setVoter for votingEscrow in deployment script --- scripts/Deployment.s.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 4b0d2d41..49f868c1 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -93,8 +93,7 @@ contract Deployment is Script { pairFactory.setPauser(TEAM_MULTI_SIG); pairFactory.setTank(TANK); - // Set voting escrow's voter and art proxy - votingEscrow.setVoter(address(voter)); + // Set voting escrow's art proxy votingEscrow.setArtProxy(address(veArtProxy)); // Set minter and voting escrow's team From e779cdffc97988af56a1ae9228592664b411a2d3 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 5 Mar 2023 14:07:47 +0800 Subject: [PATCH 042/119] feat: add FlowConvertor --- contracts/FlowConvertor.sol | 73 +++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 contracts/FlowConvertor.sol diff --git a/contracts/FlowConvertor.sol b/contracts/FlowConvertor.sol new file mode 100644 index 00000000..3b5b23b2 --- /dev/null +++ b/contracts/FlowConvertor.sol @@ -0,0 +1,73 @@ +pragma solidity 0.8.13; + +import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; +import "openzeppelin-contracts/contracts/access/Ownable.sol"; + +/** + * @dev This contract allow users to convert one token to another. + * It requires both tokens to have valid contract addresses. + * It requires that it is filled up first with liquid v2 tokens., they dont need to be exact. + * Any tokens that get sent here accidently can be sent back out, except v1 token. + */ +contract FlowConvertor is Ownable { + address public immutable v1; + address public immutable v2; + + constructor(address _v1, address _v2) { + v1 = _v1; + v2 = _v2; + } + + /** + * @dev Transfers ERC20 v1 from user to contract, and Transfer ERC20 v2 to user, 1 to 1. + */ + function redeem(uint256 amount) public { + require(amount > 0, "you dont have and v1 tokens"); + SafeERC20.safeTransferFrom( + IERC20(v1), + _msgSender(), + address(this), + amount + ); + SafeERC20.safeTransferFrom( + IERC20(v2), + address(this), + _msgSender(), + amount + ); + } + + /** + * @dev Transfers ERC20 v1 from user to contract, and Transfer ERC20 v2 to an address specified, 1 to 1. + */ + function redeemTo(address _to, uint256 amount) public { + require(amount > 0, "you dont have and v1 tokens"); + SafeERC20.safeTransferFrom( + IERC20(v1), + _msgSender(), + address(this), + amount + ); + SafeERC20.safeTransferFrom(IERC20(v2), address(this), _to, amount); + } + + /** + * @dev Allows owner to clean out the contract of ANY tokens including v2, but not v1 + */ + function inCaseTokensGetStuck( + address _token, + address _to, + uint256 _amount + ) public onlyOwner { + require(_token != address(v1), "these tkns are essentially burnt"); + SafeERC20.safeTransfer(IERC20(_token), _to, _amount); + } + + /** + * @dev Allows owner sweep out all the remaining v2 tokens. + */ + function sweepV2(address _to) public onlyOwner { + uint256 _surplus = IERC20(v2).balanceOf(address(this)); + SafeERC20.safeTransfer(IERC20(v2), _to, _surplus); + } +} \ No newline at end of file From 572b534c29025a98cd15cb209370777af25ad9b6 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 5 Mar 2023 14:12:42 +0800 Subject: [PATCH 043/119] chore: amend initial mint --- scripts/InitialMintAndLock.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 00c0232e..98136c46 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -75,7 +75,7 @@ contract InitialMintAndLock is Script { _batchInitialMintAndLock({ owner: DUNKS, numberOfVotingEscrow: 1, - amountPerVotingEscrow: ONE_MILLION, + amountPerVotingEscrow: TWO_MILLION, lockTime: FOUR_YEARS }); From ce8195ed6dae8052d953771841c18112f932d276 Mon Sep 17 00:00:00 2001 From: coolie Date: Sun, 5 Mar 2023 20:46:25 +0000 Subject: [PATCH 044/119] fix: Wrong contract/variable name used --- scripts/FlowConvertorDeployment.s.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/FlowConvertorDeployment.s.sol b/scripts/FlowConvertorDeployment.s.sol index 0f70373c..86a9008d 100644 --- a/scripts/FlowConvertorDeployment.s.sol +++ b/scripts/FlowConvertorDeployment.s.sol @@ -16,9 +16,9 @@ contract FlowConvertorDeployment is Script { vm.startBroadcast(deployerPrivateKey); - FlowVestor flowConvertor = new flowConvertor({_v1: 0x2baec546a92ca3469f71b7a091f7df61e5569889, _v2: FLOW}); + FlowConvertor flowConvertor = new FlowConvertor({_v1: 0x2baec546a92ca3469f71b7a091f7df61e5569889, _v2: FLOW}); - flowVestor.transferOwnership(TEAM_MULTI_SIG); + floeConvertor.transferOwnership(TEAM_MULTI_SIG); IERC20(FLOW).transfer(address(flowConvertor), 55_000_000e18); From b602bc1cc8113884d766d30072709bd112586bad Mon Sep 17 00:00:00 2001 From: coolie Date: Sun, 5 Mar 2023 22:11:43 +0000 Subject: [PATCH 045/119] fix: Addresses need to be checksummed --- scripts/Deployment.s.sol | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 49f868c1..b1e32ae9 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -19,12 +19,12 @@ import {Minter} from "../contracts/Minter.sol"; contract Deployment is Script { // token addresses - address private constant WCANTO = 0x826551890dc65655a0aceca109ab11abdbd7a07b; + address private constant WCANTO = 0x826551890Dc65655a0Aceca109aB11AbDbD7a07B; // privileged accounts - address private constant COUNCIL = 0x06b16991b53632c2362267579ae7c4863c72fdb8; + address private constant COUNCIL = 0x06b16991B53632C2362267579AE7C4863c72fDb8; address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; - address private constant GOVERNOR = 0x06b16991b53632c2362267579ae7c4863c72fdb8; + address private constant GOVERNOR = 0x06b16991B53632C2362267579AE7C4863c72fDb8; address private constant TANK = 0x0A868fd1523a1ef58Db1F2D135219F0e30CBf7FB; function run() external { @@ -116,21 +116,21 @@ contract Deployment is Script { // 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[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] = 0xe832c073b1b665e21150ac70fa7c798d9926ccf1; // WAIT - whitelistedTokens[12] = 0x7264610a66eca758a8ce95cf11ff5741e1fd0455; // cINU - whitelistedTokens[13] = 0xc03345448969dd8c00e9e4a85d2d9722d093af8e; // GRAV - whitelistedTokens[14] = 0xfa3c22c069b9556a4b2f7ece1ee3b467909f4864; // SOMM - whitelistedTokens[15] = 0x38d11b40d2173009adb245b869e90525950ae345; // cBONK + 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] = 0xe832c073b1b665E21150aC70Fa7c798d9926cCf1; // WAIT + whitelistedTokens[12] = 0x7264610A66EcA758A8ce95CF11Ff5741E1fd0455; // cINU + whitelistedTokens[13] = 0xc03345448969Dd8C00e9E4A85d2d9722d093aF8E; // GRAV + whitelistedTokens[14] = 0xFA3C22C069B9556A4B2f7EcE1Ee3B467909f4864; // SOMM + whitelistedTokens[15] = 0x38D11B40D2173009aDB245b869e90525950aE345; // cBONK whitelistedTokens[16] = 0x5FD55A1B9FC24967C4dB09C513C3BA0DFa7FF687; // ETH whitelistedTokens[17] = 0xd567B3d7B8FE3C79a1AD8dA978812cfC4Fa05e75; // USDT whitelistedTokens[18] = 0x74ccbe53F77b08632ce0CB91D3A545bF6B8E0979; // fBOMB From c5793ae07b9925f31c07b1856cfe6aaddb929662 Mon Sep 17 00:00:00 2001 From: coolie Date: Sun, 5 Mar 2023 22:15:08 +0000 Subject: [PATCH 046/119] fix: Unused local variable warning --- scripts/Deployment.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index b1e32ae9..ace3c9d9 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -49,7 +49,7 @@ contract Deployment is Script { Router router = new Router(address(pairFactory), WCANTO, csrNftId); // VelocimeterLibrary - VelocimeterLibrary velocimeterLib = new VelocimeterLibrary(address(router)); + new VelocimeterLibrary(address(router)); // VeArtProxy VeArtProxy veArtProxy = new VeArtProxy(); From b401330f96c2a6c1b20b7bd296e921ebe88ba5d6 Mon Sep 17 00:00:00 2001 From: coolie Date: Sun, 5 Mar 2023 22:21:55 +0000 Subject: [PATCH 047/119] fix: Wrong function name --- scripts/InitialMintAndLock.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 98136c46..aeceb0f3 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -346,7 +346,7 @@ contract InitialMintAndLock is Script { vm.stopBroadcast(); } - function _singleInitialAndLock(address owner, uint256 amount) private { + 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); From 3144982e814112a0af7ad7826890d16351af7011 Mon Sep 17 00:00:00 2001 From: coolie Date: Sun, 5 Mar 2023 22:22:20 +0000 Subject: [PATCH 048/119] fix: Typo --- scripts/InitialMintAndLock.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index aeceb0f3..3b7b43f5 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -154,7 +154,7 @@ contract InitialMintAndLock is Script { owner: ASSET_EOA, numberOfVotingEscrow: 5, amountPerVotingEscrow: ONE_MILLION, - lockTime: ONE_YEARS + lockTime: ONE_YEAR }); _singleInitialMintAndLock(0xd0cC9738866cd82B237A14c92ac60577602d6c18, 1200000000000000000); From a361687af72598165fa1a7c799d4e560e57ea83e Mon Sep 17 00:00:00 2001 From: coolie Date: Sun, 5 Mar 2023 22:24:06 +0000 Subject: [PATCH 049/119] fix: Addresses need to be checksummed --- scripts/InitialMintAndLock.s.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 3b7b43f5..e0b5b6cb 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -11,14 +11,14 @@ contract InitialMintAndLock is Script { // 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; + 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; + 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) From d6aae2723b640a564feae968bbcc376a9a1627b0 Mon Sep 17 00:00:00 2001 From: Ceazor Date: Sun, 5 Mar 2023 20:05:31 -0700 Subject: [PATCH 050/119] Added THREE_MILLIONs = 1% --- scripts/InitialMintAndLock.s.sol | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index e0b5b6cb..3d5b8ece 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -23,6 +23,7 @@ contract InitialMintAndLock is Script { // 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 @@ -52,15 +53,15 @@ contract InitialMintAndLock is Script { _batchInitialMintAndLock({ owner: FLOW_VOTER_EOA, - numberOfVotingEscrow: 5, + numberOfVotingEscrow: 6, amountPerVotingEscrow: TWO_MILLION, lockTime: FOUR_YEARS }); _batchInitialMintAndLock({ owner: FLOW_VOTER_EOA, - numberOfVotingEscrow: 3, - amountPerVotingEscrow: FOUR_MILLION, + numberOfVotingEscrow: 2, + amountPerVotingEscrow: THREE_MILLION, lockTime: FOUR_YEARS }); @@ -110,21 +111,21 @@ contract InitialMintAndLock is Script { // 3. Mint for future partners _batchInitialMintAndLock({ owner: ASSET_EOA, - numberOfVotingEscrow: 3, - amountPerVotingEscrow: FOUR_MILLION, + numberOfVotingEscrow: 4, + amountPerVotingEscrow: THREE_MILLION, lockTime: FOUR_YEARS }); _batchInitialMintAndLock({ owner: TEAM_MULTI_SIG, - numberOfVotingEscrow: 14, - amountPerVotingEscrow: FOUR_MILLION, + numberOfVotingEscrow: 18, + amountPerVotingEscrow: THREE_MILLION, lockTime: FOUR_YEARS }); _batchInitialMintAndLock({ - owner: TEAM_MULTI_SIG, - numberOfVotingEscrow: 3, + owner: ASSET_EOA, + numberOfVotingEscrow: 4, amountPerVotingEscrow: TWO_MILLION, lockTime: FOUR_YEARS }); @@ -156,7 +157,17 @@ contract InitialMintAndLock is Script { 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); From c1197520ee074510c2597e9dab92f1ad462584c3 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Mon, 6 Mar 2023 11:38:45 +0800 Subject: [PATCH 051/119] fix: typo --- scripts/FlowConvertorDeployment.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/FlowConvertorDeployment.s.sol b/scripts/FlowConvertorDeployment.s.sol index 86a9008d..28be5e01 100644 --- a/scripts/FlowConvertorDeployment.s.sol +++ b/scripts/FlowConvertorDeployment.s.sol @@ -18,7 +18,7 @@ contract FlowConvertorDeployment is Script { FlowConvertor flowConvertor = new FlowConvertor({_v1: 0x2baec546a92ca3469f71b7a091f7df61e5569889, _v2: FLOW}); - floeConvertor.transferOwnership(TEAM_MULTI_SIG); + flowConvertor.transferOwnership(TEAM_MULTI_SIG); IERC20(FLOW).transfer(address(flowConvertor), 55_000_000e18); From 933e367756b21cd6de3b3beecbf8f5e3c71bee37 Mon Sep 17 00:00:00 2001 From: coolie Date: Sat, 4 Mar 2023 13:53:41 +0000 Subject: [PATCH 052/119] refactor: Rename VELO to FLOW and fixed a test --- test/WrappedExternalBribes.t.sol | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index 28dceb4b..af7334ca 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -36,7 +36,14 @@ contract WrappedExternalBribesTest is BaseTest { 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); + voter = new Voter( + address(escrow), + address(factory), + address(gaugeFactory), + address(bribeFactory), + address(wxbribeFactory), + csrNftId + ); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -45,7 +52,12 @@ contract WrappedExternalBribesTest is BaseTest { // deployMinter() distributor = new RewardsDistributor(address(escrow), csrNftId); - minter = new Minter(address(voter), address(escrow), address(distributor), 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); From 269a9111157c729fbfdd2f3061b53917e5e3d284 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 4 Mar 2023 21:31:24 +0800 Subject: [PATCH 053/119] feat: add canto csr --- test/WrappedExternalBribes.t.sol | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/test/WrappedExternalBribes.t.sol b/test/WrappedExternalBribes.t.sol index af7334ca..28dceb4b 100644 --- a/test/WrappedExternalBribes.t.sol +++ b/test/WrappedExternalBribes.t.sol @@ -36,14 +36,7 @@ contract WrappedExternalBribesTest is BaseTest { 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 - ); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory), csrNftId); escrow.setVoter(address(voter)); wxbribeFactory.setVoter(address(voter)); @@ -52,12 +45,7 @@ contract WrappedExternalBribesTest is BaseTest { // deployMinter() distributor = new RewardsDistributor(address(escrow), csrNftId); - minter = new Minter( - address(voter), - address(escrow), - address(distributor), - 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); From 5f4e339084d53dd2b061af6d4e2c8699d20d33d7 Mon Sep 17 00:00:00 2001 From: Ceazor Date: Sun, 5 Mar 2023 21:51:10 -0700 Subject: [PATCH 054/119] double check on mints, --- contracts/Flow.sol | 2 +- scripts/FlowConvertorDeployment.s.sol | 2 +- scripts/InitialMintAndLock.s.sol | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contracts/Flow.sol b/contracts/Flow.sol index 46e5844c..14a9b571 100644 --- a/contracts/Flow.sol +++ b/contracts/Flow.sol @@ -21,7 +21,7 @@ contract Flow is IFlow { constructor(address initialSupplyRecipient, address csrRecipient) { minter = msg.sender; - _mint(initialSupplyRecipient, 82 * 1e6 * 1e18); + _mint(initialSupplyRecipient, 82800140034502500000000000); csrNftId = ITurnstile(0xEcf044C5B4b867CFda001101c617eCd347095B44).register(csrRecipient); } diff --git a/scripts/FlowConvertorDeployment.s.sol b/scripts/FlowConvertorDeployment.s.sol index 28be5e01..416f42e3 100644 --- a/scripts/FlowConvertorDeployment.s.sol +++ b/scripts/FlowConvertorDeployment.s.sol @@ -20,7 +20,7 @@ contract FlowConvertorDeployment is Script { flowConvertor.transferOwnership(TEAM_MULTI_SIG); - IERC20(FLOW).transfer(address(flowConvertor), 55_000_000e18); + IERC20(FLOW).transfer(address(flowConvertor), 50_000_000e18); vm.stopBroadcast(); } diff --git a/scripts/InitialMintAndLock.s.sol b/scripts/InitialMintAndLock.s.sol index 3d5b8ece..f932b3c8 100644 --- a/scripts/InitialMintAndLock.s.sol +++ b/scripts/InitialMintAndLock.s.sol @@ -132,21 +132,21 @@ contract InitialMintAndLock is Script { _batchInitialMintAndLock({ owner: TEAM_MULTI_SIG, - numberOfVotingEscrow: 15, + numberOfVotingEscrow: 14, amountPerVotingEscrow: TWO_MILLION, lockTime: FOUR_YEARS }); _batchInitialMintAndLock({ owner: TEAM_MULTI_SIG, - numberOfVotingEscrow: 16, + numberOfVotingEscrow: 15, amountPerVotingEscrow: ONE_MILLION, lockTime: FOUR_YEARS }); _batchInitialMintAndLock({ owner: ASSET_EOA, - numberOfVotingEscrow: 4, + numberOfVotingEscrow: 5, amountPerVotingEscrow: ONE_MILLION, lockTime: TWO_YEARS }); From a60edd43c3e38ef8a44f9beda0e2ef4ff121b7f6 Mon Sep 17 00:00:00 2001 From: Ceazor Date: Sun, 5 Mar 2023 23:53:06 -0700 Subject: [PATCH 055/119] remove WAIT Whitelisting. pool shallow --- scripts/Deployment.s.sol | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index ace3c9d9..f1d66319 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -126,14 +126,13 @@ contract Deployment is Script { whitelistedTokens[8] = 0xC5e00D3b04563950941f7137B5AfA3a534F0D6d6; // KAVA whitelistedTokens[9] = 0x5aD523d94Efb56C400941eb6F34393b84c75ba39; // AKT whitelistedTokens[10] = 0x0CE35b0D42608Ca54Eb7bcc8044f7087C18E7717; // OSMO - whitelistedTokens[11] = 0xe832c073b1b665E21150aC70Fa7c798d9926cCf1; // WAIT - whitelistedTokens[12] = 0x7264610A66EcA758A8ce95CF11Ff5741E1fd0455; // cINU - whitelistedTokens[13] = 0xc03345448969Dd8C00e9E4A85d2d9722d093aF8E; // GRAV - whitelistedTokens[14] = 0xFA3C22C069B9556A4B2f7EcE1Ee3B467909f4864; // SOMM - whitelistedTokens[15] = 0x38D11B40D2173009aDB245b869e90525950aE345; // cBONK - whitelistedTokens[16] = 0x5FD55A1B9FC24967C4dB09C513C3BA0DFa7FF687; // ETH - whitelistedTokens[17] = 0xd567B3d7B8FE3C79a1AD8dA978812cfC4Fa05e75; // USDT - whitelistedTokens[18] = 0x74ccbe53F77b08632ce0CB91D3A545bF6B8E0979; // fBOMB + 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(); From b473f448fb35f4025dc4c0bd4f155017dc5b0f47 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 7 Mar 2023 07:27:49 +0800 Subject: [PATCH 056/119] fix: remove redundant vairables --- contracts/factories/PairFactory.sol | 4 +--- test/Minter.t.sol | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/contracts/factories/PairFactory.sol b/contracts/factories/PairFactory.sol index b5f4e124..ee943ccd 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -43,10 +43,8 @@ contract PairFactory is IPairFactory { event FeeSet(address indexed setter, bool stable, uint256 fee); - constructor(uint256 _csrNftId) { - pauser = msg.sender; + constructor() { isPaused = false; - feeManager = msg.sender; stableFee = 3; // 0.03% volatileFee = 25; // 0.25% deployer = msg.sender; diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 3867a118..5fc7cfb9 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -102,13 +102,13 @@ contract MinterTest is BaseTest { uint256 claimable = distributor.claimable(1); /** * This has been updated from 128115516517529 to - * 4368856374421 because originally in FLOW the + * 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, 4368856374421); + assertGt(claimable, 4276543748717); distributor.claim(1); assertEq(distributor.claimable(1), 0); From 6161b0a51757cebf2dc8cc077a601e00f202e609 Mon Sep 17 00:00:00 2001 From: coolie Date: Mon, 6 Mar 2023 23:42:03 +0000 Subject: [PATCH 057/119] Revert "fix: Gauge reward token precision based on ERC20 token decimals" This reverts commit af760d027dbcc14c65d6b2bb7f7af5db9829cf83. --- contracts/Gauge.sol | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/contracts/Gauge.sol b/contracts/Gauge.sol index b11d7804..139b9187 100644 --- a/contracts/Gauge.sol +++ b/contracts/Gauge.sol @@ -24,6 +24,7 @@ contract Gauge is IGauge { bool public isForPair; uint internal constant DURATION = 7 days; // rewards are released over 7 days + uint internal constant PRECISION = 10 ** 18; uint internal constant MAX_REWARD_TOKENS = 16; // default snx staking contract implementation @@ -287,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) { @@ -329,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 @@ -406,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; } From 47d635d41500d531b0021d5f1b7e760126fbbb4b Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 7 Mar 2023 07:43:49 +0800 Subject: [PATCH 058/119] fix: remove isPaused = false in constructor --- contracts/factories/PairFactory.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/factories/PairFactory.sol b/contracts/factories/PairFactory.sol index ee943ccd..a15e6c1d 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -44,7 +44,6 @@ contract PairFactory is IPairFactory { event FeeSet(address indexed setter, bool stable, uint256 fee); constructor() { - isPaused = false; stableFee = 3; // 0.03% volatileFee = 25; // 0.25% deployer = msg.sender; From 64a1fa11a0fdf6b68c5b2304e2bd29d29460d992 Mon Sep 17 00:00:00 2001 From: Ceazor Date: Mon, 6 Mar 2023 19:13:01 -0700 Subject: [PATCH 059/119] pair fetch tank from PairFactory so all pairs depend on PF tank() --- contracts/Pair.sol | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/contracts/Pair.sol b/contracts/Pair.sol index 5ebd627a..dfca344e 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -37,7 +37,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 @@ -118,6 +117,10 @@ contract Pair is IPair { require(success && (data.length == 0 || abi.decode(data, (bool)))); } + function tank() public view returns (address) { + return PairFactory(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'); @@ -155,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); + _tank = tank(); + _safeTransfer(token, _tank, amount); // transfer the fees to tank MSig for gaugeless LPs + emit TankFees(token, amount, _tank); } } } From e74b7dab43927730b8ee6b1501c3200a4fbf674e Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 7 Mar 2023 10:27:34 +0800 Subject: [PATCH 060/119] fix: fix pair tanks --- contracts/Pair.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/Pair.sol b/contracts/Pair.sol index dfca344e..f031d916 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -84,7 +84,6 @@ contract Pair is IPair { constructor(uint256 _csrNftId) { factory = msg.sender; voter = PairFactory(msg.sender).voter(); - tank = PairFactory(msg.sender).tank(); (address _token0, address _token1, bool _stable) = PairFactory(msg.sender).getInitializable(); (token0, token1, stable) = (_token0, _token1, _stable); if (_stable) { @@ -158,7 +157,7 @@ contract Pair is IPair { IBribe(externalBribe).notifyRewardAmount(token, amount); // transfer fees to exBribes emit GaugeFees(token, amount, externalBribe); } else { - _tank = tank(); + address _tank = tank(); _safeTransfer(token, _tank, amount); // transfer the fees to tank MSig for gaugeless LPs emit TankFees(token, amount, _tank); } From cea2094f973fb69870e43df9b5a47bb169909134 Mon Sep 17 00:00:00 2001 From: Ceazor Date: Mon, 6 Mar 2023 23:19:36 -0700 Subject: [PATCH 061/119] transferFrom to transfer --- contracts/FlowConvertor.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/FlowConvertor.sol b/contracts/FlowConvertor.sol index 3b5b23b2..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); } /** From 914a4a2448e6ebd1cbfd92e7a1ca03662783c4e7 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 7 Mar 2023 19:03:57 +0800 Subject: [PATCH 062/119] fix: add _csrNftId in constructor of PairFactory --- contracts/factories/PairFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/factories/PairFactory.sol b/contracts/factories/PairFactory.sol index a15e6c1d..3b395196 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -43,7 +43,7 @@ contract PairFactory is IPairFactory { event FeeSet(address indexed setter, bool stable, uint256 fee); - constructor() { + constructor(uint256 _csrNftId) { stableFee = 3; // 0.03% volatileFee = 25; // 0.25% deployer = msg.sender; From 7b5e6aa61c4a514502a08080ce26beb726035904 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 7 Mar 2023 19:07:23 +0800 Subject: [PATCH 063/119] chore: fork canto mainnet in hardhat config --- hardhat.config.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 05d19884..98d3f35b 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -27,8 +27,7 @@ const config: HardhatUserConfig = { hardhat: { initialBaseFeePerGas: 0, forking: { - url: `https://opt-mainnet.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY}`, - blockNumber: 16051852 + url: "https://canto.neobase.one", } }, opera: { From 3ce0c741d79918b5bdb52a50f518c1a50544ec28 Mon Sep 17 00:00:00 2001 From: coolie Date: Mon, 6 Mar 2023 23:30:53 +0000 Subject: [PATCH 064/119] feat: Use Ownable for PairFactory --- contracts/Voter.sol | 2 +- contracts/factories/PairFactory.sol | 59 ++++------------------------- scripts/Deployment.s.sol | 6 +-- tasks/deploy/op.ts | 3 -- test/BaseTest.sol | 1 - test/utils/TestOwner.sol | 8 ---- 6 files changed, 10 insertions(+), 69 deletions(-) diff --git a/contracts/Voter.sol b/contracts/Voter.sol index 70b19557..cd6a85b4 100644 --- a/contracts/Voter.sol +++ b/contracts/Voter.sol @@ -99,7 +99,7 @@ contract Voter is IVoter { } function setEmergencyCouncil(address _council) public { - require(msg.sender == emergencyCouncil); + require(msg.sender == governor); emergencyCouncil = _council; } diff --git a/contracts/factories/PairFactory.sol b/contracts/factories/PairFactory.sol index 3b395196..a75c5ee1 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -4,20 +4,15 @@ 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; @@ -32,14 +27,9 @@ contract PairFactory is IPairFactory { 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); @@ -51,22 +41,15 @@ contract PairFactory is IPairFactory { csrNftId = _csrNftId; } - 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); - } - 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); } @@ -75,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/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index f1d66319..0d0500a6 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -90,7 +90,6 @@ contract Deployment is Script { flow.setMinter(address(minter)); // Set pair factory pauser and tank - pairFactory.setPauser(TEAM_MULTI_SIG); pairFactory.setTank(TANK); // Set voting escrow's art proxy @@ -99,10 +98,9 @@ contract Deployment is Script { // Set minter and voting escrow's team votingEscrow.setTeam(TEAM_MULTI_SIG); minter.setTeam(TEAM_MULTI_SIG); - pairFactory.setTeam(TEAM_MULTI_SIG); - // Set fee manager - pairFactory.setFeeManager(TEAM_MULTI_SIG); + // Transfer pair factory ownership to multi-sig + pairFactory.transferOwnership(TEAM_MULTI_SIG); // Set voter's governor voter.setGovernor(TEAM_MULTI_SIG); diff --git a/tasks/deploy/op.ts b/tasks/deploy/op.ts index 488c0867..afff85c7 100644 --- a/tasks/deploy/op.ts +++ b/tasks/deploy/op.ts @@ -120,9 +120,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"); diff --git a/test/BaseTest.sol b/test/BaseTest.sol index 9928a2b6..4c56cc76 100644 --- a/test/BaseTest.sol +++ b/test/BaseTest.sol @@ -121,7 +121,6 @@ abstract contract BaseTest is Test, TestOwner { 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), csrNftId); diff --git a/test/utils/TestOwner.sol b/test/utils/TestOwner.sol index 7f3ce4ec..5f55f85c 100644 --- a/test/utils/TestOwner.sol +++ b/test/utils/TestOwner.sol @@ -39,14 +39,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); } From c35d74157f0df1e50959dcef0ba9c398708d67ec Mon Sep 17 00:00:00 2001 From: Ceazor Date: Mon, 6 Mar 2023 10:56:43 -0700 Subject: [PATCH 065/119] Changes to Roles PairFactory.sol - reduced roles in PairFactory cuz deployer has perma power to setTank - made PairFactory import ownable.sol --removed team, pauser, pendingPauser, feeManger and made their functions onlyOwner Voter.sol - made governor only role that can change emergencyCouncil- not emergencyCouncil Deployment.s.sol --removed setPauser and setTeam in Deployment.s.sol for PairFactory --reversed the order of set emergencyCouncil and set governor to account for require(msg.sender == governor) -- added transferOwnership() for PairFactory instead of setTeam() --- scripts/Deployment.s.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 0d0500a6..957d57a4 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -99,14 +99,14 @@ contract Deployment is Script { votingEscrow.setTeam(TEAM_MULTI_SIG); minter.setTeam(TEAM_MULTI_SIG); - // Transfer pair factory ownership to multi-sig + // Transfer pairfactory ownership to MSIG (team) pairFactory.transferOwnership(TEAM_MULTI_SIG); - // Set voter's governor - voter.setGovernor(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)); From 20ad75a90b863ff7b0bf46f3b39ba133ba1d6035 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 8 Mar 2023 01:36:59 +0800 Subject: [PATCH 066/119] fix: fix FlowConvertorDeployment.s.sol --- scripts/FlowConvertorDeployment.s.sol | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/FlowConvertorDeployment.s.sol b/scripts/FlowConvertorDeployment.s.sol index 416f42e3..b8891caa 100644 --- a/scripts/FlowConvertorDeployment.s.sol +++ b/scripts/FlowConvertorDeployment.s.sol @@ -3,24 +3,25 @@ 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 = 0x0000000000000000000000000000000000000000; + 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 flowConvertor = new FlowConvertor({_v1: 0x2Baec546a92cA3469f71b7A091f7dF61e5569889, _v2: FLOW}); flowConvertor.transferOwnership(TEAM_MULTI_SIG); - IERC20(FLOW).transfer(address(flowConvertor), 50_000_000e18); + IFlow(FLOW).transfer(address(flowConvertor), FIFTY_MILLION); vm.stopBroadcast(); } From 5065e3394a7f62c8f20de623ca9387eeab0c2ec5 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 8 Mar 2023 01:37:51 +0800 Subject: [PATCH 067/119] fix: remove setting owner at constructor of FlowVestor --- contracts/FlowVestor.sol | 4 +--- scripts/TeamMemberVesting.s.sol | 10 +++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/contracts/FlowVestor.sol b/contracts/FlowVestor.sol index 8c835ba2..9b2a16ff 100644 --- a/contracts/FlowVestor.sol +++ b/contracts/FlowVestor.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/scripts/TeamMemberVesting.s.sol b/scripts/TeamMemberVesting.s.sol index c0f53855..ccbc795d 100644 --- a/scripts/TeamMemberVesting.s.sol +++ b/scripts/TeamMemberVesting.s.sol @@ -11,20 +11,20 @@ contract TeamMemberVesting is Script { address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; // team member addresses - address private constant T0RB1K = 0x0b776552c1aef1dc33005dd25acda22493b6615d; - address private constant MOTTO = 0x78e801136f77805239a7f533521a7a5570f572c8; - address private constant COOLIE = 0x03b88dacb7c21b54cefecc297d981e5b721a9df1; + address private constant T0RB1K = 0x0b776552c1Aef1Dc33005DD25AcDA22493b6615d; + address private constant MOTTO = 0x78e801136F77805239A7F533521A7a5570F572C8; + address private constant COOLIE = 0x03B88DacB7c21B54cEfEcC297D981E5b721A9dF1; address private constant ADMIN = 0xBC3043983276887f6b6F164Df33646479C9b1653; // TODO: Fill the address - address private constant FLOW = 0x0000000000000000000000000000000000000000; + address private constant FLOW = 0x78e489523291581205Ea3fA16a69689EcA79757A; function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); vm.startBroadcast(deployerPrivateKey); - FlowVestor flowVestor = new FlowVestor(ADMIN, FLOW); + FlowVestor flowVestor = new FlowVestor(FLOW); IERC20(FLOW).approve(address(flowVestor), 4_500_000e18); flowVestor.vestFor(T0RB1K, 2_000_000e18); From b63b3a71cd45fb9fa89c95ac16eb81bc9edeef1e Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 8 Mar 2023 02:08:57 +0800 Subject: [PATCH 068/119] chore: update hardhat.config.ts --- hardhat.config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 98d3f35b..1b6e11a1 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -28,7 +28,8 @@ const config: HardhatUserConfig = { initialBaseFeePerGas: 0, forking: { url: "https://canto.neobase.one", - } + }, + accounts: [{ privateKey: process.env.PRIVATE_KEY || '', balance: "999999999999999999999999999999999999" }] }, opera: { url: "https://rpc.fantom.network", From 337a331104a3f712bf577f0dd64c4cbe25b473c0 Mon Sep 17 00:00:00 2001 From: coolie Date: Tue, 7 Mar 2023 22:12:29 +0000 Subject: [PATCH 069/119] test: FlowConvertor redeem test --- test/FlowConvertor.t.sol | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test/FlowConvertor.t.sol 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); + } +} From 3ac2ef03853c48f0e57d0a7e03960b33601a237b Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 8 Mar 2023 12:24:11 +0800 Subject: [PATCH 070/119] fix: use IPairFactory in Pair.sol --- contracts/Pair.sol | 17 ++++++++--------- contracts/interfaces/IPairFactory.sol | 5 +++++ test/utils/TestOwner.sol | 1 + 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/contracts/Pair.sol b/contracts/Pair.sol index f031d916..8d1db394 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -5,8 +5,7 @@ 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'; @@ -83,8 +82,8 @@ contract Pair is IPair { constructor(uint256 _csrNftId) { factory = msg.sender; - voter = PairFactory(msg.sender).voter(); - (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())); @@ -117,7 +116,7 @@ contract Pair is IPair { } function tank() public view returns (address) { - return PairFactory(factory).tank(); + return IPairFactory(factory).tank(); } function setExternalBribe(address _externalBribe) external { @@ -305,7 +304,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 @@ -326,8 +325,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 @@ -384,7 +383,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/interfaces/IPairFactory.sol b/contracts/interfaces/IPairFactory.sol index f943725a..7e732fce 100644 --- a/contracts/interfaces/IPairFactory.sol +++ b/contracts/interfaces/IPairFactory.sol @@ -3,7 +3,12 @@ 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); } diff --git a/test/utils/TestOwner.sol b/test/utils/TestOwner.sol index 5f55f85c..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"; From 83062c44e4ca1c05eb5b263a0a6c46c1c11238ea Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 8 Mar 2023 21:05:09 +0800 Subject: [PATCH 071/119] fix: fix getting wrong pair address in router --- contracts/Pair.sol | 4 +++- contracts/factories/PairFactory.sol | 2 +- contracts/interfaces/IPairFactory.sol | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/Pair.sol b/contracts/Pair.sol index 8d1db394..4096c808 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -80,7 +80,7 @@ contract Pair is IPair { event ExternalBribeSet(address indexed externalBribe); event HasGaugeSet(bool value); - constructor(uint256 _csrNftId) { + constructor() { factory = msg.sender; voter = IPairFactory(msg.sender).voter(); (address _token0, address _token1, bool _stable) = IPairFactory(msg.sender).getInitializable(); @@ -97,6 +97,8 @@ 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); } diff --git a/contracts/factories/PairFactory.sol b/contracts/factories/PairFactory.sol index a75c5ee1..878ca233 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -92,7 +92,7 @@ contract PairFactory is IPairFactory, Ownable { require(getPair[token0][token1][stable] == address(0), 'PE'); // Pair: PAIR_EXISTS - single check is sufficient bytes32 salt = keccak256(abi.encodePacked(token0, token1, stable)); // notice salt includes stable as well, 3 parameters (_temp0, _temp1, _temp) = (token0, token1, stable); - pair = address(new Pair{salt:salt}(csrNftId)); + pair = address(new Pair{salt:salt}()); getPair[token0][token1][stable] = pair; getPair[token1][token0][stable] = pair; // populate mapping in the reverse direction allPairs.push(pair); diff --git a/contracts/interfaces/IPairFactory.sol b/contracts/interfaces/IPairFactory.sol index 7e732fce..0ed7eb3e 100644 --- a/contracts/interfaces/IPairFactory.sol +++ b/contracts/interfaces/IPairFactory.sol @@ -11,4 +11,5 @@ interface IPairFactory { 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); } From 72c14140726dc0fd48f1791d8fcba2e8db52f59d Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 8 Mar 2023 21:37:24 +0800 Subject: [PATCH 072/119] chore: hardcode deployer eoa address in scripts --- scripts/Deployment.s.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index 957d57a4..d94443d6 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -22,6 +22,8 @@ contract Deployment is Script { address private constant WCANTO = 0x826551890Dc65655a0Aceca109aB11AbDbD7a07B; // privileged accounts + // TODO: reset DEPLOYER_EOA + address private constant DEPLOYER_EOA = 0x92f644c99a185fEfc307fb4Bb54bCf0eD84462Ca; address private constant COUNCIL = 0x06b16991B53632C2362267579AE7C4863c72fDb8; address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; address private constant GOVERNOR = 0x06b16991B53632C2362267579AE7C4863c72fDb8; @@ -33,7 +35,7 @@ contract Deployment is Script { vm.startBroadcast(deployerPrivateKey); // Flow token - Flow flow = new Flow({initialSupplyRecipient: address(this), csrRecipient: TEAM_MULTI_SIG}); + Flow flow = new Flow({initialSupplyRecipient: DEPLOYER_EOA, csrRecipient: TEAM_MULTI_SIG}); uint256 csrNftId = flow.csrNftId(); // Gauge factory From ea45a862a8bacd0aedff43e04c37786bbd789edc Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 8 Mar 2023 22:49:07 +0800 Subject: [PATCH 073/119] chore: push latest hardhat setting --- hardhat.config.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 1b6e11a1..a80476ea 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -25,11 +25,23 @@ const remappings = fs const config: HardhatUserConfig = { networks: { hardhat: { + // mining: { + // auto: true, + // interval: 10000 + // }, + chainId: 7700, initialBaseFeePerGas: 0, forking: { url: "https://canto.neobase.one", }, - accounts: [{ privateKey: process.env.PRIVATE_KEY || '', balance: "999999999999999999999999999999999999" }] + accounts: [ + { privateKey: process.env.PRIVATE_KEY || '', balance: "999999999999999999999999999999999999" }, + // ADD private key here + // { privateKey: '', balance: "999999999999999999999999999999999999" }, + // { privateKey: '', balance: "999999999999999999999999999999999999" }, + // { privateKey: '', balance: "999999999999999999999999999999999999" }, + // { privateKey: '', balance: "999999999999999999999999999999999999" } + ] }, opera: { url: "https://rpc.fantom.network", From 8dafbf55e688febd08ac2309284e098f7046aa34 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 9 Mar 2023 08:20:43 +0800 Subject: [PATCH 074/119] fix: remove experimental features in router --- contracts/Router.sol | 125 ------------------------------------------- 1 file changed, 125 deletions(-) diff --git a/contracts/Router.sol b/contracts/Router.sol index 3f466d35..8515fd5c 100644 --- a/contracts/Router.sol +++ b/contracts/Router.sol @@ -423,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,) = (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,) = 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); - } } From 6e9c5911f526c0e83d01c20a17fb9a03e1c49663 Mon Sep 17 00:00:00 2001 From: coolie Date: Thu, 9 Mar 2023 00:46:31 +0000 Subject: [PATCH 075/119] fix: Handle tax tokens in notifyRewardAmount --- contracts/ExternalBribe.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/ExternalBribe.sol b/contracts/ExternalBribe.sol index a5ecc6d0..82c055f3 100644 --- a/contracts/ExternalBribe.sol +++ b/contracts/ExternalBribe.sol @@ -294,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; From bce355c7a2a14c38c7e3a9a6e6e8a15647fcd5da Mon Sep 17 00:00:00 2001 From: coolie Date: Thu, 9 Mar 2023 00:57:33 +0000 Subject: [PATCH 076/119] fix: Handle tax tokens in Gauge.notifyRewardAmount --- contracts/Gauge.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/Gauge.sol b/contracts/Gauge.sol index 139b9187..1e7a44e4 100644 --- a/contracts/Gauge.sol +++ b/contracts/Gauge.sol @@ -511,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); From 2225ec3f5b88c29a1cec753b7ee2e996a68f1a00 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 9 Mar 2023 12:28:37 +0800 Subject: [PATCH 077/119] fix: reduce MAX_REWARD_TOKENS from 16 to 4 in Gauge --- contracts/Gauge.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/Gauge.sol b/contracts/Gauge.sol index 1e7a44e4..4c1e6bbd 100644 --- a/contracts/Gauge.sol +++ b/contracts/Gauge.sol @@ -25,7 +25,7 @@ contract Gauge is IGauge { uint internal constant DURATION = 7 days; // rewards are released over 7 days uint internal constant PRECISION = 10 ** 18; - uint internal constant MAX_REWARD_TOKENS = 16; + uint internal constant MAX_REWARD_TOKENS = 4; // default snx staking contract implementation mapping(address => uint) public rewardRate; From 6cb145360e7641d497763e78ba3df977369bef78 Mon Sep 17 00:00:00 2001 From: Ceazor <73511897+Ceazor@users.noreply.github.com> Date: Wed, 8 Mar 2023 23:25:56 -0700 Subject: [PATCH 078/119] add TaxTkn notifyReward Logic to wExternalBribe --- contracts/WrappedExternalBribe.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/WrappedExternalBribe.sol b/contracts/WrappedExternalBribe.sol index fc6d91a6..c1403290 100644 --- a/contracts/WrappedExternalBribe.sol +++ b/contracts/WrappedExternalBribe.sol @@ -165,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; From d285c512d999d43134201cb0598b014b7b3df0e9 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 10 Mar 2023 14:03:09 +0800 Subject: [PATCH 079/119] fix: transfer all loose tokens to msig after deployment of vesting contract --- scripts/TeamMemberVesting.s.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/TeamMemberVesting.s.sol b/scripts/TeamMemberVesting.s.sol index ccbc795d..7a454051 100644 --- a/scripts/TeamMemberVesting.s.sol +++ b/scripts/TeamMemberVesting.s.sol @@ -9,7 +9,8 @@ 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 = 0x92f644c99a185fEfc307fb4Bb54bCf0eD84462Ca; // team member addresses address private constant T0RB1K = 0x0b776552c1Aef1Dc33005DD25AcDA22493b6615d; address private constant MOTTO = 0x78e801136F77805239A7F533521A7a5570F572C8; @@ -33,7 +34,8 @@ contract TeamMemberVesting is Script { flowVestor.transferOwnership(TEAM_MULTI_SIG); - IERC20(FLOW).transfer(TEAM_MULTI_SIG, 2_500_000e18); + uint256 looseTokens = IERC20(FLOW).balanceOf(DEPLOYER_EOA); + IERC20(FLOW).transfer(TEAM_MULTI_SIG, looseTokens); vm.stopBroadcast(); } From 50ffa43dda162156a748c47800e0872d923d40e1 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 10 Mar 2023 16:52:00 +0800 Subject: [PATCH 080/119] fix: update deployer eoa wallet --- scripts/Deployment.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Deployment.s.sol b/scripts/Deployment.s.sol index d94443d6..7184fdee 100644 --- a/scripts/Deployment.s.sol +++ b/scripts/Deployment.s.sol @@ -23,7 +23,7 @@ contract Deployment is Script { // privileged accounts // TODO: reset DEPLOYER_EOA - address private constant DEPLOYER_EOA = 0x92f644c99a185fEfc307fb4Bb54bCf0eD84462Ca; + address private constant DEPLOYER_EOA = 0xD93142ED5B85FcA4550153088750005759CE8318; address private constant COUNCIL = 0x06b16991B53632C2362267579AE7C4863c72fDb8; address private constant TEAM_MULTI_SIG = 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; address private constant GOVERNOR = 0x06b16991B53632C2362267579AE7C4863c72fDb8; From b6a1bbad3fd7a72a28db10a43d25f4890aa663cd Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 10 Mar 2023 17:35:36 +0800 Subject: [PATCH 081/119] fix: update deployer eoa wallet --- scripts/TeamMemberVesting.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/TeamMemberVesting.s.sol b/scripts/TeamMemberVesting.s.sol index 7a454051..2f8db8b3 100644 --- a/scripts/TeamMemberVesting.s.sol +++ b/scripts/TeamMemberVesting.s.sol @@ -10,7 +10,7 @@ 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 = 0x92f644c99a185fEfc307fb4Bb54bCf0eD84462Ca; + address private constant DEPLOYER_EOA = 0xD93142ED5B85FcA4550153088750005759CE8318; // team member addresses address private constant T0RB1K = 0x0b776552c1Aef1Dc33005DD25AcDA22493b6615d; address private constant MOTTO = 0x78e801136F77805239A7F533521A7a5570F572C8; From d08cf1d03661fbb5229951c6e89b6daf492bafef Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 10 Mar 2023 17:41:14 +0800 Subject: [PATCH 082/119] chore: remove unused address in team vesting deployment script --- scripts/TeamMemberVesting.s.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/TeamMemberVesting.s.sol b/scripts/TeamMemberVesting.s.sol index 2f8db8b3..f68b100a 100644 --- a/scripts/TeamMemberVesting.s.sol +++ b/scripts/TeamMemberVesting.s.sol @@ -16,7 +16,6 @@ contract TeamMemberVesting is Script { address private constant MOTTO = 0x78e801136F77805239A7F533521A7a5570F572C8; address private constant COOLIE = 0x03B88DacB7c21B54cEfEcC297D981E5b721A9dF1; - address private constant ADMIN = 0xBC3043983276887f6b6F164Df33646479C9b1653; // TODO: Fill the address address private constant FLOW = 0x78e489523291581205Ea3fA16a69689EcA79757A; From 7a60cde6a37d7654f5139a4946b5569c91d4bc82 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 10 Mar 2023 18:09:08 +0800 Subject: [PATCH 083/119] fix: remove unused constant in Minter.sol --- contracts/Minter.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/Minter.sol b/contracts/Minter.sol index 59632e8c..5c24a154 100644 --- a/contracts/Minter.sol +++ b/contracts/Minter.sol @@ -24,7 +24,6 @@ contract Minter is IMinter { IRewardsDistributor public immutable _rewards_distributor; 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; From 04a0d29f7015927704d4f208ae7a43db80e227d0 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:03:32 +0800 Subject: [PATCH 084/119] refactor: capitalize constant variables --- contracts/ExternalBribe.sol | 4 ++-- contracts/Gauge.sol | 4 ++-- contracts/Minter.sol | 4 ++-- contracts/Pair.sol | 4 ++-- contracts/RewardsDistributor.sol | 4 ++-- contracts/Router.sol | 4 ++-- contracts/VeloGovernor.sol | 4 ++-- contracts/Voter.sol | 4 ++-- contracts/VotingEscrow.sol | 4 ++-- contracts/WrappedExternalBribe.sol | 4 ++-- contracts/factories/BribeFactory.sol | 4 ++-- contracts/factories/GaugeFactory.sol | 4 ++-- contracts/factories/PairFactory.sol | 4 ++-- contracts/factories/WrappedExternalBribeFactory.sol | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/contracts/ExternalBribe.sol b/contracts/ExternalBribe.sol index 82c055f3..7debc02d 100644 --- a/contracts/ExternalBribe.sol +++ b/contracts/ExternalBribe.sol @@ -11,7 +11,7 @@ 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 constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable voter; // only voter can modify balances (since it only happens on vote()) address public immutable _ve; // 天使のたまご @@ -64,7 +64,7 @@ contract ExternalBribe is IBribe { } } - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/Gauge.sol b/contracts/Gauge.sol index 4c1e6bbd..b4dc9d43 100644 --- a/contracts/Gauge.sol +++ b/contracts/Gauge.sol @@ -12,7 +12,7 @@ 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 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; @@ -97,7 +97,7 @@ contract Gauge is IGauge { } } - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/Minter.sol b/contracts/Minter.sol index 5c24a154..c20ef892 100644 --- a/contracts/Minter.sol +++ b/contracts/Minter.sol @@ -13,7 +13,7 @@ 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; + 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; @@ -53,7 +53,7 @@ contract Minter is IMinter { _ve = IVotingEscrow(__ve); _rewards_distributor = IRewardsDistributor(__rewards_distributor); active_period = ((block.timestamp + (2 * WEEK)) / WEEK) * WEEK; - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } function initialMintAndLock( diff --git a/contracts/Pair.sol b/contracts/Pair.sol index 4096c808..a51c68ca 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -11,7 +11,7 @@ import 'contracts/interfaces/ITurnstile.sol'; // The base pair of pools, either stable or volatile contract Pair is IPair { - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; string public name; string public symbol; uint8 public constant decimals = 18; @@ -99,7 +99,7 @@ contract Pair is IPair { observations.push(Observation(block.timestamp, 0, 0)); uint256 _csrNftId = IPairFactory(msg.sender).csrNftId(); - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/RewardsDistributor.sol b/contracts/RewardsDistributor.sol index 351a8eac..315248dd 100644 --- a/contracts/RewardsDistributor.sol +++ b/contracts/RewardsDistributor.sol @@ -29,7 +29,7 @@ contract RewardsDistributor is IRewardsDistributor { uint max_epoch ); - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; uint constant WEEK = 7 * 86400; uint public start_time; @@ -58,7 +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); + ITurnstile(TURNSTILE).assign(_csrNftId); } function timestamp() external view returns (uint) { diff --git a/contracts/Router.sol b/contracts/Router.sol index 8515fd5c..4e75a4f3 100644 --- a/contracts/Router.sol +++ b/contracts/Router.sol @@ -18,7 +18,7 @@ contract Router is IRouter { bool stable; } - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable factory; IWETH public immutable weth; uint internal constant MINIMUM_LIQUIDITY = 10**3; @@ -33,7 +33,7 @@ contract Router is IRouter { factory = _factory; pairCodeHash = IPairFactory(_factory).pairCodeHash(); weth = IWETH(_weth); - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } receive() external payable { diff --git a/contracts/VeloGovernor.sol b/contracts/VeloGovernor.sol index 8a832a56..3cdec942 100644 --- a/contracts/VeloGovernor.sol +++ b/contracts/VeloGovernor.sol @@ -16,7 +16,7 @@ contract VeloGovernor is L2GovernorVotes, L2GovernorVotesQuorumFraction { - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public team; uint256 public constant MAX_PROPOSAL_NUMERATOR = 50; // max 5% uint256 public constant PROPOSAL_DENOMINATOR = 1000; @@ -28,7 +28,7 @@ contract VeloGovernor is L2GovernorVotesQuorumFraction(4) // 4% { team = msg.sender; - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } function votingDelay() public pure override(IGovernor) returns (uint256) { diff --git a/contracts/Voter.sol b/contracts/Voter.sol index cd6a85b4..02adb259 100644 --- a/contracts/Voter.sol +++ b/contracts/Voter.sol @@ -16,7 +16,7 @@ import 'contracts/interfaces/ITurnstile.sol'; import 'contracts/interfaces/IWrappedExternalBribeFactory.sol'; contract Voter is IVoter { - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + 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; @@ -66,7 +66,7 @@ contract Voter is IVoter { minter = msg.sender; governor = msg.sender; emergencyCouncil = msg.sender; - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol index d083cc36..81d43185 100644 --- a/contracts/VotingEscrow.sol +++ b/contracts/VotingEscrow.sol @@ -64,7 +64,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable owner; address public immutable token; address public voter; @@ -104,7 +104,7 @@ contract VotingEscrow is IERC721, IERC721Metadata, IVotes { supportedInterfaces[ERC721_INTERFACE_ID] = true; supportedInterfaces[ERC721_METADATA_INTERFACE_ID] = true; - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); // mint-ish emit Transfer(address(0), address(this), tokenId); diff --git a/contracts/WrappedExternalBribe.sol b/contracts/WrappedExternalBribe.sol index c1403290..823ad629 100644 --- a/contracts/WrappedExternalBribe.sol +++ b/contracts/WrappedExternalBribe.sol @@ -11,7 +11,7 @@ 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 constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable voter; address public immutable _ve; ExternalBribe public underlying_bribe; @@ -48,7 +48,7 @@ contract WrappedExternalBribe { } } - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/factories/BribeFactory.sol b/contracts/factories/BribeFactory.sol index 53c46210..3dcf0e01 100644 --- a/contracts/factories/BribeFactory.sol +++ b/contracts/factories/BribeFactory.sol @@ -6,12 +6,12 @@ import 'contracts/ExternalBribe.sol'; import 'contracts/interfaces/ITurnstile.sol'; contract BribeFactory is IBribeFactory { - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public last_external_bribe; uint256 public immutable csrNftId; constructor(uint256 _csrNftId) { - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); csrNftId = _csrNftId; } diff --git a/contracts/factories/GaugeFactory.sol b/contracts/factories/GaugeFactory.sol index bc839b47..8ad157a8 100644 --- a/contracts/factories/GaugeFactory.sol +++ b/contracts/factories/GaugeFactory.sol @@ -6,12 +6,12 @@ import 'contracts/Gauge.sol'; import 'contracts/interfaces/ITurnstile.sol'; contract GaugeFactory is IGaugeFactory { - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public last_gauge; uint256 public immutable csrNftId; constructor(uint256 _csrNftId) { - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); csrNftId = _csrNftId; } function createGauge(address _pool, address _external_bribe, address _ve, bool isPair, address[] memory allowedRewards) external returns (address) { diff --git a/contracts/factories/PairFactory.sol b/contracts/factories/PairFactory.sol index 878ca233..9a9f595b 100644 --- a/contracts/factories/PairFactory.sol +++ b/contracts/factories/PairFactory.sol @@ -7,7 +7,7 @@ import 'contracts/interfaces/ITurnstile.sol'; import "openzeppelin-contracts/contracts/access/Ownable.sol"; contract PairFactory is IPairFactory, Ownable { - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; bool public isPaused; uint256 public stableFee; uint256 public volatileFee; @@ -37,7 +37,7 @@ contract PairFactory is IPairFactory, Ownable { stableFee = 3; // 0.03% volatileFee = 25; // 0.25% deployer = msg.sender; - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); csrNftId = _csrNftId; } diff --git a/contracts/factories/WrappedExternalBribeFactory.sol b/contracts/factories/WrappedExternalBribeFactory.sol index 9ceaf569..3d4fc78b 100644 --- a/contracts/factories/WrappedExternalBribeFactory.sol +++ b/contracts/factories/WrappedExternalBribeFactory.sol @@ -5,7 +5,7 @@ import {WrappedExternalBribe} from 'contracts/WrappedExternalBribe.sol'; import 'contracts/interfaces/ITurnstile.sol'; contract WrappedExternalBribeFactory { - address public constant turnstile = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public voter; mapping(address => address) public oldBribeToNew; address public last_bribe; @@ -14,7 +14,7 @@ contract WrappedExternalBribeFactory { event VoterSet(address indexed setter, address indexed voter); constructor(uint256 _csrNftId) { - ITurnstile(turnstile).assign(_csrNftId); + ITurnstile(TURNSTILE).assign(_csrNftId); csrNftId = _csrNftId; } From b2bb5c8f98ac551db3568e3282dc753bd36a9126 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:08:41 +0800 Subject: [PATCH 085/119] fix: remove duplicated deployOwners --- test/NFTVote.t.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/test/NFTVote.t.sol b/test/NFTVote.t.sol index 45d68040..4e599df2 100644 --- a/test/NFTVote.t.sol +++ b/test/NFTVote.t.sol @@ -18,7 +18,6 @@ contract NFTVoteTest is BaseTest { FlagCondition flag; function setUp() public { - deployOwners(); deployCoins(); deployOwners(); From 4ff8031a01c33fab5c48d8a05864ee318129dc44 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:10:49 +0800 Subject: [PATCH 086/119] refactor: rename FOUR_YEARS in test cases --- test/Minter.t.sol | 2 +- test/MinterTeamEmissions.t.sol | 2 +- test/Pair.t.sol | 2 +- test/VeloVoting.t.sol | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Minter.t.sol b/test/Minter.t.sol index 5fc7cfb9..07060a63 100644 --- a/test/Minter.t.sol +++ b/test/Minter.t.sol @@ -73,7 +73,7 @@ contract MinterTest is BaseTest { claims[0] = Minter.Claim({ claimant: address(owner), amount: TOKEN_1M, - lockTime: 86400 * 7 * 52 * 4 + lockTime: FOUR_YEARS }); minter.initialMintAndLock(claims, 2e25); minter.startActivePeriod(); diff --git a/test/MinterTeamEmissions.t.sol b/test/MinterTeamEmissions.t.sol index 17410d2f..daa2fc46 100644 --- a/test/MinterTeamEmissions.t.sol +++ b/test/MinterTeamEmissions.t.sol @@ -91,7 +91,7 @@ contract MinterTeamEmissions is BaseTest { claims[0] = Minter.Claim({ claimant: address(owner), amount: TOKEN_1M, - lockTime: 86400 * 7 * 52 * 4 + lockTime: FOUR_YEARS }); minter.initialMintAndLock(claims, 13 * TOKEN_1M); minter.startActivePeriod(); diff --git a/test/Pair.t.sol b/test/Pair.t.sol index 0e5af918..4cc73ac4 100644 --- a/test/Pair.t.sol +++ b/test/Pair.t.sol @@ -596,7 +596,7 @@ contract PairTest is BaseTest { claims[0] = Minter.Claim({ claimant: address(owner), amount: TOKEN_1, - lockTime: 86400 * 7 * 52 * 4 + lockTime: FOUR_YEARS }); minter.initialMintAndLock(claims, TOKEN_1); minter.startActivePeriod(); diff --git a/test/VeloVoting.t.sol b/test/VeloVoting.t.sol index 2927906d..19606959 100644 --- a/test/VeloVoting.t.sol +++ b/test/VeloVoting.t.sol @@ -93,7 +93,7 @@ contract VeloVotingTest is BaseTest { claims[0] = Minter.Claim({ claimant: address(owner), amount: TOKEN_1M, - lockTime: 86400 * 7 * 52 * 4 + lockTime: FOUR_YEARS }); minter.initialMintAndLock(claims, 13 * TOKEN_1M); minter.startActivePeriod(); From 0c4dedd6ad34c4190662b73727c70ae8a20df19d Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:14:30 +0800 Subject: [PATCH 087/119] refactor: remove optimismConfig.ts --- tasks/deploy/constants/optimismConfig.ts | 97 ------------------------ tasks/deploy/op.ts | 3 +- 2 files changed, 1 insertion(+), 99 deletions(-) delete mode 100644 tasks/deploy/constants/optimismConfig.ts diff --git a/tasks/deploy/constants/optimismConfig.ts b/tasks/deploy/constants/optimismConfig.ts deleted file mode 100644 index f25a4c4d..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 - // "", // pxFLOW -- N/A - "0xc40F949F8a4e094D1b49a23ea9241D289B7b2819", // LUSD - // "", // wstETH -- N/A - // "", // HOP -- N/A - ], - partnerAddrs: [ - TEAM_EOA, // FLOW - "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 afff85c7..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 [ From c994703e64cc1709a57a45a5732d844c43c7c967 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:15:39 +0800 Subject: [PATCH 088/119] chore: remove commented code in hardhat.config.ts --- hardhat.config.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index a80476ea..ccfd719a 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -25,10 +25,6 @@ const remappings = fs const config: HardhatUserConfig = { networks: { hardhat: { - // mining: { - // auto: true, - // interval: 10000 - // }, chainId: 7700, initialBaseFeePerGas: 0, forking: { @@ -36,11 +32,6 @@ const config: HardhatUserConfig = { }, accounts: [ { privateKey: process.env.PRIVATE_KEY || '', balance: "999999999999999999999999999999999999" }, - // ADD private key here - // { privateKey: '', balance: "999999999999999999999999999999999999" }, - // { privateKey: '', balance: "999999999999999999999999999999999999" }, - // { privateKey: '', balance: "999999999999999999999999999999999999" }, - // { privateKey: '', balance: "999999999999999999999999999999999999" } ] }, opera: { From 54f3b50107cb648562b3d5ac05f6aeeac2dcb8cb Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:17:21 +0800 Subject: [PATCH 089/119] chore: move constant immutable variable tgt in WrappedExternalBribeFactory --- contracts/factories/WrappedExternalBribeFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/factories/WrappedExternalBribeFactory.sol b/contracts/factories/WrappedExternalBribeFactory.sol index 3d4fc78b..09b0d5ea 100644 --- a/contracts/factories/WrappedExternalBribeFactory.sol +++ b/contracts/factories/WrappedExternalBribeFactory.sol @@ -6,10 +6,10 @@ 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; - uint256 public immutable csrNftId; event VoterSet(address indexed setter, address indexed voter); From 692859eb0f7a27e1610fee5aedaf9747237d4e65 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:21:56 +0800 Subject: [PATCH 090/119] fix: change csrNftId to immutable in Flow.sol --- contracts/Flow.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/Flow.sol b/contracts/Flow.sol index 14a9b571..54343eed 100644 --- a/contracts/Flow.sol +++ b/contracts/Flow.sol @@ -9,7 +9,7 @@ contract Flow is IFlow { string public constant symbol = "FLOW"; uint8 public constant decimals = 18; uint public totalSupply = 0; - uint256 public csrNftId; + uint256 public immutable csrNftId; mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; From f975dbcbd2db71783ef040f31352d521a1273612 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:23:02 +0800 Subject: [PATCH 091/119] fix: add TURNSTILE address as constant in Flow.sol --- contracts/Flow.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/Flow.sol b/contracts/Flow.sol index 54343eed..b0caab09 100644 --- a/contracts/Flow.sol +++ b/contracts/Flow.sol @@ -5,6 +5,7 @@ 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; @@ -23,7 +24,7 @@ contract Flow is IFlow { minter = msg.sender; _mint(initialSupplyRecipient, 82800140034502500000000000); - csrNftId = ITurnstile(0xEcf044C5B4b867CFda001101c617eCd347095B44).register(csrRecipient); + csrNftId = ITurnstile(TURNSTILE).register(csrRecipient); } // No checks as its meant to be once off to set minting rights to BaseV1 Minter From 9ea99e15a817b35e3dfff1c7437ab86923f5d200 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 11 Mar 2023 12:24:32 +0800 Subject: [PATCH 092/119] refactor: rename variable amount0 to amount in events of Pair.sol --- contracts/Pair.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/Pair.sol b/contracts/Pair.sol index a51c68ca..943b5d24 100644 --- a/contracts/Pair.sol +++ b/contracts/Pair.sol @@ -60,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( From 6ffe615495301d6e6ee9f1fe261f7d901d8c8645 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 20 Apr 2023 12:38:25 +0800 Subject: [PATCH 093/119] fix: add wrapped bribe --- contracts/WrappedBribe.sol | 195 ++++++++++ contracts/factories/WrappedBribeFactory.sol | 28 ++ test/WrappedBribes.t.sol | 398 ++++++++++++++++++++ 3 files changed, 621 insertions(+) create mode 100644 contracts/WrappedBribe.sol create mode 100644 contracts/factories/WrappedBribeFactory.sol create mode 100644 test/WrappedBribes.t.sol diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol new file mode 100644 index 00000000..938c10f8 --- /dev/null +++ b/contracts/WrappedBribe.sol @@ -0,0 +1,195 @@ +// 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/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 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 => mapping(uint => uint)) public lastEarn; + + address[] public rewards; + mapping(address => bool) public isReward; + + /// @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); + + constructor(address _voter, address _old_bribe) { + 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); + } + } + } + + // 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)); + for (uint i = 0; i < tokens.length; i++) { + uint _reward = earned(tokens[i], tokenId); + lastEarn[tokens[i]][tokenId] = block.timestamp; + if (_reward > 0) _safeTransfer(tokens[i], msg.sender, _reward); + + 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); + for (uint i = 0; i < tokens.length; i++) { + uint _reward = earned(tokens[i], tokenId); + lastEarn[tokens[i]][tokenId] = block.timestamp; + if (_reward > 0) _safeTransfer(tokens[i], _owner, _reward); + + 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; + + periodFinish[token] = adjustedTstamp + DURATION; + + if (!isReward[token]) { + isReward[token] = true; + rewards.push(token); + } + + emit NotifyReward(msg.sender, token, adjustedTstamp, amount); + } + + 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/factories/WrappedBribeFactory.sol b/contracts/factories/WrappedBribeFactory.sol new file mode 100644 index 00000000..6ba5d250 --- /dev/null +++ b/contracts/factories/WrappedBribeFactory.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.13; + +import {WrappedBribe} from 'contracts/WrappedBribe.sol'; + +contract WrappedBribeFactory { + address public voter; + mapping(address => address) public oldBribeToNew; + address public last_bribe; + + event VoterSet(address indexed setter, address indexed voter); + + 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)); + oldBribeToNew[existing_bribe] = last_bribe; + return last_bribe; + } + + function setVoter(address _voter) external { + require(voter == address(0), "Already initialized"); + voter = _voter; + emit VoterSet(msg.sender, _voter); + } +} diff --git a/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol new file mode 100644 index 00000000..91b453b3 --- /dev/null +++ b/test/WrappedBribes.t.sol @@ -0,0 +1,398 @@ +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]); + deployPairFactoryAndRouter(); + + // deployVoter() + gaugeFactory = new GaugeFactory(); + bribeFactory = new BribeFactory(); + wxbribeFactory = new WrappedBribeFactory(); + voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + + escrow.setVoter(address(voter)); + wxbribeFactory.setVoter(address(voter)); + factory.setVoter(address(voter)); + deployPairWithOwner(address(owner)); + + // deployMinter() + distributor = new RewardsDistributor(address(escrow)); + minter = new Minter(address(voter), address(escrow), address(distributor)); + 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); + + uint256 pre = LR.balanceOf(address(owner)); + 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); + } +} \ No newline at end of file From 792e44f453b074332cb1c075e62699011e940e80 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 20 Apr 2023 12:49:57 +0800 Subject: [PATCH 094/119] feat: add handle left over bribes --- contracts/WrappedBribe.sol | 41 ++++++++++ test/WrappedBribes.t.sol | 155 +++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol index 938c10f8..007f27db 100644 --- a/contracts/WrappedBribe.sol +++ b/contracts/WrappedBribe.sol @@ -171,6 +171,47 @@ contract WrappedBribe { emit NotifyReward(msg.sender, token, adjustedTstamp, amount); } + // 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); + (_ts, _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); diff --git a/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol index 91b453b3..a35464a8 100644 --- a/test/WrappedBribes.t.sol +++ b/test/WrappedBribes.t.sol @@ -395,4 +395,159 @@ contract WrappedBribesTest is BaseTest { 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); + } + } \ No newline at end of file From 3554df75c1dc097614d4266ef9cd62103f2056e5 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 20 Apr 2023 12:54:57 +0800 Subject: [PATCH 095/119] fix: add events --- contracts/WrappedBribe.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol index 007f27db..f53ce105 100644 --- a/contracts/WrappedBribe.sol +++ b/contracts/WrappedBribe.sol @@ -32,6 +32,7 @@ contract WrappedBribe { 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) { voter = _voter; @@ -177,7 +178,7 @@ contract WrappedBribe { // require that supply of that epoch to be ZERO uint epochStart = getEpochStart(epochTimestamp); - (_ts, _supply) = underlying_bribe.supplyCheckpoints(underlying_bribe.getPriorSupplyIndex(epochStart + DURATION)); + (uint _ts, uint _supply) = underlying_bribe.supplyCheckpoints(underlying_bribe.getPriorSupplyIndex(epochStart + DURATION)); if (epochStart + DURATION > _bribeStart(_ts)) { require(_supply == 0, "this epoch has votes"); } From a2820f416757bdde1957ccf181b3cb6cb0ec9090 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 20 Apr 2023 14:06:36 +0800 Subject: [PATCH 096/119] fix: add csr to wrapped bribe --- contracts/WrappedBribe.sol | 5 +++- contracts/factories/WrappedBribeFactory.sol | 19 ++++++++------- scripts/DeployWrappedBribeFactory.s.sol | 26 +++++++++++++++++++++ test/WrappedBribes.t.sol | 15 ++++++------ 4 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 scripts/DeployWrappedBribeFactory.s.sol diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol index f53ce105..6328e3d9 100644 --- a/contracts/WrappedBribe.sol +++ b/contracts/WrappedBribe.sol @@ -10,6 +10,7 @@ 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; @@ -34,7 +35,7 @@ contract WrappedBribe { 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) { + constructor(address _voter, address _old_bribe, uint256 _csrNftId) { voter = _voter; _ve = IVoter(_voter)._ve(); underlying_bribe = ExternalBribe(_old_bribe); @@ -46,6 +47,8 @@ contract WrappedBribe { rewards.push(underlying_reward); } } + + ITurnstile(TURNSTILE).assign(_csrNftId); } // simple re-entrancy check diff --git a/contracts/factories/WrappedBribeFactory.sol b/contracts/factories/WrappedBribeFactory.sol index 6ba5d250..e1cfdb18 100644 --- a/contracts/factories/WrappedBribeFactory.sol +++ b/contracts/factories/WrappedBribeFactory.sol @@ -2,27 +2,28 @@ pragma solidity 0.8.13; import {WrappedBribe} from 'contracts/WrappedBribe.sol'; +import 'contracts/interfaces/ITurnstile.sol'; contract WrappedBribeFactory { - address public voter; + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + uint256 public immutable csrNftId; + address public immutable voter; mapping(address => address) public oldBribeToNew; address public last_bribe; - event VoterSet(address indexed setter, address indexed voter); + 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)); + last_bribe = address(new WrappedBribe(voter, existing_bribe, csrNftId)); oldBribeToNew[existing_bribe] = last_bribe; return last_bribe; } - - function setVoter(address _voter) external { - require(voter == address(0), "Already initialized"); - voter = _voter; - emit VoterSet(msg.sender, _voter); - } } diff --git a/scripts/DeployWrappedBribeFactory.s.sol b/scripts/DeployWrappedBribeFactory.s.sol new file mode 100644 index 00000000..3c2ff518 --- /dev/null +++ b/scripts/DeployWrappedBribeFactory.s.sol @@ -0,0 +1,26 @@ +// 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/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol index a35464a8..4038ee84 100644 --- a/test/WrappedBribes.t.sol +++ b/test/WrappedBribes.t.sol @@ -33,23 +33,22 @@ contract WrappedBribesTest is BaseTest { mintFlow(owners, amounts); mintLR(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); - escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0]); + escrow = new VotingEscrow(address(FLOW), address(artProxy), owners[0], csrNftId); deployPairFactoryAndRouter(); // deployVoter() - gaugeFactory = new GaugeFactory(); - bribeFactory = new BribeFactory(); - wxbribeFactory = new WrappedBribeFactory(); - voter = new Voter(address(escrow), address(factory), address(gaugeFactory), address(bribeFactory), address(wxbribeFactory)); + 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)); - wxbribeFactory.setVoter(address(voter)); factory.setVoter(address(voter)); 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)); FLOW.setMinter(address(minter)); address[] memory tokens = new address[](5); From 31435b3f40991f47de5526932d40ffcf037aba85 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 23 Apr 2023 22:13:38 +0800 Subject: [PATCH 097/119] feat: add updateRewardAmount in wrapped bribe contract for balance discrepancy --- contracts/WrappedBribe.sol | 46 +++++++++++++++++++++- test/WrappedBribes.t.sol | 80 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol index 6328e3d9..d3269cdf 100644 --- a/contracts/WrappedBribe.sol +++ b/contracts/WrappedBribe.sol @@ -24,6 +24,7 @@ contract WrappedBribe { address[] public rewards; mapping(address => bool) public isReward; + mapping(address => uint) public tokenRewardBalance; /// @notice A checkpoint for marking balance struct RewardCheckpoint { @@ -82,10 +83,17 @@ contract WrappedBribe { // 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) _safeTransfer(tokens[i], msg.sender, _reward); + 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); } @@ -95,10 +103,17 @@ contract WrappedBribe { 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) _safeTransfer(tokens[i], _owner, _reward); + 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); } @@ -164,6 +179,7 @@ contract WrappedBribe { amount = balanceAfter - balanceBefore; tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount; + tokenRewardBalance[token] += amount; periodFinish[token] = adjustedTstamp + DURATION; @@ -175,6 +191,32 @@ contract WrappedBribe { 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; + + 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"); diff --git a/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol index 4038ee84..00402c59 100644 --- a/test/WrappedBribes.t.sol +++ b/test/WrappedBribes.t.sol @@ -549,4 +549,84 @@ contract WrappedBribesTest is BaseTest { 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); + } } \ No newline at end of file From 417aa0917f5fac84009258595ca1ad897289cd2e Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sun, 23 Apr 2023 22:36:17 +0800 Subject: [PATCH 098/119] fix: add test case for updateRewardAmount --- test/WrappedBribes.t.sol | 72 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol index 00402c59..a170cc5a 100644 --- a/test/WrappedBribes.t.sol +++ b/test/WrappedBribes.t.sol @@ -629,4 +629,76 @@ contract WrappedBribesTest is BaseTest { 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 From a501c31c9fb8e1abf63866f41f0365242712add4 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 25 Apr 2023 21:43:02 +0800 Subject: [PATCH 099/119] feat: add autobribe --- contracts/AutoBribe.sol | 141 ++++++++++++++++++++ contracts/WrappedBribe.sol | 1 + contracts/factories/WrappedBribeFactory.sol | 20 ++- test/WrappedBribes.t.sol | 3 +- 4 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 contracts/AutoBribe.sol diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol new file mode 100644 index 00000000..a22ce335 --- /dev/null +++ b/contracts/AutoBribe.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT + +import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; +import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; +import "openzeppelin-contracts/contracts/utils/math/SafeMath.sol"; +import "openzeppelin-contracts/contracts/access/Ownable.sol"; +import "openzeppelin-contracts/contracts/utils/Context.sol"; +import "openzeppelin-contracts/contracts/utils/Address.sol"; +import 'contracts/interfaces/ITurnstile.sol'; +import {WrappedBribe} from '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 know the appropriate wrappedExternalBribe contract address +// 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 check for additional bribe tokens that may have been sent to the contract by accident +// each new deposit will make a bribe immediately! +// calling the bribe function is public and is rewarded with a share of the bribe token +// !!!!!!!!!!!this contract only handles a single bribe token, and a single bribe contract!!!!!!!!! + +contract AutoBribe is Ownable { + using SafeERC20 for IERC20; + using SafeMath for uint256; + + address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public immutable wBribe; + + address public project; + uint256 public nextWeek; + address[] public bribeTokens; + mapping(address => bool) bribeTokensDeposited; + mapping(address => uint256) bribeTokenToWeeksLeft; + + constructor(address _wBribe, address _team, uint256 _csrNftId) { + wBribe = _wBribe; + _transferOwnership(_team); + ITurnstile(TURNSTILE).assign(_csrNftId); + } + + //####USER FUNCTIONS##### + + function depositAll( + address[] memory _bribeTokens, + uint256 _weeks + ) external { + uint256 length = _bribeTokens.length; + for (uint256 i = 0; i < length; ) { + address bribeToken = _bribeTokens[i]; + deposit( + bribeToken, + IERC20(bribeToken).balanceOf(msg.sender), + _weeks + ); + unchecked { + ++i; + } + } + } + + 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"); + IERC20(_bribeToken).safeTransferFrom( + msg.sender, + address(this), + _amount + ); + if (!bribeTokensDeposited[_bribeToken]) { + bribeTokensDeposited[_bribeToken] = true; + bribeTokens.push(_bribeToken); + } + bribeTokenToWeeksLeft[_bribeToken] = _weeks; + } + + function bribe() public { + uint256 length = bribeTokens.length; + address _bribeToken; + for (uint256 i = 0; i < length; ) { + if (block.timestamp >= nextWeek) { + _bribeToken = bribeTokens[i]; + uint256 weeksLeft = bribeTokenToWeeksLeft[_bribeToken]; + uint256 bribeAmount = balance(_bribeToken) / weeksLeft; + uint256 gasReward = bribeAmount / 10000; + IERC20(_bribeToken).safeTransferFrom( + address(this), + msg.sender, + gasReward + ); + WrappedBribe(wBribe).notifyRewardAmount(_bribeToken, bribeAmount - gasReward); + bribeTokenToWeeksLeft[_bribeToken] = weeksLeft - 1; + } + unchecked { + ++i; + } + } + + nextWeek = nextWeek + 604800; + } + + function balance(address _bribeToken) public view returns (uint) { + return IERC20(_bribeToken).balanceOf(address(this)); + } + + //####Admin Functions##### + function emptyOut() public { + require(msg.sender == project); + + uint256 length = bribeTokens.length; + uint256 amount; + + for (uint256 i = 0; i < length; ) { + address bribeToken = bribeTokens[i]; + amount = balance(bribeToken); + bribeTokensDeposited[bribeToken] = false; + bribeTokenToWeeksLeft[bribeToken] = 0; + IERC20(bribeToken).safeTransfer(msg.sender, amount); + + unchecked { + ++i; + } + } + } + + function setProject(address _newWallet) public { + require(msg.sender == project || msg.sender == owner()); + project = _newWallet; + } + + function inCaseTokensGetStuck(address _token) external onlyOwner { + require(!bribeTokensDeposited[_token], "!bribeToken"); + uint256 amount = IERC20(_token).balanceOf(address(this)); + IERC20(_token).safeTransfer(msg.sender, amount); + } +} diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol index d3269cdf..de849d64 100644 --- a/contracts/WrappedBribe.sol +++ b/contracts/WrappedBribe.sol @@ -5,6 +5,7 @@ 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'; diff --git a/contracts/factories/WrappedBribeFactory.sol b/contracts/factories/WrappedBribeFactory.sol index e1cfdb18..63bf322d 100644 --- a/contracts/factories/WrappedBribeFactory.sol +++ b/contracts/factories/WrappedBribeFactory.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.13; +import {AutoBribe} from 'contracts/AutoBribe.sol'; import {WrappedBribe} from 'contracts/WrappedBribe.sol'; import 'contracts/interfaces/ITurnstile.sol'; @@ -8,10 +9,13 @@ contract WrappedBribeFactory { address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; uint256 public immutable csrNftId; address public immutable voter; + address public immutable team; mapping(address => address) public oldBribeToNew; + mapping(address => address) public oldBribeToAutoBribe; address public last_bribe; - constructor(address _voter, uint256 _csrNftId) { + constructor(address _team, address _voter, uint256 _csrNftId) { + team = _team; voter = _voter; ITurnstile(TURNSTILE).assign(_csrNftId); csrNftId = _csrNftId; @@ -26,4 +30,18 @@ contract WrappedBribeFactory { oldBribeToNew[existing_bribe] = last_bribe; return last_bribe; } + + function createAutoBribe(address existing_bribe) external returns (address auto_bribe) { + address wBribe = oldBribeToNew[existing_bribe]; + require( + oldBribeToNew[existing_bribe] != address(0), + "Wrapped bribe not yet created" + ); + require( + oldBribeToAutoBribe[existing_bribe] == address(0), + "Auto bribe already created" + ); + auto_bribe = address(new AutoBribe(wBribe, team, csrNftId)); + oldBribeToAutoBribe[existing_bribe] = auto_bribe; + } } diff --git a/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol index a170cc5a..0a67a1c5 100644 --- a/test/WrappedBribes.t.sol +++ b/test/WrappedBribes.t.sol @@ -40,7 +40,7 @@ contract WrappedBribesTest is BaseTest { 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); + wxbribeFactory = new WrappedBribeFactory(address(owner), address(voter), csrNftId); escrow.setVoter(address(voter)); factory.setVoter(address(voter)); @@ -307,7 +307,6 @@ contract WrappedBribesTest is BaseTest { // Middle of epoch 4 vm.warp(block.timestamp + 1 weeks / 2); - uint256 pre = LR.balanceOf(address(owner)); console2.log(""); console2.log("Epoch 4: BEFORE checking 1"); uint256 earned = wxbribe.earned(address(LR), 1); From 8632d46e74f4c57a7a9fcfd18dac040d0b7e2dd3 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 25 Apr 2023 21:59:43 +0800 Subject: [PATCH 100/119] refactor: reuse declared vairables in WrappedBribeFactory --- contracts/factories/WrappedBribeFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/factories/WrappedBribeFactory.sol b/contracts/factories/WrappedBribeFactory.sol index 63bf322d..43f95ca1 100644 --- a/contracts/factories/WrappedBribeFactory.sol +++ b/contracts/factories/WrappedBribeFactory.sol @@ -34,7 +34,7 @@ contract WrappedBribeFactory { function createAutoBribe(address existing_bribe) external returns (address auto_bribe) { address wBribe = oldBribeToNew[existing_bribe]; require( - oldBribeToNew[existing_bribe] != address(0), + wBribe != address(0), "Wrapped bribe not yet created" ); require( From d530a9c12958b2f3d8595d0fb096ec7ef9d2ac56 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 26 Apr 2023 09:28:14 +0800 Subject: [PATCH 101/119] feat: add seal() in AutoBribe --- contracts/AutoBribe.sol | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index a22ce335..7a501899 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -12,13 +12,11 @@ import {WrappedBribe} from '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 know the appropriate wrappedExternalBribe contract address // 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 check for additional bribe tokens that may have been sent to the contract by accident -// each new deposit will make a bribe immediately! +// 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 only handles a single bribe token, and a single bribe contract!!!!!!!!! +// !!!!!!!!!!!this contract handles multiple bribe tokens, and a single bribe contract!!!!!!!!! contract AutoBribe is Ownable { using SafeERC20 for IERC20; @@ -28,6 +26,7 @@ contract AutoBribe is Ownable { address public immutable wBribe; address public project; + bool sealed; uint256 public nextWeek; address[] public bribeTokens; mapping(address => bool) bribeTokensDeposited; @@ -93,7 +92,10 @@ contract AutoBribe is Ownable { msg.sender, gasReward ); - WrappedBribe(wBribe).notifyRewardAmount(_bribeToken, bribeAmount - gasReward); + WrappedBribe(wBribe).notifyRewardAmount( + _bribeToken, + bribeAmount - gasReward + ); bribeTokenToWeeksLeft[_bribeToken] = weeksLeft - 1; } unchecked { @@ -111,7 +113,7 @@ contract AutoBribe is Ownable { //####Admin Functions##### function emptyOut() public { require(msg.sender == project); - + require(!sealed); uint256 length = bribeTokens.length; uint256 amount; @@ -128,6 +130,17 @@ contract AutoBribe is Ownable { } } + //Allows project to seal the vault making it not possible for them to withdraw their tokens + function seal() public { + require(msg.sender = project); + sealed = true; + } + + //Allows Velocimeter to re allow project to withdraw their tokens + function unSeal() public onlyOwner { + sealed = false; + } + function setProject(address _newWallet) public { require(msg.sender == project || msg.sender == owner()); project = _newWallet; From e41e46e97d502896512c62c868492b22b6d1228e Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 27 Apr 2023 11:09:30 +0800 Subject: [PATCH 102/119] fix: add identifier for sealed in AutoBribe --- contracts/AutoBribe.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index 7a501899..2885ca2e 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -26,7 +26,7 @@ contract AutoBribe is Ownable { address public immutable wBribe; address public project; - bool sealed; + bool public sealed; uint256 public nextWeek; address[] public bribeTokens; mapping(address => bool) bribeTokensDeposited; From c630a4d18b5d34dd0c6902a609b8ab3fff96afee Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Thu, 27 Apr 2023 11:12:40 +0800 Subject: [PATCH 103/119] fix: use non-reserved keyword for variable name in AutoBribe --- contracts/AutoBribe.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index 2885ca2e..499abd5b 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -26,7 +26,7 @@ contract AutoBribe is Ownable { address public immutable wBribe; address public project; - bool public sealed; + bool public depositSealed; uint256 public nextWeek; address[] public bribeTokens; mapping(address => bool) bribeTokensDeposited; @@ -113,7 +113,7 @@ contract AutoBribe is Ownable { //####Admin Functions##### function emptyOut() public { require(msg.sender == project); - require(!sealed); + require(!depositSealed); uint256 length = bribeTokens.length; uint256 amount; @@ -133,12 +133,12 @@ contract AutoBribe is Ownable { //Allows project to seal the vault making it not possible for them to withdraw their tokens function seal() public { require(msg.sender = project); - sealed = true; + depositSealed = true; } //Allows Velocimeter to re allow project to withdraw their tokens function unSeal() public onlyOwner { - sealed = false; + depositSealed = false; } function setProject(address _newWallet) public { From 768381c3e57d955cfe429a3a6efebfd5f416291d Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 08:06:21 +0800 Subject: [PATCH 104/119] feat: update AutoBribe --- contracts/AutoBribe.sol | 103 +++++++++---- test/AutoBribe.t.sol | 326 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 402 insertions(+), 27 deletions(-) create mode 100644 test/AutoBribe.t.sol diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index 499abd5b..024fc230 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MIT -import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; -import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; -import "openzeppelin-contracts/contracts/utils/math/SafeMath.sol"; import "openzeppelin-contracts/contracts/access/Ownable.sol"; import "openzeppelin-contracts/contracts/utils/Context.sol"; import "openzeppelin-contracts/contracts/utils/Address.sol"; -import 'contracts/interfaces/ITurnstile.sol'; -import {WrappedBribe} from 'contracts/WrappedBribe.sol'; +import "contracts/interfaces/ITurnstile.sol"; +import "contracts/interfaces/IERC20.sol"; +import "contracts/WrappedBribe.sol"; pragma solidity 0.8.13; @@ -19,18 +17,26 @@ pragma solidity 0.8.13; // !!!!!!!!!!!this contract handles multiple bribe tokens, and a single bribe contract!!!!!!!!! contract AutoBribe is Ownable { - using SafeERC20 for IERC20; - using SafeMath for uint256; - - address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public constant TURNSTILE = + 0xEcf044C5B4b867CFda001101c617eCd347095B44; address public immutable wBribe; address public project; bool public depositSealed; uint256 public nextWeek; address[] public bribeTokens; - mapping(address => bool) bribeTokensDeposited; - mapping(address => uint256) bribeTokenToWeeksLeft; + mapping(address => bool) public bribeTokensDeposited; + mapping(address => uint256) public bribeTokenToWeeksLeft; + + 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 _wBribe, address _team, uint256 _csrNftId) { wBribe = _wBribe; @@ -66,16 +72,19 @@ contract AutoBribe is Ownable { 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"); - IERC20(_bribeToken).safeTransferFrom( - msg.sender, + _safeTransferFrom(_bribeToken, msg.sender, address(this), _amount); + uint256 allowance = IERC20(_bribeToken).allowance( address(this), - _amount + wBribe ); + _safeApprove(_bribeToken, wBribe, allowance + _amount); if (!bribeTokensDeposited[_bribeToken]) { bribeTokensDeposited[_bribeToken] = true; bribeTokens.push(_bribeToken); } - bribeTokenToWeeksLeft[_bribeToken] = _weeks; + bribeTokenToWeeksLeft[_bribeToken] += _weeks; + + emit Deposited(_bribeToken, _amount, _weeks); } function bribe() public { @@ -87,11 +96,7 @@ contract AutoBribe is Ownable { uint256 weeksLeft = bribeTokenToWeeksLeft[_bribeToken]; uint256 bribeAmount = balance(_bribeToken) / weeksLeft; uint256 gasReward = bribeAmount / 10000; - IERC20(_bribeToken).safeTransferFrom( - address(this), - msg.sender, - gasReward - ); + _safeTransfer(_bribeToken, msg.sender, gasReward); WrappedBribe(wBribe).notifyRewardAmount( _bribeToken, bribeAmount - gasReward @@ -103,6 +108,8 @@ contract AutoBribe is Ownable { } } + emit Bribed(nextWeek, msg.sender); + nextWeek = nextWeek + 604800; } @@ -112,43 +119,85 @@ contract AutoBribe is Ownable { //####Admin Functions##### function emptyOut() public { - require(msg.sender == project); - require(!depositSealed); + 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); - bribeTokensDeposited[bribeToken] = false; bribeTokenToWeeksLeft[bribeToken] = 0; - IERC20(bribeToken).safeTransfer(msg.sender, amount); + _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); + require(msg.sender == project, "only project can seal"); depositSealed = true; + + emit Sealed(block.timestamp); } //Allows Velocimeter to re allow project to withdraw their tokens function unSeal() public onlyOwner { depositSealed = false; + + emit UnSealed(block.timestamp); } function setProject(address _newWallet) public { - require(msg.sender == project || msg.sender == owner()); + require( + msg.sender == project || msg.sender == owner(), + "only project or team" + ); project = _newWallet; } function inCaseTokensGetStuck(address _token) external onlyOwner { require(!bribeTokensDeposited[_token], "!bribeToken"); uint256 amount = IERC20(_token).balanceOf(address(this)); - IERC20(_token).safeTransfer(msg.sender, amount); + _safeTransfer(_token, msg.sender, amount); + } + + 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/test/AutoBribe.t.sol b/test/AutoBribe.t.sol new file mode 100644 index 00000000..5abab559 --- /dev/null +++ b/test/AutoBribe.t.sol @@ -0,0 +1,326 @@ +pragma solidity 0.8.13; + +import "./BaseTest.sol"; +import "contracts/AutoBribe.sol"; +import "contracts/WrappedBribe.sol"; +import "contracts/factories/WrappedBribeFactory.sol"; +import "forge-std/console2.sol"; + +contract AutoBribeTest is BaseTest { + VotingEscrow escrow; + GaugeFactory gaugeFactory; + BribeFactory bribeFactory; + WrappedBribeFactory wbribeFactory; + 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); + 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(wbribeFactory), + csrNftId + ); + wbribeFactory = new WrappedBribeFactory( + address(owner), + 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)); + + // USDC - FRAX stable + gauge = Gauge(voter.createGauge(address(pair))); + xbribe = ExternalBribe(gauge.external_bribe()); + wbribe = WrappedBribe(wbribeFactory.oldBribeToNew(address(xbribe))); + autoBribe = AutoBribe(wbribeFactory.createAutoBribe(address(xbribe))); + + vm.startPrank(address(owner)); + autoBribe.setProject(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 testCanDepositAllAndBribeEveryWeek(uint256 depositWeeks) public { + vm.assume(depositWeeks <= 52 && depositWeeks > 0); + vm.warp(block.timestamp + 1 weeks / 2); + + // deposit tokens + address[] memory bribeTokens = new address[](2); + bribeTokens[0] = address(LR); + bribeTokens[1] = address(FLOW); + + // Project depoit tokens + vm.startPrank(address(owner2)); + LR.approve(address(autoBribe), type(uint256).max); + FLOW.approve(address(autoBribe), type(uint256).max); + autoBribe.depositAll(bribeTokens, 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, + 1e25 + ); + assertEq( + FLOW.balanceOf(address(wbribe)) + + FLOW.balanceOf(address(this)) - + balanceBeforeFLOW, + 1e25 + ); + } + + 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 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 + ); + } +} From c41aca5a253f3e2769aea645db2300fe579ad69b Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 08:12:37 +0800 Subject: [PATCH 105/119] chore: update deployment script for wrapped bribe factory --- scripts/DeployWrappedBribeFactory.s.sol | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/DeployWrappedBribeFactory.s.sol b/scripts/DeployWrappedBribeFactory.s.sol index 3c2ff518..32453762 100644 --- a/scripts/DeployWrappedBribeFactory.s.sol +++ b/scripts/DeployWrappedBribeFactory.s.sol @@ -9,6 +9,8 @@ import {WrappedBribeFactory} from "../contracts/factories/WrappedBribeFactory.so contract DeployWrappedBribeFactory is Script { // token addresses + address private constant TEAM_MULTI_SIG = + 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; address private constant FLOW = 0xB5b060055F0d1eF5174329913ef861bC3aDdF029; // TODO address private constant VOTER = 0x8e3525Dbc8356c08d2d55F3ACb6416b5979D3389; @@ -19,7 +21,11 @@ contract DeployWrappedBribeFactory is Script { uint256 csrNftId = Flow(FLOW).csrNftId(); // Wrapped external bribe factory - WrappedBribeFactory wrappedBribeFactory = new WrappedBribeFactory(VOTER, csrNftId); + WrappedBribeFactory wrappedBribeFactory = new WrappedBribeFactory( + TEAM_MULTI_SIG, + VOTER, + csrNftId + ); vm.stopBroadcast(); } From 9db21612d80554502381cc24fff14bc14c158683 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 10:22:11 +0800 Subject: [PATCH 106/119] fix: fix AutoBribe --- contracts/AutoBribe.sol | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index 024fc230..5fddb16f 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -23,6 +23,7 @@ contract AutoBribe is Ownable { address public project; bool public depositSealed; + bool public initialized; uint256 public nextWeek; address[] public bribeTokens; mapping(address => bool) public bribeTokensDeposited; @@ -95,7 +96,7 @@ contract AutoBribe is Ownable { _bribeToken = bribeTokens[i]; uint256 weeksLeft = bribeTokenToWeeksLeft[_bribeToken]; uint256 bribeAmount = balance(_bribeToken) / weeksLeft; - uint256 gasReward = bribeAmount / 10000; + uint256 gasReward = bribeAmount / 200; _safeTransfer(_bribeToken, msg.sender, gasReward); WrappedBribe(wBribe).notifyRewardAmount( _bribeToken, @@ -155,9 +156,12 @@ contract AutoBribe is Ownable { function setProject(address _newWallet) public { require( - msg.sender == project || msg.sender == owner(), + msg.sender == project || (msg.sender == owner() && !initialized), "only project or team" ); + if (!initialized) { + initialized = true; + } project = _newWallet; } From 930bf2da754ff2aa857e700d3c91ba2d637e8648 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 10:27:41 +0800 Subject: [PATCH 107/119] fix: add tests for setProject --- contracts/AutoBribe.sol | 2 +- test/AutoBribe.t.sol | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index 5fddb16f..48d9e307 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -157,7 +157,7 @@ contract AutoBribe is Ownable { function setProject(address _newWallet) public { require( msg.sender == project || (msg.sender == owner() && !initialized), - "only project or team" + "only project / team can only set once" ); if (!initialized) { initialized = true; diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 5abab559..73638dd1 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -323,4 +323,21 @@ contract AutoBribeTest is BaseTest { depositAmountFLOW ); } + + function testTeamCannotSetProjectTwice() public { + vm.startPrank(address(owner)); + vm.expectRevert("only project / team can only set once"); + autoBribe.setProject(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(); + } } From dbb230dd86a3bd515e8947fa5c1bc24e3abe5433 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 11:48:14 +0800 Subject: [PATCH 108/119] feat: add last updated in wrapped bribe --- contracts/WrappedBribe.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol index de849d64..7224b764 100644 --- a/contracts/WrappedBribe.sol +++ b/contracts/WrappedBribe.sol @@ -21,6 +21,7 @@ contract WrappedBribe { 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; @@ -208,6 +209,7 @@ contract WrappedBribe { tokenRewardBalance[tokens[i]] = rewardBalance + difference; periodFinish[tokens[i]] = adjustedTstamp + DURATION; + lastUpdated[tokens[i]] = block.timetstamp; emit NotifyReward(msg.sender, tokens[i], adjustedTstamp, difference); } From e70068617ec41e40c0ed3b28b560012f0a1c7993 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 11:49:28 +0800 Subject: [PATCH 109/119] fix: fix typo --- contracts/WrappedBribe.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/WrappedBribe.sol b/contracts/WrappedBribe.sol index 7224b764..7014876b 100644 --- a/contracts/WrappedBribe.sol +++ b/contracts/WrappedBribe.sol @@ -209,7 +209,7 @@ contract WrappedBribe { tokenRewardBalance[tokens[i]] = rewardBalance + difference; periodFinish[tokens[i]] = adjustedTstamp + DURATION; - lastUpdated[tokens[i]] = block.timetstamp; + lastUpdated[tokens[i]] = block.timestamp; emit NotifyReward(msg.sender, tokens[i], adjustedTstamp, difference); } From 9ffbfe3373455b6d9f120ab7fa88f5dee3fdf13e Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 12:15:11 +0800 Subject: [PATCH 110/119] fix: remove createAutoBribe --- contracts/factories/WrappedBribeFactory.sol | 16 ---------------- test/AutoBribe.t.sol | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/contracts/factories/WrappedBribeFactory.sol b/contracts/factories/WrappedBribeFactory.sol index 43f95ca1..ce3f937d 100644 --- a/contracts/factories/WrappedBribeFactory.sol +++ b/contracts/factories/WrappedBribeFactory.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.13; -import {AutoBribe} from 'contracts/AutoBribe.sol'; import {WrappedBribe} from 'contracts/WrappedBribe.sol'; import 'contracts/interfaces/ITurnstile.sol'; @@ -11,7 +10,6 @@ contract WrappedBribeFactory { address public immutable voter; address public immutable team; mapping(address => address) public oldBribeToNew; - mapping(address => address) public oldBribeToAutoBribe; address public last_bribe; constructor(address _team, address _voter, uint256 _csrNftId) { @@ -30,18 +28,4 @@ contract WrappedBribeFactory { oldBribeToNew[existing_bribe] = last_bribe; return last_bribe; } - - function createAutoBribe(address existing_bribe) external returns (address auto_bribe) { - address wBribe = oldBribeToNew[existing_bribe]; - require( - wBribe != address(0), - "Wrapped bribe not yet created" - ); - require( - oldBribeToAutoBribe[existing_bribe] == address(0), - "Auto bribe already created" - ); - auto_bribe = address(new AutoBribe(wBribe, team, csrNftId)); - oldBribeToAutoBribe[existing_bribe] = auto_bribe; - } } diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 73638dd1..7648ef4c 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -87,7 +87,7 @@ contract AutoBribeTest is BaseTest { gauge = Gauge(voter.createGauge(address(pair))); xbribe = ExternalBribe(gauge.external_bribe()); wbribe = WrappedBribe(wbribeFactory.oldBribeToNew(address(xbribe))); - autoBribe = AutoBribe(wbribeFactory.createAutoBribe(address(xbribe))); + autoBribe = new AutoBribe(address(wbribe), address(owner)); vm.startPrank(address(owner)); autoBribe.setProject(address(owner2)); From 483497ac94f06d895427866d0ec7efead36fe4ef Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 15:57:38 +0800 Subject: [PATCH 111/119] fix: remove team in constructor of WrappedBribeFactory --- contracts/factories/WrappedBribeFactory.sol | 4 +--- scripts/DeployWrappedBribeFactory.s.sol | 3 --- test/WrappedBribes.t.sol | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/contracts/factories/WrappedBribeFactory.sol b/contracts/factories/WrappedBribeFactory.sol index ce3f937d..e1cfdb18 100644 --- a/contracts/factories/WrappedBribeFactory.sol +++ b/contracts/factories/WrappedBribeFactory.sol @@ -8,12 +8,10 @@ contract WrappedBribeFactory { address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; uint256 public immutable csrNftId; address public immutable voter; - address public immutable team; mapping(address => address) public oldBribeToNew; address public last_bribe; - constructor(address _team, address _voter, uint256 _csrNftId) { - team = _team; + constructor(address _voter, uint256 _csrNftId) { voter = _voter; ITurnstile(TURNSTILE).assign(_csrNftId); csrNftId = _csrNftId; diff --git a/scripts/DeployWrappedBribeFactory.s.sol b/scripts/DeployWrappedBribeFactory.s.sol index 32453762..267669b1 100644 --- a/scripts/DeployWrappedBribeFactory.s.sol +++ b/scripts/DeployWrappedBribeFactory.s.sol @@ -9,8 +9,6 @@ import {WrappedBribeFactory} from "../contracts/factories/WrappedBribeFactory.so contract DeployWrappedBribeFactory is Script { // token addresses - address private constant TEAM_MULTI_SIG = - 0x13eeB8EdfF60BbCcB24Ec7Dd5668aa246525Dc51; address private constant FLOW = 0xB5b060055F0d1eF5174329913ef861bC3aDdF029; // TODO address private constant VOTER = 0x8e3525Dbc8356c08d2d55F3ACb6416b5979D3389; @@ -22,7 +20,6 @@ contract DeployWrappedBribeFactory is Script { uint256 csrNftId = Flow(FLOW).csrNftId(); // Wrapped external bribe factory WrappedBribeFactory wrappedBribeFactory = new WrappedBribeFactory( - TEAM_MULTI_SIG, VOTER, csrNftId ); diff --git a/test/WrappedBribes.t.sol b/test/WrappedBribes.t.sol index 0a67a1c5..4d54f252 100644 --- a/test/WrappedBribes.t.sol +++ b/test/WrappedBribes.t.sol @@ -40,7 +40,7 @@ contract WrappedBribesTest is BaseTest { 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(owner), address(voter), csrNftId); + wxbribeFactory = new WrappedBribeFactory(address(voter), csrNftId); escrow.setVoter(address(voter)); factory.setVoter(address(voter)); From a8398ede12cb80f55d6202af4b78efacbcf80663 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 15:58:17 +0800 Subject: [PATCH 112/119] feat: add AutoBribeFactory --- contracts/factories/AutoBribeFactory.sol | 27 ++++++++++++++++++++++++ test/AutoBribe.t.sol | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 contracts/factories/AutoBribeFactory.sol diff --git a/contracts/factories/AutoBribeFactory.sol b/contracts/factories/AutoBribeFactory.sol new file mode 100644 index 00000000..279a951a --- /dev/null +++ b/contracts/factories/AutoBribeFactory.sol @@ -0,0 +1,27 @@ +// 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 wBribeFactory; + + constructor(address _team, address _wBribeFactory, uint256 _csrNftId) { + team = _team; + wBribeFactory = _wBribeFactory; + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; + } + + function createAutoBribe( + address wbribe + ) external returns (address auto_bribe) { + require(wbribe != address(0), "Wrapped bribe not yet created"); + auto_bribe = address(new AutoBribe(wbribe, team, csrNftId)); + } +} diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 7648ef4c..103bf133 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -87,7 +87,7 @@ contract AutoBribeTest is BaseTest { gauge = Gauge(voter.createGauge(address(pair))); xbribe = ExternalBribe(gauge.external_bribe()); wbribe = WrappedBribe(wbribeFactory.oldBribeToNew(address(xbribe))); - autoBribe = new AutoBribe(address(wbribe), address(owner)); + autoBribe = new AutoBribe(address(wbribe), address(owner), csrNftId); vm.startPrank(address(owner)); autoBribe.setProject(address(owner2)); From f5b35d771fbbaf4563e5ad15f9d499b09339f3d5 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Fri, 28 Apr 2023 17:53:50 +0800 Subject: [PATCH 113/119] fix: fix test cases --- contracts/factories/AutoBribeFactory.sol | 10 ++-------- test/AutoBribe.t.sol | 11 +++++++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/contracts/factories/AutoBribeFactory.sol b/contracts/factories/AutoBribeFactory.sol index 279a951a..53363379 100644 --- a/contracts/factories/AutoBribeFactory.sol +++ b/contracts/factories/AutoBribeFactory.sol @@ -2,26 +2,20 @@ 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 wBribeFactory; - constructor(address _team, address _wBribeFactory, uint256 _csrNftId) { + constructor(address _team, address _wBribeFactory) { team = _team; wBribeFactory = _wBribeFactory; - ITurnstile(TURNSTILE).assign(_csrNftId); - csrNftId = _csrNftId; } function createAutoBribe( address wbribe ) external returns (address auto_bribe) { require(wbribe != address(0), "Wrapped bribe not yet created"); - auto_bribe = address(new AutoBribe(wbribe, team, csrNftId)); + auto_bribe = address(new AutoBribe(wbribe, team)); } } diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 103bf133..99f0b0a6 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -4,6 +4,7 @@ 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 { @@ -11,6 +12,7 @@ contract AutoBribeTest is BaseTest { GaugeFactory gaugeFactory; BribeFactory bribeFactory; WrappedBribeFactory wbribeFactory; + WrappedExternalBribeFactory wxbribeFactory; Voter voter; RewardsDistributor distributor; Minter minter; @@ -47,22 +49,23 @@ contract AutoBribeTest is BaseTest { // 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(wbribeFactory), + address(wxbribeFactory), csrNftId ); wbribeFactory = new WrappedBribeFactory( - address(owner), address(voter), csrNftId ); escrow.setVoter(address(voter)); factory.setVoter(address(voter)); + wxbribeFactory.setVoter(address(voter)); deployPairWithOwner(address(owner)); // deployMinter() @@ -86,8 +89,8 @@ contract AutoBribeTest is BaseTest { // USDC - FRAX stable gauge = Gauge(voter.createGauge(address(pair))); xbribe = ExternalBribe(gauge.external_bribe()); - wbribe = WrappedBribe(wbribeFactory.oldBribeToNew(address(xbribe))); - autoBribe = new AutoBribe(address(wbribe), address(owner), csrNftId); + wbribe = WrappedBribe(wbribeFactory.createBribe(address(xbribe))); + autoBribe = new AutoBribe(address(wbribe), address(owner)); vm.startPrank(address(owner)); autoBribe.setProject(address(owner2)); From 51e8e8650349b9f0efdf720daba02bb04d59ae34 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Sat, 29 Apr 2023 19:39:18 +0800 Subject: [PATCH 114/119] fix --- contracts/factories/AutoBribeFactory.sol | 10 ++++++++-- test/AutoBribe.t.sol | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/contracts/factories/AutoBribeFactory.sol b/contracts/factories/AutoBribeFactory.sol index 53363379..279a951a 100644 --- a/contracts/factories/AutoBribeFactory.sol +++ b/contracts/factories/AutoBribeFactory.sol @@ -2,20 +2,26 @@ 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 wBribeFactory; - constructor(address _team, address _wBribeFactory) { + constructor(address _team, address _wBribeFactory, uint256 _csrNftId) { team = _team; wBribeFactory = _wBribeFactory; + ITurnstile(TURNSTILE).assign(_csrNftId); + csrNftId = _csrNftId; } function createAutoBribe( address wbribe ) external returns (address auto_bribe) { require(wbribe != address(0), "Wrapped bribe not yet created"); - auto_bribe = address(new AutoBribe(wbribe, team)); + auto_bribe = address(new AutoBribe(wbribe, team, csrNftId)); } } diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 99f0b0a6..2772e360 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -90,7 +90,7 @@ contract AutoBribeTest is BaseTest { gauge = Gauge(voter.createGauge(address(pair))); xbribe = ExternalBribe(gauge.external_bribe()); wbribe = WrappedBribe(wbribeFactory.createBribe(address(xbribe))); - autoBribe = new AutoBribe(address(wbribe), address(owner)); + autoBribe = new AutoBribe(address(wbribe), address(owner), csrNftId); vm.startPrank(address(owner)); autoBribe.setProject(address(owner2)); From ef2a44115fabda2ac69a811905e7331f768d59e5 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 2 May 2023 11:25:57 +0800 Subject: [PATCH 115/119] fix: set nextWeek to block.timestamp in constructor --- contracts/AutoBribe.sol | 1 + test/AutoBribe.t.sol | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index 48d9e307..db62223b 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -41,6 +41,7 @@ contract AutoBribe is Ownable { constructor(address _wBribe, address _team, uint256 _csrNftId) { wBribe = _wBribe; + nextWeek = block.timestamp; _transferOwnership(_team); ITurnstile(TURNSTILE).assign(_csrNftId); } diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 2772e360..cc06f4a0 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -265,6 +265,39 @@ contract AutoBribeTest is BaseTest { ); } + 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(); + + uint256 pre = LR.balanceOf(address(wbribe)); + + autoBribe.bribe(); + + uint256 post = LR.balanceOf(address(wbribe)); + + autoBribe.bribe(); + + uint256 post_post = LR.balanceOf(address(wbribe)); + + assertGt(post - pre, 0); + assertEq(post_post - post, 0); + } + function testEmptyOut( uint256 depositAmountLR, uint256 depositAmountFLOW, From 4468ebbe6e19e698c0617efaf5dad7eecd713c66 Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 2 May 2023 11:55:32 +0800 Subject: [PATCH 116/119] fix: add checking to avoid re-bribing in the same week --- contracts/AutoBribe.sol | 27 ++++++++++++--------------- test/AutoBribe.t.sol | 10 +--------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index db62223b..bd74552e 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -90,29 +90,26 @@ contract AutoBribe is Ownable { } function bribe() public { + require(block.timestamp >= nextWeek, "already bribed this week"); uint256 length = bribeTokens.length; address _bribeToken; for (uint256 i = 0; i < length; ) { - if (block.timestamp >= nextWeek) { - _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; - } + _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; } } - - emit Bribed(nextWeek, msg.sender); - nextWeek = nextWeek + 604800; + emit Bribed(nextWeek, msg.sender); } function balance(address _bribeToken) public view returns (uint) { diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index cc06f4a0..ac926bec 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -284,18 +284,10 @@ contract AutoBribeTest is BaseTest { autoBribe.deposit(address(LR), depositAmountLR, depositWeeks); vm.stopPrank(); - uint256 pre = LR.balanceOf(address(wbribe)); - autoBribe.bribe(); - uint256 post = LR.balanceOf(address(wbribe)); - + vm.expectRevert("already bribed this week"); autoBribe.bribe(); - - uint256 post_post = LR.balanceOf(address(wbribe)); - - assertGt(post - pre, 0); - assertEq(post_post - post, 0); } function testEmptyOut( From 8ddce9b89c133f75fc0101d835b9356554da541f Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 3 May 2023 15:57:40 +0800 Subject: [PATCH 117/119] fix: amend AutoBribe --- contracts/AutoBribe.sol | 120 ++++++++++++++++++++++++---------------- test/AutoBribe.t.sol | 13 ++--- 2 files changed, 77 insertions(+), 56 deletions(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index bd74552e..69e2d2f0 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -1,13 +1,11 @@ // SPDX-License-Identifier: MIT import "openzeppelin-contracts/contracts/access/Ownable.sol"; -import "openzeppelin-contracts/contracts/utils/Context.sol"; -import "openzeppelin-contracts/contracts/utils/Address.sol"; import "contracts/interfaces/ITurnstile.sol"; import "contracts/interfaces/IERC20.sol"; import "contracts/WrappedBribe.sol"; -pragma solidity 0.8.13; +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 @@ -28,6 +26,7 @@ contract AutoBribe is Ownable { address[] public bribeTokens; mapping(address => bool) public bribeTokensDeposited; mapping(address => uint256) public bribeTokenToWeeksLeft; + string public bribeName; event Deposited( address indexed _bribeToken, @@ -39,33 +38,59 @@ contract AutoBribe is Ownable { event Sealed(uint256 indexed _timestamp); event UnSealed(uint256 indexed _timestamp); - constructor(address _wBribe, address _team, uint256 _csrNftId) { + constructor( + address _wBribe, + address _team, + uint256 _csrNftId, + string _name + ) { wBribe = _wBribe; nextWeek = block.timestamp; _transferOwnership(_team); ITurnstile(TURNSTILE).assign(_csrNftId); + bribeName = _name; } - //####USER FUNCTIONS##### + //######################################## + //###########PUBLIC FUNCTIONS############# + //######################################## - function depositAll( - address[] memory _bribeTokens, - uint256 _weeks - ) external { - uint256 length = _bribeTokens.length; + //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; ) { - address bribeToken = _bribeTokens[i]; - deposit( - bribeToken, - IERC20(bribeToken).balanceOf(msg.sender), - _weeks + _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, @@ -89,34 +114,7 @@ contract AutoBribe is Ownable { emit Deposited(_bribeToken, _amount, _weeks); } - 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); - } - - function balance(address _bribeToken) public view returns (uint) { - return IERC20(_bribeToken).balanceOf(address(this)); - } - - //####Admin Functions##### + //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"); @@ -145,6 +143,16 @@ contract AutoBribe is Ownable { 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; @@ -152,11 +160,8 @@ contract AutoBribe is Ownable { emit UnSealed(block.timestamp); } - function setProject(address _newWallet) public { - require( - msg.sender == project || (msg.sender == owner() && !initialized), - "only project / team can only set once" - ); + function initProject(address _newWallet) public onlyOwner { + require(!initialized, "project wallet can only be set once by team"); if (!initialized) { initialized = true; } @@ -169,6 +174,25 @@ contract AutoBribe is Ownable { _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( diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index ac926bec..1db744f7 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -58,10 +58,7 @@ contract AutoBribeTest is BaseTest { address(wxbribeFactory), csrNftId ); - wbribeFactory = new WrappedBribeFactory( - address(voter), - csrNftId - ); + wbribeFactory = new WrappedBribeFactory(address(voter), csrNftId); escrow.setVoter(address(voter)); factory.setVoter(address(voter)); @@ -93,7 +90,7 @@ contract AutoBribeTest is BaseTest { autoBribe = new AutoBribe(address(wbribe), address(owner), csrNftId); vm.startPrank(address(owner)); - autoBribe.setProject(address(owner2)); + autoBribe.initProject(address(owner2)); vm.stopPrank(); } @@ -352,10 +349,10 @@ contract AutoBribeTest is BaseTest { ); } - function testTeamCannotSetProjectTwice() public { + function testTeamCannotInitProjectTwice() public { vm.startPrank(address(owner)); - vm.expectRevert("only project / team can only set once"); - autoBribe.setProject(address(owner2)); + vm.expectRevert("project wallet can only be set once by team"); + autoBribe.initProject(address(owner2)); vm.stopPrank(); } From bf563b77bf3b50bb53ab1ad3909311670632d52c Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Wed, 3 May 2023 16:36:26 +0800 Subject: [PATCH 118/119] fix: fix data location --- contracts/AutoBribe.sol | 2 +- contracts/factories/AutoBribeFactory.sol | 7 +-- test/AutoBribe.t.sol | 58 +++--------------------- 3 files changed, 11 insertions(+), 56 deletions(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index 69e2d2f0..d3b63330 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -42,7 +42,7 @@ contract AutoBribe is Ownable { address _wBribe, address _team, uint256 _csrNftId, - string _name + string memory _name ) { wBribe = _wBribe; nextWeek = block.timestamp; diff --git a/contracts/factories/AutoBribeFactory.sol b/contracts/factories/AutoBribeFactory.sol index 279a951a..05a37ec6 100644 --- a/contracts/factories/AutoBribeFactory.sol +++ b/contracts/factories/AutoBribeFactory.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.13; import {AutoBribe} from "contracts/AutoBribe.sol"; -import 'contracts/interfaces/ITurnstile.sol'; +import "contracts/interfaces/ITurnstile.sol"; contract AutoBribeFactory { address public constant TURNSTILE = @@ -19,9 +19,10 @@ contract AutoBribeFactory { } function createAutoBribe( - address wbribe + address wbribe, + string memory name ) external returns (address auto_bribe) { require(wbribe != address(0), "Wrapped bribe not yet created"); - auto_bribe = address(new AutoBribe(wbribe, team, csrNftId)); + auto_bribe = address(new AutoBribe(wbribe, team, csrNftId, name)); } } diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 1db744f7..3a088662 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -87,7 +87,12 @@ contract AutoBribeTest is BaseTest { gauge = Gauge(voter.createGauge(address(pair))); xbribe = ExternalBribe(gauge.external_bribe()); wbribe = WrappedBribe(wbribeFactory.createBribe(address(xbribe))); - autoBribe = new AutoBribe(address(wbribe), address(owner), csrNftId); + autoBribe = new AutoBribe( + address(wbribe), + address(owner), + csrNftId, + "AUTO" + ); vm.startPrank(address(owner)); autoBribe.initProject(address(owner2)); @@ -159,57 +164,6 @@ contract AutoBribeTest is BaseTest { ); } - function testCanDepositAllAndBribeEveryWeek(uint256 depositWeeks) public { - vm.assume(depositWeeks <= 52 && depositWeeks > 0); - vm.warp(block.timestamp + 1 weeks / 2); - - // deposit tokens - address[] memory bribeTokens = new address[](2); - bribeTokens[0] = address(LR); - bribeTokens[1] = address(FLOW); - - // Project depoit tokens - vm.startPrank(address(owner2)); - LR.approve(address(autoBribe), type(uint256).max); - FLOW.approve(address(autoBribe), type(uint256).max); - autoBribe.depositAll(bribeTokens, 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, - 1e25 - ); - assertEq( - FLOW.balanceOf(address(wbribe)) + - FLOW.balanceOf(address(this)) - - balanceBeforeFLOW, - 1e25 - ); - } - function testRedeposit( uint256 depositAmountLR, uint256 depositWeeks From 7d31a8de0b1acc278a34ef7c59a258343f02c19a Mon Sep 17 00:00:00 2001 From: 0xmotto <0xmotto@protonmail.com> Date: Tue, 23 May 2023 17:58:30 +0800 Subject: [PATCH 119/119] fix: check bribe token whitelisted in AutoBribe --- contracts/AutoBribe.sol | 12 ++++++++++-- contracts/factories/AutoBribeFactory.sol | 6 ++++-- test/AutoBribe.t.sol | 17 +++++++++++++++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/contracts/AutoBribe.sol b/contracts/AutoBribe.sol index d3b63330..b7ef0e11 100644 --- a/contracts/AutoBribe.sol +++ b/contracts/AutoBribe.sol @@ -3,6 +3,7 @@ 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; @@ -17,6 +18,7 @@ pragma solidity ^0.8.13; contract AutoBribe is Ownable { address public constant TURNSTILE = 0xEcf044C5B4b867CFda001101c617eCd347095B44; + address public immutable voter; address public immutable wBribe; address public project; @@ -39,11 +41,13 @@ contract AutoBribe is Ownable { event UnSealed(uint256 indexed _timestamp); constructor( + address _voter, address _wBribe, address _team, - uint256 _csrNftId, - string memory _name + string memory _name, + uint256 _csrNftId ) { + voter = _voter; wBribe = _wBribe; nextWeek = block.timestamp; _transferOwnership(_team); @@ -99,6 +103,10 @@ contract AutoBribe is Ownable { 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), diff --git a/contracts/factories/AutoBribeFactory.sol b/contracts/factories/AutoBribeFactory.sol index 05a37ec6..56360e5c 100644 --- a/contracts/factories/AutoBribeFactory.sol +++ b/contracts/factories/AutoBribeFactory.sol @@ -9,9 +9,11 @@ contract AutoBribeFactory { 0xEcf044C5B4b867CFda001101c617eCd347095B44; uint256 public immutable csrNftId; address public immutable team; + address public immutable voter; address public immutable wBribeFactory; - constructor(address _team, address _wBribeFactory, uint256 _csrNftId) { + constructor(address _voter, address _team, address _wBribeFactory, uint256 _csrNftId) { + voter = _voter; team = _team; wBribeFactory = _wBribeFactory; ITurnstile(TURNSTILE).assign(_csrNftId); @@ -23,6 +25,6 @@ contract AutoBribeFactory { string memory name ) external returns (address auto_bribe) { require(wbribe != address(0), "Wrapped bribe not yet created"); - auto_bribe = address(new AutoBribe(wbribe, team, csrNftId, name)); + auto_bribe = address(new AutoBribe(voter, wbribe, team, name, csrNftId)); } } diff --git a/test/AutoBribe.t.sol b/test/AutoBribe.t.sol index 3a088662..775e2e8b 100644 --- a/test/AutoBribe.t.sol +++ b/test/AutoBribe.t.sol @@ -37,6 +37,7 @@ contract AutoBribeTest is BaseTest { amounts[2] = 1e25; mintFlow(owners, amounts); mintLR(owners, amounts); + mintWETH(owners, amounts); VeArtProxy artProxy = new VeArtProxy(); escrow = new VotingEscrow( address(FLOW), @@ -88,10 +89,11 @@ contract AutoBribeTest is BaseTest { xbribe = ExternalBribe(gauge.external_bribe()); wbribe = WrappedBribe(wbribeFactory.createBribe(address(xbribe))); autoBribe = new AutoBribe( + address(voter), address(wbribe), address(owner), - csrNftId, - "AUTO" + "AUTO", + csrNftId ); vm.startPrank(address(owner)); @@ -164,6 +166,17 @@ contract AutoBribeTest is BaseTest { ); } + 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