Understanding UUPS Upgradeability
SpokePool contracts are UUPSUpgradeable proxy contracts:- Proxy address remains constant - Users always interact with the same address
- Implementation can be changed - Logic contracts can be upgraded without changing the proxy
- Upgrade logic lives in implementation - Unlike Transparent Proxies, upgrade function is in the implementation contract
The UUPS pattern provides gas savings over Transparent Proxy pattern and prevents accidental upgrades via admin calls to implementation contracts.
Cross-Chain Ownership Model
All SpokePools have cross-chain ownership:- HubPool owns all SpokePools - The HubPool contract on Ethereum L1 is the admin of all L2/sidechain SpokePools
- Chain adapters relay messages - Each chain has a specialized adapter that uses the native bridge to relay admin calls
- Per-chain admin verification - Each SpokePool variant implements
_requireAdminSender()to verify the caller using chain-specific logic
Admin Verification Examples
Upgrade Process
Upgrading a SpokePool involves several steps, from deploying a new implementation to executing the upgrade via HubPool.1. Deploy New Implementation
Deploy the new implementation contract
Deploy a new implementation without upgrading the proxy:Save the new implementation address from the deployment output.
2. Generate Upgrade Calldata
Use the upgrade script to generate calldata for the HubPool:- Upgrades to the new implementation via
upgradeToAndCall() - Pauses deposits to verify the upgrade succeeded
- Unpauses deposits to confirm the proxy correctly delegates to the new implementation
The pause/unpause sequence is a safety mechanism. If the new implementation is broken, the upgrade will revert atomically during the unpause call.
Example Output
3. Execute Cross-Chain Upgrade
Call HubPool.relaySpokePoolAdminFunction()
The HubPool owner calls Parameters:
relaySpokePoolAdminFunction() with:chainId: Target chain ID (e.g.,42161for Arbitrum)message: Calldata from the upgrade script
HubPool relays message via adapter
The HubPool:
- Identifies the appropriate chain adapter for the target chain
- Calls the adapter via
delegatecall - Adapter bridges the message using the native bridge (e.g., Arbitrum Inbox, OP Messenger)
Message executes on destination chain
After the bridge delay:
- Message arrives at the SpokePool
_requireAdminSender()verifies the callerupgradeToAndCall()executes, upgrading the implementation- Post-upgrade multicall runs (pause/unpause)
Upgrade Script Deep Dive
The upgrade script generates safe upgrade calldata:Why Pause/Unpause?
The pause/unpause sequence ensures:- The upgrade succeeds - If the new implementation is incompatible, the multicall reverts
- The proxy delegates correctly - The unpause call proves the proxy routes calls to the new implementation
- Atomicity - The entire upgrade reverts if any step fails
Solana/SVM Upgrades
Solana program upgrades follow a different process:1. Write Upgrade Buffer
2. Transfer Buffer Authority
3. Execute via Squads Multisig
Add program to Squads
In Squads UI (
https://app.squads.so/):- Go to Developers → Programs
- Add your program ID
Create upgrade transaction
- Click Upgrade
- Fill in buffer address and refund recipient
- Verify buffer authority (prompted)
- Submit upgrade proposal
4. Upgrade IDL
After upgrading the program, update the IDL:Safety Checklist
Before upgrading:- Test extensively - Run full test suite and fork tests
- Check storage layout - Verify no storage collisions with Foundry’s
forge inspect - Audit changes - Review all code changes since last upgrade
- Verify implementation - Use the verification guide to verify the new implementation on block explorers
- Test on testnet first - Always upgrade testnet deployments before mainnet
- Coordinate with relayers - Notify relayers of upgrade schedule
- Monitor after upgrade - Watch for errors in the first hour post-upgrade
- Have rollback plan - Be prepared to upgrade to previous implementation if issues arise
Troubleshooting
Upgrade reverts with “Not admin”
The cross-chain message is not properly authenticated. Check:- HubPool address matches
crossDomainAdminon SpokePool - Chain adapter is correctly configured for the target chain
- Native bridge is functioning (not paused/disabled)
Upgrade succeeds but contract is broken
This should not happen if the pause/unpause verification is working. If it does:- Immediately prepare a rollback upgrade
- Test rollback implementation thoroughly
- Execute rollback upgrade ASAP
- Investigate why the verification didn’t catch the issue
IDL upgrade fails on Solana
Verify:- IDL buffer authority is set to multisig
- Program ID is correct
- Squads transaction was constructed properly
- All signers have approved
Next Steps
- Learn about contract verification to verify upgraded implementations
- Review HubPool contract details
- Understand chain adapters used for cross-chain messages