From 0993a05789c80242a5d0ad7020d33f3ea36722c3 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 9 May 2026 23:19:50 +0400 Subject: [PATCH 1/3] soldeer migration Mirrors rain.solmem, rain.math.binary, rain.math.saturating. Closes #6. - foundry.toml: libs="dependencies", [dependencies] forge-std=1.16.1, [soldeer] recursive_deps=false - forge-std submodule and .gitmodules removed - Source AND test imports updated to forge-std-1.16.1/src/* (LibRainDeploy itself imports Vm and console2 from forge-std for forge scripting cheatcodes) - .soldeerignore with depth-anchored patterns - REUSE.toml extended for .soldeerignore, remappings.txt, soldeer.lock - CI: drop submodules:recursive, drop sol-prelude, add forge soldeer install before each task; static job moved to rainix's reusable - Publish workflow: thin wrapper calling rainix's reusable - flake bumped; default devShell now points at sol-shell - README rewritten Verified: forge test passes (30/30) on the soldeer-managed forge-std. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/publish-soldeer.yaml | 9 ++ .github/workflows/rainix-sol-static.yaml | 5 + .github/workflows/rainix.yaml | 11 +- .gitignore | 4 +- .gitmodules | 3 - .soldeerignore | 24 +++++ README.md | 96 ++++++++++++----- REUSE.toml | 26 +++-- flake.lock | 127 ++++++++++++++++++----- flake.nix | 21 ++-- foundry.toml | 8 +- lib/forge-std | 1 - remappings.txt | 1 + soldeer.lock | 6 ++ src/lib/LibRainDeploy.sol | 4 +- test/src/lib/LibRainDeploy.t.sol | 2 +- 16 files changed, 258 insertions(+), 90 deletions(-) create mode 100644 .github/workflows/publish-soldeer.yaml create mode 100644 .github/workflows/rainix-sol-static.yaml delete mode 100644 .gitmodules create mode 100644 .soldeerignore delete mode 160000 lib/forge-std create mode 100644 remappings.txt create mode 100644 soldeer.lock diff --git a/.github/workflows/publish-soldeer.yaml b/.github/workflows/publish-soldeer.yaml new file mode 100644 index 0000000..b57bdc2 --- /dev/null +++ b/.github/workflows/publish-soldeer.yaml @@ -0,0 +1,9 @@ +name: Publish to Soldeer +on: + push: + tags: + - "v*" +jobs: + publish: + uses: rainlanguage/rainix/.github/workflows/publish-soldeer.yaml@main + secrets: inherit diff --git a/.github/workflows/rainix-sol-static.yaml b/.github/workflows/rainix-sol-static.yaml new file mode 100644 index 0000000..4b60fb2 --- /dev/null +++ b/.github/workflows/rainix-sol-static.yaml @@ -0,0 +1,5 @@ +name: rainix-sol-static +on: [push] +jobs: + static: + uses: rainlanguage/rainix/.github/workflows/rainix-sol-static.yaml@main diff --git a/.github/workflows/rainix.yaml b/.github/workflows/rainix.yaml index 05e4310..ada301e 100644 --- a/.github/workflows/rainix.yaml +++ b/.github/workflows/rainix.yaml @@ -4,17 +4,15 @@ on: branches: - main pull_request: - concurrency: group: ${{ github.ref }}-rainix cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} - jobs: rainix: strategy: matrix: os: [ubuntu-latest] - task: [rainix-sol-legal, rainix-sol-test, rainix-sol-static] + task: [rainix-sol-legal, rainix-sol-test] fail-fast: false runs-on: ${{ matrix.os }} env: @@ -22,9 +20,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - submodules: recursive fetch-depth: 0 - - uses: nixbuild/nix-quick-install-action@v30 with: nix_conf: | @@ -39,10 +35,7 @@ jobs: restore-prefixes-first-match: nix-${{ runner.os }}- gc-max-store-size-linux: 5G gc-max-store-size-macos: 5G - - - run: nix develop -c rainix-sol-prelude - if: matrix.task == 'rainix-rs-test' || matrix.task == 'rainix-rs-static' || matrix.task == 'test-wasm-build' - + - run: nix develop -c forge soldeer install - name: Run ${{ matrix.task }} env: ETH_RPC_URL: ${{ secrets.CI_DEPLOY_SEPOLIA_RPC_URL || vars.CI_DEPLOY_SEPOLIA_RPC_URL }} diff --git a/.gitignore b/.gitignore index 8a6dbfd..5ae68ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ cache +dependencies out .fixes -.env \ No newline at end of file +.env +.pre-commit-config.yaml diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 888d42d..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/forge-std"] - path = lib/forge-std - url = https://github.com/foundry-rs/forge-std diff --git a/.soldeerignore b/.soldeerignore new file mode 100644 index 0000000..43d7880 --- /dev/null +++ b/.soldeerignore @@ -0,0 +1,24 @@ +.DS_Store +.gas-snapshot +.git +.github +.gitignore +.gitmodules +.pre-commit-config.yaml +.soldeerignore +.vscode +/audit +/cache +/dependencies +/docs +/flake.lock +/flake.nix +/foundry.lock +/foundry.toml +/lib +/out +/remappings.txt +/slither.config.json +/soldeer.lock +/target +/test diff --git a/README.md b/README.md index d88d4be..6776143 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,79 @@ # rain.deploy -Tooling to deploy Solidity code managed with foundry and nix to production using -the Zoltu deterministic deployment proxy to supported networks. +Tooling to deploy Solidity contracts deterministically across EVM networks via +the Zoltu deployment proxy. -Fundamentally Rain code is EVM compatible so can be deployed to any EVM network. -All code is open source and permissionlessly deployable and useable, but only a -subset of all possible networks will be active deploy targets for the Rain -organisation/ecosystem based on use cases and demand. +Fundamentally Rain code is EVM-compatible and permissionlessly deployable +anywhere, but only a curated subset of networks are active deploy targets for +the Rain organisation. This library provides shared infrastructure for that +subset. -Additionally, because Rain is expected to operate across many networks, several -questions naturally arise: +It answers: - Are the dependencies of the current deployment available on this network? - Does this deployment match other deployments on other networks? -- Have I deployed sucessfully to all expected networks? +- Have I deployed successfully to all expected networks? - How do I track deployments over time and share addresses with other people? -- How do I ensure the deployed code is bytecode equivalent to local compilations? - -This repo helps to tool and answer these questions in as foolproof a way as -possible, without overreliance on processes that can be forgotten or -misunderstood. - -- The Zoltu deterministic deployment proxy is used to ensure that addresses are - the same across all networks. -- The interface into the library allows lists of supported networks and - dependencies to be provided by the caller. -- Standard error handling and guards are provided to prevent deployments to - networks missing dependencies and other silent failures in the deployment. -- Deployments only succeed if the resulting address matches a precalculated - address (ideally committed to a repo somewhere) -- Post-deploy bytecode integrity checks are supported, such as those provided by - the Rain Extrospection lib. \ No newline at end of file +- How do I ensure deployed code is bytecode-equivalent to local compilations? + +Approach: + +- Zoltu deterministic deployment proxy: same address on every supported network. +- Caller-provided supported-network and dependency lists. +- Hard guards against deploying to networks where dependencies are missing. +- Pre-calculated addresses asserted post-deploy: silent failures fail loudly. +- Bytecode integrity checks (e.g. via the Rain Extrospection lib) supported + post-deploy. + +## Install + +Via [soldeer](https://soldeer.xyz): + +```sh +forge soldeer install rain-deploy~ +``` + +## Develop + +This repo uses [nix](https://nixos.org/download.html). The default shell is the +slim `sol-shell` from [rainix](https://github.com/rainlanguage/rainix). + +```sh +nix develop # enter the shell +forge soldeer install # install deps declared in foundry.toml +forge test +``` + +Tasks: + +- `rainix-sol-test` — `forge test` +- `rainix-sol-static` — slither +- `rainix-sol-legal` — `reuse lint` + +Use the nix-pinned `forge` for all development. + +## Publish + +Tag `v` on `main`. The +[`Publish to Soldeer`](.github/workflows/publish-soldeer.yaml) wrapper delegates +to rainix's reusable workflow, which derives the package name from the repo name +(`rain.deploy` → `rain-deploy`). + +## License + +DecentraLicense 1.0 (DCL-1.0) — full text in +[`LICENSES/`](LICENSES/LicenseRef-DCL-1.0.txt). Roughly `CAL-1.0` +([opensource.org](https://opensource.org/license/cal-1-0)) plus user-data +disclosure obligations consistent with permissionless-blockchain assumptions. + +This repo is [REUSE 3.2](https://reuse.software/spec-3.2/) compliant. Verify +locally: + +```sh +nix develop -c rainix-sol-legal +``` + +## Contributions + +Welcome under the same license. Contributors warrant that their contributions +are compliant. diff --git a/REUSE.toml b/REUSE.toml index 2a75cfe..68daa58 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -2,17 +2,21 @@ version = 1 [[annotations]] path = [ - ".gas-snapshot", - ".github/**/", - ".gitignore", - ".gitmodules", - "audit/**/", - "README.md", - "flake.lock", - "flake.nix", - "foundry.toml", - "foundry.lock", - "slither.config.json", + ".gas-snapshot", + ".github/**/", + ".gitignore", + ".gitmodules", + ".soldeerignore", + "audit/**/", + "README.md", + "flake.lock", + "flake.nix", + "foundry.toml", + "foundry.lock", + "remappings.txt", + "slither.config.json", + "REUSE.toml", + "soldeer.lock", ] SPDX-FileCopyrightText = "Copyright (c) 2020 Rain Open Source Software Ltd" SPDX-License-Identifier = "LicenseRef-DCL-1.0" diff --git a/flake.lock b/flake.lock index 24c6179..444f616 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,21 @@ { "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -182,11 +198,11 @@ "nixpkgs": "nixpkgs_5" }, "locked": { - "lastModified": 1769324704, - "narHash": "sha256-aef15vEgiMEls1hTMt46rJuKNSO2cIOfiP99patq9yc=", + "lastModified": 1773213477, + "narHash": "sha256-Pv1Z3QqGkSGEUV+9pM5vYIiI7VJo7Tfm6ZmR+JSp1zo=", "owner": "shazow", "repo": "foundry.nix", - "rev": "e830409ba1bdecdc5ef9a1ec92660fc2da9bc68d", + "rev": "3c73daa86c823d706824fd9bbcb85aa23fd0f668", "type": "github" }, "original": { @@ -195,6 +211,48 @@ "type": "github" } }, + "git-hooks-nix": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs_6" + }, + "locked": { + "lastModified": 1774104215, + "narHash": "sha256-EAtviqz0sEAxdHS4crqu7JGR5oI3BwaqG0mw7CmXkO8=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "f799ae951fde0627157f40aec28dec27b22076d0", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "rainix", + "git-hooks-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1666753130, @@ -288,11 +346,27 @@ }, "nixpkgs_6": { "locked": { - "lastModified": 1769364508, - "narHash": "sha256-Wy8EVYSLq5Fb/rYH3LRxAMCnW75f9hOg2562AXVFmPk=", + "lastModified": 1770073757, + "narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "47472570b1e607482890801aeaf29bfb749884f6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_7": { + "locked": { + "lastModified": 1776017067, + "narHash": "sha256-oEp8fqJweZd5doqvH/aBAtc6NzZh+fh0tOhR09gQXck=", "owner": "nixos", "repo": "nixpkgs", - "rev": "6077bc4fb29be43d525984f63b69d37b9b1e62fe", + "rev": "a5a7cf16648d79134eb4da0e3354b08913917b2f", "type": "github" }, "original": { @@ -301,7 +375,7 @@ "type": "github" } }, - "nixpkgs_7": { + "nixpkgs_8": { "locked": { "lastModified": 1744536153, "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", @@ -317,13 +391,13 @@ "type": "github" } }, - "nixpkgs_8": { + "nixpkgs_9": { "locked": { - "lastModified": 1766653575, - "narHash": "sha256-TPgxCS7+hWc4kPhzkU5dD2M5UuPhLuuaMNZ/IpwKQvI=", + "lastModified": 1771923393, + "narHash": "sha256-Fy0+UXELv9hOE8WjYhJt8fMDLYTU2Dqn3cX4BwoGBos=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3c1016e6acd16ad96053116d0d3043029c9e2649", + "rev": "ea7f1f06811ce7fcc81d6c6fd4213150c23edcf2", "type": "github" }, "original": { @@ -378,17 +452,18 @@ "inputs": { "flake-utils": "flake-utils_7", "foundry": "foundry_2", - "nixpkgs": "nixpkgs_6", + "git-hooks-nix": "git-hooks-nix", + "nixpkgs": "nixpkgs_7", "nixpkgs-old": "nixpkgs-old", "rust-overlay": "rust-overlay_2", "solc": "solc_2" }, "locked": { - "lastModified": 1770274701, - "narHash": "sha256-00kymonJVHUtCBBaXMqmVF3b78dtDdXJg8K7P2U9lbA=", + "lastModified": 1778353627, + "narHash": "sha256-VPQ1laFtOhxmr2gxyCw9NALG0gT0zdn3n8M8O7aKIDc=", "owner": "rainlanguage", "repo": "rainix", - "rev": "51c1c74a0e6bc5c49336b02ef97684d01e1e8ad4", + "rev": "c53066a076b1e883787bf60bc38d375803c2ae02", "type": "github" }, "original": { @@ -425,14 +500,14 @@ }, "rust-overlay_2": { "inputs": { - "nixpkgs": "nixpkgs_7" + "nixpkgs": "nixpkgs_8" }, "locked": { - "lastModified": 1769309768, - "narHash": "sha256-AbOIlNO+JoqRJkK1VrnDXhxuX6CrdtIu2hSuy4pxi3g=", + "lastModified": 1773216618, + "narHash": "sha256-iZlowevS+xKLGOXtZwpIrz3SWe7PtoGUfEeVZNib+WE=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "140c9dc582cb73ada2d63a2180524fcaa744fad5", + "rev": "07d7dc6fcc5eae76b4fb0e19d4afd939437bec97", "type": "github" }, "original": { @@ -463,27 +538,27 @@ "solc-macos-amd64-list-json": { "flake": false, "locked": { - "narHash": "sha256-P+ZslplK4cQ/wnV/wykVKb+yTCviI0eylA3sk9uHmRo=", + "narHash": "sha256-oEiXc95EghuYCudzkPA9XBFOnMdgWFfTO2/4XUfSTpc=", "type": "file", - "url": "https://github.com/argotorg/solc-bin/raw/a11f1ad/macosx-amd64/list.json" + "url": "https://github.com/argotorg/solc-bin/raw/83cb756/macosx-amd64/list.json" }, "original": { "type": "file", - "url": "https://github.com/argotorg/solc-bin/raw/a11f1ad/macosx-amd64/list.json" + "url": "https://github.com/argotorg/solc-bin/raw/83cb756/macosx-amd64/list.json" } }, "solc_2": { "inputs": { "flake-utils": "flake-utils_9", - "nixpkgs": "nixpkgs_8", + "nixpkgs": "nixpkgs_9", "solc-macos-amd64-list-json": "solc-macos-amd64-list-json" }, "locked": { - "lastModified": 1768831671, - "narHash": "sha256-0mmlYRtZK+eomevkQCCH7PL8QlSuALZQsjLroCWGE08=", + "lastModified": 1772085240, + "narHash": "sha256-+NEcuhT2A0QQumVx9Ze6g2iuNicyuW028Jq/HUJHGh4=", "owner": "hellwolf", "repo": "solc.nix", - "rev": "80ad871b93d15c7bccf71617f78f73c2d291a9c7", + "rev": "d3cc119973e484ea366f4b997b404bb00d7829ca", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 28dcb2c..1c21d2e 100644 --- a/flake.nix +++ b/flake.nix @@ -7,13 +7,14 @@ rain.url = "github:rainlanguage/rain.cli"; }; - outputs = { self, flake-utils, rainix, rain }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = rainix.pkgs.${system}; - in rec { - packages = rainix.packages.${system}; - devShells = rainix.devShells.${system}; - } - ); -} \ No newline at end of file + outputs = + { + flake-utils, + rainix, + ... + }: + flake-utils.lib.eachDefaultSystem (system: { + packages = rainix.packages.${system}; + devShells.default = rainix.devShells.${system}.sol-shell; + }); +} diff --git a/foundry.toml b/foundry.toml index ad271be..0e14f2f 100644 --- a/foundry.toml +++ b/foundry.toml @@ -4,10 +4,16 @@ [profile.default] src = "src" out = "out" -libs = ["lib"] +libs = ["dependencies"] cbor_metadata = false bytecode_hash = "none" +[dependencies] +forge-std = "1.16.1" + +[soldeer] +recursive_deps = false + [rpc_endpoints] arbitrum = "${ARBITRUM_RPC_URL}" base = "${BASE_RPC_URL}" diff --git a/lib/forge-std b/lib/forge-std deleted file mode 160000 index 1801b05..0000000 --- a/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1801b0541f4fda118a10798fd3486bb7051c5dd6 diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 0000000..f4f4742 --- /dev/null +++ b/remappings.txt @@ -0,0 +1 @@ +forge-std-1.16.1/=dependencies/forge-std-1.16.1/ diff --git a/soldeer.lock b/soldeer.lock new file mode 100644 index 0000000..e9184e4 --- /dev/null +++ b/soldeer.lock @@ -0,0 +1,6 @@ +[[dependencies]] +name = "forge-std" +version = "1.16.1" +url = "https://soldeer-revisions.s3.amazonaws.com/forge-std/1_16_1_08-05-2026_08:51:16_forge-std-1.16.zip" +checksum = "839b61832925c7152c7b6dffbfa4998d9e606211179bd8f604733124e8a7cb57" +integrity = "60e55d10150354ca4a1e2985c5456c834b92b82ef85ab0e1d92a7786cddbd219" diff --git a/src/lib/LibRainDeploy.sol b/src/lib/LibRainDeploy.sol index 9103d92..d63e64f 100644 --- a/src/lib/LibRainDeploy.sol +++ b/src/lib/LibRainDeploy.sol @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Vm} from "forge-std/Vm.sol"; -import {console2} from "forge-std/console2.sol"; +import {Vm} from "forge-std-1.16.1/src/Vm.sol"; +import {console2} from "forge-std-1.16.1/src/console2.sol"; /// @title LibRainDeploy /// Library for deploying contracts via the Zoltu factory across all the networks diff --git a/test/src/lib/LibRainDeploy.t.sol b/test/src/lib/LibRainDeploy.t.sol index f14c2f7..8a39f30 100644 --- a/test/src/lib/LibRainDeploy.t.sol +++ b/test/src/lib/LibRainDeploy.t.sol @@ -2,7 +2,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd pragma solidity ^0.8.25; -import {Test} from "forge-std/Test.sol"; +import {Test} from "forge-std-1.16.1/src/Test.sol"; import {LibRainDeploy} from "../../../src/lib/LibRainDeploy.sol"; /// @title MockDeployable From 2c96bcdf6c8eff68c0aeb5a774ec54ba80ce7dbf Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 9 May 2026 23:26:45 +0400 Subject: [PATCH 2/3] ci: filter dependencies/forge-std- from slither Soldeer installs forge-std under dependencies/forge-std-/ rather than lib/forge-std/, so the previous filter no longer matched and slither was flagging forge-std internals (Vm.sol pragma range, console.sol naming) as project findings. Co-Authored-By: Claude Opus 4.7 (1M context) --- slither.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither.config.json b/slither.config.json index 70d6fd0..70f3181 100644 --- a/slither.config.json +++ b/slither.config.json @@ -1,4 +1,4 @@ { - "filter_paths": "lib/forge-std", + "filter_paths": "dependencies/forge-std-", "detectors_to_exclude": "assembly" } From 38ccb596947a0332d5cb8ebcfd787fd586cffef5 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Sat, 9 May 2026 23:30:16 +0400 Subject: [PATCH 3/3] ci: retrigger after RPC archive upgrade Co-Authored-By: Claude Opus 4.7 (1M context)