From 013e7c579a169eefa1c88643415b24ca2f297f4d Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 11 Feb 2026 21:24:03 +0400 Subject: [PATCH 1/6] idempotent deploy --- .github/workflows/manual-sol-artifacts.yml | 51 ++++++---------------- .gitmodules | 3 ++ foundry.toml | 12 +++++ lib/rain.deploy | 1 + script/Deploy.sol | 11 +++++ src/lib/deploy/LibMetaBoardDeploy.sol | 22 ++++++++++ 6 files changed, 62 insertions(+), 38 deletions(-) create mode 160000 lib/rain.deploy create mode 100644 src/lib/deploy/LibMetaBoardDeploy.sol diff --git a/.github/workflows/manual-sol-artifacts.yml b/.github/workflows/manual-sol-artifacts.yml index 49fcb2f2..8b7bfb87 100644 --- a/.github/workflows/manual-sol-artifacts.yml +++ b/.github/workflows/manual-sol-artifacts.yml @@ -2,40 +2,11 @@ name: Manual sol artifacts on: workflow_dispatch: inputs: - network: - description: "Network to deploy to" - required: true - type: choice - options: - - arbitrum - - arbitrum_sepolia - - avalanche - - base - - bsc - - ethereum - - flare - - mumbai - - oasis_sapphire - - polygon - - sepolia - - songbird - - linea - - matchain - - bera - - sonic jobs: deploy: runs-on: ubuntu-latest steps: - - run: | - network=${{ inputs.network }} - echo "etherscan_api_key_secret_name=CI_DEPLOY_${network^^}_ETHERSCAN_API_KEY" >> $GITHUB_ENV - echo "rpc_secret_name=CI_DEPLOY_${network^^}_RPC_URL" >> $GITHUB_ENV - echo "verify_secret_name=CI_DEPLOY_${network^^}_VERIFY" >> $GITHUB_ENV - echo "verifier_secret_name=CI_DEPLOY_${network^^}_VERIFIER" >> $GITHUB_ENV - echo "verifier_url_secret_name=CI_DEPLOY_${network^^}_VERIFIER_URL" >> $GITHUB_ENV - - uses: actions/checkout@v4 with: submodules: recursive @@ -58,14 +29,18 @@ jobs: # 1G = 1073741824 gc-max-store-size-linux: 1G - # - run: nix develop --command rainix-sol-prelude - - name: deploy to ${{ inputs.network }} - run: nix develop --command rainix-sol-artifacts + - run: nix develop -c rainix-sol-prelude + - run: nix develop -c forge selectors up --all + - run: nix develop -c forge script script/Deploy.sol:Deploy -vvvvv --slow --broadcast --verify env: - DEPLOY_BROADCAST: "1" DEPLOYMENT_KEY: ${{ github.ref == 'refs/heads/main' && secrets.PRIVATE_KEY || secrets.PRIVATE_KEY_DEV }} - ETH_RPC_URL: ${{ secrets[env.rpc_secret_name] || vars[env.rpc_secret_name] || '' }} - ETHERSCAN_API_KEY: ${{ secrets[env.etherscan_api_key_secret_name] || vars[env.etherscan_api_key_secret_name] || ''}} - DEPLOY_VERIFY: ${{ secrets[env.verify_secret_name] || vars[env.verify_secret_name] || '' }} - DEPLOY_VERIFIER: ${{ secrets[env.verifier_secret_name] || vars[env.verifier_secret_name] || '' }} - DEPLOY_VERIFIER_URL: ${{ secrets[env.verifier_url_secret_name] || vars[env.verifier_url_secret_name] || '' }} + + CI_DEPLOY_ARBITRUM_RPC_URL: ${{ secrets.CI_DEPLOY_ARBITRUM_RPC_URL || vars.CI_DEPLOY_ARBITRUM_RPC_URL || '' }} + CI_DEPLOY_BASE_RPC_URL: ${{ secrets.CI_DEPLOY_BASE_RPC_URL || vars.CI_DEPLOY_BASE_RPC_URL || '' }} + CI_DEPLOY_FLARE_RPC_URL: ${{ secrets.CI_DEPLOY_FLARE_RPC_URL || vars.CI_DEPLOY_FLARE_RPC_URL || '' }} + CI_DEPLOY_POLYGON_RPC_URL: ${{ secrets.CI_DEPLOY_POLYGON_RPC_URL || vars.CI_DEPLOY_POLYGON_RPC_URL || '' }} + + CI_DEPLOY_ARBITRUM_ETHERSCAN_API_KEY: ${{ secrets.CI_DEPLOY_ARBITRUM_ETHERSCAN_API_KEY || vars.CI_DEPLOY_ARBITRUM_ETHERSCAN_API_KEY || '' }} + CI_DEPLOY_BASE_ETHERSCAN_API_KEY: ${{ secrets.CI_DEPLOY_BASE_ETHERSCAN_API_KEY || vars.CI_DEPLOY_BASE_ETHERSCAN_API_KEY || '' }} + CI_DEPLOY_FLARE_ETHERSCAN_API_KEY: ${{ secrets.CI_DEPLOY_FLARE_ETHERSCAN_API_KEY || vars.CI_DEPLOY_FLARE_ETHERSCAN_API_KEY || '' }} + CI_DEPLOY_POLYGON_ETHERSCAN_API_KEY: ${{ secrets.CI_DEPLOY_POLYGON_ETHERSCAN_API_KEY || vars.CI_DEPLOY_POLYGON_ETHERSCAN_API_KEY || '' }} \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 888d42dc..024439b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "lib/forge-std"] path = lib/forge-std url = https://github.com/foundry-rs/forge-std +[submodule "lib/rain.deploy"] + path = lib/rain.deploy + url = https://github.com/rainlanguage/rain.deploy diff --git a/foundry.toml b/foundry.toml index 5055808f..a8b63444 100644 --- a/foundry.toml +++ b/foundry.toml @@ -12,3 +12,15 @@ cbor_metadata = false [fuzz] runs = 5096 + +[rpc_endpoints] +arbitrum = "${CI_DEPLOY_ARBITRUM_RPC_URL}" +base = "${CI_DEPLOY_BASE_RPC_URL}" +flare = "${CI_DEPLOY_FLARE_RPC_URL}" +polygon = "${CI_DEPLOY_POLYGON_RPC_URL}" + +[etherscan] +arbitrum = { key = "${CI_DEPLOY_ARBITRUM_ETHERSCAN_API_KEY}" } +base = { key = "${CI_DEPLOY_BASE_ETHERSCAN_API_KEY}" } +flare = { key = "${CI_DEPLOY_FLARE_ETHERSCAN_API_KEY}" } +polygon = { key = "${CI_DEPLOY_POLYGON_ETHERSCAN_API_KEY}" } \ No newline at end of file diff --git a/lib/rain.deploy b/lib/rain.deploy new file mode 160000 index 00000000..e419a46e --- /dev/null +++ b/lib/rain.deploy @@ -0,0 +1 @@ +Subproject commit e419a46e2a1317a63639ac13fc5a22d7e967fbef diff --git a/script/Deploy.sol b/script/Deploy.sol index 7577d142..b405b698 100644 --- a/script/Deploy.sol +++ b/script/Deploy.sol @@ -12,6 +12,17 @@ contract Deploy is Script { function run() external { uint256 deployerPrivateKey = vm.envUint("DEPLOYMENT_KEY"); + LibRainDeploy.deployAndBroadcastToSupportedNetworks( + vm, + LibRainDeploy.supportedNetworks(), + deployerPrivateKey, + type(MetaBoard).creationCode, + "", + LibMetaBoardDeploy.METABOARD_DEPLOYED_ADDRESS, + LibMetaBoardDeploy.METABOARD_DEPLOYED_CODEHASH, + new address[](0) + ); + vm.startBroadcast(deployerPrivateKey); new MetaBoard(); diff --git a/src/lib/deploy/LibMetaBoardDeploy.sol b/src/lib/deploy/LibMetaBoardDeploy.sol new file mode 100644 index 00000000..8cbaf479 --- /dev/null +++ b/src/lib/deploy/LibMetaBoardDeploy.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity ^0.8.25; + +/// @title LibMetaBoardDeploy +/// A library containing the deployed address and code hash of the MetaBoard +/// contract when deployed with the rain standard zoltu deployer. This allows +/// idempotent deployments against precommitted addresses and hashes that can be +/// easily verified automatically in tests and scripts rather than relying on +/// registries or manual verification. +library LibMetaBoardDeploy { + /// The address of the `MetaBoard` contract when deployed with the rain + /// standard zoltu deployer. + address constant METABOARD_DEPLOYED_ADDRESS = address(0); + + /// The code hash of the `MetaBoard` contract when deployed with the rain + /// standard zoltu deployer. This can be used to verify that the deployed + /// contract has the expected bytecode, which provides stronger guarantees + /// than just checking the address. + bytes32 constant METABOARD_DEPLOYED_CODEHASH = + bytes32(0); +} From f6e206a7792b8aef2e6e7423a4f7ae2b78bf224b Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 11 Feb 2026 21:30:42 +0400 Subject: [PATCH 2/6] fix build --- .gas-snapshot | 8 ++++---- foundry.toml | 4 ++++ script/Deploy.sol | 8 ++------ src/lib/deploy/LibMetaBoardDeploy.sol | 3 +-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 31bfb552..c9b01aeb 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,10 +1,10 @@ -LibDescribedByMetaEmitForDescribedAddressTest:testEmitForDescribedAddressHappy(bytes) (runs: 5096, μ: 256737, ~: 256683) -LibDescribedByMetaEmitForDescribedAddressTest:testEmitForDescribedAddressMismatch(bytes,bytes) (runs: 5092, μ: 258640, ~: 258619) +LibDescribedByMetaEmitForDescribedAddressTest:testEmitForDescribedAddressHappy(bytes) (runs: 5096, μ: 256735, ~: 256683) +LibDescribedByMetaEmitForDescribedAddressTest:testEmitForDescribedAddressMismatch(bytes,bytes) (runs: 5096, μ: 258640, ~: 258619) LibMetaCheckMetaHashedV1_2Test:testCheckMetaHashedV1_2BadMagicBadHash(bytes,bytes32) (runs: 5096, μ: 5633, ~: 5616) LibMetaCheckMetaHashedV1_2Test:testCheckMetaHashedV1_2BadMagicGoodHash(bytes) (runs: 5096, μ: 5719, ~: 5694) -LibMetaCheckMetaHashedV1_2Test:testCheckMetaHashedV1_2GoodMagicBadHash(bytes,bytes32) (runs: 5096, μ: 5782, ~: 5771) +LibMetaCheckMetaHashedV1_2Test:testCheckMetaHashedV1_2GoodMagicBadHash(bytes,bytes32) (runs: 5096, μ: 5783, ~: 5771) LibMetaCheckMetaHashedV1_2Test:testCheckMetaHashedV1_2Happy(bytes) (runs: 5096, μ: 1102, ~: 1095) LibMetaCheckMetaUnhashedV1_2Test:testCheckMetaUnhashedV1_2Fuzz(bytes) (runs: 5096, μ: 5818, ~: 5797) LibMetaIsRainMetaV1_2Test:testIsRainMetaV1_2Fuzz(bytes) (runs: 5096, μ: 1025, ~: 1020) MetaBoardHashTest:testMetaboardHash(bytes) (runs: 5096, μ: 191156, ~: 191140) -MetaBoardTest:testEmitMeta(bytes32,bytes) (runs: 5096, μ: 202190, ~: 202079) \ No newline at end of file +MetaBoardTest:testEmitMeta(bytes32,bytes) (runs: 5096, μ: 202188, ~: 202079) \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index a8b63444..6cedb32a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -10,6 +10,10 @@ evm_version = "cancun" bytecode_hash = "none" cbor_metadata = false +remappings = [ + "rain.deploy/=lib/rain.deploy/src/" +] + [fuzz] runs = 5096 diff --git a/script/Deploy.sol b/script/Deploy.sol index b405b698..a948ae5a 100644 --- a/script/Deploy.sol +++ b/script/Deploy.sol @@ -4,6 +4,8 @@ pragma solidity =0.8.25; import {Script} from "forge-std/Script.sol"; import {MetaBoard} from "src/concrete/MetaBoard.sol"; +import {LibRainDeploy} from "rain.deploy/lib/LibRainDeploy.sol"; +import {LibMetaBoardDeploy} from "src/lib/deploy/LibMetaBoardDeploy.sol"; /// @title Deploy /// @notice A script that deploys all contracts. This is intended to be run on @@ -22,11 +24,5 @@ contract Deploy is Script { LibMetaBoardDeploy.METABOARD_DEPLOYED_CODEHASH, new address[](0) ); - - vm.startBroadcast(deployerPrivateKey); - - new MetaBoard(); - - vm.stopBroadcast(); } } diff --git a/src/lib/deploy/LibMetaBoardDeploy.sol b/src/lib/deploy/LibMetaBoardDeploy.sol index 8cbaf479..ee87e219 100644 --- a/src/lib/deploy/LibMetaBoardDeploy.sol +++ b/src/lib/deploy/LibMetaBoardDeploy.sol @@ -17,6 +17,5 @@ library LibMetaBoardDeploy { /// standard zoltu deployer. This can be used to verify that the deployed /// contract has the expected bytecode, which provides stronger guarantees /// than just checking the address. - bytes32 constant METABOARD_DEPLOYED_CODEHASH = - bytes32(0); + bytes32 constant METABOARD_DEPLOYED_CODEHASH = bytes32(0); } From ec01fb92a07e77bb3c08d5a2c9f9eb3173e1936b Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 11 Feb 2026 21:41:32 +0400 Subject: [PATCH 3/6] deploy test --- .gitignore | 2 ++ src/lib/deploy/LibMetaBoardDeploy.sol | 4 ++-- test/lib/deploy/LibMetaBoardDeploy.t.sol | 27 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 test/lib/deploy/LibMetaBoardDeploy.t.sol diff --git a/.gitignore b/.gitignore index 1570ab1e..a69c24ce 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ cache .vscode .direnv/ +.env + # Rust target \ No newline at end of file diff --git a/src/lib/deploy/LibMetaBoardDeploy.sol b/src/lib/deploy/LibMetaBoardDeploy.sol index ee87e219..6b197ae7 100644 --- a/src/lib/deploy/LibMetaBoardDeploy.sol +++ b/src/lib/deploy/LibMetaBoardDeploy.sol @@ -11,11 +11,11 @@ pragma solidity ^0.8.25; library LibMetaBoardDeploy { /// The address of the `MetaBoard` contract when deployed with the rain /// standard zoltu deployer. - address constant METABOARD_DEPLOYED_ADDRESS = address(0); + address constant METABOARD_DEPLOYED_ADDRESS = address(0xfb8437AeFBB8031064E274527C5fc08e30Ac6928); /// The code hash of the `MetaBoard` contract when deployed with the rain /// standard zoltu deployer. This can be used to verify that the deployed /// contract has the expected bytecode, which provides stronger guarantees /// than just checking the address. - bytes32 constant METABOARD_DEPLOYED_CODEHASH = bytes32(0); + bytes32 constant METABOARD_DEPLOYED_CODEHASH = bytes32(0x60e0735a3406074fd8f85adb2813d0d7c346337ea4bcc6f2ef4eb25077a4933c); } diff --git a/test/lib/deploy/LibMetaBoardDeploy.t.sol b/test/lib/deploy/LibMetaBoardDeploy.t.sol new file mode 100644 index 00000000..28b73040 --- /dev/null +++ b/test/lib/deploy/LibMetaBoardDeploy.t.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {Test} from "forge-std/Test.sol"; +import {LibRainDeploy} from "rain.deploy/lib/LibRainDeploy.sol"; +import {LibMetaBoardDeploy} from "src/lib/deploy/LibMetaBoardDeploy.sol"; +import {MetaBoard} from "src/concrete/MetaBoard.sol"; + +contract LibMetaBoardDeployTest is Test { + function testDeployAddress() external { + vm.createSelectFork(vm.envString("CI_FORK_ETH_RPC_URL")); + + address deployedAddress = LibRainDeploy.deployZoltu(type(MetaBoard).creationCode); + + assertEq(deployedAddress, LibMetaBoardDeploy.METABOARD_DEPLOYED_ADDRESS); + assertTrue(address(deployedAddress).code.length > 0, "Deployed address has no code"); + + assertEq(address(deployedAddress).codehash, LibMetaBoardDeploy.METABOARD_DEPLOYED_CODEHASH); + } + + function testExpectedCodeHash() external { + MetaBoard metaBoard = new MetaBoard(); + + assertEq(address(metaBoard).codehash, LibMetaBoardDeploy.METABOARD_DEPLOYED_CODEHASH); + } +} From f1df4692335d3120990127670881e39bae8ec4a1 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 11 Feb 2026 21:52:51 +0400 Subject: [PATCH 4/6] fmt --- src/lib/deploy/LibMetaBoardDeploy.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/deploy/LibMetaBoardDeploy.sol b/src/lib/deploy/LibMetaBoardDeploy.sol index 6b197ae7..a7d051bc 100644 --- a/src/lib/deploy/LibMetaBoardDeploy.sol +++ b/src/lib/deploy/LibMetaBoardDeploy.sol @@ -17,5 +17,6 @@ library LibMetaBoardDeploy { /// standard zoltu deployer. This can be used to verify that the deployed /// contract has the expected bytecode, which provides stronger guarantees /// than just checking the address. - bytes32 constant METABOARD_DEPLOYED_CODEHASH = bytes32(0x60e0735a3406074fd8f85adb2813d0d7c346337ea4bcc6f2ef4eb25077a4933c); + bytes32 constant METABOARD_DEPLOYED_CODEHASH = + bytes32(0x60e0735a3406074fd8f85adb2813d0d7c346337ea4bcc6f2ef4eb25077a4933c); } From 9338fa0090300e96e7d2ce2e30f9457f48ae45ee Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 11 Feb 2026 21:53:22 +0400 Subject: [PATCH 5/6] rainix-sol-artifacts rm --- .github/workflows/rainix.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/rainix.yaml b/.github/workflows/rainix.yaml index 320de20d..d1bfe879 100644 --- a/.github/workflows/rainix.yaml +++ b/.github/workflows/rainix.yaml @@ -17,8 +17,6 @@ jobs: task: rainix-sol-test - os: ubuntu-latest task: rainix-sol-static - - os: ubuntu-latest - task: rainix-sol-artifacts # We don't need to do rust static analysis on multiple platforms - os: ubuntu-latest task: rainix-rs-static From ba4c61f911df86a6a0e79c8147019ec3660ebf65 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Wed, 11 Feb 2026 21:54:10 +0400 Subject: [PATCH 6/6] fix ci --- .github/workflows/rainix.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rainix.yaml b/.github/workflows/rainix.yaml index d1bfe879..188d09d9 100644 --- a/.github/workflows/rainix.yaml +++ b/.github/workflows/rainix.yaml @@ -50,6 +50,7 @@ jobs: - name: Run ${{ matrix.task }} env: ETH_RPC_URL: ${{ secrets.CI_DEPLOY_SEPOLIA_RPC_URL || vars.CI_DEPLOY_SEPOLIA_RPC_URL }} + CI_FORK_ETH_RPC_URL: ${{ secrets.RPC_URL_ETHEREUM_FORK || vars.RPC_URL_ETHEREUM_FORK || '' }} ETHERSCAN_API_KEY: ${{ secrets.EXPLORER_VERIFICATION_KEY }} run: nix develop -c ${{ matrix.task }}