Skip to content

Commit 12c2d7c

Browse files
rplusqclaude
andauthored
chore(deployments): reconcile 10.json to live chain + add timelock deploy infra (#50)
* chore(deployments): reconcile 10.json to live chain + add Arb/Base timelock deploy infra - 10.json was stale: LTS entries pointed at old immutable contracts; StakeWeight/ Distributor/Pauser impls predated P3/#45. Reconciled all proxy entries to live on-chain values (verified via EIP-1967 slots + getPostClaimHandlers). - Add TimelockDeploy.s.sol + arbitrum/base RPC aliases so ProxyAdmin ownership and the token admin role can be moved behind a per-chain timelock. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(deploy): consolidate Etherscan verification on V2 single key Etherscan V2 uses one API key across all chains (routed by chainid); the per-explorer V1 keys are deprecated. Add arbitrum/base [etherscan] entries and collapse optimism + the Makefile onto ${API_KEY_ETHERSCAN}, dropping API_KEY_OPTIMISTIC_ETHERSCAN from the env sample. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: rplusq <rplusq@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent a9845d8 commit 12c2d7c

5 files changed

Lines changed: 77 additions & 14 deletions

File tree

evm/.common.example.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# API keys
22
export API_KEY_INFURA=
3+
# Etherscan V2: one key verifies on every supported chain (mainnet, optimism, arbitrum, base, ...)
34
export API_KEY_ETHERSCAN=
4-
export API_KEY_OPTIMISTIC_ETHERSCAN=
55
# Foundry
66
export FOUNDRY_PROFILE="default"

evm/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ fund-deployer:
108108
_deploy:
109109
$(eval include .common.env)
110110
$(eval include $(ENV_FILE))
111-
$(eval ETHSCAN_KEY = $(if $(findstring optimism,$(ENV_FILE)),${API_KEY_OPTIMISTIC_ETHERSCAN},${API_KEY_ETHERSCAN}))
111+
$(eval ETHSCAN_KEY = ${API_KEY_ETHERSCAN})
112112

113113
ifeq ($(IS_ANVIL),)
114114
$(eval RPC_URL = https://${CHAIN_NAME}.infura.io/v3/${API_KEY_INFURA})
@@ -174,7 +174,7 @@ endif
174174
_p3_deploy:
175175
$(eval include .common.env)
176176
$(eval include $(ENV_FILE))
177-
$(eval ETHSCAN_KEY = $(if $(findstring optimism,$(ENV_FILE)),${API_KEY_OPTIMISTIC_ETHERSCAN},${API_KEY_ETHERSCAN}))
177+
$(eval ETHSCAN_KEY = ${API_KEY_ETHERSCAN})
178178

179179
ifeq ($(IS_ANVIL),)
180180
$(eval RPC_URL = https://${CHAIN_NAME}.infura.io/v3/${API_KEY_INFURA})

evm/deployments/10.json

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,34 @@
1616
}
1717
},
1818
"LockedTokenStakerBackers": {
19-
"address": "0x688CfB3e55fCE2540b5491E923Dc6a9C4f240176"
19+
"address": "0x37BAdde9E3c9E108065Db36dCcce91E00556e334",
20+
"admin": "0x8B79481a2d8EEbe0F4d6Fd1705b0598540875407",
21+
"implementation": "0xB52b4633eA577A143fAa811127CeE7163b023bFb",
22+
"proxy": {
23+
"implementation": "0xB52b4633eA577A143fAa811127CeE7163b023bFb",
24+
"admin": "0x8B79481a2d8EEbe0F4d6Fd1705b0598540875407",
25+
"type": "transparent"
26+
}
2027
},
2128
"LockedTokenStakerReown": {
22-
"address": "0x5f630a47DE14e346fC28deB8fE379833A6F6B9B2"
29+
"address": "0xCcCf4C051C6F5a82D6bD76a1F66fc3cCdE8b3D6b",
30+
"admin": "0x54594f1aF2A6bd876bF0f6d45FB7c3cb54eFB5d5",
31+
"implementation": "0xABB9F4CCb5025c446c7FF2e000c705332d21f760",
32+
"proxy": {
33+
"implementation": "0xABB9F4CCb5025c446c7FF2e000c705332d21f760",
34+
"admin": "0x54594f1aF2A6bd876bF0f6d45FB7c3cb54eFB5d5",
35+
"type": "transparent"
36+
}
2337
},
2438
"LockedTokenStakerWalletConnect": {
25-
"address": "0x8621034C9acD397cc5921d036225f75699c710FA"
39+
"address": "0xb6034870fdd84f09cB63433297C667A1A7771824",
40+
"admin": "0xBa900e340f781A18C34Ff9D73CDb9756329a71d9",
41+
"implementation": "0xEc32c9280163795921caF79205C6850C67023F04",
42+
"proxy": {
43+
"implementation": "0xEc32c9280163795921caF79205C6850C67023F04",
44+
"admin": "0xBa900e340f781A18C34Ff9D73CDb9756329a71d9",
45+
"type": "transparent"
46+
}
2647
},
2748
"ManagerTimelock": {
2849
"address": "0xB5EFe3783Db55B913C79CBdB81C9d2C0a993f5f0"
@@ -39,29 +60,29 @@
3960
"Pauser": {
4061
"address": "0x9163de7F22A9f3ad261B3dBfbB9A42886816adE7",
4162
"admin": "0x8714E77FA6Aca75A9b21d79295ec7cF04E4821a8",
42-
"implementation": "0xB7D30c8C3bF4b7cb9F06A3D7654E8971021ad58e",
63+
"implementation": "0xf69771dAc1c783F6Ae6ddbC3BF6B4869E7c43a70",
4364
"proxy": {
44-
"implementation": "0xB7D30c8C3bF4b7cb9F06A3D7654E8971021ad58e",
65+
"implementation": "0xf69771dAc1c783F6Ae6ddbC3BF6B4869E7c43a70",
4566
"admin": "0x8714E77FA6Aca75A9b21d79295ec7cF04E4821a8",
4667
"type": "transparent"
4768
}
4869
},
4970
"StakeWeight": {
5071
"address": "0x521B4C065Bbdbe3E20B3727340730936912DfA46",
5172
"admin": "0x9898b105fe3679f2d31c3A06B58757D913D88e5F",
52-
"implementation": "0xC746f9a45a06CBF2ad761442821C91A479151cc3",
73+
"implementation": "0x6845541121e555D1245fe17c6b44273B089C3844",
5374
"proxy": {
54-
"implementation": "0xC746f9a45a06CBF2ad761442821C91A479151cc3",
75+
"implementation": "0x6845541121e555D1245fe17c6b44273B089C3844",
5576
"admin": "0x9898b105fe3679f2d31c3A06B58757D913D88e5F",
5677
"type": "transparent"
5778
}
5879
},
5980
"StakingRewardDistributor": {
6081
"address": "0xF368F535e329c6d08DFf0d4b2dA961C4e7F3fCAF",
6182
"admin": "0x28672bf553c6AB214985868f68A3a491E227aCcB",
62-
"implementation": "0xF6d23184E44f282883c0d145C973442fc7A33AB8",
83+
"implementation": "0x98c27ae4C11F67CDE0E3aFDf90fBba01Bf826238",
6384
"proxy": {
64-
"implementation": "0xF6d23184E44f282883c0d145C973442fc7A33AB8",
85+
"implementation": "0x98c27ae4C11F67CDE0E3aFDf90fBba01Bf826238",
6586
"admin": "0x28672bf553c6AB214985868f68A3a491E227aCcB",
6687
"type": "transparent"
6788
}

evm/foundry.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,21 @@ verbosity = 2
4242
tab_width = 4
4343
wrap_comments = true
4444

45+
# Etherscan V2: a single API key covers every supported chain (routed by chainid),
46+
# so all entries share ${API_KEY_ETHERSCAN}. The legacy per-explorer V1 keys are deprecated.
4547
[etherscan]
4648
sepolia = { key = "${API_KEY_ETHERSCAN}" }
4749
mainnet = { key = "${API_KEY_ETHERSCAN}" }
48-
optimism = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" }
49-
optimism_sepolia = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" }
50+
optimism = { key = "${API_KEY_ETHERSCAN}" }
51+
optimism_sepolia = { key = "${API_KEY_ETHERSCAN}" }
52+
arbitrum = { key = "${API_KEY_ETHERSCAN}", chain = 42161 }
53+
base = { key = "${API_KEY_ETHERSCAN}", chain = 8453 }
5054

5155
[rpc_endpoints]
5256
localhost = "http://localhost:8545"
5357
mainnet = "https://mainnet.infura.io/v3/${API_KEY_INFURA}"
5458
sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}"
5559
optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}"
5660
optimism_sepolia = "https://optimism-sepolia.infura.io/v3/${API_KEY_INFURA}"
61+
arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}"
62+
base = "https://base-mainnet.infura.io/v3/${API_KEY_INFURA}"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.25 <0.9.0;
3+
4+
import { console2 } from "forge-std/console2.sol";
5+
import { Timelock } from "src/Timelock.sol";
6+
import { BaseScript } from "script/Base.s.sol";
7+
8+
/// @title TimelockDeploy
9+
/// @notice Deploys a standalone Timelock for chains that lack one (Arbitrum, Base), so the WCT ProxyAdmin
10+
/// owner and token DEFAULT_ADMIN_ROLE can sit behind a timelock rather than the admin multisig
11+
/// directly. The role/ownership hand-off itself is done separately from the multisig — this script
12+
/// ONLY deploys the timelock.
13+
/// @dev Config mirrors EthereumDeploy: 1-week delay, multisig as sole proposer + executor, dedicated
14+
/// canceller. Timelock is self-administered (OZ admin = address(0)), so future role changes require
15+
/// a timelock proposal.
16+
///
17+
/// IMPORTANT: on production chains BaseScript reverts unless ETH_FROM is set, to avoid falling back to the
18+
/// public test mnemonic. ALWAYS pass your real signer. Example:
19+
/// CHAIN_ID=42161 ETH_FROM=<ledger-addr> ADMIN_ADDRESS=<multisig> TIMELOCK_CANCELLER_ADDRESS=<canceller> \
20+
/// forge script script/deploy/TimelockDeploy.s.sol --rpc-url arbitrum --broadcast --ledger --sender $ETH_FROM
21+
/// (repeat with CHAIN_ID=8453 --rpc-url base for Base)
22+
contract TimelockDeploy is BaseScript {
23+
function run() public broadcast returns (Timelock timelock) {
24+
address admin = vm.envAddress("ADMIN_ADDRESS");
25+
address canceller = vm.envAddress("TIMELOCK_CANCELLER_ADDRESS");
26+
27+
// 1 weeks == 604800s, the max allowed by Timelock and matching the Ethereum/Optimism delay.
28+
timelock = new Timelock(1 weeks, _singleAddressArray(admin), _singleAddressArray(admin), canceller);
29+
30+
console2.log("Timelock deployed at:", address(timelock));
31+
console2.log(" min delay (s): ", timelock.getMinDelay());
32+
console2.log(" proposer+executor: ", admin);
33+
console2.log(" canceller: ", canceller);
34+
console2.log("Next: from the multisig, hand off ownership (grant DEFAULT_ADMIN_ROLE + transferOwnership, then renounce).");
35+
}
36+
}

0 commit comments

Comments
 (0)