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
74 changes: 74 additions & 0 deletions .github/workflows/manual-sol-artifacts-0-1-30.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: Manual sol artifacts (0.1.30 orchestrator set)
# Least-privilege: the broadcast authenticates via `secrets.PRIVATE_KEY`, so
# the ambient GITHUB_TOKEN needs nothing beyond read.
permissions:
contents: read
on:
workflow_dispatch:
inputs:
suite:
description: 'Suite to deploy (one contract per suite, deploy in listed order)'
required: true
type: choice
options:
# ===================================================================
# The audited 0.1.30 orchestrator set — the ST0x orchestrator and its
# on-chain dependency closure — shipped to the selected network via
# script/DeployProdV4_0_1_30.sol (stored 0.1.30 creation bytecode;
# the set the audited tag sol-v0.1.30 compiles to byte-identically —
# the commit Protofire's st0x.deploy 6.0 report reviews).
#
# Deploy in the listed order; later entries reference earlier ones
# via dependency pointers so an out-of-order run trips the
# dep-codehash check. The Zoltu deploy is idempotent per network, so
# re-dispatching a suite already on-chain is a no-op.
# ===================================================================
# 1. Corporate-actions facet (no on-chain dependencies).
- stox-corporate-actions-facet
# 2. Receipt impl (no on-chain dependencies).
- stox-receipt
# 3. Receipt vault impl (depends on the corporate-actions facet its
# fallback delegatecalls).
- stox-receipt-vault
# 4. OARV beacon-set deployer (its constructor bakes beacons over the
# receipt and receipt-vault impls above).
- stox-offchain-asset-receipt-vault-beacon-set-deployer
# 5. Orchestrator impl (its vault-logic version lock reads the OARV
# beacon-set deployer above; initialize reverts until it exists).
- st0x-orchestrator
# 6. Orchestrator beacon-set deployer (its constructor bakes a beacon
# over the orchestrator impl above).
- st0x-orchestrator-beacon-set-deployer
network:
description: 'Network to ship the 0.1.30 orchestrator set to'
required: true
type: choice
options:
# Closed set of vetted networks — mirrored by the deploy script's
# `deploymentNetwork()` guard.
- 'base'
- 'ethereum'
- 'hyperevm'
jobs:
deploy:
uses: rainlanguage/rainix/.github/workflows/rainix-manual-sol-artifacts.yaml@main
with:
suite: ${{ inputs.suite }}
network: ${{ inputs.network }}
# HyperEVM's RPC rejects forge's EIP-1559 fee-history estimation;
# type-0 transactions work on every supported network.
legacy: ${{ inputs.network == 'hyperevm' }}
# Ship the stored 0.1.30 creation bytecode, not current source.
script: script/DeployProdV4_0_1_30.sol:Deploy
# The current source diverged from 0.1.30 (H01 remediation + optimizer
# change), so Etherscan verification against current source would fail
# the run. Deploy unverified; verify manually from the sol-v0.1.30 tag.
verify: false
# Runs unverified, so it needs only the deployer key and the supported
# networks' RPCs. The reusable declares every other secret as optional and
# falls back to `|| vars.* || ''` for any it isn't given.
secrets:
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
RPC_URL_BASE_FORK: ${{ secrets.RPC_URL_BASE_FORK }}
RPC_URL_ETHEREUM_FORK: ${{ secrets.RPC_URL_ETHEREUM_FORK }}
RPC_URL_HYPEREVM_FORK: ${{ secrets.RPC_URL_HYPEREVM_FORK }}
219 changes: 219 additions & 0 deletions script/DeployProdV4_0_1_30.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

import {Script, console2} from "forge-std-1.16.1/src/Script.sol";

import {LibRainDeploy} from "rain-deploy-0.1.4/src/lib/LibRainDeploy.sol";
import {LibProdDeployV4} from "../src/generated/LibProdDeployV4.sol";
import {LibStoxDeployNetworks} from "../src/lib/LibStoxDeployNetworks.sol";

/// @dev Error thrown when the DEPLOYMENT_SUITE env var does not match any known
/// suite.
error UnknownDeploymentSuite(bytes32 suite);

/// @dev Error thrown when the DEPLOYMENT_NETWORK env var does not match any
/// supported network.
error UnknownDeploymentNetwork(string network);

// One suite per contract to avoid Zoltu factory nonce issues.
//
// This script ships the audited 0.1.30 orchestrator set — the ST0x orchestrator
// and its on-chain dependency closure — to the selected network via the stored
// 0.1.30 creation bytecode. The 0.1.30 snapshot is the set the source at tag
// `sol-v0.1.30` (commit 4f126183) compiles to byte-identically, which is the
// commit Protofire's `st0x.deploy 6.0` report (Aug 2026) reviews. Each suite
// deploys the stored `LibProdDeployV4.*_CREATION_CODE_0_1_30` bytes and asserts
// against the `_0_1_30` address/codehash pins, so the on-chain result is the
// audited deployment regardless of what the current source compiles to.
//
// The closure is exactly what a working orchestrator needs on the target
// network and nothing more:
//
// - `ST0xOrchestrator.initialize` (and mint/burn) hard-revert via the
// vault-logic version lock unless the 0.1.30
// `StoxOffchainAssetReceiptVaultBeaconSetDeployer` it was built against is
// on-chain, so that set-deployer must be deployed first.
// - The set-deployer's constructor bakes beacons over the 0.1.30 `StoxReceipt`
// and `StoxReceiptVault` implementations, which must have code.
// - The 0.1.30 `StoxReceiptVault` `fallback()` delegatecalls the 0.1.30
// `StoxCorporateActionsFacet`, so the facet must be on-chain before the
// vault.
//
// The wrapped-token-vault chain, the authorizers and the unified deployer are
// deliberately absent: the orchestrator does not need them, and every
// network's production instances come from the audited 0.1.1 bootstrap set
// (`script/DeployProdV4_0_1_1.sol`). Unlike earlier releases there are no
// 0.1.1 twins — the H01 remediation's optimizer change moved every address —
// so all six suites deploy fresh on every network, Base included.

bytes32 constant DEPLOYMENT_SUITE_STOX_CORPORATE_ACTIONS_FACET = keccak256("stox-corporate-actions-facet");
bytes32 constant DEPLOYMENT_SUITE_STOX_RECEIPT = keccak256("stox-receipt");
bytes32 constant DEPLOYMENT_SUITE_STOX_RECEIPT_VAULT = keccak256("stox-receipt-vault");
bytes32 constant DEPLOYMENT_SUITE_STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_BEACON_SET_DEPLOYER =
keccak256("stox-offchain-asset-receipt-vault-beacon-set-deployer");
bytes32 constant DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR = keccak256("st0x-orchestrator");
bytes32 constant DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER =
keccak256("st0x-orchestrator-beacon-set-deployer");

contract Deploy is Script {
/// @dev Broadcasts a single contract via the Zoltu deterministic deployer
/// on the selected network. Reads `DEPLOYMENT_KEY` from the environment,
/// logs diagnostic information (expected address, codehash, dependency
/// state), then delegates to `LibRainDeploy.deployAndBroadcast`.
/// @param creationCode The creation bytecode of the contract to deploy.
/// @param contractPath Fully qualified contract path
/// (e.g. "src/concrete/ST0xOrchestrator.sol:ST0xOrchestrator").
/// @param expectedAddress The deterministic address the contract must deploy
/// to.
/// @param expectedCodeHash The expected codehash of the deployed runtime
/// bytecode.
/// @param dependencies Addresses of contracts that must already be
/// deployed on the selected network before this contract is deployed.
function deploySuite(
bytes memory creationCode,
string memory contractPath,
address expectedAddress,
bytes32 expectedCodeHash,
address[] memory dependencies
) internal {
string[] memory networks = new string[](1);
networks[0] = deploymentNetwork();
uint256 deployerPrivateKey = vm.envUint("DEPLOYMENT_KEY");

console2.log("Suite deploying (0.1.30):", contractPath);
console2.log("Expected address:", expectedAddress);
console2.log("Expected codehash:");
console2.logBytes32(expectedCodeHash);
console2.log("Chain ID:", block.chainid);
console2.log("Block number:", block.number);
console2.log("Dependencies count:", dependencies.length);
for (uint256 i = 0; i < dependencies.length; i++) {
console2.log(" Dep address:", dependencies[i]);
console2.log(" Dep code length:", dependencies[i].code.length);
console2.log(" Dep codehash:");
console2.logBytes32(dependencies[i].codehash);
}

LibRainDeploy.deployAndBroadcast(
vm,
networks,
deployerPrivateKey,
creationCode,
contractPath,
expectedAddress,
expectedCodeHash,
dependencies
);
}

/// @notice The network the suite broadcasts to, from the
/// `DEPLOYMENT_NETWORK` env var, validated against the supported set.
/// No default: an unset network
/// reverts rather than silently picking a chain.
/// @return network The validated `foundry.toml` rpc alias.
function deploymentNetwork() internal view returns (string memory network) {
network = vm.envOr("DEPLOYMENT_NETWORK", string(""));
bytes32 networkHash = keccak256(bytes(network));
if (
networkHash != keccak256(bytes(LibRainDeploy.BASE))
&& networkHash != keccak256(bytes(LibStoxDeployNetworks.ETHEREUM))
&& networkHash != keccak256(bytes(LibStoxDeployNetworks.HYPEREVM))
) {
revert UnknownDeploymentNetwork(network);
}
}

/// @notice Entry point for the 0.1.30 orchestrator-set deployment script.
/// @dev Requires env vars:
/// - `DEPLOYMENT_KEY`: private key for the deployer account.
/// - `DEPLOYMENT_SUITE`: which contract to deploy (e.g.
/// "st0x-orchestrator"). One contract per run.
/// - `DEPLOYMENT_NETWORK`: network to ship to — `base`, `ethereum` or
/// `hyperevm`.
function run() public {
bytes32 suite = keccak256(bytes(vm.envString("DEPLOYMENT_SUITE")));
address[] memory noDeps = new address[](0);

if (suite == DEPLOYMENT_SUITE_STOX_CORPORATE_ACTIONS_FACET) {
// StoxCorporateActionsFacet impl. No on-chain dependencies (the
// receipt-vault impl hardcodes its address but does not link to it
// at deploy time).
deploySuite(
LibProdDeployV4.STOX_CORPORATE_ACTIONS_FACET_CREATION_CODE_0_1_30,
"src/concrete/StoxCorporateActionsFacet.sol:StoxCorporateActionsFacet",
LibProdDeployV4.STOX_CORPORATE_ACTIONS_FACET_0_1_30,
LibProdDeployV4.STOX_CORPORATE_ACTIONS_FACET_CODEHASH_0_1_30,
noDeps
);
} else if (suite == DEPLOYMENT_SUITE_STOX_RECEIPT) {
deploySuite(
LibProdDeployV4.STOX_RECEIPT_CREATION_CODE_0_1_30,
"src/concrete/StoxReceipt.sol:StoxReceipt",
LibProdDeployV4.STOX_RECEIPT_0_1_30,
LibProdDeployV4.STOX_RECEIPT_CODEHASH_0_1_30,
noDeps
);
} else if (suite == DEPLOYMENT_SUITE_STOX_RECEIPT_VAULT) {
// StoxReceiptVault impl. Its `fallback()` delegatecalls the
// hardcoded corporate-actions facet, and a delegatecall to a
// code-less address silently no-ops — so the facet must already be
// on-chain. Declared as a dependency so LibRainDeploy reverts
// MissingDependency if the facet is not yet deployed on the
// network.
address[] memory deps = new address[](1);
deps[0] = LibProdDeployV4.STOX_CORPORATE_ACTIONS_FACET_0_1_30;
deploySuite(
LibProdDeployV4.STOX_RECEIPT_VAULT_CREATION_CODE_0_1_30,
"src/concrete/StoxReceiptVault.sol:StoxReceiptVault",
LibProdDeployV4.STOX_RECEIPT_VAULT_0_1_30,
LibProdDeployV4.STOX_RECEIPT_VAULT_CODEHASH_0_1_30,
deps
);
} else if (suite == DEPLOYMENT_SUITE_STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_BEACON_SET_DEPLOYER) {
// Its constructor bakes beacons over the StoxReceipt and
// StoxReceiptVault impls, both of which must already have code.
address[] memory deps = new address[](2);
deps[0] = LibProdDeployV4.STOX_RECEIPT_0_1_30;
deps[1] = LibProdDeployV4.STOX_RECEIPT_VAULT_0_1_30;
deploySuite(
LibProdDeployV4.STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_BEACON_SET_DEPLOYER_CREATION_CODE_0_1_30,
"src/concrete/deploy/StoxOffchainAssetReceiptVaultBeaconSetDeployer.sol:StoxOffchainAssetReceiptVaultBeaconSetDeployer",
LibProdDeployV4.STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_BEACON_SET_DEPLOYER_0_1_30,
LibProdDeployV4.STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_BEACON_SET_DEPLOYER_CODEHASH_0_1_30,
deps
);
} else if (suite == DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR) {
// ST0xOrchestrator impl. Parameterless constructor, so no
// constructor dependency — but `initialize` (and mint/burn)
// hard-revert via the vault-logic version lock unless the 0.1.30
// OARV beacon-set deployer has code, so an orchestrator deployed
// before it is guaranteed-inert. Declared as a dependency to
// enforce the working order structurally.
address[] memory deps = new address[](1);
deps[0] = LibProdDeployV4.STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_BEACON_SET_DEPLOYER_0_1_30;
deploySuite(
LibProdDeployV4.ST0X_ORCHESTRATOR_CREATION_CODE_0_1_30,
"src/concrete/ST0xOrchestrator.sol:ST0xOrchestrator",
LibProdDeployV4.ST0X_ORCHESTRATOR_0_1_30,
LibProdDeployV4.ST0X_ORCHESTRATOR_CODEHASH_0_1_30,
deps
);
} else if (suite == DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER) {
// Its constructor bakes an `UpgradeableBeacon` over the
// ST0xOrchestrator impl, which must already have code (OZ rejects
// a code-less beacon implementation).
address[] memory deps = new address[](1);
deps[0] = LibProdDeployV4.ST0X_ORCHESTRATOR_0_1_30;
deploySuite(
LibProdDeployV4.ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER_CREATION_CODE_0_1_30,
"src/concrete/deploy/ST0xOrchestratorBeaconSetDeployer.sol:ST0xOrchestratorBeaconSetDeployer",
LibProdDeployV4.ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER_0_1_30,
LibProdDeployV4.ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER_CODEHASH_0_1_30,
deps
);
} else {
revert UnknownDeploymentSuite(suite);
}
}
}
25 changes: 25 additions & 0 deletions src/generated/0_1_30/ST0xOrchestrator.pointers.sol

Large diffs are not rendered by default.

Loading
Loading