@dydxfoundation/governance
Version:
dYdX governance smart contracts
346 lines (345 loc) • 20.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deployPhase2 = void 0;
const utils_1 = require("ethers/lib/utils");
const lodash_1 = __importDefault(require("lodash"));
const types_1 = require("../../types");
const StarkProxyV1__factory_1 = require("../../types/factories/StarkProxyV1__factory");
const deploy_config_1 = require("../deploy-config");
const get_deployer_address_1 = require("../deploy-config/get-deployer-address");
const constants_1 = require("../lib/constants");
const logging_1 = require("../lib/logging");
const util_1 = require("../lib/util");
const types_2 = require("../types");
const deploy_upgradeable_1 = require("./helpers/deploy-upgradeable");
const transfer_tokens_1 = require("./helpers/transfer-tokens");
async function deployPhase2({ startStep = 0,
// Mock contracts.
starkPerpetualAddress, dydxCollateralTokenAddress,
// Phase 1 deployed contracts.
dydxTokenAddress, governorAddress, shortTimelockAddress, longTimelockAddress, merklePauserTimelockAddress: merkleTimelockAddress,
// Phase 2 deployed contracts.
rewardsTreasuryAddress, rewardsTreasuryProxyAdminAddress, safetyModuleAddress, safetyModuleProxyAdminAddress, strategyAddress, communityTreasuryAddress, communityTreasuryProxyAdminAddress, rewardsTreasuryVesterAddress, communityTreasuryVesterAddress, claimsProxyAddress, liquidityStakingAddress, liquidityStakingProxyAdminAddress, merkleDistributorAddress, merkleDistributorProxyAdminAddress, starkProxyAddresses, starkProxyProxyAdminAddresses, }) {
(0, logging_1.log)('Beginning phase 2 deployment\n');
const deployConfig = (0, deploy_config_1.getDeployConfig)();
const deployer = await (0, get_deployer_address_1.getDeployerSigner)();
const deployerAddress = deployer.address;
(0, logging_1.log)(`Beginning deployment with deployer ${deployerAddress}\n`);
// Phase 1 deployed contracts.
const dydxToken = new types_1.DydxToken__factory(deployer).attach(dydxTokenAddress);
const governor = new types_1.DydxGovernor__factory(deployer).attach(governorAddress);
const longTimelock = new types_1.Executor__factory(deployer).attach(longTimelockAddress);
const shortTimelock = new types_1.Executor__factory(deployer).attach(shortTimelockAddress);
// Phase 2 deployed contracts.
let rewardsTreasury;
let rewardsTreasuryProxyAdmin;
let safetyModule;
let safetyModuleProxyAdmin;
let strategy;
let communityTreasury;
let communityTreasuryProxyAdmin;
let rewardsTreasuryVester;
let communityTreasuryVester;
let claimsProxy;
let liquidityStaking;
let liquidityStakingProxyAdmin;
let merkleDistributor;
let merkleDistributorProxyAdmin;
let starkProxies;
let starkProxyProxyAdmins;
const deployerBalance = await dydxToken.balanceOf(deployerAddress);
if (deployerBalance.lt((0, util_1.toWad)(50000000))) {
throw new Error(`Need at least 500M DYDX to run this deploy script. Current balance: ${(0, utils_1.formatEther)(deployerBalance)}`);
}
if (startStep <= 1) {
(0, logging_1.log)('Step 1. Deploy upgradeable Rewards Treasury');
[rewardsTreasury, , rewardsTreasuryProxyAdmin] = await (0, deploy_upgradeable_1.deployUpgradeable)(types_1.Treasury__factory, deployer, [], []);
rewardsTreasuryAddress = rewardsTreasury.address;
rewardsTreasuryProxyAdminAddress = rewardsTreasuryProxyAdmin.address;
}
else {
if (!rewardsTreasuryAddress) {
throw new Error('Expected parameter rewardsTreasuryAddress to be specified.');
}
if (!rewardsTreasuryProxyAdminAddress) {
throw new Error('Expected parameter rewardsTreasuryProxyAdminAddress to be specified.');
}
rewardsTreasury = new types_1.Treasury__factory(deployer).attach(rewardsTreasuryAddress);
rewardsTreasuryProxyAdmin = new types_1.ProxyAdmin__factory(deployer).attach(rewardsTreasuryProxyAdminAddress);
}
if (startStep <= 2) {
(0, logging_1.log)('Step 2. Deploy and initialize upgradeable Safety Module');
[safetyModule, , safetyModuleProxyAdmin] = await (0, deploy_upgradeable_1.deployUpgradeable)(types_1.SafetyModuleV1__factory, deployer, [
dydxTokenAddress,
dydxTokenAddress,
rewardsTreasuryAddress,
deployConfig.SM_DISTRIBUTION_START,
deployConfig.SM_DISTRIBUTION_END,
], [
deployConfig.EPOCH_LENGTH,
deployConfig.EPOCH_ZERO_START,
deployConfig.BLACKOUT_WINDOW,
]);
safetyModuleAddress = safetyModule.address;
safetyModuleProxyAdminAddress = safetyModuleProxyAdmin.address;
}
else {
if (!safetyModuleAddress) {
throw new Error('Expected parameter safetyModuleAddress to be specified.');
}
if (!safetyModuleProxyAdminAddress) {
throw new Error('Expected parameter safetyModuleProxyAdminAddress to be specified.');
}
safetyModule = new types_1.SafetyModuleV1__factory(deployer).attach(safetyModuleAddress);
safetyModuleProxyAdmin = new types_1.ProxyAdmin__factory(deployer).attach(safetyModuleProxyAdminAddress);
}
if (startStep <= 3) {
(0, logging_1.log)('Step 3. Deploy strategy');
strategy = await new types_1.GovernanceStrategy__factory(deployer).deploy(dydxTokenAddress, safetyModuleAddress);
strategyAddress = strategy.address;
}
else {
if (!strategyAddress) {
throw new Error('Expected parameter strategyAddress to be specified.');
}
strategy = new types_1.GovernanceStrategy__factory(deployer).attach(strategyAddress);
}
if (startStep <= 4) {
(0, logging_1.log)('Step 4. Set strategy on governor');
await (0, util_1.waitForTx)(await governor.setGovernanceStrategy(strategyAddress));
}
if (startStep <= 5) {
(0, logging_1.log)('Step 5. Deploy upgradeable Community Treasury');
[communityTreasury, , communityTreasuryProxyAdmin] = await (0, deploy_upgradeable_1.deployUpgradeable)(types_1.Treasury__factory, deployer, [], []);
communityTreasuryAddress = communityTreasury.address;
communityTreasuryProxyAdminAddress = communityTreasuryProxyAdmin.address;
}
else {
if (!communityTreasuryAddress) {
throw new Error('Expected parameter communityTreasuryAddress to be specified.');
}
if (!communityTreasuryProxyAdminAddress) {
throw new Error('Expected parameter communityTreasuryProxyAdminAddress to be specified.');
}
communityTreasury = new types_1.Treasury__factory(deployer).attach(communityTreasuryAddress);
communityTreasuryProxyAdmin = new types_1.ProxyAdmin__factory(deployer).attach(communityTreasuryProxyAdminAddress);
}
if (startStep <= 6) {
(0, logging_1.log)('Step 6. Deploy rewards treasury vester');
rewardsTreasuryVester = await new types_1.TreasuryVester__factory(deployer).deploy(dydxTokenAddress, rewardsTreasuryAddress, deployConfig.REWARDS_TREASURY_VESTER_CONFIG.VESTING_AMOUNT, deployConfig.REWARDS_TREASURY_VESTER_CONFIG.VESTING_BEGIN, deployConfig.REWARDS_TREASURY_VESTER_CONFIG.VESTING_CLIFF, deployConfig.REWARDS_TREASURY_VESTER_CONFIG.VESTING_END);
rewardsTreasuryVesterAddress = rewardsTreasuryVester.address;
}
else {
if (!rewardsTreasuryVesterAddress) {
throw new Error('Expected parameter rewardsTreasuryVesterAddress to be specified.');
}
rewardsTreasuryVester = new types_1.TreasuryVester__factory(deployer).attach(rewardsTreasuryVesterAddress);
}
if (startStep <= 7) {
(0, logging_1.log)('Step 7. Deploy community treasury vester');
communityTreasuryVester = await new types_1.TreasuryVester__factory(deployer).deploy(dydxTokenAddress, communityTreasuryAddress, deployConfig.COMMUNITY_TREASURY_VESTER_CONFIG.VESTING_AMOUNT, deployConfig.COMMUNITY_TREASURY_VESTER_CONFIG.VESTING_BEGIN, deployConfig.COMMUNITY_TREASURY_VESTER_CONFIG.VESTING_CLIFF, deployConfig.COMMUNITY_TREASURY_VESTER_CONFIG.VESTING_END);
communityTreasuryVesterAddress = communityTreasuryVester.address;
}
else {
if (!communityTreasuryVesterAddress) {
throw new Error('Expected parameter communityTreasuryVesterAddress to be specified.');
}
communityTreasuryVester = new types_1.TreasuryVester__factory(deployer).attach(communityTreasuryVesterAddress);
}
if (startStep <= 8) {
(0, logging_1.log)('Step 8. Deploy merkle distributor proxy + merkle distributor proxy admin + merkle distributor');
[merkleDistributor, , merkleDistributorProxyAdmin] = await (0, deploy_upgradeable_1.deployUpgradeable)(types_1.MerkleDistributorV1__factory, deployer, [
dydxTokenAddress,
rewardsTreasuryAddress,
], [
constants_1.ZERO_ADDRESS,
deployConfig.MERKLE_DISTRIBUTOR_CONFIG.IPNS_NAME,
deployConfig.MERKLE_DISTRIBUTOR_CONFIG.IPFS_UPDATE_PERIOD,
(0, util_1.toWad)(deployConfig.MERKLE_DISTRIBUTOR_CONFIG.MARKET_MAKER_REWARDS_AMOUNT),
(0, util_1.toWad)(deployConfig.MERKLE_DISTRIBUTOR_CONFIG.TRADER_REWARDS_AMOUNT),
(0, util_1.toWad)(deployConfig.MERKLE_DISTRIBUTOR_CONFIG.TRADER_SCORE_ALPHA),
deployConfig.EPOCH_ZERO_START,
deployConfig.EPOCH_LENGTH,
]);
merkleDistributorAddress = merkleDistributor.address;
merkleDistributorProxyAdminAddress = merkleDistributorProxyAdmin.address;
}
else {
if (!merkleDistributorAddress) {
throw new Error('Expected parameter merkleDistributorAddress to be specified.');
}
merkleDistributor = new types_1.MerkleDistributorV1__factory(deployer).attach(merkleDistributorAddress);
if (!merkleDistributorProxyAdminAddress) {
throw new Error('Expected parameter merkleDistributorProxyAdminAddress to be specified.');
}
merkleDistributorProxyAdmin = new types_1.ProxyAdmin__factory(deployer).attach(merkleDistributorProxyAdminAddress);
}
// TODO: Add steps 9–10.
if (startStep <= 11) {
(0, logging_1.log)('Step 11. Deploy liquidity staking proxy + liquidity staking proxy admin + liquidity staking');
[liquidityStaking, , liquidityStakingProxyAdmin] = await (0, deploy_upgradeable_1.deployUpgradeable)(types_1.LiquidityStakingV1__factory, deployer, [
dydxCollateralTokenAddress,
dydxTokenAddress,
rewardsTreasuryAddress,
deployConfig.LS_DISTRIBUTION_START,
deployConfig.LS_DISTRIBUTION_END,
], [
deployConfig.EPOCH_LENGTH,
deployConfig.EPOCH_ZERO_START,
deployConfig.BLACKOUT_WINDOW,
]);
liquidityStakingAddress = liquidityStaking.address;
liquidityStakingProxyAdminAddress = liquidityStakingProxyAdmin.address;
}
else {
if (!liquidityStakingAddress) {
throw new Error('Expected parameter liquidityStakingAddress to be specified.');
}
liquidityStaking = new types_1.LiquidityStakingV1__factory(deployer).attach(liquidityStakingAddress);
if (!liquidityStakingProxyAdminAddress) {
throw new Error('Expected parameter liquidityStakingProxyAdminAddress to be specified.');
}
liquidityStakingProxyAdmin = new types_1.ProxyAdmin__factory(deployer).attach(liquidityStakingProxyAdminAddress);
}
if (startStep <= 12) {
(0, logging_1.log)('Step 12. Add treasury contracts token transfer allowlist');
await (0, util_1.waitForTx)(await dydxToken.addToTokenTransferAllowlist([
rewardsTreasuryAddress,
communityTreasuryAddress,
]));
}
if (startStep <= 13) {
(0, logging_1.log)('Step 13. Give incentive contracts infinite approval to pull funds from rewards treasury');
await (0, util_1.waitForTx)(await rewardsTreasury.approve(dydxTokenAddress, safetyModuleAddress, constants_1.MAX_UINT_AMOUNT));
await (0, util_1.waitForTx)(await rewardsTreasury.approve(dydxTokenAddress, merkleDistributorAddress, constants_1.MAX_UINT_AMOUNT));
await (0, util_1.waitForTx)(await rewardsTreasury.approve(dydxTokenAddress, liquidityStakingAddress, constants_1.MAX_UINT_AMOUNT));
}
if (startStep <= 14) {
(0, logging_1.log)('Step 14. Deploy claims proxy contract');
claimsProxy = await new types_1.ClaimsProxy__factory(deployer).deploy(safetyModuleAddress, liquidityStakingAddress, merkleDistributorAddress, rewardsTreasuryVesterAddress);
claimsProxyAddress = claimsProxy.address;
}
else {
if (!claimsProxyAddress) {
throw new Error('Expected parameter claimsProxyAddress to be specified.');
}
claimsProxy = new types_1.ClaimsProxy__factory(deployer).attach(claimsProxyAddress);
}
if (startStep <= 15) {
(0, logging_1.log)('Step 15. Grant CLAIM_OPERATOR_ROLE to claims proxy for incentives contracts');
await (0, util_1.waitForTx)(await safetyModule.grantRole((0, util_1.getRole)(types_2.Role.CLAIM_OPERATOR_ROLE), claimsProxyAddress));
await (0, util_1.waitForTx)(await liquidityStaking.grantRole((0, util_1.getRole)(types_2.Role.CLAIM_OPERATOR_ROLE), claimsProxyAddress));
await (0, util_1.waitForTx)(await merkleDistributor.grantRole((0, util_1.getRole)(types_2.Role.CLAIM_OPERATOR_ROLE), claimsProxyAddress));
}
if (startStep <= 16) {
(0, logging_1.log)('Step 16. Set rewards rates for staking contracts');
await (0, util_1.waitForTx)(await liquidityStaking.setRewardsPerSecond(deployConfig.LS_REWARDS_PER_SECOND));
await (0, util_1.waitForTx)(await safetyModule.setRewardsPerSecond(deployConfig.SM_REWARDS_PER_SECOND));
}
// TODO: Add steps 17-20.
if (startStep <= 21) {
// start with allocation to `ZERO_ADDRESS` set to 0 (since `ZERO_ADDRESS` initially has 100% of allocation)
(0, logging_1.log)('Step 21: Deploy StarkProxies for borrowers and set borrower allocations');
const deployedStarkProxies = [];
const deployedStarkProxyProxyAdmins = [];
const borrowers = [constants_1.ZERO_ADDRESS];
const borrowerAllocations = [0];
for (let i = 0; i < deployConfig.STARK_PROXY_CONFIG.BORROWER_CONFIGS.length; i++) {
const [starkProxy, , starkProxyProxyAdmin] = await (0, deploy_upgradeable_1.deployUpgradeable)(StarkProxyV1__factory_1.StarkProxyV1__factory, deployer, [
liquidityStakingAddress,
starkPerpetualAddress,
dydxCollateralTokenAddress,
merkleDistributorAddress,
], [deployerAddress]);
const allocation = deployConfig.STARK_PROXY_CONFIG.BORROWER_CONFIGS[i].BORROWER_ALLOCATION;
deployedStarkProxies.push(starkProxy);
deployedStarkProxyProxyAdmins.push(starkProxyProxyAdmin);
borrowers.push(starkProxy.address);
borrowerAllocations.push(allocation);
}
await (0, util_1.waitForTx)(await liquidityStaking.setBorrowerAllocations(borrowers, borrowerAllocations));
starkProxies = deployedStarkProxies;
starkProxyProxyAdmins = deployedStarkProxyProxyAdmins;
starkProxyAddresses = deployedStarkProxies.map((s) => s.address);
starkProxyProxyAdminAddresses = deployedStarkProxyProxyAdmins.map((s) => s.address);
}
else {
const numBorrowers = deployConfig.STARK_PROXY_CONFIG.BORROWER_CONFIGS.length;
if (!starkProxyAddresses || starkProxyAddresses.length !== numBorrowers) {
throw new Error(`Expected parameter starkProxyAddresses to be specified and have length ${numBorrowers}.`);
}
starkProxies = starkProxyAddresses.map((s) => new StarkProxyV1__factory_1.StarkProxyV1__factory(deployer).attach(s));
if (!starkProxyProxyAdminAddresses || starkProxyProxyAdminAddresses.length !== numBorrowers) {
throw new Error(`Expected parameter starkProxyProxyAdminAddresses to be specified and have length ${numBorrowers}.`);
}
starkProxyProxyAdmins = starkProxyProxyAdminAddresses.map((s) => new types_1.ProxyAdmin__factory(deployer).attach(s));
}
if (startStep <= 22) {
(0, logging_1.log)('Step 22. Grant GUARDIAN_ROLE to short timelock, VETO_GUARDIAN_ROLE to Merkle timelock, and all other roles to borrower, for each StarkProxy');
// Revoke roles from each Stark Proxy.
const starkProxyTxs = lodash_1.default.flatten(await Promise.all(starkProxies.map(async (sp, i) => {
const borrowerAddress = deployConfig.STARK_PROXY_CONFIG.BORROWER_CONFIGS[i].BORROWER_ADDRESS;
return [
await sp.grantRole((0, util_1.getRole)(types_2.Role.GUARDIAN_ROLE), shortTimelockAddress),
await sp.grantRole((0, util_1.getRole)(types_2.Role.VETO_GUARDIAN_ROLE), merkleTimelockAddress),
await sp.grantRole((0, util_1.getRole)(types_2.Role.OWNER_ROLE), borrowerAddress),
await sp.grantRole((0, util_1.getRole)(types_2.Role.DELEGATION_ADMIN_ROLE), borrowerAddress),
await sp.grantRole((0, util_1.getRole)(types_2.Role.WITHDRAWAL_OPERATOR_ROLE), borrowerAddress),
await sp.grantRole((0, util_1.getRole)(types_2.Role.BORROWER_ROLE), borrowerAddress),
await sp.grantRole((0, util_1.getRole)(types_2.Role.EXCHANGE_OPERATOR_ROLE), borrowerAddress),
];
})));
await Promise.all(starkProxyTxs.map((tx) => (0, util_1.waitForTx)(tx)));
}
if (startStep <= 23) {
(0, logging_1.log)('Step 23. Grant contract ownership and roles to timelocks');
const txs = [
// Assign roles for the Merkle Distributor Module.
await merkleDistributor.grantRole((0, util_1.getRole)(types_2.Role.PAUSER_ROLE), merkleTimelockAddress),
await merkleDistributor.grantRole((0, util_1.getRole)(types_2.Role.CONFIG_UPDATER_ROLE), shortTimelockAddress),
await merkleDistributor.grantRole((0, util_1.getRole)(types_2.Role.OWNER_ROLE), shortTimelockAddress),
await merkleDistributor.grantRole((0, util_1.getRole)(types_2.Role.UNPAUSER_ROLE), shortTimelockAddress),
// Assign roles for the Liquidity Staking Module.
await liquidityStaking.grantRole((0, util_1.getRole)(types_2.Role.OWNER_ROLE), shortTimelockAddress),
await liquidityStaking.grantRole((0, util_1.getRole)(types_2.Role.EPOCH_PARAMETERS_ROLE), shortTimelockAddress),
await liquidityStaking.grantRole((0, util_1.getRole)(types_2.Role.REWARDS_RATE_ROLE), shortTimelockAddress),
await liquidityStaking.grantRole((0, util_1.getRole)(types_2.Role.BORROWER_ADMIN_ROLE), shortTimelockAddress),
// Assign roles for the Safety Module.
await safetyModule.grantRole((0, util_1.getRole)(types_2.Role.OWNER_ROLE), shortTimelockAddress),
await safetyModule.grantRole((0, util_1.getRole)(types_2.Role.SLASHER_ROLE), shortTimelockAddress),
await safetyModule.grantRole((0, util_1.getRole)(types_2.Role.EPOCH_PARAMETERS_ROLE), shortTimelockAddress),
await safetyModule.grantRole((0, util_1.getRole)(types_2.Role.REWARDS_RATE_ROLE), shortTimelockAddress),
// Assign roles for the Governor.
await governor.grantRole((0, util_1.getRole)(types_2.Role.OWNER_ROLE), longTimelock.address),
await governor.grantRole((0, util_1.getRole)(types_2.Role.ADD_EXECUTOR_ROLE), shortTimelock.address),
];
await Promise.all(txs.map((tx) => (0, util_1.waitForTx)(tx)));
}
if (startStep <= 24) {
(0, logging_1.log)('Step 24. Send tokens to rewards treasury');
await (0, transfer_tokens_1.transferWithPrompt)(dydxToken, rewardsTreasuryAddress, deployConfig.REWARDS_TREASURY_FRONTLOADED_FUNDS);
}
(0, logging_1.log)('\n=== PHASE 2 DEPLOYMENT COMPLETE ===\n');
return {
rewardsTreasury,
rewardsTreasuryProxyAdmin,
safetyModule,
safetyModuleProxyAdmin,
strategy,
communityTreasury,
communityTreasuryProxyAdmin,
rewardsTreasuryVester,
communityTreasuryVester,
claimsProxy,
liquidityStaking,
liquidityStakingProxyAdmin,
merkleDistributor,
merkleDistributorProxyAdmin,
starkProxies,
starkProxyProxyAdmins,
};
}
exports.deployPhase2 = deployPhase2;