Skip to content
Draft
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^3.0.0",
"ganache-cli": "^6.12.2",
"hardhat": "^2.12.6",
"hardhat": "^2.19.5",
"husky": "^4.2.3",
"lerna": "^3.22.1",
"lint-staged": "^10.1.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"decimal.js": "^10.2.1",
"dotenv": "^9.0.0",
"eth-crypto": "^2.4.0",
"hardhat-deploy": "0.9.1",
"hardhat-deploy": "1.0.4",
"hardhat-gas-reporter": "^1.0.4",
"hardhat-typechain": "^0.3.5",
"lodash.uniqby": "^4.7.0",
Expand Down
1 change: 0 additions & 1 deletion packages/scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"@uma/financial-templates-lib": "^2.37.2",
"dotenv": "^6.2.0",
"ethers": "^5.4.2",
"hardhat": "^2.12.6",
"lodash": "^4.17.21",
"minimist": "^1.2.0",
"web3": "^1.6.0",
Expand Down
6 changes: 5 additions & 1 deletion packages/scripts/src/admin-proposals/common/networks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const supportedNetworks = ["mainnet", "polygon", "arbitrum", "optimism", "base", "blast"] as const;
export const supportedNetworks = ["mainnet", "polygon", "arbitrum", "optimism", "base", "blast"] as const;
export type SupportedNetwork = typeof supportedNetworks[number];

export const networksNumber: Record<SupportedNetwork, number> = {
Expand All @@ -10,6 +10,10 @@ export const networksNumber: Record<SupportedNetwork, number> = {
blast: 81457,
};

export function isSupportedNetwork(key: string): key is SupportedNetwork {
return (supportedNetworks as readonly string[]).includes(key);
}

export const l2Networks = supportedNetworks.filter((network) => network !== "mainnet");
export type L2Network = typeof l2Networks[number];

Expand Down
57 changes: 57 additions & 0 deletions packages/scripts/src/admin-proposals/executeAndRelayVoteV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// This script executes a governance vote on the Ethereum mainnet or its fork. It also spoofs the relaying of
// the executed proposal on all forked L2 networks when L1 is forked.
// Export following environment variables:
// - MNEMONIC: Mnemonic for the operator to execute the proposal on L1.
// - NODE_URL_1: Mainnet node URL (not required when using localhost for a forked network).
// - NODE_URL_137: Forked Polygon node URL (not required when using mainnet for L1).
// - NODE_URL_10: Forked Optimism node URL (not required when using mainnet for L1).
// - NODE_URL_42161: Forked Arbitrum node URL (not required when using mainnet for L1).
// - NODE_URL_8453: Forked Base node URL (not required when using mainnet for L1).
// - NODE_URL_81457: Forked Blast node URL (not required when using mainnet for L1).
// - L1_EXECUTE_TX: (optional) L1 transaction hash of the executed proposal, will execute the proposal on L1 if not set.
// - PROPOSAL_NUMBER: (optional) Proposal number to execute, will execute the last proposal if not set.
// Then run the script with:
// yarn hardhat run packages/scripts/src/admin-proposals/executeAndRelayVoteV2.ts --network <network>
// Note: use localhost for the forked network, for L1 mainnet need to export NODE_URL_1 environment variable.

import { getMnemonicSigner } from "@uma/common";
import hre from "hardhat";
import {
getJsonRpcProvider,
getL1ExecuteProposalReceipt,
l2Networks,
ovmNetworks,
spoofArbitrumRelay,
spoofOVMRelay,
spoofPolygonRelay,
} from "./common";

async function main() {
const l1Signer = getMnemonicSigner().connect(hre.ethers.provider);

// Executes the proposal on L1 unless L1_EXECUTE_TX was provided.
const l1TxReceipt = await getL1ExecuteProposalReceipt(l1Signer);

// Only spoof the relay on L2 when L1 is forked.
if (hre.network.name !== "localhost") return;

// Checks node URL for each forked L2 network is set.
l2Networks.forEach(getJsonRpcProvider);

// Spoof the relay of executed proposal on each L2.
for (const networkName of ovmNetworks) {
await spoofOVMRelay(networkName, l1TxReceipt);
}
await spoofArbitrumRelay(l1TxReceipt);
await spoofPolygonRelay(l1TxReceipt);
}

main().then(
() => {
process.exit(0);
},
(err) => {
console.error(err);
process.exit(1);
}
);
127 changes: 127 additions & 0 deletions packages/scripts/src/admin-proposals/remove-identifier/0_Propose.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// This script can be run against a public or forked networks.
// Export following environment variables:
// - NODE_URL_1: Mainnet node URL (not required when using localhost for a forked network).
// - NODE_URL_137: Public or forked Polygon node URL.
// - NODE_URL_10: Public or forked Optimism node URL.
// - NODE_URL_42161: Public or forked Arbitrum node URL.
// - NODE_URL_8453: Public or forked Base node URL.
// - NODE_URL_81457: Public or forked Blast node URL.
// - GCKMS_WALLET: GCKMS wallet name, required only on public mainnet.
// - IDENTIFIER: Identifier to remove.
// - UMIP_NUMBER: UMIP number to use in the proposal title.
// Then run the script with:
// yarn hardhat run packages/scripts/src/admin-proposals/remove-identifier/0_Propose.ts --network <network>
// Note: use localhost for the forked network, for L1 mainnet need to export NODE_URL_1 environment variable.

import hre from "hardhat";

import {
GovernorHubEthers,
GovernorRootTunnelEthers,
IdentifierWhitelistEthers,
ParentMessengerBaseEthers,
ProposerV2Ethers,
VotingTokenEthers,
} from "@uma/contracts-node";

import { PopulatedTransaction } from "ethers";
import { formatBytes32String } from "ethers/lib/utils";
import { getContractInstance, getContractInstanceWithProvider } from "../../utils/contracts";
import { fundArbitrumParentMessengerForRelays, relayGovernanceMessages } from "../../utils/relay";
import {
AdminProposalTransaction,
PROPOSER_ADDRESS,
getProposerSigner,
getUmipNumber,
isSupportedNetwork,
networksNumber,
supportedNetworks,
} from "../common";
import { getRetryProvider } from "@uma/common";

async function main() {
const adminProposalTransactions: AdminProposalTransaction[] = [];

if (!process.env.IDENTIFIER) throw new Error("IDENTIFIER is not set");
const oldIdentifier = formatBytes32String(process.env.IDENTIFIER);

const umipNumber = getUmipNumber();

const arbitrumParentMessenger = await getContractInstance<ParentMessengerBaseEthers>("Arbitrum_ParentMessenger");

const governorRootTunnel = await getContractInstance<GovernorRootTunnelEthers>("GovernorRootTunnel"); // for polygon
const governorHub = await getContractInstance<GovernorHubEthers>("GovernorHub"); // rest of l2

const proposerSigner = await getProposerSigner(PROPOSER_ADDRESS);

console.log("1. LOADING DEPLOYED CONTRACT STATE");

const votingToken = await getContractInstance<VotingTokenEthers>("VotingToken");

const proposerV2 = await getContractInstance<ProposerV2Ethers>("ProposerV2");
const identifierWhitelist = await getContractInstance<IdentifierWhitelistEthers>("IdentifierWhitelist");

// remove the identifier from whitelist
const removeIdentifierTx = await identifierWhitelist.populateTransaction.removeSupportedIdentifier(oldIdentifier);
if (!removeIdentifierTx.data) throw "removeIdentifierTx.data is null";
adminProposalTransactions.push({ to: identifierWhitelist.address, value: 0, data: removeIdentifierTx.data });

for (const networkName of supportedNetworks.filter((network) => network !== "mainnet")) {
if (!isSupportedNetwork(networkName)) throw new Error(`Unsupported network: ${networkName}`);
const l2ChainId = networksNumber[networkName];
const isPolygon = l2ChainId === 137;
const isArbitrum = l2ChainId === 42161;

const governanceMessages: { targetAddress: string; tx: PopulatedTransaction }[] = [];

const l2IdentifierWhitelist = await getContractInstanceWithProvider<IdentifierWhitelistEthers>(
"IdentifierWhitelist",
getRetryProvider(l2ChainId)
);

const removeIdentifierL2Tx = await l2IdentifierWhitelist.populateTransaction.removeSupportedIdentifier(
oldIdentifier
);
governanceMessages.push({ targetAddress: l2IdentifierWhitelist.address, tx: removeIdentifierL2Tx });

if (isArbitrum) await fundArbitrumParentMessengerForRelays(arbitrumParentMessenger, proposerSigner, 1);

const relayedMessages = await relayGovernanceMessages(
governanceMessages,
isPolygon ? governorRootTunnel : governorHub,
l2ChainId
);

adminProposalTransactions.push(...relayedMessages);
}

const defaultBond = await proposerV2.bond();
const allowance = await votingToken.allowance(PROPOSER_ADDRESS, proposerV2.address);
if (allowance.lt(defaultBond)) {
console.log("Approving proposer bond");
const approveTx = await votingToken.connect(proposerSigner).approve(proposerV2.address, defaultBond);
await approveTx.wait();
}

const tx = await (await getContractInstance<ProposerV2Ethers>("ProposerV2", proposerV2.address))
.connect(proposerSigner)
.propose(
adminProposalTransactions,
hre.ethers.utils.toUtf8Bytes(`UMIP-${umipNumber} remove ${process.env.IDENTIFIER} identifier`)
);

await tx.wait();

console.log("Proposal done!🎉");
console.log("\nProposal data:\n", tx.data);
}

main().then(
() => {
process.exit(0);
},
(err) => {
console.error(err);
process.exit(1);
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// This script can be run against a public or forked networks.
// Export following environment variables:
// - NODE_URL_1: Mainnet node URL (not required when using localhost for a forked network).
// - NODE_URL_137: Public or forked Polygon node URL.
// - NODE_URL_10: Public or forked Optimism node URL.
// - NODE_URL_42161: Public or forked Arbitrum node URL.
// - NODE_URL_8453: Public or forked Base node URL.
// - NODE_URL_81457: Public or forked Blast node URL.
// - IDENTIFIER: Identifier to remove.
// Then run the script with:
// yarn hardhat run packages/scripts/src/admin-proposals/remove-identifier/1_Verify.ts --network <network>
// Note: use localhost for the forked network, for L1 mainnet need to export NODE_URL_1 environment variable.

import { strict as assert } from "assert";
import hre from "hardhat";
import { IdentifierWhitelistEthers } from "@uma/contracts-node";
import { formatBytes32String } from "ethers/lib/utils";
import { getContractInstanceWithProvider } from "../../utils/contracts";
import { getJsonRpcProvider, supportedNetworks } from "../common";

async function main() {
if (!process.env.IDENTIFIER) throw new Error("IDENTIFIER is not set");
const oldIdentifier = formatBytes32String(process.env.IDENTIFIER);

for (const networkName of supportedNetworks) {
const provider = networkName === "mainnet" ? hre.ethers.provider : await getJsonRpcProvider(networkName);
const identifierWhitelist = await getContractInstanceWithProvider<IdentifierWhitelistEthers>(
"IdentifierWhitelist",
provider
);

console.log(
`Validating identifier ${process.env.IDENTIFIER} on ${networkName} at IdentifierWhitelist address: ${identifierWhitelist.address}`
);
assert(!(await identifierWhitelist.isIdentifierSupported(oldIdentifier)));
console.log(`✅ ${process.env.IDENTIFIER} identifier is not supported on ${networkName}`);
}
}

main().then(
() => {
process.exit(0);
},
(err) => {
console.error(err);
process.exit(1);
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Removal of supported identifier

This directory contains scripts to remove an identifier from the IdentifierWhitelist on all supported governance based networks.

## Testing on forked networks

Spin up forked networks, each in a separate terminal, e.g.:

```sh
HARDHAT_CHAIN_ID=1 yarn hardhat node --fork https://mainnet.infura.io/v3/<YOUR-INFURA-KEY> --port 9545 --no-deploy

HARDHAT_CHAIN_ID=137 yarn hardhat node --fork https://polygon-mainnet.infura.io/v3/<YOUR-INFURA-KEY> --port 9546 --no-deploy

HARDHAT_CHAIN_ID=10 yarn hardhat node --fork https://optimism-mainnet.infura.io/v3/<YOUR-INFURA-KEY> --port 9547 --no-deploy

HARDHAT_CHAIN_ID=42161 yarn hardhat node --fork https://arbitrum-mainnet.infura.io/v3/<YOUR-INFURA-KEY> --port 9548 --no-deploy

HARDHAT_CHAIN_ID=8453 yarn hardhat node --fork https://base-mainnet.infura.io/v3/<YOUR-INFURA-KEY> --port 9549 --no-deploy

HARDHAT_CHAIN_ID=81457 yarn hardhat node --fork https://blast-mainnet.infura.io/v3/<YOUR-INFURA-KEY> --port 9550 --no-deploy
```

Note that Ethereum mainnet must use port `9545` as the scripts rely on hardhat `localhost` network when forking. For other networks, you can use any other free port and pass its node URL as an environment variable.

Export the required environment:

```sh
export MNEMONIC=<YOUR-MNEMONIC>
export NODE_URL_137=http://localhost:9546
export NODE_URL_10=http://localhost:9547
export NODE_URL_42161=http://localhost:9548
export NODE_URL_8453=http://localhost:9549
export NODE_URL_81457=http://localhost:9550
export UMIP_NUMBER=<UMIP-NUMBER>
export IDENTIFIER=<IDENTIFIER-TO-REMOVE>
```

Note: make sure the wallet corresponding to the `MNEMONIC` is sufficiently funded on the forked networks (use `hardhat_setBalance` if needed).

Request to impersonate accounts and seed wallet on the forked mainnet that we'll need to propose and vote on the admin proposal:

```sh
./packages/scripts/setupFork.sh
```

Propose the governance vote to remove the supported identifier on the forked mainnet:

```sh
yarn hardhat run packages/scripts/src/admin-proposals/remove-identifier/0_Propose.ts --network localhost
```

Simulate the vote on the proposal without executing it yet:

```sh
SKIP_EXECUTE=1 yarn hardhat run packages/scripts/src/admin-proposals/simulateVoteV2.ts --network localhost
```

Execute the proposal on the forked mainnet and spoof relaying the governance transactions to forked L2 networks:

```sh
yarn hardhat run packages/scripts/src/admin-proposals/executeAndRelayVoteV2.ts --network localhost
```

Verify the proposal execution on the forked networks:

```sh
yarn hardhat run packages/scripts/src/admin-proposals/remove-identifier/1_Verify.ts --network localhost
```

## Public networks

Update the required `NODE_URL_` environment variables to point to public networks.

Propose the governance vote to remove the supported identifier on the mainnet:

```sh
GCKMS_WALLET=deployer yarn hardhat run packages/scripts/src/admin-proposals/remove-identifier/0_Propose.ts --network mainnet
```

Note: make sure to first authenticate to `gcloud`.

If the vote is resolved to approve the migration, execute the proposal on the mainnet and wait for it to be relayed to the L2 networks:

```sh
yarn hardhat run packages/scripts/src/admin-proposals/executeAndRelayVoteV2.ts --network mainnet
```

Verify the proposal execution on all the networks:

```sh
yarn hardhat run packages/scripts/src/admin-proposals/remove-identifier/1_Verify.ts --network mainnet
```
Loading