Modifying predeployed contracts
OP Stack Hacks are explicitly things that you can do with the OP Stack that are not currently intended for production use.
OP Stack Hacks are not for the faint of heart. You will not be able to receive significant developer support for OP Stack Hacks — be prepared to get your hands dirty and to work without support.
OP Stack blockchains have a number of predeployed contracts (opens in a new tab) that provide important functionality.
Most of those contracts are proxies that can be upgraded using the proxyAdminOwner
which was configured when the network was initially deployed.
Before you begin
In this tutorial, you learn how to modify predeployed contracts for an OP Stack chain by upgrading the proxy. The predeploys are controlled from a predeploy called ProxyAdmin
(opens in a new tab), whose address is 0x4200000000000000000000000000000000000018
.
The function to call is upgrade(address,address)
(opens in a new tab).
The first parameter is the proxy to upgrade, and the second is the address of a new implementation.
Modify the legacy L1BlockNumber
contract
For example, the legacy L1BlockNumber
contract is at 0x420...013
.
To disable this function, we'll set the implementation to 0x00...00
.
We do this using the Foundry (opens in a new tab) command cast
.
We'll need several constants.
-
Set these addresses as variables in your terminal.
L1BLOCKNUM=0x4200000000000000000000000000000000000013 PROXY_ADMIN=0x4200000000000000000000000000000000000018 ZERO_ADDR=0x0000000000000000000000000000000000000000
-
Set
PRIVKEY
to the private key of your ADMIN address. -
Set
ETH_RPC_URL
. If you're on the computer that runs the blockchain, use this command.export ETH_RPC_URL=http://localhost:8545
Verify L1BlockNumber
works correctly.
See that when you call the contract you get a block number, and twelve seconds later you get the next one (block time on L1 is twelve seconds).
cast call $L1BLOCKNUM 'number()' | cast --to-dec
sleep 12 && cast call $L1BLOCKNUM 'number()' | cast --to-dec
Get the current implementation for the contract.
L1BLOCKNUM_IMPLEMENTATION=`cast call $L1BLOCKNUM "implementation()" | sed 's/000000000000000000000000//'`
echo $L1BLOCKNUM_IMPLEMENTATION
Change the implementation to the zero address
cast send --private-key $PRIVKEY $PROXY_ADMIN "upgrade(address,address)" $L1BLOCKNUM $ZERO_ADDR
See that the implementation is address zero, and that calling it fails.
cast call $L1BLOCKNUM 'implementation()'
cast call $L1BLOCKNUM 'number()'
Fix the predeploy by returning it to the previous implementation, and verify it works.
cast send --private-key $PRIVKEY $PROXY_ADMIN "upgrade(address,address)" $L1BLOCKNUM $L1BLOCKNUM_IMPLEMENTATION
cast call $L1BLOCKNUM 'number()' | cast --to-dec