@dydxfoundation/governance
Version:
dYdX governance smart contracts
98 lines (97 loc) • 5.51 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.executeSafetyModuleUpgradeNoProposal = exports.executeSafetyModuleUpgradeViaProposal = void 0;
const bignumber_js_1 = __importDefault(require("bignumber.js"));
const utils_1 = require("ethers/lib/utils");
const config_1 = __importDefault(require("../../src/config"));
const deploy_config_1 = require("../../src/deploy-config");
const get_deployer_address_1 = require("../../src/deploy-config/get-deployer-address");
const logging_1 = require("../../src/lib/logging");
const util_1 = require("../../src/lib/util");
const impersonate_account_1 = require("../../src/migrations/helpers/impersonate-account");
const safety_module_fix_proposal_1 = require("../../src/migrations/safety-module-fix-proposal");
const types_1 = require("../../types");
const evm_1 = require("../helpers/evm");
const MOCK_PROPOSAL_IPFS_HASH = ('0x0000000000000000000000000000000000000000000000000000000000000000');
async function executeSafetyModuleUpgradeViaProposal({ dydxTokenAddress, governorAddress, longTimelockAddress, safetyModuleAddress, safetyModuleProxyAdminAddress, safetyModuleNewImplAddress, }) {
const deployConfig = (0, deploy_config_1.getDeployConfig)();
const deployer = await (0, get_deployer_address_1.getDeployerSigner)();
const dydxToken = new types_1.DydxToken__factory(deployer).attach(dydxTokenAddress);
const governor = new types_1.DydxGovernor__factory(deployer).attach(governorAddress);
// Pick a voter with enough tokens to meet the quorum requirement.
const voterAddress = deployConfig.TOKEN_ALLOCATIONS.DYDX_TRADING.ADDRESS;
const voter = await (0, impersonate_account_1.impersonateAndFundAccount)(voterAddress);
const voterBalance = await dydxToken.balanceOf(voterAddress);
if (voterBalance.lt(new bignumber_js_1.default('1e26').toFixed())) {
throw new Error('Not enough votes to pass the proposal.');
}
// Vote on an existing proposal (can be used with mainnet forking).
let proposalId;
if (config_1.default.SM_FIX_PROPOSAL_ID !== null) {
proposalId = config_1.default.SM_FIX_PROPOSAL_ID;
}
else {
(0, logging_1.log)('Creating proposal');
({ proposalId } = await (0, safety_module_fix_proposal_1.createSafetyModuleFixProposal)({
proposalIpfsHashHex: MOCK_PROPOSAL_IPFS_HASH,
governorAddress,
longTimelockAddress,
safetyModuleAddress,
safetyModuleProxyAdminAddress,
safetyModuleNewImplAddress,
signer: voter,
}));
(0, logging_1.log)('Waiting for voting to begin');
for (let i = 0; i < deployConfig.VOTING_DELAY_BLOCKS + 1; i++) {
if (i > 0 && i % 2000 === 0) {
(0, logging_1.log)('mining', i);
}
await (0, evm_1.advanceBlock)();
}
}
let proposalState = await governor.getProposalState(proposalId);
if (proposalState !== 2) {
throw new Error('Expected proposal to be in the voting phase.');
}
(0, logging_1.log)('Submitting vote');
await (0, util_1.waitForTx)(await governor.connect(voter).submitVote(proposalId, true));
(0, logging_1.log)('Waiting for voting to end');
let minedCount = 0;
for (;;) {
for (let i = 0; i < 2000; i++) {
await (0, evm_1.advanceBlock)();
minedCount++;
}
(0, logging_1.log)('mining', minedCount);
proposalState = await governor.getProposalState(proposalId);
if (proposalState !== 2) {
break;
}
}
if (proposalState !== 4) {
throw new Error(`Expected proposal to have succeeded but state was ${proposalState}`);
}
(0, logging_1.log)('Queueing the proposal');
await (0, util_1.waitForTx)(await governor.queue(proposalId));
const delaySeconds = deployConfig.LONG_TIMELOCK_CONFIG.DELAY;
await (0, evm_1.increaseTimeAndMine)(delaySeconds);
(0, logging_1.log)('Executing the proposal');
await (0, util_1.waitForTx)(await governor.execute(proposalId));
(0, logging_1.log)('Proposal executed');
(0, logging_1.log)('\n=== SAFETY MODULE FIX COMPLETE ===\n');
}
exports.executeSafetyModuleUpgradeViaProposal = executeSafetyModuleUpgradeViaProposal;
async function executeSafetyModuleUpgradeNoProposal({ longTimelockAddress, safetyModuleAddress, safetyModuleProxyAdminAddress, safetyModuleNewImplAddress, }) {
// NOTE: On mainnet, the upgrade and the call to the initializer are performed atomically
// via a governance proposal. It's important that these steps are atomic or else the
// initializer can be called to extract funds from the contract.
const mockLongTimelock = await (0, impersonate_account_1.impersonateAndFundAccount)(longTimelockAddress);
const safetyModuleProxyAdmin = new types_1.ProxyAdmin__factory(mockLongTimelock).attach(safetyModuleProxyAdminAddress);
const initializeCalldata = new utils_1.Interface(types_1.SafetyModuleV2__factory.abi).encodeFunctionData('initialize', []);
await (0, util_1.waitForTx)(await safetyModuleProxyAdmin.upgradeAndCall(safetyModuleAddress, safetyModuleNewImplAddress, initializeCalldata));
(0, logging_1.log)('\n=== SAFETY MODULE FIX COMPLETE ===\n');
}
exports.executeSafetyModuleUpgradeNoProposal = executeSafetyModuleUpgradeNoProposal;