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
6 changes: 6 additions & 0 deletions .github/workflows/git-clean.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: Git is clean
on: [push]
jobs:
copy-artifacts:
uses: rainlanguage/rainix/.github/workflows/rainix-copy-artifacts.yaml@main
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/package-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ jobs:
uses: rainlanguage/rainix/.github/workflows/rainix-tag-release.yaml@main
with:
soldeer-package: rain-factory-deploy
snapshot-generate-cmd: forge script ./script/BuildPointers.sol && forge fmt
snapshot-generate-cmd: forge script ./script/Build.sol --sig "cutRelease()" && forge fmt
secrets: inherit
19 changes: 11 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ live in `rain.factory` and arrive as the `rain-factory` Soldeer dependency

## Deploy-pin invariants (the hazards)

- `src/generated/<tag>/` snapshots are **frozen**: a release ADDS a new tag dir,
never edits or deletes an existing one. CI enforces append-only.
- `[external.package].version` is the **last released** version — it names the
current `src/generated/<tag>/` snapshot. A normal PR does not bump it; only a
release moves it, in lockstep with the snapshot.
- `LibCloneFactoryDeploy.sol` aliases the current tag's snapshot;
`script/BuildPointers.sol` regenerates both. Generated files — do not
hand-edit.
- `src/generated/candidate/` is the **rolling** snapshot, rewritten from what
source compiles to by `script/Build.sol` and currency-checked by CI.
`LibCloneFactoryDeploy.sol` aliases it.
- `src/generated/<tag>/` snapshots are **frozen**: `cutRelease()` freezes the
candidate into a new tag dir; a release only ADDS one, never edits or deletes
an existing one. CI enforces append-only.
- `[external.package].version` is the **last released** version. A normal PR
does not bump it; only a release moves it, in lockstep with a new frozen
`<tag>/`.
- Generated files (`src/generated/`, `src/lib/LibCloneFactoryDeploy.sol`) — do
not hand-edit; `script/Build.sol` regenerates them.

## Release / deploy shape

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# rain.factory.deploy

The **deployment** half of `rain.factory`: the concrete `CloneFactory` contract,
its deployed address + codehash pins (`LibCloneFactoryDeploy`), the frozen
per-tag deploy-pin snapshots under `src/generated/<tag>/`, and the deploy
script.
its deployed address + codehash pins (`LibCloneFactoryDeploy`), the rolling
`src/generated/candidate/` snapshot those pins alias, the frozen per-release
snapshots under `src/generated/<tag>/`, and the deploy script.

The **library** half — the `ICloneable*` interfaces — lives in
[`rain.factory`](https://github.com/rainlanguage/rain.factory) and is imported
Expand All @@ -20,7 +20,8 @@ tagging: the `Manual sol artifacts` workflow runs `script/Deploy.sol` for the
`clone-factory` suite. Tagging then runs `rainix-tag-release`, which never
broadcasts a deploy itself; its mechanics live in rainix.

Nothing publishes on merge, so `[external.package].version` and the frozen
`src/generated/<tag>/` snapshot it names only ever move together.
Nothing publishes on merge: a release bumps `[external.package].version` and
freezes the current `src/generated/candidate/` snapshot into a new
`src/generated/<tag>/` in lockstep.

See rainlanguage/rain.factory#46 for the split rationale.
14 changes: 7 additions & 7 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# into `[profile.*]` by the fixer). `version` is the last-published Soldeer
# release — a deploy repo moves it only via a manual `sol-v*` tag, in lockstep
# with the frozen `src/generated/<tag>/` snapshot it names — and is read here by
# `script/BuildPointers.sol` (`deployTag()`) to locate that snapshot.
# `script/Build.sol`'s `cutRelease()` to locate the snapshot it freezes.
[external.package]
name = "rain-factory-deploy"
version = "0.1.5"
Expand All @@ -26,9 +26,9 @@ evm_version = "cancun"
bytecode_hash = "none"
cbor_metadata = false

# BuildPointers reads the version from foundry.toml and writes the generated
# per-tag snapshots + the current-pin lib under src/. Nothing else in this repo
# touches the filesystem.
# `script/Build.sol` writes the generated candidate snapshot and the alias lib
# under `src/`, and reads the release version from this file when `cutRelease()`
# runs. Nothing else in this repo touches the filesystem.
fs_permissions = [
{ access = "read", path = "./foundry.toml" },
{ access = "read-write", path = "./src" },
Expand All @@ -39,11 +39,11 @@ libs = ["dependencies"]
runs = 2048

[dependencies]
forge-std = "1.16.1"
forge-std = "1.16.2"
"@openzeppelin-contracts" = "5.6.1"
"rain-extrospection" = "0.1.1"
"rain-deploy" = "0.1.3"
"rain-sol-codegen" = "0.1.3"
"rain-deploy" = "0.1.7"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"rain-sol-codegen" = "0.1.36"
"rain-factory" = "0.1.5"

[soldeer]
Expand Down
93 changes: 93 additions & 0 deletions script/Build.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

import {BuildScript} from "rain-deploy-0.1.7/src/abstract/BuildScript.sol";
import {DeployCandidate} from "../src/abstract/RainDeploySuitesBase.sol";
import {CloneFactoryDeploySuites} from "../src/abstract/CloneFactoryDeploySuites.sol";
import {LibRainDeploySnapshot} from "rain-deploy-0.1.7/src/lib/LibRainDeploySnapshot.sol";

/// One contract's generated files: the rolling snapshot, the alias lib that
/// re-exports its pins and the released-suites lib emitted from its record.
struct GeneratedContract {
/// Places the snapshot inside `src/generated/<dir>/` and names both
/// generated libs.
string contractName;
/// Prefix for the constants the alias lib exports, e.g. `CLONE_FACTORY`.
string constantPrefix;
/// Snapshots are written from its `sourceCreationCode` and
/// `snapshot.dependencies`; the released lib takes its suite key and
/// artifact path from its `snapshot`.
DeployCandidate candidate;
}

/// @title Build
/// @notice Generates the deploy pins for every contract this repo deploys.
/// `generatedContracts()` is the only list, read by every hook below.
///
/// `run()` (what CI regenerates against) rewrites the rolling
/// `src/generated/candidate/` snapshot, the alias lib and the released-suites
/// libs. `cutRelease()` freezes the candidate into `src/generated/<tag>/`
/// first. The frozen `0_1_3`/`0_1_4`/`0_1_5` snapshots are append-only
/// historical records, never regenerated here.
contract Build is BuildScript, CloneFactoryDeploySuites {
/// Every contract this repo generates deploy pins for.
/// @return The generated contracts.
function generatedContracts() internal pure returns (GeneratedContract[] memory) {
GeneratedContract[] memory contracts = new GeneratedContract[](1);
contracts[0] = GeneratedContract({
contractName: "CloneFactory", constantPrefix: "CLONE_FACTORY", candidate: cloneFactoryCandidate()
});
return contracts;
}

/// @inheritdoc BuildScript
/// @dev In declaration order — the order the aggregate emits its entries
/// in.
function snapshotContractNames() internal pure override returns (string[] memory) {
GeneratedContract[] memory contracts = generatedContracts();
string[] memory names = new string[](contracts.length);
for (uint256 i = 0; i < contracts.length; i++) {
names[i] = contracts[i].contractName;
}
return names;
}

/// @inheritdoc BuildScript
/// @dev Every alias lib, every released-suites lib and the aggregate over
/// them.
function regenerateLibs() internal override {
GeneratedContract[] memory contracts = generatedContracts();
for (uint256 i = 0; i < contracts.length; i++) {
LibRainDeploySnapshot.writeAliasLib(
vm,
LibRainDeploySnapshot.LIB_DIR,
contracts[i].contractName,
contracts[i].constantPrefix,
LibRainDeploySnapshot.CANDIDATE
);
LibRainDeploySnapshot.writeReleasedSuitesLib(
vm,
LibRainDeploySnapshot.LIB_DIR,
recordRoot(),
contracts[i].contractName,
contracts[i].candidate.snapshot
);
}
LibRainDeploySnapshot.writeReleasedSuitesAggregate(vm, LibRainDeploySnapshot.LIB_DIR, snapshotContractNames());
}

/// @inheritdoc BuildScript
function regenerateSnapshots() internal override {
GeneratedContract[] memory contracts = generatedContracts();
for (uint256 i = 0; i < contracts.length; i++) {
LibRainDeploySnapshot.writeSnapshot(
vm,
LibRainDeploySnapshot.CANDIDATE,
contracts[i].contractName,
contracts[i].candidate.sourceCreationCode,
contracts[i].candidate.snapshot.dependencies
);
}
}
}
112 changes: 0 additions & 112 deletions script/BuildPointers.sol

This file was deleted.

39 changes: 5 additions & 34 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,10 @@
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

import {Script} from "forge-std-1.16.1/src/Script.sol";
import {CloneFactory} from "../src/concrete/CloneFactory.sol";
import {LibRainDeploy} from "rain-deploy-0.1.3/src/lib/LibRainDeploy.sol";
import {LibCloneFactoryDeploy} from "../src/lib/LibCloneFactoryDeploy.sol";

/// @dev Hash of the "clone-factory" deployment suite string.
bytes32 constant DEPLOYMENT_SUITE_CLONE_FACTORY = keccak256("clone-factory");
import {RainDeployBroadcast} from "rain-deploy-0.1.7/src/abstract/RainDeployBroadcast.sol";
import {CloneFactoryDeploySuites} from "../src/abstract/CloneFactoryDeploySuites.sol";

/// @title Deploy
/// @notice A script that deploys a CloneFactory.
contract Deploy is Script {
mapping(string => mapping(address => bytes32)) internal sDepCodeHashes;

function run() external {
uint256 deployerPrivateKey = vm.envUint("DEPLOYMENT_KEY");

bytes32 suite = keccak256(bytes(vm.envOr("DEPLOYMENT_SUITE", string("clone-factory"))));
if (suite == DEPLOYMENT_SUITE_CLONE_FACTORY) {
LibRainDeploy.deployAndBroadcast(
vm,
LibRainDeploy.supportedNetworks(),
deployerPrivateKey,
type(CloneFactory).creationCode,
"src/concrete/CloneFactory.sol:CloneFactory",
LibCloneFactoryDeploy.CLONE_FACTORY_DEPLOYED_ADDRESS,
LibCloneFactoryDeploy.CLONE_FACTORY_DEPLOYED_CODEHASH,
new address[](0),
sDepCodeHashes
);
} else {
revert(
"Invalid deployment suite specified. Please set the DEPLOYMENT_SUITE environment variable to 'clone-factory'."
);
}
}
}
/// @notice The declaration plus `RainDeployBroadcast`; the `Manual sol
/// artifacts` workflow dispatches the `clone-factory` suite.
contract Deploy is CloneFactoryDeploySuites, RainDeployBroadcast {}
2 changes: 1 addition & 1 deletion slither.config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"detectors_to_exclude": "assembly-usage,solc-version,pragma,unindexed-event-address",
"filter_paths": "dependencies/forge-std-1.16.1,dependencies/@openzeppelin-contracts-5.6.1"
"filter_paths": "dependencies,src/abstract/(CloneFactoryDeploySuites|RainDeploySuitesBase)\\.sol"
}
24 changes: 12 additions & 12 deletions soldeer.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ integrity = "bce03af7ada1eee21a7fff393f238bcd7cd75a022a4db55ffb6b0dbb32433d35"

[[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"
version = "1.16.2"
url = "https://soldeer-revisions.s3.amazonaws.com/forge-std/1_16_2_03-07-2026_07:37:45_forge-std-1.16.zip"
checksum = "405dccc9d60d753f6abc412b4adf0359f4390f65dbadbbb277a12b4946ed8969"
integrity = "5fb4325b60d7d4194bd0481e2f94398cf1d9c6561dd12a66fb2748ef4a68205f"

[[dependencies]]
name = "rain-deploy"
version = "0.1.3"
url = "https://soldeer-revisions.s3.amazonaws.com/rain-deploy/0_1_3_20-05-2026_13:02:35_rain.zip"
checksum = "6e9a7a1562ee2766a1cc3a4a077b853ec628a3070b282e6e9102a252f2a6a5b5"
integrity = "10bff708d9e5d8b77655b8a8fc0c755cef8e3fc876cc3ff100425d27b08294a0"
version = "0.1.7"
url = "https://soldeer-revisions.s3.amazonaws.com/rain-deploy/0_1_7_19-08-2026_05:57:12_rain.zip"
checksum = "d0e868184ad16fc6abb704bb1dddab57ebf2beb042529690e030568f5c81a9b3"
integrity = "e51da6f2b3a0f427a0aac5d7714bed2027f5cf0f39b31f0692e9623ceeaa47f2"

[[dependencies]]
name = "rain-extrospection"
Expand All @@ -35,7 +35,7 @@ integrity = "6e6eb9dc5174068e39d6ac80981210723088dde56c9cb0925ffe657ba3154cbc"

[[dependencies]]
name = "rain-sol-codegen"
version = "0.1.3"
url = "https://soldeer-revisions.s3.amazonaws.com/rain-sol-codegen/0_1_3_15-07-2026_08:55:10_rain.sol.zip"
checksum = "e9b8fa2e32ad2c5e2ea6c4f32a909c4d8969b207a486fdbe9d542f14b4125143"
integrity = "f78a6eee689ce93859736cb7d3b149802168e400688512b8865cf625e0bf3534"
version = "0.1.36"
url = "https://soldeer-revisions.s3.amazonaws.com/rain-sol-codegen/0_1_36_18-08-2026_09:20:33_rain.sol.zip"
checksum = "b5d101d46941a95fee441224e101004139814ae9afa2793138874bd7e93991ff"
integrity = "164e2655ac8b66bcf52c799421706d3dfaab987addaaeadd74574e70fd2eb6ed"
Loading
Loading