Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 {}
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