diff --git a/contracts/addresses/11155111.json b/contracts/addresses/11155111.json index a4d56bd86..c25a1087a 100644 --- a/contracts/addresses/11155111.json +++ b/contracts/addresses/11155111.json @@ -88,10 +88,15 @@ "EPOCH_VOTING_CUTOFF": "172800" }, "governance": "0x7eedda08119826757c98a4680e94f3b5e1f33af6", - "uniV4DonationsInitiative": "0xc2348442f31d0182d3178d7b0c34ad58ddcf1400", - "curveV2GaugeRewardsInitiative": "0x0000000000000000000000000000000000000000", - "curvePool": "0x5b3f6b88fa29e85778394992d9bcd95ef2fceebe", - "gauge": "0x0000000000000000000000000000000000000000", - "LQTYToken": "0x878fc269a85619da792b054e2288cf5f9cc3e2e1" + "curveUsdcBoldPool": "0x5b3f6b88fa29e85778394992d9bcd95ef2fceebe", + "curveUsdcBoldGauge": "0x0000000000000000000000000000000000000000", + "curveUsdcBoldInitiative": "0x0000000000000000000000000000000000000000", + "curveLusdBoldPool": "0x0000000000000000000000000000000000000000", + "curveLusdBoldGauge": "0x0000000000000000000000000000000000000000", + "curveLusdBoldInitiative": "0x0000000000000000000000000000000000000000", + "defiCollectiveInitiative": "0x0000000000000000000000000000000000000000", + "stakingV1": "0x0Ade63786E85C97F6741B47DA09f8790B062a767", + "LQTYToken": "0x878fc269a85619da792b054e2288cf5f9cc3e2e1", + "LUSDToken": "0x0A69fa2A565BD6Fa9c3890ecAa30b149AAF99136" } } diff --git a/contracts/script/DeployGovernance.s.sol b/contracts/script/DeployGovernance.s.sol index ccffedff5..fe2da6b6f 100644 --- a/contracts/script/DeployGovernance.s.sol +++ b/contracts/script/DeployGovernance.s.sol @@ -5,9 +5,9 @@ import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol"; import {Script} from "forge-std/Script.sol"; -import {ICurveStableswapFactoryNG} from "V2-gov/src/interfaces/ICurveStableswapFactoryNG.sol"; -import {ICurveStableswapNG} from "V2-gov/src/interfaces/ICurveStableswapNG.sol"; -import {ILiquidityGauge} from "V2-gov/src/interfaces/ILiquidityGauge.sol"; +import {ICurveStableSwapFactoryNG} from "test/Interfaces/Curve/ICurveStableSwapFactoryNG.sol"; +import {ICurveStableSwapNG} from "test/Interfaces/Curve/ICurveStableSwapNG.sol"; +import {ILiquidityGaugeV6} from "test/Interfaces/Curve/ILiquidityGaugeV6.sol"; import {IGovernance} from "V2-gov/src/interfaces/IGovernance.sol"; @@ -20,6 +20,7 @@ contract DeployGovernance is Script { using Strings for *; struct DeployGovernanceParams { + uint256 epochStart; address deployer; bytes32 salt; address stakingV1; @@ -28,6 +29,11 @@ contract DeployGovernance is Script { address bold; } + address constant LUSD = 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0; + address constant CRV = 0xD533a949740bb3306d119CC777fa900bA034cd52; + address constant FUNDS_SAFE = 0xF06016D822943C42e3Cb7FC3a6A3B1889C1045f8; + address constant DEFI_COLLECTIVE_GRANTS_ADDRESS = 0xDc6f869d2D34E4aee3E89A51f2Af6D54F0F7f690; + // Governance Constants uint128 private constant REGISTRATION_FEE = 1000e18; uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.0001e18; // 0.01% @@ -36,26 +42,30 @@ contract DeployGovernance is Script { uint128 private constant VOTING_THRESHOLD_FACTOR = 0.02e18; uint88 private constant MIN_CLAIM = 0; uint88 private constant MIN_ACCRUAL = 0; - uint32 private constant EPOCH_DURATION = 7 days; + uint32 internal constant EPOCH_DURATION = 7 days; uint32 private constant EPOCH_VOTING_CUTOFF = 6 days; - // UniV4Donations Constants - uint24 private constant FEE = 400; - int24 constant MAX_TICK_SPACING = 32767; - // CurveV2GaugeRewards Constants uint256 private constant DURATION = 7 days; // Contracts Governance private governance; address[] private initialInitiatives; - CurveV2GaugeRewards private curveV2GaugeRewards; - ILiquidityGauge private gauge; - function deployGovernance(DeployGovernanceParams memory p, address _curveFactoryAddress, address _curvePoolAddress) - internal - returns (address, string memory) - { + ICurveStableSwapNG private curveUsdcBoldPool; + ILiquidityGaugeV6 private curveUsdcBoldGauge; + CurveV2GaugeRewards private curveUsdcBoldInitiative; + + ICurveStableSwapNG private curveLusdBoldPool; + ILiquidityGaugeV6 private curveLusdBoldGauge; + CurveV2GaugeRewards private curveLusdBoldInitiative; + + function deployGovernance( + DeployGovernanceParams memory p, + address _curveFactoryAddress, + address _curveUsdcBoldPoolAddress, + address _curveLusdBoldPoolAddress + ) internal returns (address, string memory) { (address governanceAddress, IGovernance.Configuration memory governanceConfiguration) = computeGovernanceAddressAndConfig(p); @@ -65,33 +75,43 @@ contract DeployGovernance is Script { assert(governanceAddress == address(governance)); - // Curve initiative + curveUsdcBoldPool = ICurveStableSwapNG(_curveUsdcBoldPoolAddress); + curveLusdBoldPool = ICurveStableSwapNG(_curveLusdBoldPoolAddress); + if (block.chainid == 1) { // mainnet - deployCurveV2GaugeRewards({ + (curveUsdcBoldGauge, curveUsdcBoldInitiative) = deployCurveV2GaugeRewards({ + _governance: governance, + _bold: p.bold, + _curveFactoryAddress: _curveFactoryAddress, + _curvePool: curveUsdcBoldPool + }); + + (curveLusdBoldGauge, curveLusdBoldInitiative) = deployCurveV2GaugeRewards({ _governance: governance, _bold: p.bold, - _bribeToken: p.lqty, // TODO: this should be CRV _curveFactoryAddress: _curveFactoryAddress, - _curvePoolAddress: _curvePoolAddress + _curvePool: curveLusdBoldPool }); - // TODO: BOLD/LUSD pool + initialInitiatives.push(address(curveUsdcBoldInitiative)); + initialInitiatives.push(address(curveLusdBoldInitiative)); + initialInitiatives.push(DEFI_COLLECTIVE_GRANTS_ADDRESS); } governance.registerInitialInitiatives{gas: 600000}(initialInitiatives); - return (governanceAddress, _getGovernanceManifestJson(_curvePoolAddress, p.lqty)); + return (governanceAddress, _getGovernanceManifestJson(p)); } - function computeGovernanceAddress(DeployGovernanceParams memory p) internal view returns (address) { + function computeGovernanceAddress(DeployGovernanceParams memory p) internal pure returns (address) { (address governanceAddress,) = computeGovernanceAddressAndConfig(p); return governanceAddress; } function computeGovernanceAddressAndConfig(DeployGovernanceParams memory p) internal - view + pure returns (address, IGovernance.Configuration memory) { IGovernance.Configuration memory governanceConfiguration = IGovernance.Configuration({ @@ -102,8 +122,7 @@ contract DeployGovernance is Script { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: block.timestamp - EPOCH_DURATION, - /// @audit Ensures that `initialInitiatives` can be voted on + epochStart: p.epochStart, epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }); @@ -114,66 +133,69 @@ contract DeployGovernance is Script { ); address governanceAddress = vm.computeCreate2Address(p.salt, keccak256(bytecode)); - return (governanceAddress, governanceConfiguration); } function deployCurveV2GaugeRewards( IGovernance _governance, address _bold, - address _bribeToken, address _curveFactoryAddress, - address _curvePoolAddress - ) private { - ICurveStableswapFactoryNG curveFactory = ICurveStableswapFactoryNG(_curveFactoryAddress); - ICurveStableswapNG curvePool = ICurveStableswapNG(_curvePoolAddress); - gauge = ILiquidityGauge(curveFactory.deploy_gauge(address(curvePool))); - - curveV2GaugeRewards = - new CurveV2GaugeRewards(address(_governance), _bold, _bribeToken, address(gauge), DURATION); + ICurveStableSwapNG _curvePool + ) private returns (ILiquidityGaugeV6 gauge, CurveV2GaugeRewards curveV2GaugeRewards) { + ICurveStableSwapFactoryNG curveFactory = ICurveStableSwapFactoryNG(_curveFactoryAddress); + gauge = ILiquidityGaugeV6(curveFactory.deploy_gauge(address(_curvePool))); + curveV2GaugeRewards = new CurveV2GaugeRewards(address(_governance), _bold, CRV, address(gauge), DURATION); // add BOLD as reward token gauge.add_reward(_bold, address(curveV2GaugeRewards)); - initialInitiatives.push(address(curveV2GaugeRewards)); + // add LUSD as reward token to be distributed by the Funds Safe + gauge.add_reward(LUSD, FUNDS_SAFE); + + // renounce gauge manager role + gauge.set_gauge_manager(address(0)); } - function _getGovernanceDeploymentConstants() internal pure returns (string memory) { + function _getGovernanceDeploymentConstants(DeployGovernanceParams memory p) internal pure returns (string memory) { return string.concat( "{", string.concat( - string.concat('"REGISTRATION_FEE":"', uint256(REGISTRATION_FEE).toString(), '",'), - string.concat( - '"REGISTRATION_THRESHOLD_FACTOR":"', uint256(REGISTRATION_THRESHOLD_FACTOR).toString(), '",' - ), - string.concat( - '"UNREGISTRATION_THRESHOLD_FACTOR":"', uint256(UNREGISTRATION_THRESHOLD_FACTOR).toString(), '",' - ), - string.concat('"UNREGISTRATION_AFTER_EPOCHS":"', uint256(UNREGISTRATION_AFTER_EPOCHS).toString(), '",'), - string.concat('"VOTING_THRESHOLD_FACTOR":"', uint256(VOTING_THRESHOLD_FACTOR).toString(), '",'), - string.concat('"MIN_CLAIM":"', uint256(MIN_CLAIM).toString(), '",'), - string.concat('"MIN_ACCRUAL":"', uint256(MIN_ACCRUAL).toString(), '",'), - string.concat('"EPOCH_DURATION":"', uint256(EPOCH_DURATION).toString(), '",'), - string.concat('"EPOCH_VOTING_CUTOFF":"', uint256(EPOCH_VOTING_CUTOFF).toString(), '" ') // no comma + string.concat('"REGISTRATION_FEE":"', REGISTRATION_FEE.toString(), '",'), + string.concat('"REGISTRATION_THRESHOLD_FACTOR":"', REGISTRATION_THRESHOLD_FACTOR.toString(), '",'), + string.concat('"UNREGISTRATION_THRESHOLD_FACTOR":"', UNREGISTRATION_THRESHOLD_FACTOR.toString(), '",'), + string.concat('"UNREGISTRATION_AFTER_EPOCHS":"', UNREGISTRATION_AFTER_EPOCHS.toString(), '",'), + string.concat('"VOTING_THRESHOLD_FACTOR":"', VOTING_THRESHOLD_FACTOR.toString(), '",'), + string.concat('"MIN_CLAIM":"', MIN_CLAIM.toString(), '",'), + string.concat('"MIN_ACCRUAL":"', MIN_ACCRUAL.toString(), '",'), + string.concat('"EPOCH_START":"', p.epochStart.toString(), '",') + ), + string.concat( + string.concat('"EPOCH_DURATION":"', EPOCH_DURATION.toString(), '",'), + string.concat('"EPOCH_VOTING_CUTOFF":"', EPOCH_VOTING_CUTOFF.toString(), '",'), + string.concat('"FUNDS_SAFE":"', FUNDS_SAFE.toHexString(), '"') // no comma ), "}" ); } - function _getGovernanceManifestJson(address _curvePoolAddress, address _lqty) - internal - view - returns (string memory) - { + function _getGovernanceManifestJson(DeployGovernanceParams memory p) internal view returns (string memory) { return string.concat( "{", string.concat( - string.concat('"constants":', _getGovernanceDeploymentConstants(), ","), + string.concat('"constants":', _getGovernanceDeploymentConstants(p), ","), string.concat('"governance":"', address(governance).toHexString(), '",'), - string.concat('"curveV2GaugeRewardsInitiative":"', address(curveV2GaugeRewards).toHexString(), '",'), - string.concat('"curvePool":"', _curvePoolAddress.toHexString(), '",'), - string.concat('"gauge":"', address(gauge).toHexString(), '",'), - string.concat('"LQTYToken":"', _lqty.toHexString(), '" ') // no comma + string.concat('"curveUsdcBoldPool":"', address(curveUsdcBoldPool).toHexString(), '",'), + string.concat('"curveUsdcBoldGauge":"', address(curveUsdcBoldGauge).toHexString(), '",'), + string.concat('"curveUsdcBoldInitiative":"', address(curveUsdcBoldInitiative).toHexString(), '",'), + string.concat('"curveLusdBoldPool":"', address(curveLusdBoldPool).toHexString(), '",'), + string.concat('"curveLusdBoldGauge":"', address(curveLusdBoldGauge).toHexString(), '",'), + string.concat('"curveLusdBoldInitiative":"', address(curveLusdBoldInitiative).toHexString(), '",') + ), + string.concat( + string.concat('"defiCollectiveInitiative":"', DEFI_COLLECTIVE_GRANTS_ADDRESS.toHexString(), '",'), + string.concat('"stakingV1":"', p.stakingV1.toHexString(), '",'), + string.concat('"LQTYToken":"', p.lqty.toHexString(), '",'), + string.concat('"LUSDToken":"', p.lusd.toHexString(), '"') // no comma ), "}" ); diff --git a/contracts/script/DeployLiquity2.s.sol b/contracts/script/DeployLiquity2.s.sol index ec9906895..5e29b9ef4 100644 --- a/contracts/script/DeployLiquity2.s.sol +++ b/contracts/script/DeployLiquity2.s.sol @@ -54,6 +54,10 @@ import {MockStakingV1} from "V2-gov/test/mocks/MockStakingV1.sol"; import {DeployGovernance} from "./DeployGovernance.s.sol"; +function _latestUTCMidnightBetweenWednesdayAndThursday() view returns (uint256) { + return block.timestamp / 1 weeks * 1 weeks; +} + contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, MetadataDeployment, Logging { using Strings for *; using StringFormatting for *; @@ -63,13 +67,15 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, string constant DEPLOYMENT_MODE_BOLD_ONLY = "bold-only"; string constant DEPLOYMENT_MODE_USE_EXISTING_BOLD = "use-existing-bold"; + uint256 constant MAINNET_EPOCH_START = 1736985600; + address WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; // used for gas compensation and as collateral of the first branch // tapping disallowed IWETH WETH; - IERC20 USDC; + IERC20Metadata USDC; address WSTETH_ADDRESS = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; address RETH_ADDRESS = 0xae78736Cd615f374D3085123A210448E74Fc6393; address ETH_ORACLE_ADDRESS = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; @@ -98,7 +104,7 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, ICurveStableswapNGFactory constant curveStableswapFactoryMainnet = ICurveStableswapNGFactory(0x6A8cbed756804B16E05E741eDaBd5cB544AE21bf); uint128 constant BOLD_TOKEN_INDEX = 0; - uint128 constant USDC_INDEX = 1; + uint128 constant OTHER_TOKEN_INDEX = 1; // Uni V3 uint24 constant UNIV3_FEE = 0.3e4; @@ -241,12 +247,18 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, string.concat("Bad deployment mode: ", deploymentMode) ); + uint256 epochStart = vm.envOr( + "EPOCH_START", + (block.chainid == 1 ? _latestUTCMidnightBetweenWednesdayAndThursday() : block.timestamp) - EPOCH_DURATION + ); + useTestnetPriceFeeds = vm.envOr("USE_TESTNET_PRICEFEEDS", false); _log("Deployer: ", deployer.toHexString()); _log("Deployer balance: ", deployer.balance.decimal()); _log("Deployment mode: ", deploymentMode); _log("CREATE2 salt: ", 'keccak256(bytes("', saltStr, '")) = ', uint256(SALT).toHexString()); + _log("Governance epoch start: ", epochStart.toString()); _log("Use testnet PriceFeeds: ", useTestnetPriceFeeds ? "yes" : "no"); // Deploy Bold or pick up existing deployment @@ -275,7 +287,7 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, if (block.chainid == 1) { // mainnet WETH = IWETH(WETH_ADDRESS); - USDC = IERC20(USDC_ADDRESS); + USDC = IERC20Metadata(USDC_ADDRESS); curveStableswapFactory = curveStableswapFactoryMainnet; uniV3Router = uniV3RouterMainnet; uniV3Quoter = uniV3QuoterMainnet; @@ -324,6 +336,7 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, collSymbols[1] = "rETH"; DeployGovernanceParams memory deployGovernanceParams = DeployGovernanceParams({ + epochStart: epochStart, deployer: deployer, salt: SALT, stakingV1: stakingV1, @@ -384,9 +397,18 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, // ); } + ICurveStableswapNGPool lusdCurvePool; + if (block.chainid == 1) { + lusdCurvePool = _deployCurvePool(deployed.boldToken, IERC20Metadata(LUSD_ADDRESS)); + } + // Governance - (address governanceAddress, string memory governanceManifest) = - deployGovernance(deployGovernanceParams, address(curveStableswapFactory), address(deployed.usdcCurvePool)); + (address governanceAddress, string memory governanceManifest) = deployGovernance( + deployGovernanceParams, + address(curveStableswapFactory), + address(deployed.usdcCurvePool), + address(lusdCurvePool) + ); address computedGovernanceAddress = computeGovernanceAddress(deployGovernanceParams); assert(governanceAddress == computedGovernanceAddress); @@ -509,7 +531,7 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, r.boldToken = BoldToken(_deployGovernanceParams.bold); // USDC and USDC-BOLD pool - r.usdcCurvePool = _deployCurveBoldUsdcPool(r.boldToken); + r.usdcCurvePool = _deployCurvePool(r.boldToken, USDC); r.contractsArray = new LiquityContracts[](vars.numCollaterals); vars.collaterals = new IERC20Metadata[](vars.numCollaterals); @@ -598,7 +620,7 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, USDC, WETH, r.usdcCurvePool, - USDC_INDEX, // USDC Curve pool index + OTHER_TOKEN_INDEX, // USDC Curve pool index BOLD_TOKEN_INDEX, // BOLD Curve pool index UNIV3_FEE_USDC_WETH, UNIV3_FEE_WETH_COLL, @@ -748,7 +770,7 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, USDC, WETH, _usdcCurvePool, - USDC_INDEX, // USDC Curve pool index + OTHER_TOKEN_INDEX, // USDC Curve pool index BOLD_TOKEN_INDEX, // BOLD Curve pool index UNIV3_FEE_USDC_WETH, UNIV3_FEE_WETH_COLL, @@ -780,7 +802,10 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, return leverageZapperHybrid; } - function _deployCurveBoldUsdcPool(IBoldToken _boldToken) internal returns (ICurveStableswapNGPool) { + function _deployCurvePool(IBoldToken _boldToken, IERC20Metadata _otherToken) + internal + returns (ICurveStableswapNGPool) + { if (block.chainid == 31337) { // local return ICurveStableswapNGPool(address(0)); @@ -789,23 +814,24 @@ contract DeployLiquity2Script is DeployGovernance, UniPriceConverter, StdCheats, // deploy Curve StableswapNG pool address[] memory coins = new address[](2); coins[BOLD_TOKEN_INDEX] = address(_boldToken); - coins[USDC_INDEX] = address(USDC); + coins[OTHER_TOKEN_INDEX] = address(_otherToken); uint8[] memory assetTypes = new uint8[](2); // 0: standard bytes4[] memory methodIds = new bytes4[](2); address[] memory oracles = new address[](2); - ICurveStableswapNGPool curvePool = curveStableswapFactory.deploy_plain_pool( - "USDC-BOLD", - "USDCBOLD", - coins, - 200, // A - 1000000, // fee - 20000000000, // _offpeg_fee_multiplier - 865, // _ma_exp_time - 0, // implementation id - assetTypes, - methodIds, - oracles - ); + + ICurveStableswapNGPool curvePool = curveStableswapFactory.deploy_plain_pool({ + name: string.concat("BOLD/", _otherToken.symbol(), " Pool"), + symbol: string.concat("BOLD", _otherToken.symbol()), + coins: coins, + A: 100, + fee: 4000000, + offpeg_fee_multiplier: 20000000000, + ma_exp_time: 866, + implementation_id: 0, + asset_types: assetTypes, + method_ids: methodIds, + oracles: oracles + }); return curvePool; } diff --git a/contracts/test/E2E.t.sol b/contracts/test/E2E.t.sol index 8cd25c912..34c1579fa 100644 --- a/contracts/test/E2E.t.sol +++ b/contracts/test/E2E.t.sol @@ -159,6 +159,10 @@ contract E2ETest is Test { ICurveStableSwapNG curveUsdcBold; ILiquidityGaugeV6 curveUsdcBoldGauge; CurveV2GaugeRewards curveUsdcBoldInitiative; + ICurveStableSwapNG curveLusdBold; + ILiquidityGaugeV6 curveLusdBoldGauge; + CurveV2GaugeRewards curveLusdBoldInitiative; + address defiCollectiveInitiative; BranchContracts[] branches; address[] ownables; @@ -177,9 +181,13 @@ contract E2ETest is Test { boldToken = IBoldToken(BOLD = json.readAddress(".boldToken")); hintHelpers = IHintHelpers(json.readAddress(".hintHelpers")); governance = Governance(json.readAddress(".governance.governance")); - curveUsdcBold = ICurveStableSwapNG(json.readAddress(".governance.curvePool")); - curveUsdcBoldGauge = ILiquidityGaugeV6(json.readAddress(".governance.gauge")); - curveUsdcBoldInitiative = CurveV2GaugeRewards(json.readAddress(".governance.curveV2GaugeRewardsInitiative")); + curveUsdcBold = ICurveStableSwapNG(json.readAddress(".governance.curveUsdcBoldPool")); + curveUsdcBoldGauge = ILiquidityGaugeV6(json.readAddress(".governance.curveUsdcBoldGauge")); + curveUsdcBoldInitiative = CurveV2GaugeRewards(json.readAddress(".governance.curveUsdcBoldInitiative")); + curveLusdBold = ICurveStableSwapNG(json.readAddress(".governance.curveLusdBoldPool")); + curveLusdBoldGauge = ILiquidityGaugeV6(json.readAddress(".governance.curveLusdBoldGauge")); + curveLusdBoldInitiative = CurveV2GaugeRewards(json.readAddress(".governance.curveLusdBoldInitiative")); + defiCollectiveInitiative = json.readAddress(".governance.defiCollectiveInitiative"); vm.label(address(collateralRegistry), "CollateralRegistry"); vm.label(address(hintHelpers), "HintHelpers"); @@ -601,6 +609,13 @@ contract E2ETest is Test { string.concat("Ownership of ", vm.getLabel(ownables[i]), " should have been renounced") ); } + + ILiquidityGaugeV6[1] memory gauges = [curveUsdcBoldGauge]; + + for (uint256 i = 0; i < gauges.length; ++i) { + address gaugeManager = gauges[i].manager(); + assertEq(gaugeManager, address(0), "Gauge manager role should have been renounced"); + } } function test_Initially_NewInitiativeCannotBeRegistered() external { @@ -655,6 +670,9 @@ contract E2ETest is Test { assertEqDecimal(borrowed, 0, 18, "Mainnet deployment script should not have borrowed anything"); assertNotEq(address(curveUsdcBoldGauge), address(0), "Mainnet should have USDC-BOLD gauge"); assertNotEq(address(curveUsdcBoldInitiative), address(0), "Mainnet should have USDC-BOLD initiative"); + assertNotEq(address(curveLusdBold), address(0), "Mainnet should have LUSD-BOLD pool"); + assertNotEq(address(curveLusdBoldGauge), address(0), "Mainnet should have LUSD-BOLD gauge"); + assertNotEq(address(curveLusdBoldInitiative), address(0), "Mainnet should have LUSD-BOLD initiative"); } address borrower = providerOf[BOLD] = makeAddr("borrower"); @@ -670,15 +688,27 @@ contract E2ETest is Test { { skip(5 minutes); - uint256 boldAmount = boldToken.balanceOf(borrower) * 4 / 5; + uint256 boldAmount = boldToken.balanceOf(borrower) * 2 / 5; uint256 usdcAmount = boldAmount * 10 ** usdc.decimals() / 10 ** boldToken.decimals(); + uint256 lusdAmount = boldAmount; + _addCurveLiquidity(liquidityProvider, curveUsdcBold, boldAmount, BOLD, usdcAmount, USDC); + if (address(curveLusdBold) != address(0)) { + _addCurveLiquidity(liquidityProvider, curveLusdBold, boldAmount, BOLD, lusdAmount, LUSD); + } + if (address(curveUsdcBoldGauge) != address(0)) { _depositIntoCurveGauge( liquidityProvider, curveUsdcBoldGauge, curveUsdcBold.balanceOf(liquidityProvider) ); } + + if (address(curveLusdBoldGauge) != address(0)) { + _depositIntoCurveGauge( + liquidityProvider, curveLusdBoldGauge, curveLusdBold.balanceOf(liquidityProvider) + ); + } } address stabilityDepositor = makeAddr("stabilityDepositor"); @@ -719,7 +749,7 @@ contract E2ETest is Test { address staker = makeAddr("staker"); { - uint256 lqtyStake = 10_000 ether; + uint256 lqtyStake = 30_000 ether; _depositLQTY(staker, lqtyStake); skip(5 minutes); @@ -737,11 +767,25 @@ contract E2ETest is Test { ); assertApproxEqAbsDecimal(staker.balance, ethAmount * lqtyStake / totalLQTYStaked, 1e4, 18, "ETH reward"); - if (address(curveUsdcBoldInitiative) != address(0)) { + if ( + address(curveUsdcBoldInitiative) != address(0) || address(curveLusdBoldInitiative) != address(0) + || defiCollectiveInitiative != address(0) + ) { skip(5 minutes); - _allocateLQTY_begin(staker); - _allocateLQTY_vote(address(curveUsdcBoldInitiative), 10_000 ether); + + if (address(curveUsdcBoldInitiative) != address(0)) { + _allocateLQTY_vote(address(curveUsdcBoldInitiative), int256(lqtyStake / 3)); + } + + if (address(curveLusdBoldInitiative) != address(0)) { + _allocateLQTY_vote(address(curveLusdBoldInitiative), int256(lqtyStake / 3)); + } + + if (defiCollectiveInitiative != address(0)) { + _allocateLQTY_vote(defiCollectiveInitiative, int256(lqtyStake / 3)); + } + _allocateLQTY_end(); } } @@ -828,6 +872,10 @@ contract E2ETest is Test { function test_ManagerOfCurveGauge_CanReassignRewardDistributor() external { vm.skip(address(curveUsdcBoldGauge) == address(0)); + address manager = curveUsdcBoldGauge.manager(); + vm.label(manager, "manager"); + vm.skip(manager == address(0)); + address newRewardDistributor = makeAddr("newRewardDistributor"); uint256 rewardAmount = 10_000 ether; _openTrove(0, newRewardDistributor, 0, rewardAmount); @@ -838,8 +886,6 @@ contract E2ETest is Test { curveUsdcBoldGauge.deposit_reward_token(BOLD, rewardAmount, 7 days); vm.stopPrank(); - address manager = curveUsdcBoldGauge.manager(); - vm.label(manager, "manager"); vm.prank(manager); curveUsdcBoldGauge.set_reward_distributor(BOLD, newRewardDistributor); diff --git a/contracts/test/Interfaces/Curve/ICurveStableSwapFactoryNG.sol b/contracts/test/Interfaces/Curve/ICurveStableSwapFactoryNG.sol new file mode 100644 index 000000000..8185babc2 --- /dev/null +++ b/contracts/test/Interfaces/Curve/ICurveStableSwapFactoryNG.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +interface ICurveStableSwapFactoryNG { + function deploy_plain_pool( + string calldata _name, + string calldata _symbol, + address[] calldata _coins, + uint256 _A, + uint256 _fee, + uint256 _offpeg_fee_multiplier, + uint256 _ma_exp_time, + uint256 _implementation_idx, + uint8[] calldata _asset_types, + bytes4[] calldata _method_ids, + address[] calldata _oracles + ) external returns (address); + + function deploy_gauge(address _pool) external returns (address); +} diff --git a/contracts/test/Interfaces/Curve/ILiquidityGaugeV6.sol b/contracts/test/Interfaces/Curve/ILiquidityGaugeV6.sol index 8cd0641e2..5cdc239c1 100644 --- a/contracts/test/Interfaces/Curve/ILiquidityGaugeV6.sol +++ b/contracts/test/Interfaces/Curve/ILiquidityGaugeV6.sol @@ -6,6 +6,7 @@ import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/exten interface ILiquidityGaugeV6 { function add_reward(address _reward_token, address _distributor) external; function set_reward_distributor(address _reward_token, address _distributor) external; + function set_gauge_manager(address _gauge_manager) external; function deposit_reward_token(address _reward_token, uint256 _amount, uint256 _epoch) external; function deposit(uint256 _amount) external; function claim_rewards() external;