How to run a local dev node with Stylus support
Stylus is currently tagged as an alpha release. The code has not been audited, and should not be used in production scenarios. This documentation is currently in public preview.
To provide feedback, click the Request an update button at the top of this document, join the Arbitrum Discord, or reach out to our team directly by completing this form.
This how-to guides you through the process of setting up a local Arbitrum Nitro dev node, with Stylus support, to help you deploy and test smart contracts written in Solidity or any of the languages supported by Stylus in a fully controlled environment. By following these steps, you'll deploy and run a full development environment on your local machine that includes a Nitro dev node (L2), a dev-mode geth parent chain (L1), and multiple instances with different roles.
Step 1. Install prerequisites
You'll need docker and docker compose to run your node. Follow the instructions in their site to install them.
Step 2. Clone the nitro-testnode repo
You'll need the stylus branch.
git clone -b stylus --recurse-submodules https://github.com/OffchainLabs/nitro-testnode.git && cd nitro-testnode
Step 3. Run your node
./test-node.bash --init
Step 4. Successive runs
To relaunch the node after the first installation, run the following command.
./test-node.bash
Note that running with the --init flag will clear all chain data and redeploy!
Token bridge
An L1-L2 token bridge can be deployed by using the parameter --tokenbridge. The list of contracts can be found by running docker compose run --entrypoint sh tokenbridge -c "cat network.json".
Running an L3 chain
An L3 chain can be deployed on top of the L2 chain, by using the parameter --l3node. Its deployment configuration can be found by running docker exec nitro-testnode-sequencer-1 cat /config/l3deployment.json.
Additional arguments
You can find a list of additional arguments to use with test-node.bash by using --help.
./test-node.bash --help
Helper scripts
The repository includes a set of helper scripts for basic actions like funding accounts or bridging funds. You can see a list of the available scripts by running:
./test-node.bash script --help
If you want to see information of a particular script, you can add the name of the script to the help command.
./test-node.bash script send-l1 --help
Here's an example of how to run the script that funds an address on L2. Replace 0x11223344556677889900 with the address you want to fund.
./test-node.bash script send-l2 --to address_0x11223344556677889900 --ethamount 5
Blockscout
Nitro comes with a local Blockscout block explorer. To access it, add the param --blockscout when running your node.
./test-node.bash --blockscout
The block explorer will be available at http://localhost:4000
Default endpoints and addresses
Node RPC endpoints are available at:
| Node | Chain id | RPC endpoint |
|---|---|---|
| L1 geth devnet | 1337 | http://localhost:8545 |
| L2 nitro devnet | 412346 | http://localhost:8547 and ws://localhost:8548 |
| L3 nitro (if enabled) | 333333 | http://localhost:3347 |
The following accounts will be prefunded with Ether:
L2 Nitro devnet:
0x683642c22feDE752415D4793832Ab75EFdF6223cwith private key0xe887f7d17d07cc7b8004053fb8826f6657084e88904bb61590e498ca04704cf2Both networks (L1 and L2):
0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0Ewith private key0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659
You can fund other addresses by using the scripts send-l1 and send-l2 as explained here.
How to get the core contracts
For addresses of the deployed core protocol contracts, run
docker exec nitro-testnode-sequencer-1 cat /config/deployment.json
For the outbox address, run (replace "PUT_THE_ROLLUP_ADDRESS_HERE" with rollup address):
curl 'http://localhost:8545/' -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":0,"method":"eth_call","params":[{"to":"PUT_THE_ROLLUP_ADDRESS_HERE","data":"0xce11e6ab"},"latest"]}'
Some default addresses can be found here:
"l2Network": {
"chainID": 412346,
"confirmPeriodBlocks": 20,
"ethBridge": {
"bridge": "0x2b360a9881f21c3d7aa0ea6ca0de2a3341d4ef3c",
"inbox": "0xff4a24b22f94979e9ba5f3eb35838aa814bad6f1",
"outbox": "0x49940929c7cA9b50Ff57a01d3a92817A414E6B9B",
"rollup": "0x65a59d67da8e710ef9a01eca37f83f84aedec416",
"sequencerInbox": "0xe7362d0787b51d8c72d504803e5b1d6dcda89540"
},
"explorerUrl": "",
"isArbitrum": true,
"isCustom": true,
"name": "ArbLocal",
"partnerChainID": 1337,
"retryableLifetimeSeconds": 604800,
"nitroGenesisBlock": 0,
"depositTimeout": 900000,
"tokenBridge": {
"l1CustomGateway": "0x3DF948c956e14175f43670407d5796b95Bb219D8",
"l1ERC20Gateway": "0x4A2bA922052bA54e29c5417bC979Daaf7D5Fe4f4",
"l1GatewayRouter": "0x525c2aBA45F66987217323E8a05EA400C65D06DC",
"l1MultiCall": "0xDB2D15a3EB70C347E0D2C2c7861cAFb946baAb48",
"l1ProxyAdmin": "0xe1080224B632A93951A7CFA33EeEa9Fd81558b5e",
"l1Weth": "0x408Da76E87511429485C32E4Ad647DD14823Fdc4",
"l1WethGateway": "0xF5FfD11A55AFD39377411Ab9856474D2a7Cb697e",
"l2CustomGateway": "0x525c2aBA45F66987217323E8a05EA400C65D06DC",
"l2ERC20Gateway": "0xe1080224B632A93951A7CFA33EeEa9Fd81558b5e",
"l2GatewayRouter": "0x1294b86822ff4976BfE136cB06CF43eC7FCF2574",
"l2Multicall": "0xDB2D15a3EB70C347E0D2C2c7861cAFb946baAb48",
"l2ProxyAdmin": "0xda52b25ddB0e3B9CC393b0690Ac62245Ac772527",
"l2Weth": "0x408Da76E87511429485C32E4Ad647DD14823Fdc4",
"l2WethGateway": "0x4A2bA922052bA54e29c5417bC979Daaf7D5Fe4f4"
}
}