-
Notifications
You must be signed in to change notification settings - Fork 6
chore(deployments): reconcile 10.json to live chain + add timelock deploy infra #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| # API keys | ||
| export API_KEY_INFURA= | ||
| # Etherscan V2: one key verifies on every supported chain (mainnet, optimism, arbitrum, base, ...) | ||
| export API_KEY_ETHERSCAN= | ||
| export API_KEY_OPTIMISTIC_ETHERSCAN= | ||
| # Foundry | ||
| export FOUNDRY_PROFILE="default" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity >=0.8.25 <0.9.0; | ||
|
|
||
| import { console2 } from "forge-std/console2.sol"; | ||
| import { Timelock } from "src/Timelock.sol"; | ||
| import { BaseScript } from "script/Base.s.sol"; | ||
|
|
||
| /// @title TimelockDeploy | ||
| /// @notice Deploys a standalone Timelock for chains that lack one (Arbitrum, Base), so the WCT ProxyAdmin | ||
| /// owner and token DEFAULT_ADMIN_ROLE can sit behind a timelock rather than the admin multisig | ||
| /// directly. The role/ownership hand-off itself is done separately from the multisig — this script | ||
| /// ONLY deploys the timelock. | ||
| /// @dev Config mirrors EthereumDeploy: 1-week delay, multisig as sole proposer + executor, dedicated | ||
| /// canceller. Timelock is self-administered (OZ admin = address(0)), so future role changes require | ||
| /// a timelock proposal. | ||
| /// | ||
| /// IMPORTANT: on production chains BaseScript reverts unless ETH_FROM is set, to avoid falling back to the | ||
| /// public test mnemonic. ALWAYS pass your real signer. Example: | ||
| /// CHAIN_ID=42161 ETH_FROM=<ledger-addr> ADMIN_ADDRESS=<multisig> TIMELOCK_CANCELLER_ADDRESS=<canceller> \ | ||
| /// forge script script/deploy/TimelockDeploy.s.sol --rpc-url arbitrum --broadcast --ledger --sender $ETH_FROM | ||
| /// (repeat with CHAIN_ID=8453 --rpc-url base for Base) | ||
| contract TimelockDeploy is BaseScript { | ||
| function run() public broadcast returns (Timelock timelock) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Auto Review Issue: No deployment artifact written for Arbitrum/Base timelock Severity: MEDIUM Context:
Minimally: gate the JSON write behind |
||
| address admin = vm.envAddress("ADMIN_ADDRESS"); | ||
| address canceller = vm.envAddress("TIMELOCK_CANCELLER_ADDRESS"); | ||
|
|
||
| // 1 weeks == 604800s, the max allowed by Timelock and matching the Ethereum/Optimism delay. | ||
| timelock = new Timelock(1 weeks, _singleAddressArray(admin), _singleAddressArray(admin), canceller); | ||
|
|
||
| console2.log("Timelock deployed at:", address(timelock)); | ||
| console2.log(" min delay (s): ", timelock.getMinDelay()); | ||
| console2.log(" proposer+executor: ", admin); | ||
| console2.log(" canceller: ", canceller); | ||
| console2.log("Next: from the multisig, hand off ownership (grant DEFAULT_ADMIN_ROLE + transferOwnership, then renounce)."); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤖 Auto Review Issue: Arbitrum/Base not in BaseScript production-chain guard — test mnemonic fallback risk
Severity: HIGH
Category: security
Tool: Claude Auto Review
Context:
BaseScriptconstructor only gates the test-mnemonic fallback formainnetandoptimism. Arbitrum (42161) and Base (8453) are not inisMainnetOrOptimism, so a broadcaster is silently derived from the publictest test test…junkmnemonic ifETH_FROMis unset.0xf39F…2266). Anyone with that key could immediately callgrantRole/revokeRoleon it, subverting the CONT-10 remediation entirely.DEFAULT_ADMIN_ROLEfor WCT on Arbitrum/Base.ETH_FROM— easy to miss on a new chain.The script already documents this via an
IMPORTANTcomment (line 18-20), but documentation doesn't prevent mistakes for a security-critical contract. The fix belongs inBaseScript:Fix this →