AtomicStackDeployer
0xd8c485f7011f05862fa352f909dac60bb29f0146
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
4,515 bytes
ABI entries
13
5 read · 1 write
License
none
Contract information
- Address
- 0xd8c485f7011f05862fa352f909dac60bb29f0146
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x7ab2059EfA…9e64E3d0F8
- Creation tx
- 0x28cb4201ba…b663918230
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (5)
committedPlanHash() → bytes32
executor() → address
owner() → address
resultHash() → bytes32
used() → bool
Events (1)
StackDeployed
ABI
[
{
"inputs": [
{
"internalType": "bytes32",
"name": "planHash",
"type": "bytes32"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "index",
"type": "uint8"
},
{
"internalType": "address",
"name": "expected",
"type": "address"
},
{
"internalType": "address",
"name": "actual",
"type": "address"
}
],
"name": "AddressMismatch",
"type": "error"
},
{
"inputs": [],
"name": "AlreadyUsed",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint8",
"name": "index",
"type": "uint8"
}
],
"name": "DeploymentFailed",
"type": "error"
},
{
"inputs": [],
"name": "HookDeploymentFailed",
"type": "error"
},
{
"inputs": [],
"name": "PlanHashMismatch",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "planHash",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "resultHash",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "launchFactory",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "executor",
"type": "address"
}
],
"name": "StackDeployed",
"type": "event"
},
{
"inputs": [],
"name": "committedPlanHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "bytes",
"name": "graduationManagerInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "redemptionManagerInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "ladderManagerInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "create2DeployerInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "feeControllerInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "launchHookInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "launchRouterInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "earlyExitFeeModelInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "controllerImplementationInitCode",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "launchFactoryInitCode",
"type": "bytes"
},
{
"internalType": "bytes32",
"name": "hookSalt",
"type": "bytes32"
},
{
"components": [
{
"internalType": "address",
"name": "graduationManager",
"type": "address"
},
{
"internalType": "address",
"name": "redemptionManager",
"type": "address"
},
{
"internalType": "address",
"name": "ladderManager",
"type": "address"
},
{
"internalType": "address",
"name": "create2Deployer",
"type": "address"
},
{
"internalType": "address",
"name": "feeController",
"type": "address"
},
{
"internalType": "address",
"name": "launchHook",
"type": "address"
},
{
"internalType": "address",
"name": "launchRouter",
"type": "address"
},
{
"internalType": "address",
"name": "earlyExitFeeModel",
"type": "address"
},
{
"internalType": "address",
"name": "controllerImplementation",
"type": "address"
},
{
"internalType": "address",
"name": "launchFactory",
"type": "address"
}
],
"internalType": "struct AtomicStackDeployer.Addresses",
"name": "expected",
"type": "tuple"
}
],
"internalType": "struct AtomicStackDeployer.Plan",
"name": "plan",
"type": "tuple"
}
],
"name": "execute",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "graduationManager",
"type": "address"
},
{
"internalType": "address",
"name": "redemptionManager",
"type": "address"
},
{
"internalType": "address",
"name": "ladderManager",
"type": "address"
},
{
"internalType": "address",
"name": "create2Deployer",
"type": "address"
},
{
"internalType": "address",
"name": "feeController",
"type": "address"
},
{
"internalType": "address",
"name": "launchHook",
"type": "address"
},
{
"internalType": "address",
"name": "launchRouter",
"type": "address"
},
{
"internalType": "address",
"name": "earlyExitFeeModel",
"type": "address"
},
{
"internalType": "address",
"name": "controllerImplementation",
"type": "address"
},
{
"internalType": "address",
"name": "launchFactory",
"type": "address"
}
],
"internalType": "struct AtomicStackDeployer.Addresses",
"name": "deployed",
"type": "tuple"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "executor",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "resultHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "used",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
interface ICreate2Deployer {
function deployOnce(bytes32 salt, bytes calldata initCode) external returns (address deployed);
function used() external view returns (bool);
}
interface IRegistryBootstrap {
function configureRegistry(address registryAdmin) external;
}
interface IFeeControllerBootstrap {
function configure(address registryAdmin, address hook) external;
}
/// @notice One-use atomic deployer for one immutable Rivers protocol stack.
/// @dev The owner commits to the exact plan hash at construction. Successful execution
/// is permissionless so a nonprivileged relayer can transport the large calldata
/// without a hardware-wallet QR. The relayer cannot alter the committed plan.
contract AtomicStackDeployer {
struct Addresses {
address graduationManager;
address redemptionManager;
address ladderManager;
address create2Deployer;
address feeController;
address launchHook;
address launchRouter;
address earlyExitFeeModel;
address controllerImplementation;
address launchFactory;
}
struct Plan {
bytes graduationManagerInitCode;
bytes redemptionManagerInitCode;
bytes ladderManagerInitCode;
bytes create2DeployerInitCode;
bytes feeControllerInitCode;
bytes launchHookInitCode;
bytes launchRouterInitCode;
bytes earlyExitFeeModelInitCode;
bytes controllerImplementationInitCode;
bytes launchFactoryInitCode;
bytes32 hookSalt;
Addresses expected;
}
address public immutable owner;
bytes32 public immutable committedPlanHash;
bool public used;
address public executor;
bytes32 public resultHash;
error AlreadyUsed();
error PlanHashMismatch();
error DeploymentFailed(uint8 index);
error AddressMismatch(uint8 index, address expected, address actual);
error HookDeploymentFailed();
event StackDeployed(
bytes32 indexed planHash, bytes32 indexed resultHash, address indexed launchFactory, address executor
);
constructor(bytes32 planHash) {
owner = msg.sender;
committedPlanHash = planHash;
}
function execute(Plan calldata plan) external returns (Addresses memory deployed) {
if (used) revert AlreadyUsed();
bytes32 planHash = keccak256(abi.encode(plan));
if (planHash != committedPlanHash) revert PlanHashMismatch();
used = true;
deployed.graduationManager = _deploy(0, plan.graduationManagerInitCode, plan.expected.graduationManager);
deployed.redemptionManager = _deploy(1, plan.redemptionManagerInitCode, plan.expected.redemptionManager);
deployed.ladderManager = _deploy(2, plan.ladderManagerInitCode, plan.expected.ladderManager);
deployed.create2Deployer = _deploy(3, plan.create2DeployerInitCode, plan.expected.create2Deployer);
deployed.feeController = _deploy(4, plan.feeControllerInitCode, plan.expected.feeController);
deployed.launchHook =
ICreate2Deployer(deployed.create2Deployer).deployOnce(plan.hookSalt, plan.launchHookInitCode);
if (
deployed.launchHook != plan.expected.launchHook || deployed.launchHook.code.length == 0
|| !ICreate2Deployer(deployed.create2Deployer).used()
) revert HookDeploymentFailed();
deployed.launchRouter = _deploy(5, plan.launchRouterInitCode, plan.expected.launchRouter);
deployed.earlyExitFeeModel = _deploy(6, plan.earlyExitFeeModelInitCode, plan.expected.earlyExitFeeModel);
deployed.controllerImplementation =
_deploy(7, plan.controllerImplementationInitCode, plan.expected.controllerImplementation);
deployed.launchFactory = _deploy(8, plan.launchFactoryInitCode, plan.expected.launchFactory);
IRegistryBootstrap(deployed.launchHook).configureRegistry(deployed.launchFactory);
IFeeControllerBootstrap(deployed.feeController).configure(deployed.launchFactory, deployed.launchHook);
IRegistryBootstrap(deployed.launchRouter).configureRegistry(deployed.launchFactory);
executor = msg.sender;
resultHash = keccak256(abi.encode(deployed));
emit StackDeployed(planHash, resultHash, deployed.launchFactory, msg.sender);
}
function _deploy(uint8 index, bytes calldata initCode, address expected) private returns (address deployed) {
bytes memory code = initCode;
assembly ("memory-safe") {
deployed := create(0, add(code, 0x20), mload(code))
}
if (deployed == address(0) || deployed.code.length == 0) revert DeploymentFailed(index);
if (deployed != expected) revert AddressMismatch(index, expected, deployed);
}
}
Chain explorer5853msChain node87ms