Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finalize deployment script #701

Merged
merged 3 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions contracts/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,10 @@ FORK_CHAIN_ID=1
# Must be explicitly set when using 2-stage deployment (bold-only, use-existing-bold)
# SALT=Liquity2

# Start of Governance epoch #1
# Defaults to one epoch before `block.timestamp` on testnet
# Defaults to one epoch before latest midnight (UTC) between Wednesday & Tuesday on mainnet
# EPOCH_START=

# Better call traces, e.g. when WETH/wstETH/RETH or Curve, etc. is involved
# ETHERSCAN_API_KEY=
15 changes: 10 additions & 5 deletions contracts/addresses/11155111.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,15 @@
"EPOCH_VOTING_CUTOFF": "172800"
},
"governance": "0x7eedda08119826757c98a4680e94f3b5e1f33af6",
"uniV4DonationsInitiative": "0xc2348442f31d0182d3178d7b0c34ad58ddcf1400",
"curveV2GaugeRewardsInitiative": "0x0000000000000000000000000000000000000000",
"curvePool": "0x5b3f6b88fa29e85778394992d9bcd95ef2fceebe",
"gauge": "0x0000000000000000000000000000000000000000",
"LQTYToken": "0x878fc269a85619da792b054e2288cf5f9cc3e2e1"
Copy link
Collaborator Author

@danielattilasimon danielattilasimon Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bpierre heads up, I am renaming some fields in the manifest, because they're ambiguous: we'll have multiple Curve pools, gauges and initiatives on mainnet.

  • curveV2GaugeRewardsInitiative => curveUsdcBoldInitiative
  • curvePool => curveUsdcBoldPool
  • gauge => curveUsdcBoldGauge

Also deleting uniV4DonationsInitiative as we're not going to deploy a Uni v4 initiative.

"curveUsdcBoldPool": "0x5b3f6b88fa29e85778394992d9bcd95ef2fceebe",
"curveUsdcBoldGauge": "0x0000000000000000000000000000000000000000",
"curveUsdcBoldInitiative": "0x0000000000000000000000000000000000000000",
"curveLusdBoldPool": "0x0000000000000000000000000000000000000000",
"curveLusdBoldGauge": "0x0000000000000000000000000000000000000000",
"curveLusdBoldInitiative": "0x0000000000000000000000000000000000000000",
"defiCollectiveInitiative": "0x0000000000000000000000000000000000000000",
"stakingV1": "0x0Ade63786E85C97F6741B47DA09f8790B062a767",
"LQTYToken": "0x878fc269a85619da792b054e2288cf5f9cc3e2e1",
"LUSDToken": "0x0A69fa2A565BD6Fa9c3890ecAa30b149AAF99136"
}
}
140 changes: 81 additions & 59 deletions contracts/script/DeployGovernance.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -20,6 +20,7 @@ contract DeployGovernance is Script {
using Strings for *;

struct DeployGovernanceParams {
uint256 epochStart;
address deployer;
bytes32 salt;
address stakingV1;
Expand All @@ -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%
Expand All @@ -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);

Expand All @@ -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({
Expand All @@ -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
});
Expand All @@ -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
),
"}"
);
Expand Down
Loading
Loading