Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2d17b6f
Add ST0xOrchestrator: per-token mint/burn proxy
hardyjosh Jul 1, 2026
cbcb158
Redesign ST0xOrchestrator as a singleton (meeting + David's review)
hardyjosh Jul 2, 2026
10a1491
Burn walk: revert on insufficient receipts, never mint-on-demand
hardyjosh Jul 3, 2026
841fb0b
Orchestrator review pass: interface, nonce replay, hook auto-lower, s…
hardyjosh Jul 3, 2026
c453710
withdrawReceipt: add nonReentrant for parity with sibling sweeps
hardyjosh Jul 3, 2026
3a80dc7
fmt: match CI-pinned forge fmt output
hardyjosh Jul 3, 2026
ef6fb41
Zero slither findings: real fixes where possible, justified disables …
hardyjosh Jul 3, 2026
471d405
tests: one contract per file (rainix-sol-single-contract)
hardyjosh Jul 3, 2026
46eff22
Harden burn hook against zero-value griefing + fold in mutation-test …
Jul 3, 2026
ba1cf81
Drop @custom:oz-upgrades-unsafe-allow tag (no-custom-natspec CI check)
hardyjosh Jul 6, 2026
47062c1
CHANGELOG: describe the shipped singleton orchestrator, not the redes…
hardyjosh Jul 6, 2026
68aa14f
refactor(orchestrator): single Zoltu beacon-set deployer + fold in de…
thedavidmeister Jul 7, 2026
32883de
docs(audit): add May 2026 st0x.deploy audit report
thedavidmeister Jul 7, 2026
5d3d65c
refactor(orchestrator): give the beacon-set deployer a real ERC-165 i…
thedavidmeister Jul 7, 2026
51b162e
refactor(orchestrator): move the Deployment event onto the deployer i…
thedavidmeister Jul 7, 2026
9d8a94f
ci: assert every generated deploy pointer is pinned in LibProdDeployV4
thedavidmeister Jul 7, 2026
bd5a988
refactor(deploy): version deploy constants by st0x-deploy release tag
thedavidmeister Jul 7, 2026
4f742d1
feat(deploy): pin per-release creation + runtime bytecode as frozen h…
thedavidmeister Jul 7, 2026
4c598af
test(deploy): verify frozen per-release bytecode reproduces + matches…
thedavidmeister Jul 7, 2026
7de9339
test(deploy): assert the deployed 0.1.2 orchestrator + deployer on-chain
thedavidmeister Jul 7, 2026
aff859b
Address #222 review + CodeRabbit threads
thedavidmeister Jul 7, 2026
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
2 changes: 2 additions & 0 deletions .github/workflows/manual-sol-artifacts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ on:
- stox-receipt-v4
- stox-receipt-vault-v4
- stox-wrapped-token-vault-v4
- st0x-orchestrator-v4
# 2. Beacon (depends on stox-wrapped-token-vault-v4)
- stox-wrapped-token-vault-beacon-v4
# 3. Deployers (depend on their beacons/implementations)
- stox-wrapped-token-vault-beacon-set-deployer-v4
- stox-offchain-asset-receipt-vault-beacon-set-deployer-v4
- st0x-orchestrator-beacon-set-deployer-v4
# 4. Unified deployer (depends on the two set-deployers above)
- stox-unified-deployer-v4
# 5. Authorizers (no on-chain dependencies)
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# Changelog

## V4 (rain.vats 0.1.6)

### New contracts

- **ST0xOrchestrator**: Singleton mint/burn proxy for the whole ST0x
receipt-vault set (Initializable, one instance behind a `BeaconProxy`; all
per-token state keyed by the token's vault address). Holds the vault's
`DEPOSIT` + `WITHDRAW` roles and owns every ERC-1155 receipt; callers never
touch one. Roles are split: `MINT_ROLE` mints, `BURN_ROLE` burns, and
`EMERGENCY_ROLE` handles recovery (`setBurnIndex`, `withdrawReceipt`,
`withdrawShares`, `sweepERC1155`) — deliberately separate so the key that can
reposition pointers or sweep assets can never also mint. Every mint carries
the recipient's own `MintAuthV1` authorisation of `(token, to, amount, nonce)`
— an EIP-712 signature (ECDSA or EIP-1271) or, absent one, an
`IMintRecipient.authorizeMint` callback on `to` — with replay protection
namespaced by recipient: `(to, nonce)` is single-use. Burn walks a per-token
sequential receipt-id pointer and reverts `InsufficientReceipts` on a
shortfall — it NEVER mints to cover an overrun; recovery is manual (transfer
receipts in, which auto-lower the pointer via the ERC-1155 receiver hook, or
`EMERGENCY_ROLE` `setBurnIndex`). A vault-logic version lock makes
`initialize` and `mint`/`burn` refuse to run unless the production vault +
receipt beacons still point at the implementations pinned in
`LibProdDeployV4`, halting the orchestrator until it is upgraded in lockstep
with any vault-logic upgrade.
- **ST0xOrchestratorBeaconSetDeployer**: Deploys the `ST0xOrchestrator`
singleton as a `BeaconProxy` behind a shared `UpgradeableBeacon` owned by the
owner multisig. Config-in-constructor base; the Zoltu-deployable concrete
subclass with hardcoded `LibProdDeploy*` config lands with the deploy wiring.

## V3 (corporate actions)

V3 introduces the corporate-actions diamond facet and wires it into the receipt
Expand Down
Binary file added audit/Report_st0x.deploy_may_2026_4.0.pdf
Binary file not shown.
8 changes: 8 additions & 0 deletions script/BuildPointers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
import {
StoxOffchainAssetReceiptVaultPaymentMintAuthorizerV1
} from "../src/concrete/authorize/StoxOffchainAssetReceiptVaultPaymentMintAuthorizerV1.sol";
import {ST0xOrchestrator} from "../src/concrete/ST0xOrchestrator.sol";
import {ST0xOrchestratorBeaconSetDeployer} from "../src/concrete/deploy/ST0xOrchestratorBeaconSetDeployer.sol";

contract BuildPointers is Script {
function addressConstantString(address addr) internal pure returns (string memory) {
Expand Down Expand Up @@ -91,5 +93,11 @@ contract BuildPointers is Script {
"StoxOffchainAssetReceiptVaultPaymentMintAuthorizerV1",
type(StoxOffchainAssetReceiptVaultPaymentMintAuthorizerV1).creationCode
);
// ST0x orchestrator (0.1.7 codebase). The beacon-set deployer's
// constructor bakes the orchestrator impl via
// `LibProdDeployV4.ST0X_ORCHESTRATOR_RAIN_VATS_0_1_7`, so the impl must
// be built (and thus Zoltu-deployed at that address) before the deployer.
buildContractPointers("ST0xOrchestrator", type(ST0xOrchestrator).creationCode);
buildContractPointers("ST0xOrchestratorBeaconSetDeployer", type(ST0xOrchestratorBeaconSetDeployer).creationCode);
}
}
27 changes: 27 additions & 0 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {
StoxOffchainAssetReceiptVaultPaymentMintAuthorizerV1
} from "../src/concrete/authorize/StoxOffchainAssetReceiptVaultPaymentMintAuthorizerV1.sol";
import {StoxCorporateActionsFacet} from "../src/concrete/StoxCorporateActionsFacet.sol";
import {ST0xOrchestrator} from "../src/concrete/ST0xOrchestrator.sol";
import {ST0xOrchestratorBeaconSetDeployer} from "../src/concrete/deploy/ST0xOrchestratorBeaconSetDeployer.sol";

/// @dev Error thrown when the DEPLOYMENT_SUITE env var does not match any
/// known suite.
Expand Down Expand Up @@ -52,6 +54,9 @@ bytes32 constant DEPLOYMENT_SUITE_STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_AUTHORIZER_V
bytes32 constant DEPLOYMENT_SUITE_STOX_OFFCHAIN_ASSET_RECEIPT_VAULT_PAYMENT_MINT_AUTHORIZER_V1_V4 =
keccak256("stox-offchain-asset-receipt-vault-payment-mint-authorizer-v1-v4");
bytes32 constant DEPLOYMENT_SUITE_STOX_CORPORATE_ACTIONS_FACET_V4 = keccak256("stox-corporate-actions-facet-v4");
bytes32 constant DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR_V4 = keccak256("st0x-orchestrator-v4");
bytes32 constant DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER_V4 =
keccak256("st0x-orchestrator-beacon-set-deployer-v4");

contract Deploy is Script {
/// @dev Deploys a single contract via the Zoltu deterministic deployer on
Expand Down Expand Up @@ -202,6 +207,28 @@ contract Deploy is Script {
LibProdDeployV4.STOX_CORPORATE_ACTIONS_FACET_CODEHASH_RAIN_VATS_0_1_6,
noDeps
);
} else if (suite == DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR_V4) {
// ST0xOrchestrator impl — parameterless (Initializable). Depends
// on nothing at deploy time. 0.1.7 codebase (new audit round).
deploySuite(
type(ST0xOrchestrator).creationCode,
"src/concrete/ST0xOrchestrator.sol:ST0xOrchestrator",
LibProdDeployV4.ST0X_ORCHESTRATOR_RAIN_VATS_0_1_7,
LibProdDeployV4.ST0X_ORCHESTRATOR_CODEHASH_RAIN_VATS_0_1_7,
noDeps
);
} else if (suite == DEPLOYMENT_SUITE_ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER_V4) {
// Depends on the ST0xOrchestrator impl (embedded via
// LibProdDeployV4 in the constructor). 0.1.7 codebase.
address[] memory deps = new address[](1);
deps[0] = LibProdDeployV4.ST0X_ORCHESTRATOR_RAIN_VATS_0_1_7;
deploySuite(
type(ST0xOrchestratorBeaconSetDeployer).creationCode,
"src/concrete/deploy/ST0xOrchestratorBeaconSetDeployer.sol:ST0xOrchestratorBeaconSetDeployer",
LibProdDeployV4.ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER_RAIN_VATS_0_1_7,
LibProdDeployV4.ST0X_ORCHESTRATOR_BEACON_SET_DEPLOYER_CODEHASH_RAIN_VATS_0_1_7,
deps
);
} else {
revert UnknownDeploymentSuite(suite);
}
Expand Down
Loading
Loading