Skip to content

Commit 6947233

Browse files
committed
remove claim ownership
1 parent abd070e commit 6947233

File tree

4 files changed

+208
-105
lines changed

4 files changed

+208
-105
lines changed

contracts/script/GenerateAdminProxyAlloc.s.sol

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,56 @@ import {AdminProxy} from "../src/AdminProxy.sol";
66

77
/// @title GenerateAdminProxyAlloc
88
/// @notice Generates genesis alloc JSON for deploying AdminProxy at a deterministic address
9-
/// @dev Run with: forge script script/GenerateAdminProxyAlloc.s.sol -vvv
9+
/// @dev Run with: OWNER=0xYourAddress forge script script/GenerateAdminProxyAlloc.s.sol -vvv
1010
///
1111
/// This script outputs the bytecode and storage layout needed to deploy AdminProxy
12-
/// in the genesis block. The contract is deployed with owner = address(0), allowing
13-
/// the first caller to claim ownership post-genesis.
12+
/// in the genesis block. The owner is set directly in storage slot 0.
1413
///
1514
/// Usage:
16-
/// 1. Run this script to get the bytecode
17-
/// 2. Add to genesis.json alloc section at desired address (e.g., 0x...AD00)
18-
/// 3. Set that address as mintAdmin in chainspec config
15+
/// 1. Set OWNER env var to your initial admin EOA address
16+
/// 2. Run this script to get the bytecode and storage
17+
/// 3. Add to genesis.json alloc section at desired address (e.g., 0x...Ad00)
18+
/// 4. Set that address as mintAdmin in chainspec config
1919
contract GenerateAdminProxyAlloc is Script {
2020
// Suggested deterministic address for AdminProxy
2121
// Using a memorable address in the precompile-adjacent range
2222
address constant SUGGESTED_ADDRESS = 0x000000000000000000000000000000000000Ad00;
2323

2424
function run() external {
25+
// Get owner from environment, default to zero if not set
26+
address owner = vm.envOr("OWNER", address(0));
27+
2528
// Deploy to get runtime bytecode
2629
AdminProxy proxy = new AdminProxy();
2730

2831
// Get runtime bytecode (not creation code)
2932
bytes memory runtimeCode = address(proxy).code;
3033

34+
// Convert owner to storage slot value (left-padded to 32 bytes)
35+
bytes32 ownerSlotValue = bytes32(uint256(uint160(owner)));
36+
3137
console.log("========== AdminProxy Genesis Alloc ==========");
3238
console.log("");
3339
console.log("Suggested address:", SUGGESTED_ADDRESS);
40+
console.log("Owner (from OWNER env):", owner);
3441
console.log("");
42+
43+
if (owner == address(0)) {
44+
console.log("WARNING: OWNER not set! Set OWNER env var to your admin EOA.");
45+
console.log("Example: OWNER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 forge script ...");
46+
console.log("");
47+
}
48+
3549
console.log("Add this to your genesis.json 'alloc' section:");
3650
console.log("");
3751
console.log("{");
3852
console.log(' "alloc": {');
3953
console.log(' "000000000000000000000000000000000000Ad00": {');
4054
console.log(' "balance": "0x0",');
4155
console.log(' "code": "0x%s",', vm.toString(runtimeCode));
42-
console.log(' "storage": {}');
56+
console.log(' "storage": {');
57+
console.log(' "0x0": "0x%s"', vm.toString(ownerSlotValue));
58+
console.log(" }");
4359
console.log(" }");
4460
console.log(" }");
4561
console.log("}");
@@ -58,30 +74,37 @@ contract GenerateAdminProxyAlloc is Script {
5874
console.log("==============================================");
5975
console.log("");
6076
console.log("Post-genesis steps:");
61-
console.log("1. Call claimOwnership() from desired EOA");
77+
console.log("1. Owner can immediately use the proxy (no claiming needed)");
6278
console.log("2. Deploy multisig (e.g., Safe)");
6379
console.log("3. Call transferOwnership(multisigAddress)");
6480
console.log("4. From multisig, call acceptOwnership()");
6581
console.log("");
6682

6783
// Also output raw values for programmatic use
6884
console.log("Raw bytecode length:", runtimeCode.length);
85+
console.log("Owner storage slot (0x0):", vm.toString(ownerSlotValue));
6986
}
7087
}
7188

7289
/// @title GenerateAdminProxyAllocJSON
7390
/// @notice Outputs just the JSON snippet for easy copy-paste
91+
/// @dev Run with: OWNER=0xYourAddress forge script script/GenerateAdminProxyAlloc.s.sol:GenerateAdminProxyAllocJSON -vvv
7492
contract GenerateAdminProxyAllocJSON is Script {
7593
function run() external {
94+
address owner = vm.envOr("OWNER", address(0));
95+
7696
AdminProxy proxy = new AdminProxy();
7797
bytes memory runtimeCode = address(proxy).code;
98+
bytes32 ownerSlotValue = bytes32(uint256(uint160(owner)));
7899

79100
// Output minimal JSON that can be merged into genesis
80101
string memory json = string(
81102
abi.encodePacked(
82103
'{"000000000000000000000000000000000000Ad00":{"balance":"0x0","code":"0x',
83104
vm.toString(runtimeCode),
84-
'","storage":{}}}'
105+
'","storage":{"0x0":"0x',
106+
vm.toString(ownerSlotValue),
107+
'"}}}'
85108
)
86109
);
87110

contracts/src/AdminProxy.sol

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,22 @@ pragma solidity ^0.8.24;
33

44
/// @title AdminProxy
55
/// @notice A proxy contract for managing admin rights to precompiles and other contracts.
6-
/// @dev Deployed at genesis with zero owner, allowing first-come claim. Supports two-step
6+
/// @dev Deployed at genesis with owner set via storage slot. Supports two-step
77
/// ownership transfer for safe handoff to multisigs or other governance contracts.
88
///
99
/// This contract solves the bootstrap problem where admin addresses (e.g., multisigs)
1010
/// are not known at genesis time. The proxy is set as admin in the chainspec, and
11-
/// ownership can be claimed and transferred post-genesis.
11+
/// an initial EOA owner is set in genesis storage. Post-genesis, ownership can be
12+
/// transferred to a multisig.
13+
///
14+
/// Storage Layout:
15+
/// - Slot 0: owner (address)
16+
/// - Slot 1: pendingOwner (address)
1217
///
1318
/// Usage:
14-
/// 1. Deploy at genesis with zero owner (via genesis alloc)
19+
/// 1. Deploy at genesis via alloc with owner set in storage slot 0
1520
/// 2. Set proxy address as `mintAdmin` in chainspec and as FeeVault owner
16-
/// 3. Post-genesis: call claimOwnership() to become initial owner
17-
/// 4. Deploy multisig, then transferOwnership() -> acceptOwnership() to hand off
21+
/// 3. Post-genesis: deploy multisig, then transferOwnership() -> acceptOwnership()
1822
contract AdminProxy {
1923
/// @notice Current owner of the proxy
2024
address public owner;
@@ -51,18 +55,9 @@ contract AdminProxy {
5155
_;
5256
}
5357

54-
/// @notice Initialize with zero owner - first caller can claim ownership
55-
constructor() {
56-
owner = address(0);
57-
}
58-
59-
/// @notice Claim ownership when owner is zero (genesis bootstrap)
60-
/// @dev Can only be called once, when owner is address(0)
61-
function claimOwnership() external {
62-
if (owner != address(0)) revert NotOwner();
63-
owner = msg.sender;
64-
emit OwnershipTransferred(address(0), msg.sender);
65-
}
58+
/// @notice Constructor is empty - owner is set via genesis storage slot 0
59+
/// @dev When deploying at genesis, set storage["0x0"] to the owner address
60+
constructor() {}
6661

6762
/// @notice Start two-step ownership transfer
6863
/// @param newOwner Address of the new owner (e.g., multisig)

0 commit comments

Comments
 (0)