Skip to content

Commit

Permalink
Merge pull request #16 from OffchainLabs/upg-2.0.0
Browse files Browse the repository at this point in the history
Orbit upgrade action for contracts v2.1.0
  • Loading branch information
gzeoneth authored Aug 20, 2024
2 parents dc54bae + 1746e9e commit 9e73bef
Show file tree
Hide file tree
Showing 39 changed files with 1,838 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
UpgradeArbOSVersionAtTimestampActionTest:test_1() (gas: 165)
40 changes: 34 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ A set of contracts that are similar to Arbitrum [gov-action-contracts](https://g
[yarn](https://classic.yarnpkg.com/lang/en/docs/install/) and [foundry](https://book.getfoundry.sh/getting-started/installation) are required to run the scripts

Most of the action contracts only support the following ownership setup:

- Rollup Contract on Parent Chain owned by a `ParentUpgradeExecutor`
- Rollup ProxyAdmin on Parent Chain owned by a `ParentUpgradeExecutor`
- Arb Owner on the Child Orbit Chain is granted to alias of `ParentUpgradeExecutor`
- Arb Owner on the Child Orbit Chain is granted to `ChildUpgradeExecutor`

For token bridge related operations, these are the additional requirements:

- Token Bridge ProxyAdmin on Parent Chain owned by `ParentUpgradeExecutor`
- Token Bridge ProxyAdmin on Child Orbit Chain owned by `ChildUpgradeExecutor`
- Parent Chain Gateway Router and Custom Gateway owned by `ParentUpgradeExecutor`
Expand All @@ -26,6 +28,7 @@ yarn install
## Check Version and Upgrade Path

Run the follow command to check the version of Nitro contracts deployed on the parent chain of your Orbit chain.

```
$ INBOX_ADDRESS=0xaE21fDA3de92dE2FDAF606233b2863782Ba046F9 yarn orbit:contracts:version --network arb1
Get the version of Orbit chain's nitro contracts (inbox 0xaE21fDA3de92dE2FDAF606233b2863782Ba046F9), hosted on chain 42161
Expand All @@ -38,28 +41,53 @@ Version of deployed RollupAdminLogic: v1.1.1
Version of deployed RollupUserLogic: v1.1.1
This deployment can be upgraded to v1.2.1 using NitroContracts1Point2Point1UpgradeAction
```
For other networks, replace `arb1` with the network name and configure INFURA_KEY or the rpc in hardhat.config.ts

For other networks, replace `arb1` with the network name and configure INFURA_KEY or the rpc in hardhat.config.ts

## Nitro Contracts Upgrades
*This section is also referenced in the documentation on ["How to upgrade ArbOS on your Orbit chain"](https://docs.arbitrum.io/launch-orbit-chain/how-tos/arbos-upgrade)*

For ArbOS upgrades, a pre-requisite is to deploy new Nitro contracts to the parent chain of your Orbit chain before scheduling the ArbOS upgrade. These contracts include the rollup logic, fraud proof contracts, and interfaces for interacting with Nitro precompiles.
_This section is also referenced in the documentation on ["How to upgrade ArbOS on your Orbit chain"](https://docs.arbitrum.io/launch-orbit-chain/how-tos/arbos-upgrade)_

For ArbOS upgrades, a pre-requisite is to deploy new Nitro contracts to the parent chain of your Orbit chain before scheduling the ArbOS upgrade. These contracts include the rollup logic, fraud proof contracts, and interfaces for interacting with Nitro precompiles.

### Nitro contracts 2.1.0 (for ArbOS 31 Bianca)

The [`nitro-contracts 2.1.0` upgrade action](scripts/foundry/contract-upgrades/2.1.0) will deploy `nitro-contracts v2.1.0` contracts to your Orbit's parent chain. Note that this action will only work for chains with `nitro-contracts v1.2.1` or `nitro-contracts v1.3.0`.

Note: nitro contracts upgrade brings support for AnyTrust fast confirmations and Stylus. However, Stylus will be enabled only when `ArbOS 31 Bianca` upgrade takes place, once it will be officially supported for Orbit chains.

### Nitro contracts 1.2.1 (for ArbOS 20 Atlas)

The [`nitro-contracts 1.2.1` upgrade action](scripts/foundry/contract-upgrades/1.2.1) will deploy `nitro-contracts v1.2.1` contracts to your Orbit's parent chain. Note that this action will only work for chains with `nitro-contracts v1.1.0` or `nitro-contracts v.1.1.1`. ArbOS 20 Atlas, shipped via [Nitro v2.3.0](https://github.com/OffchainLabs/nitro/releases/tag/v2.3.0), requires [**`nitro-contracts v1.2.1`**](https://github.com/OffchainLabs/nitro-contracts/releases/tag/v1.2.1) or higher.

## Scheduling the ArbOS upgrade
*This section is also referenced in the documentation on ["How to upgrade ArbOS on your Orbit chain"](https://docs.arbitrum.io/launch-orbit-chain/how-tos/arbos-upgrade)*

Next, you will need to schedule the actual upgrade using the [ArbOS upgrade at timestamp action](scripts/foundry/arbos-upgrades/at-timestamp).
_This section is also referenced in the documentation on ["How to upgrade ArbOS on your Orbit chain"](https://docs.arbitrum.io/launch-orbit-chain/how-tos/arbos-upgrade)_

Next, you will need to schedule the actual upgrade using the [ArbOS upgrade at timestamp action](scripts/foundry/arbos-upgrades/at-timestamp).

This action schedule an upgrade of the ArbOS to a specific version at a specific timestamp.

## Common upgrade paths

Here is a list of common upgrade paths that can be used to upgrade the Orbit chains.

### ArbOS 31 Bianca

1. TBD

### ArbOS 20 Atlas

1. Upgrade your Nitro node(s) to [Nitro v2.3.1](https://github.com/OffchainLabs/nitro/releases/tag/v2.3.1)
1. Upgrade `nitro-contracts` to `v1.2.1` using [nitro-contract 1.2.1 upgrade action](scripts/foundry/contract-upgrades/1.2.1)
2. Schedule the ArbOS 20 Atlas upgrade using [ArbOS upgrade at timestamp action](scripts/foundry/arbos-upgrades/at-timestamp)
1. Schedule the ArbOS 20 Atlas upgrade using [ArbOS upgrade at timestamp action](scripts/foundry/arbos-upgrades/at-timestamp)

# Other Actions

## Enable Fast Confirmation

See [EnableFastConfirmAction](scripts/foundry/fast-confirm)

## Enable Stylus Cache Manager

See [setCacheManager](scripts/foundry/stylus/setCacheManager]
46 changes: 46 additions & 0 deletions contracts/child-chain/stylus/AddWasmCacheManagerAction.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "@arbitrum/nitro-contracts-2.1.0/src/precompiles/ArbSys.sol";

// ArbOwner interface will include addWasmCacheManager as of stylus upgrade
interface IUpdatedArbOwner {
function addWasmCacheManager(address manager) external;
}

// ArbWasmCache precompile interface
interface IArbWasmCache {
/// @notice See if the user is a cache manager.
function isCacheManager(address manager) external view returns (bool);
}

// @notice For deployment on an Orbit chain;
// adds wasm cache manager only when the stylus ArbOS upgrade activates.
contract AddWasmCacheManagerAction {
// wasm cache manager to add
address public immutable wasmCachemanager;

// ArbOS version; use value as it's set and commonly used, NOT the value returned by
// ArbSys, which adds 55. E.g., the value here should be 31, not 85
uint256 public immutable targetArbOSVersion;

constructor(address _wasmCachemanager, uint256 _targetArbOSVersion) {
wasmCachemanager = _wasmCachemanager;
targetArbOSVersion = _targetArbOSVersion;
}

function perform() external {
// getter returns a value offset by 55: https://github.com/OffchainLabs/nitro/blob/a20a1c70cc11ac52c7cfe6a20f00c880c2009a8f/precompiles/ArbSys.go#L64
uint256 currentArbOsVersion = ArbSys(0x0000000000000000000000000000000000000064).arbOSVersion() - 55;
// revert if target arbos version not reached; since this is executed by a retryable, can be re-executed until target version is reached
require(targetArbOSVersion == currentArbOsVersion, "AddWasmCacheManagerAction: ArbOS version");

IUpdatedArbOwner(0x0000000000000000000000000000000000000070).addWasmCacheManager(wasmCachemanager);

// verify:
require(
IArbWasmCache(0x0000000000000000000000000000000000000072).isCacheManager(wasmCachemanager),
"AddWasmCacheManagerAction: is cache manager"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "@arbitrum/nitro-contracts-2.1.0/src/osp/IOneStepProofEntry.sol";
import "@arbitrum/nitro-contracts-2.1.0/src/rollup/IRollupAdmin.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

interface IChallengeManagerUpgradeInit {
function postUpgradeInit(IOneStepProofEntry osp_, bytes32 condRoot, IOneStepProofEntry condOsp) external;
function osp() external returns (address);
}

interface IRollupUpgrade {
function upgradeTo(address newImplementation) external;
function upgradeSecondaryTo(address newImplementation) external;
function anyTrustFastConfirmer() external returns (address);
}

interface ISequencerInbox_v1_2_1 {
function isUsingFeeToken() external returns (bool);
}

/**
* @title DeployNitroContracts2Point1Point0UpgradeActionScript
* @notice Set wasm module root and upgrade challenge manager for stylus ArbOS upgrade.
* Also upgrade Rollup logic contracts to include fast confirmations feature.
*/
contract NitroContracts2Point1Point0UpgradeAction {
bytes32 public immutable newWasmModuleRoot;
address public immutable newChallengeManagerImpl;
IOneStepProofEntry public immutable osp;
bytes32 public immutable condRoot;
IOneStepProofEntry public immutable condOsp;

address public immutable newRollupAdminLogic;
address public immutable newRollupUserLogic;

constructor(
bytes32 _newWasmModuleRoot,
address _newChallengeManagerImpl,
IOneStepProofEntry _osp,
bytes32 _condRoot,
IOneStepProofEntry _condOsp,
address _newRollupAdminLogic,
address _newRollupUserLogic
) {
require(
_newWasmModuleRoot != bytes32(0), "NitroContracts2Point1Point0UpgradeAction: _newWasmModuleRoot is empty"
);
require(
Address.isContract(_newChallengeManagerImpl),
"NitroContracts2Point1Point0UpgradeAction: _newChallengeManagerImpl is not a contract"
);
require(Address.isContract(address(_osp)), "NitroContracts2Point1Point0UpgradeAction: _osp is not a contract");
require(
Address.isContract(address(_condOsp)),
"NitroContracts2Point1Point0UpgradeAction: _condOsp is not a contract"
);
require(
Address.isContract(_newRollupAdminLogic),
"NitroContracts2Point1Point0UpgradeAction: _newRollupAdminLogic is not a contract"
);
require(
Address.isContract(_newRollupUserLogic),
"NitroContracts2Point1Point0UpgradeAction: _newRollupUserLogic is not a contract"
);

newWasmModuleRoot = _newWasmModuleRoot;
newChallengeManagerImpl = _newChallengeManagerImpl;
osp = _osp;
condRoot = _condRoot;
condOsp = _condOsp;
newRollupAdminLogic = _newRollupAdminLogic;
newRollupUserLogic = _newRollupUserLogic;
}

function perform(IRollupCore rollup, ProxyAdmin proxyAdmin) external {
/// check if previous upgrade v1.2.1 was performed by polling function which was introduced in that version
ISequencerInbox_v1_2_1 sequencerInbox = ISequencerInbox_v1_2_1(address(rollup.sequencerInbox()));
try sequencerInbox.isUsingFeeToken() returns (bool) {}
catch {
revert("NitroContracts2Point1Point0UpgradeAction: sequencer inbox needs to be at version >= 1.2.1");
}

/// check that condRoot is being used
require(rollup.wasmModuleRoot() == condRoot, "NitroContracts2Point1Point0UpgradeAction: wasm root mismatch");

/// do the upgrade
_upgradeChallengerManager(rollup, proxyAdmin);
_upgradeRollup(address(rollup));
}

function _upgradeChallengerManager(IRollupCore rollup, ProxyAdmin proxyAdmin) internal {
// set the new challenge manager impl
TransparentUpgradeableProxy challengeManager =
TransparentUpgradeableProxy(payable(address(rollup.challengeManager())));
proxyAdmin.upgradeAndCall(
challengeManager,
newChallengeManagerImpl,
abi.encodeCall(IChallengeManagerUpgradeInit.postUpgradeInit, (osp, condRoot, condOsp))
);

// verify
require(
proxyAdmin.getProxyImplementation(challengeManager) == newChallengeManagerImpl,
"NitroContracts2Point1Point0UpgradeAction: new challenge manager implementation set"
);
require(
IChallengeManagerUpgradeInit(address(challengeManager)).osp() == address(osp),
"NitroContracts2Point1Point0UpgradeAction: new OSP not set"
);

// set new wasm module root
IRollupAdmin(address(rollup)).setWasmModuleRoot(newWasmModuleRoot);

// verify:
require(
rollup.wasmModuleRoot() == newWasmModuleRoot,
"NitroContracts2Point1Point0UpgradeAction: wasm module root not set"
);
}

function _upgradeRollup(address rollupProxy) internal {
IRollupUpgrade rollup = IRollupUpgrade(rollupProxy);

// set new logic contracts
rollup.upgradeTo(newRollupAdminLogic);
rollup.upgradeSecondaryTo(newRollupUserLogic);

// verify
require(
rollup.anyTrustFastConfirmer() == address(0),
"NitroContracts2Point1Point0UpgradeAction: unexpected fast confirmer address"
);
}
}
67 changes: 67 additions & 0 deletions contracts/parent-chain/fast-confirm/EnableFastConfirmAction.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

interface IRollupAdmin {
function anyTrustFastConfirmer() external view returns (address);
function isValidator(address) external view returns (bool);
function setAnyTrustFastConfirmer(address _anyTrustFastConfirmer) external;
function setMinimumAssertionPeriod(uint256 _minimumAssertionPeriod) external;
function setValidator(address[] memory _validator, bool[] memory _val) external;
}

interface IGnosisSafeProxyFactory {
function createProxyWithNonce(address _singleton, bytes memory initializer, uint256 saltNonce)
external
returns (address proxy);
}

contract EnableFastConfirmAction {
address public immutable GNOSIS_SAFE_PROXY_FACTORY;
address public immutable GNOSIS_SAFE_1_3_0;
address public immutable GNOSIS_COMPATIBILITY_FALLBACK_HANDLER;

constructor(address gnosisSafeProxyFactory, address gnosisSafe1_3_0, address gnosisCompatibilityFallbackHandler) {
require(gnosisSafeProxyFactory.code.length > 0, "gnosisSafeProxyFactory doesn't exist on this chain");
require(gnosisSafe1_3_0.code.length > 0, "gnosisSafe1_3_0 doesn't exist on this chain");
require(
gnosisCompatibilityFallbackHandler.code.length > 0,
"gnosisCompatibilityFallbackHandler doesn't exist on this chain"
);
GNOSIS_SAFE_PROXY_FACTORY = gnosisSafeProxyFactory;
GNOSIS_SAFE_1_3_0 = gnosisSafe1_3_0;
GNOSIS_COMPATIBILITY_FALLBACK_HANDLER = gnosisCompatibilityFallbackHandler;
}

function perform(IRollupAdmin rollup, address[] calldata fastConfirmCommittee, uint256 threshold, uint256 salt)
external
{
require(rollup.anyTrustFastConfirmer() == address(0), "Fast confirm already enabled");
require(threshold > 0 && threshold <= fastConfirmCommittee.length, "Invalid threshold");
for (uint256 i = 0; i < fastConfirmCommittee.length; i++) {
require(fastConfirmCommittee[i] != address(0), "Invalid address");
require(rollup.isValidator(fastConfirmCommittee[i]), "fastConfirmCommittee members must be validator");
}
address fastConfirmer = IGnosisSafeProxyFactory(GNOSIS_SAFE_PROXY_FACTORY).createProxyWithNonce(
GNOSIS_SAFE_1_3_0,
abi.encodeWithSignature(
"setup(address[],uint256,address,bytes,address,address,uint256,address)",
fastConfirmCommittee,
threshold,
address(0),
"",
GNOSIS_COMPATIBILITY_FALLBACK_HANDLER,
address(0),
0,
address(0)
),
salt
);
rollup.setAnyTrustFastConfirmer(fastConfirmer);
address[] memory validators = new address[](1);
validators[0] = fastConfirmer;
bool[] memory val = new bool[](1);
val[0] = true;
rollup.setValidator(validators, val);
rollup.setMinimumAssertionPeriod(1);
}
}
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ test = 'test'
cache_path = 'cache_forge'
solc_version = '0.8.16'
optimizer_runs = 2000
fs_permissions = [{ access = "read", path = "node_modules/@arbitrum/nitro-contracts-1.2.1"}, { access = "read-write", path = "./scripts/foundry"}]
fs_permissions = [{ access = "read", path = "node_modules/@arbitrum/"}, { access = "read", path = "node_modules/@openzeppelin/"},{ access = "read-write", path = "./scripts/foundry"}]
script = 'scripts'
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@
},
"devDependencies": {
"@arbitrum/nitro-contracts-1.2.1": "npm:@arbitrum/[email protected]",
"@offchainlabs/upgrade-executor": "1.1.0-beta.0",
"@arbitrum/nitro-contracts-1.3.0": "npm:@arbitrum/[email protected]",
"@arbitrum/nitro-contracts-2.1.0": "npm:@arbitrum/[email protected]",
"@arbitrum/token-bridge-1.2.2": "npm:@arbitrum/[email protected]",
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-foundry": "^1.1.1",
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
"@nomicfoundation/hardhat-toolbox": "^4.0.0",
"@nomicfoundation/hardhat-verify": "^2.0.0",
"@offchainlabs/upgrade-executor": "1.1.0-beta.0",
"@typechain/ethers-v6": "^0.5.0",
"@typechain/hardhat": "^9.0.0",
"@types/chai": "^4.2.0",
Expand Down
8 changes: 8 additions & 0 deletions scripts/foundry/contract-upgrades/2.1.0/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## These env vars are used for ExecuteNitroContracts2Point1Point0UpgradeScript

UPGRADE_ACTION_ADDRESS=
ROLLUP_ADDRESS=
PROXY_ADMIN_ADDRESS=
PARENT_UPGRADE_EXECUTOR_ADDRESS=
WASM_MODULE_ROOT=0x260f5fa5c3176a856893642e149cf128b5a8de9f828afec8d11184415dd8dc69
PARENT_CHAIN_IS_ARBITRUM=true
Loading

0 comments on commit 9e73bef

Please sign in to comment.