Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.16;

interface IRollupAdminLogic {
function upgradeSecondaryTo(address newImplementation) external;
function upgradeTo(address newImplementation) external;
}

/**
* @title NitroContracts3Point2Point0UpgradeAction
* @notice Upgrade action for nitro contracts v3.2.0
* @dev Only upgrades Rollup contract, other diff between v3.2.0 and v3.1.0 are irrelevant.
*/
contract NitroContracts3Point2Point0UpgradeAction {
address public immutable newRollupAdminLogicImpl;
address public immutable newRollupUserLogicImpl;

constructor(address _newRollupAdminLogicImpl, address _newRollupUserLogicImpl) {
require(_newRollupAdminLogicImpl.code.length > 0, "invalid rollup admin logic impl");
require(_newRollupUserLogicImpl.code.length > 0, "invalid rollup user logic impl");
newRollupAdminLogicImpl = _newRollupAdminLogicImpl;
newRollupUserLogicImpl = _newRollupUserLogicImpl;
}

function perform(address rollup) external {
// skip sequencer inbox upgrade since it only adds custom DA header support
// skip OSP upgrade since it only adds custom DA validation support

// RollupAdminLogic is the primary implementation
// RollupUserLogic is the secondary implementation
// see: https://github.com/OffchainLabs/nitro-contracts/blob/d9a2f3353ff13c706b7807b097e7ba591d970d85/src/libraries/AdminFallbackProxy.sol#L141-L143

IRollupAdminLogic(rollup).upgradeTo(newRollupAdminLogicImpl);
IRollupAdminLogic(rollup).upgradeSecondaryTo(newRollupUserLogicImpl);
}
}
135 changes: 87 additions & 48 deletions scripts/chain-versioner/chainVersioner.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import metadataHashes from './referentMetadataHashes.json'
import contractAddresses from './referentContractAddresses.json'
import {
IBridge__factory,
IInbox__factory,
Expand Down Expand Up @@ -74,6 +75,7 @@ export type ChainVersionerReport = OrbitVersionerReport
* Load the referent metadata hashes
*/
const referentMetadataHashes: MetadataHashesByVersion = metadataHashes
const referentContractAddresses: MetadataHashesByVersion = contractAddresses

/**
* Script will
Expand Down Expand Up @@ -104,64 +106,56 @@ export async function runChainVersioner(
const challengeManagerAddress = await rollup.challengeManager()
const rollupEventInboxAddress = await rollup.rollupEventInbox()

// get metadata hashes
const metadataHashes: { [key: string]: string } = {
Inbox: await _getMetadataHash(
await _getLogicAddress(inboxAddress, provider),
provider
),
Outbox: await _getMetadataHash(
await _getLogicAddress(outboxAddress, provider),
provider
),
SequencerInbox: await _getMetadataHash(
await _getLogicAddress(seqInboxAddress, provider),
provider
),
Bridge: await _getMetadataHash(
await _getLogicAddress(bridgeAddress, provider),
provider
),
RollupEventInbox: await _getMetadataHash(
await _getLogicAddress(rollupEventInboxAddress, provider),
provider
),
RollupProxy: await _getMetadataHash(rollupAddress, provider),
RollupAdminLogic: await _getMetadataHash(
await _getLogicAddress(rollupAddress, provider),
provider
),
RollupUserLogic: await _getMetadataHash(
await _getAddressAtStorageSlot(
rollupAddress,
provider,
'0x2b1dbce74324248c222f0ec2d5ed7bd323cfc425b336f0253c5ccfda7265546d'
),
provider
),
ChallengeManager: await _getMetadataHash(
await _getLogicAddress(challengeManagerAddress, provider),
provider
// get logic addresses for each contract
const logicAddresses: { [key: string]: string } = {
Inbox: await _getLogicAddress(inboxAddress, provider),
Outbox: await _getLogicAddress(outboxAddress, provider),
SequencerInbox: await _getLogicAddress(seqInboxAddress, provider),
Bridge: await _getLogicAddress(bridgeAddress, provider),
RollupEventInbox: await _getLogicAddress(rollupEventInboxAddress, provider),
RollupProxy: rollupAddress,
RollupAdminLogic: await _getLogicAddress(rollupAddress, provider),
RollupUserLogic: await _getAddressAtStorageSlot(
rollupAddress,
provider,
'0x2b1dbce74324248c222f0ec2d5ed7bd323cfc425b336f0253c5ccfda7265546d'
),
ChallengeManager: await _getLogicAddress(challengeManagerAddress, provider),
}

if (process.env.DEV === 'true') {
log('\nMetadataHashes of deployed contracts:', metadataHashes, '\n')
log('\nLogic addresses of deployed contracts:', logicAddresses, '\n')
}

let isFeeTokenChain = false
const versions: { [key: string]: string | null } = {}
// get and print version per bridge contract
Object.keys(metadataHashes).forEach(key => {
const { version, isErc20 } = _getVersionOfDeployedContract(
metadataHashes[key]
)
versions[key] = version
if (key === 'Bridge' && isErc20) isFeeTokenChain = true

for (const key of Object.keys(logicAddresses)) {
// try address-based lookup first (for create2 deployments like v3.2.0+)
let result = _getVersionOfDeployedContractByAddress(logicAddresses[key])

if (!result.version) {
// fall back to metadata hash lookup
try {
const metadataHash = await _getMetadataHash(
logicAddresses[key],
provider
)
if (process.env.DEV === 'true') {
log(`MetadataHash of deployed ${key}:`, metadataHash)
}
result = _getVersionOfDeployedContract(metadataHash)
} catch {
// metadata hash extraction can fail for contracts without standard metadata
}
}

versions[key] = result.version
if (key === 'Bridge' && result.isErc20) isFeeTokenChain = true
log(
`Version of deployed ${key}: ${versions[key] ? versions[key] : 'unknown'}`
)
})
}

// TODO: make this more generic to support other other upgrade paths in the future
// TODO: also check osp
Expand All @@ -188,6 +182,10 @@ function _checkForPossibleUpgrades(
): UpgradeRecommendation {
// version need to be in descending order
const targetVersionsDescending = [
{
version: 'v3.2.0',
actionName: 'NitroContracts3Point2Point0UpgradeAction',
},
{
version: 'v3.1.0',
actionName: 'BOLD UpgradeAction',
Expand Down Expand Up @@ -294,7 +292,19 @@ function _canBeUpgradedToTargetVersion(

let supportedSourceVersionsPerContract: { [key: string]: string[] } = {}

if (targetVersion === 'v3.1.0') {
if (targetVersion === 'v3.2.0') {
supportedSourceVersionsPerContract = {
Inbox: ['v3.1.0'],
Outbox: ['v3.1.0'],
Bridge: ['v3.1.0'],
RollupEventInbox: ['any'],
RollupProxy: ['any'],
RollupAdminLogic: ['v3.1.0'],
RollupUserLogic: ['v3.1.0'],
ChallengeManager: ['v3.1.0'],
SequencerInbox: ['v3.1.0'],
}
} else if (targetVersion === 'v3.1.0') {
// todo: remove once nitro supports bold for L3's
if (parentChainId !== 1n && parentChainId !== 11155111n) {
supportedSourceVersionsPerContract = {
Expand Down Expand Up @@ -498,6 +508,35 @@ function _canBeUpgradedToTargetVersion(
return true
}

function _getVersionOfDeployedContractByAddress(logicAddress: string): {
version: string | null
isErc20: boolean
} {
const normalized = logicAddress.toLowerCase()
for (const [version] of Object.entries(referentContractAddresses).reverse()) {
const versionAddresses = referentContractAddresses[version]
const allAddresses = [
...Object.values(versionAddresses.eth).flat(),
...Object.values(versionAddresses.erc20).flat(),
...versionAddresses.RollupProxy,
...versionAddresses.RollupAdminLogic,
...versionAddresses.RollupUserLogic,
...versionAddresses.ChallengeManager,
].map(a => a.toLowerCase())

if (allAddresses.includes(normalized)) {
const erc20Addresses = [
...Object.values(versionAddresses.erc20).flat(),
].map(a => a.toLowerCase())
if (erc20Addresses.includes(normalized)) {
return { version, isErc20: true }
}
return { version, isErc20: false }
}
}
return { version: null, isErc20: false }
}

function _getVersionOfDeployedContract(metadataHash: string): {
version: string | null
isErc20: boolean
Expand Down
42 changes: 42 additions & 0 deletions scripts/chain-versioner/referentContractAddresses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"v3.2.0": {
Comment thread
yahgwai marked this conversation as resolved.
"eth": {
"Inbox": [
"0x2c358843740dB38a40f96FD627D4DA1dd859E554",
"0x8D3b93dfFFf4842E7B61FB553b383db2C6BC91c6"
],
"Outbox": ["0x396765AEbE540575ef927F769b0d7b89594f931c"],
"SequencerInbox": [
"0xDA2e941cc4C7D8166Ec207CB7f7B09bA4f94406c",
"0x3636c0bB4Cfd072d06cbf59754A2830D05fD3419",
"0x17d9a7f836cB3A97aCcf96E59f56504457044945",
"0xF6995BDC439B27deEA5d5d08e95E92451a7d36F5",
"0x41e2B560F0B41FBc4A063Eac5298da4C246BEA1B",
"0xb015D78fb9B890e96FD3E23819b2C8D9fffA3cC5"
],
"Bridge": ["0xC678f7B95A7D1F77c6024c0086301D21402854b1"],
"RollupEventInbox": ["0x796FeE4adceD1cb47a3e3d1B6925472F8fC8f1f9"]
},
"erc20": {
"Inbox": [
"0x02E5bFcF09Cc317EDDCaca72a1b1265A57197Db5",
"0xBfd8916b9DCB60B3b437D2B3a6FF56F78DcD9Ff2"
],
"Outbox": ["0x5128805C5331A3D445B72545d2461B2C3B05218c"],
"SequencerInbox": [
"0xB8594C833f519126B614979867216EB4BAE82B6d",
"0x5Bf5D77bed887dC32beE7852920A6C93A3D950f1",
"0xD5396bCeE766352B4f87E75708E35E4844883Fb5",
"0xC7FeB25D44D87F753C4ecCb974426Aea8c817f72",
"0xE3E3A0EeFe4f3388eaf4AAA9A77Df0D0d489b776",
"0x2D721E1704c48c9F16353a3b346Aa1EFEc9aA86c"
],
"Bridge": ["0x0124687D1F2869b0C2335B98ddc7FCf59DA2CEa1"],
"RollupEventInbox": ["0x2706682dD3bD709b055E0266D98BA380FE22B807"]
},
"RollupProxy": [],
"RollupAdminLogic": ["0xAb7A44CE7e66963d2116dCe74AB63eeF88266C82"],
"RollupUserLogic": ["0xedC23dFC7D1e57EC07eA5ff7419634DbAe08Ed2C"],
"ChallengeManager": ["0xCAaa9332F940362aEAAADD1B0A59c229C4fD8f79"]
}
}
10 changes: 10 additions & 0 deletions scripts/foundry/contract-upgrades/3.2.0/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Forge configuration (uncomment/adjust as needed)
## All FOUNDRY_* env vars are supported: https://book.getfoundry.sh/reference/config/
# FOUNDRY_BROADCAST=true
# ETH_PRIVATE_KEY=0x...

## Chain and contract addresses
PARENT_CHAIN_RPC=
ROLLUP_ADDRESS=
UPGRADE_ACTION_ADDRESS=0x352b46fc500757e07a7e6063870c3a2b2c72da90
PARENT_UPGRADE_EXECUTOR_ADDRESS=
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import {DeploymentHelpersScript} from "../../helper/DeploymentHelpers.s.sol";
import {
NitroContracts3Point2Point0UpgradeAction
} from "../../../../contracts/parent-chain/contract-upgrades/NitroContracts3Point2Point0UpgradeAction.sol";
import {MockArbSys} from "../../helper/MockArbSys.sol";

/**
* @title DeployNitroContracts3Point2Point0UpgradeActionScript
* @notice Deploys implementation contracts and the NitroContracts3Point2Point0UpgradeAction contract.
*/
contract DeployNitroContracts3Point2Point0UpgradeActionScript is DeploymentHelpersScript {
function run() public {
vm.startBroadcast();

// see scripts/orbit-versioner/referentContractAddresses.json
// there is only one address shared across all chains
address newAdminLogic = 0xAb7A44CE7e66963d2116dCe74AB63eeF88266C82;
Comment thread
yahgwai marked this conversation as resolved.
address newUserLogic = 0xedC23dFC7D1e57EC07eA5ff7419634DbAe08Ed2C;

// Deploy the action contract last. The CLI identifies the deployed action
// by taking the last CREATE from the broadcast file.
new NitroContracts3Point2Point0UpgradeAction{salt: 0}(newAdminLogic, newUserLogic);

vm.stopBroadcast();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.16;

import "forge-std/Script.sol";
import {
NitroContracts3Point2Point0UpgradeAction
} from "../../../../contracts/parent-chain/contract-upgrades/NitroContracts3Point2Point0UpgradeAction.sol";
import {IUpgradeExecutor} from "@offchainlabs/upgrade-executor/src/IUpgradeExecutor.sol";

/**
* @title ExecuteNitroContracts3Point2Point0UpgradeScript
* @notice Executes nitro contracts 3.2.0 upgrade through UpgradeExecutor
*/
contract ExecuteNitroContracts3Point2Point0UpgradeScript is Script {
function run() public {
NitroContracts3Point2Point0UpgradeAction upgradeAction =
NitroContracts3Point2Point0UpgradeAction(vm.envAddress("UPGRADE_ACTION_ADDRESS"));

require(
address(upgradeAction).code.length > 0,
"Upgrade action contract not found at provided address, run deployment script first"
);

// prepare upgrade calldata
bytes memory upgradeCalldata =
abi.encodeCall(NitroContracts3Point2Point0UpgradeAction.perform, (vm.envAddress("ROLLUP_ADDRESS")));

// execute the upgrade
IUpgradeExecutor executor = IUpgradeExecutor(vm.envAddress("PARENT_UPGRADE_EXECUTOR_ADDRESS"));
vm.startBroadcast();
executor.execute(address(upgradeAction), upgradeCalldata);
vm.stopBroadcast();
}
}
Loading
Loading