Skip to content

Commit

Permalink
Mumbai deployment (compound-finance#561)
Browse files Browse the repository at this point in the history
* Mumbai deployment

add mumbai, polygon to hardhat config,etherscan.ts

add mumbai base

add configuration.json

add Timelock

remove safemath fns, solium-disables from timelock

remove chai

base mumbai/usdc deploy

base PolygonBridgeReceiver

rename Timelock to BridgeTimelock; add setGuardian

ITimelock

s/Timelock/BridgeTimelock/g

add Unauthorized error, import ITimelock, calculate eta

implement IFxMessageProcessor

deploy todos

deploy BridgeTimelock

misc updates to PolygonBridgeReceiver

remove guardian from BridgeTimelock

initialize PolygonBridgeReceiver

add USDC

add WBTC, WETH

add WMATIC

mumbai relations

custom errors for BridgeTimelock

immutables for BridgeTimelock

camelCase for immutables

add Bulker and Fauceteer

mint tokens

update ethereum_urls

update ITimelock immutables

disable ProposalConstraint

SAND

update BulkerScenario

replace BridgeTimelock with Timelock

replace FxBaseChildTunnel with FxChild; create Vendoza manifest

update .solhintignore

Abstract out BaseBridgeReceiver from PolygonBridgeReceiver

delete solium hints from Timelock

confirm that initialize is called by initializer

* Cross-chain scenarios (compound-finance#568)

* update Mumbai deploy script

* construct l1DeploymentManager

* construct proposal data

* propose and execute

* event listener

* rework into promise

* use Goerli timelock while initializing

* impersonate fxChild

* functioning end-to-end scenario

* clean up

* add auxiliaryDeploymentManager; remove context.deploymentManager and world.hre

* pull auxiliary deployment manager from world

* impersonate address helper

* refactor proposal construction

* setNextBaseFeeToZero

* extract fastGovernanceExecute

* skip unnecessary decode step; send directly message to fxChild

* refactor timelockInterface

* fastL2GovernanceExecute, relayMumbaiMessage

* rename to BridgeReceiver

* filter governance scenarios for bridged deployments

* move Context helpers to utils

* move utils into scenario/utils

* move fastL2GovernanceExecute to scenario/utils

* remove unnecessary calls to world.deploymentManager

* rename to l2ProposalData

* newTimelockDelay

* better error messages, types for relayMumbaiMessage

* clean-up

* lint

* clean-up

* more clean-up

* bump default stall

* update ProposalConstraint

* external execute function, with return

* add fxChild to Mumbai roots

* pull fxRoot from fxChild

* add fxRoot to Goerli roots, stateSender relation, getContractOrThrow

* COMP_WHALES note

* refactor relayMumbaiMessage

* remove dated comment

* post rebase MigrationConstraint update

* update GOERLI_TIMELOCK

* update Mumbai assets

* add error messages for ERCO20 Supply scenarios

* delete extra runDeployScript

* reduce bump in BulkerScenario

* spider the auxiliaryDeploymentManager

* bump signature expiry to 10K

* restore POLYGONSCAN_KEY

* delete payable

* convert executeTransaction to executeProposal

* Cross-chain migrations (compound-finance#575)

* update migration task, hreForBase

* update migrationTemplate, tests

* remove initializer

* update relayMessage error message

* single quotes

* move helpers from plugins/.../utils to scenario/utils

* reduce borrowMin

* reduce baseMinForRewards

* import fxChild instead of adding it to roots

* 10K baseMinForRewards

* memory, not storage for state proposal

* reduce delay to 10 minutes

* use .existing for fxRoot; restore runDeployScript

* undo bump to allowBySig expiry

* rename mainnetTimelock to govTimelock

* rename l2Timelock to localTimelock

* add check for already queued transaction

* spider auxiliaryDeploymentManager instead of runDeployScript

* Modified deployment roots from GitHub Actions

* add polyon, polygonMumbai Etherscan api keys

* idempotent bridgeReceiver initialization

Co-authored-by: GitHub Actions Bot <>
  • Loading branch information
scott-silver authored Sep 22, 2022
1 parent d09d9e8 commit b5aa739
Show file tree
Hide file tree
Showing 42 changed files with 1,430 additions and 169 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/deploy-market.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- kovan
- mainnet
- goerli
- mumbai
deployment:
description: Deployment Name (e.g. "usdc")
required: true
Expand All @@ -26,11 +27,12 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- name: Seacrest
uses: hayesgm/seacrest@v1
with:
ethereum_url: "${{ fromJSON('{\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"kovan\":\"https://kovan.infura.io/v3/$INFURA_KEY\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"goerli\":\"https://goerli.infura.io/v3/$INFURA_KEY\"}')[inputs.network] }}"
ethereum_url: "${{ fromJSON('{\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"kovan\":\"https://kovan.infura.io/v3/$INFURA_KEY\",\"mainnet\":\"https://mainnet.infura.io/v3/$INFURA_KEY\",\"goerli\":\"https://goerli.infura.io/v3/$INFURA_KEY\",\"mumbai\":\"https://polygon-mumbai.infura.io/v3/$INFURA_KEY\"}')[inputs.network] }}"
port: 8585
if: github.event.inputs.eth_pk == ''

Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/enact-migration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- kovan
- mainnet
- goerli
- mumbai
deployment:
description: Deployment Name (e.g. "usdc")
required: true
Expand All @@ -34,11 +35,12 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- name: Seacrest
uses: hayesgm/seacrest@v1
with:
ethereum_url: "${{ fromJSON('{\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"kovan\":\"https://kovan-eth.compound.finance\",\"mainnet\":\"https://mainnet-eth.compound.finance\",\"goerli\":\"https://goerli.infura.io/v3/$INFURA_KEY\"}')[inputs.network] }}"
ethereum_url: "${{ fromJSON('{\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"kovan\":\"https://kovan-eth.compound.finance\",\"mainnet\":\"https://mainnet-eth.compound.finance\",\"goerli\":\"https://goerli.infura.io/v3/$INFURA_KEY\",\"mumbai\":\"https://polygon-mumbai.infura.io/v3/$INFURA_KEY\"}')[inputs.network] }}"
port: 8585
if: github.event.inputs.eth_pk == ''

Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/prepare-migration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- kovan
- mainnet
- goerli
- mumbai
deployment:
description: Deployment Name (e.g. "usdc")
required: true
Expand All @@ -29,11 +30,12 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- name: Seacrest
uses: hayesgm/seacrest@v1
with:
ethereum_url: "${{ fromJSON('{\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"kovan\":\"https://kovan-eth.compound.finance\",\"mainnet\":\"https://mainnet-eth.compound.finance\",\"goerli\":\"https://goerli.infura.io/v3/$INFURA_KEY\"}')[inputs.network] }}"
ethereum_url: "${{ fromJSON('{\"fuji\":\"https://api.avax-test.network/ext/bc/C/rpc\",\"kovan\":\"https://kovan-eth.compound.finance\",\"mainnet\":\"https://mainnet-eth.compound.finance\",\"goerli\":\"https://goerli.infura.io/v3/$INFURA_KEY\",\"mumbai\":\"https://polygon-mumbai.infura.io/v3/$INFURA_KEY\"}')[inputs.network] }}"
port: 8585
if: github.event.inputs.eth_pk == ''

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-contract-linter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- uses: actions/checkout@v2
with:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-eslint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-gas-profiler.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-scenarios.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/run-unit-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jobs:
ETHERSCAN_KEY: ${{ secrets.ETHERSCAN_KEY }}
SNOWTRACE_KEY: ${{ secrets.SNOWTRACE_KEY }}
INFURA_KEY: ${{ secrets.INFURA_KEY }}
POLYGONSCAN_KEY: ${{ secrets.POLYGONSCAN_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@v2
Expand Down
3 changes: 2 additions & 1 deletion .solhintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
contracts/test/*
contracts/vendor/*
contracts/liquidator/vendor/*
contracts/liquidator/README.md
contracts/liquidator/README.md
contracts/bridges/vendor/*
31 changes: 31 additions & 0 deletions contracts/ITimelock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

/**
* @dev Interface for interacting with a Timelock
*/
interface ITimelock {
event NewAdmin(address indexed newAdmin);
event NewPendingAdmin(address indexed newPendingAdmin);
event NewDelay(uint indexed newDelay);
event CancelTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
event ExecuteTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);
event QueueTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint eta);

function GRACE_PERIOD() virtual external view returns (uint);
function MINIMUM_DELAY() virtual external view returns (uint);
function MAXIMUM_DELAY() virtual external view returns (uint);

function admin() virtual external view returns (address);
function pendingAdmin() virtual external view returns (address);
function setPendingAdmin(address pendingAdmin_) virtual external;
function acceptAdmin() virtual external;

function delay() virtual external view returns (uint);
function setDelay(uint delay) virtual external;

function queuedTransactions(bytes32 txHash) virtual external returns (bool);
function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) virtual external returns (bytes32);
function cancelTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) virtual external;
function executeTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) virtual external payable returns (bytes memory);
}
136 changes: 136 additions & 0 deletions contracts/bridges/BaseBridgeReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "../ITimelock.sol";

contract BaseBridgeReceiver {
error AlreadyInitialized();
error BadData();
error InvalidProposalId();
error ProposalNotQueued();
error TransactionAlreadyQueued();
error Unauthorized();

event Initialized(address indexed govTimelock, address indexed localTimelock);
event NewLocalTimelock(address indexed oldLocalTimelock, address indexed newLocalTimelock);
event NewGovTimelock(address indexed oldGovTimelock, address indexed newGovTimelock);
event ProposalCreated(address indexed messageSender, uint id, address[] targets, uint[] values, string[] signatures, bytes[] calldatas, uint eta);
event ProposalExecuted(uint id);

address public govTimelock;
address public localTimelock;
bool public initialized;

uint public proposalCount;

struct Proposal {
uint id;
address[] targets;
uint[] values;
string[] signatures;
bytes[] calldatas;
uint eta;
bool executed;
}

mapping (uint => Proposal) public proposals;

enum ProposalState {
Queued,
Expired,
Executed
}

function initialize(address _govTimelock, address _localTimelock) external {
if (initialized) revert AlreadyInitialized();
govTimelock = _govTimelock;
localTimelock = _localTimelock;
initialized = true;
emit Initialized(_govTimelock, _localTimelock);
}

function acceptLocalTimelockAdmin() external {
if (msg.sender != localTimelock) revert Unauthorized();
ITimelock(localTimelock).acceptAdmin();
}

function setLocalTimelock(address newTimelock) public {
if (msg.sender != localTimelock) revert Unauthorized();
address oldLocalTimelock = localTimelock;
localTimelock = newTimelock;
emit NewLocalTimelock(oldLocalTimelock, newTimelock);
}

function setGovTimelock(address newTimelock) public {
if (msg.sender != localTimelock) revert Unauthorized();
address oldGovTimelock = govTimelock;
govTimelock = newTimelock;
emit NewGovTimelock(oldGovTimelock, newTimelock);
}

function processMessage(
address messageSender,
bytes calldata data
) internal {
if (messageSender != govTimelock) revert Unauthorized();

address[] memory targets;
uint256[] memory values;
string[] memory signatures;
bytes[] memory calldatas;

(targets, values, signatures, calldatas) = abi.decode(
data,
(address[], uint256[], string[], bytes[])
);

if (values.length != targets.length) revert BadData();
if (signatures.length != targets.length) revert BadData();
if (calldatas.length != targets.length) revert BadData();

uint delay = ITimelock(localTimelock).delay();
uint eta = block.timestamp + delay;

for (uint8 i = 0; i < targets.length; ) {
if (ITimelock(localTimelock).queuedTransactions(keccak256(abi.encode(targets[i], values[i], signatures[i], calldatas[i], eta)))) revert TransactionAlreadyQueued();
ITimelock(localTimelock).queueTransaction(targets[i], values[i], signatures[i], calldatas[i], eta);
unchecked { i++; }
}

proposalCount++;
Proposal memory proposal = Proposal({
id: proposalCount,
targets: targets,
values: values,
signatures: signatures,
calldatas: calldatas,
eta: eta,
executed: false
});

proposals[proposal.id] = proposal;
emit ProposalCreated(messageSender, proposal.id, targets, values, signatures, calldatas, eta);
}

function executeProposal(uint proposalId) external {
if (state(proposalId) != ProposalState.Queued) revert ProposalNotQueued();
Proposal storage proposal = proposals[proposalId];
proposal.executed = true;
for (uint i = 0; i < proposal.targets.length; i++) {
ITimelock(localTimelock).executeTransaction(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta);
}
emit ProposalExecuted(proposalId);
}

function state(uint proposalId) public view returns (ProposalState) {
if (proposalId > proposalCount || proposalId == 0) revert InvalidProposalId();
Proposal memory proposal = proposals[proposalId];
if (proposal.executed) {
return ProposalState.Executed;
} else if (block.timestamp >= (proposal.eta + ITimelock(localTimelock).GRACE_PERIOD())) {
return ProposalState.Expired;
} else {
return ProposalState.Queued;
}
}
}
33 changes: 33 additions & 0 deletions contracts/bridges/polygon/PolygonBridgeReceiver.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "../vendor/fx-portal/contracts/FxChild.sol";
import "../BaseBridgeReceiver.sol";

contract PolygonBridgeReceiver is IFxMessageProcessor, BaseBridgeReceiver {
error InvalidChild();

event NewFxChild(address indexed oldFxChild, address indexed newFxChild);

address public fxChild;

constructor(address _fxChild) {
fxChild = _fxChild;
}

function changeFxChild(address newFxChild) public {
if (msg.sender != localTimelock) revert Unauthorized();
address oldFxChild = fxChild;
fxChild = newFxChild;
emit NewFxChild(oldFxChild, newFxChild);
}

function processMessageFromRoot(
uint256 stateId,
address messageSender,
bytes calldata data
) public override {
if (msg.sender != fxChild) revert InvalidChild();
processMessage(messageSender, data);
}
}
11 changes: 11 additions & 0 deletions contracts/bridges/vendor/fx-portal/contracts/FxChild.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// IFxMessageProcessor represents interface to process message
interface IFxMessageProcessor {
function processMessageFromRoot(
uint256 stateId,
address rootMessageSender,
bytes calldata data
) external;
}
Loading

0 comments on commit b5aa739

Please sign in to comment.