Install golang and rust
Install docker and docker-compose
wget -qO- https://get.pnpm.io/install.sh | sh -
curl -L https://foundry.paradigm.xyz | bash
foundryup
download jq from https://jqlang.github.io/jq/
sudo mv jq-linux-amd64 /usr/bin/jq
sudo apt install direnv
cargo install just
git clone https://github.com/uprendis/eth-pos-devnet.git
docker compose up -d # use docker-compose if running an older version
docker logs --follow eth-pos-devnet_geth_1 # read logs
sudo ./clean.sh # stop and erase the datadirs
It'll listen on 8545 for http web3 API
Here is the original instruction: https://docs.prylabs.network/docs/advanced/proof-of-stake-devnet
The genesis will pre-fund all dev accounts
git clone https://github.com/ethereum-optimism/optimism.git
cd optimism
git checkout v1.9.3 # I tested this version but it probably works with the latest one too
make build
mkdir build
cd packages/contracts-bedrock
Create file deploy-config/devnetL1.json
with this content:
{
"l1ChainID": 32382,
"l2ChainID": 901,
"l2BlockTime": 2,
"maxSequencerDrift": 300,
"sequencerWindowSize": 200,
"channelTimeout": 120,
"p2pSequencerAddress": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc",
"batchInboxAddress": "0xff00000000000000000000000000000000000901",
"batchSenderAddress": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
"l1StartingBlockTag": "earliest",
"l2OutputOracleSubmissionInterval": 10,
"l2OutputOracleStartingTimestamp": 0,
"l2OutputOracleStartingBlockNumber": 0,
"l2OutputOracleProposer": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
"l2OutputOracleChallenger": "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65",
"l2GenesisBlockGasLimit": "0x1c9c380",
"l1BlockTime": 12,
"baseFeeVaultRecipient": "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955",
"l1FeeVaultRecipient": "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f",
"sequencerFeeVaultRecipient": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
"l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
"sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
"baseFeeVaultWithdrawalNetwork": 0,
"l1FeeVaultWithdrawalNetwork": 0,
"sequencerFeeVaultWithdrawalNetwork": 0,
"proxyAdminOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"finalSystemOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"superchainConfigGuardian": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"finalizationPeriodSeconds": 2,
"fundDevAccounts": true,
"l2GenesisBlockBaseFeePerGas": "0x1",
"gasPriceOracleOverhead": 2100,
"gasPriceOracleScalar": 1000000,
"gasPriceOracleBaseFeeScalar": 1368,
"gasPriceOracleBlobBaseFeeScalar": 810949,
"enableGovernance": true,
"governanceTokenSymbol": "NB",
"governanceTokenName": "Nebra",
"governanceTokenOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"eip1559Denominator": 50,
"eip1559DenominatorCanyon": 250,
"eip1559Elasticity": 6,
"l1GenesisBlockTimestamp": "0x123",
"l2GenesisRegolithTimeOffset": "0x0",
"l2GenesisCanyonTimeOffset": "0x0",
"l2GenesisDeltaTimeOffset": "0x0",
"l2GenesisEcotoneTimeOffset": "0x0",
"l2GenesisFjordTimeOffset": "0x0",
"l1CancunTimeOffset": "0x0",
"systemConfigStartBlock": 0,
"requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
"faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameMaxDepth": 50,
"faultGameClockExtension": 0,
"faultGameMaxClockDuration": 1200,
"faultGameGenesisBlock": 0,
"faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
"faultGameSplitDepth": 14,
"faultGameWithdrawalDelay": 604800,
"preimageOracleMinProposalSize": 10000,
"preimageOracleChallengePeriod": 120,
"proofMaturityDelaySeconds": 12,
"disputeGameFinalityDelaySeconds": 6,
"respectedGameType": 254,
"useFaultProofs": false,
"useAltDA": false,
"daCommitmentType": "KeccakCommitment",
"daChallengeWindow": 16,
"daResolveWindow": 16,
"daBondSize": 1000000,
"daResolverRefundPercentage": 0
}
# deploy the L1 contracts
# This step has to be ran against a clean network without prior deployments! Clean your L1 network if you've already deployed before
# the private key is for a standard dev account, it's prefunded. It's from mnemonic 'test test test test test test test test test test test junk'
DEPLOYMENT_OUTFILE=deployments/artifact.json DEPLOY_CONFIG_PATH=deploy-config/devnetL1.json forge script -vvv scripts/deploy/Deploy.s.sol:Deploy --rpc-url 127.0.0.1:8545 --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# intermediate files for genesis
FORK=latest STATE_DUMP_PATH=deployments/state_dump.json DEPLOY_CONFIG_PATH=deploy-config/devnetL1.json CONTRACT_ADDRESSES_PATH=deployments/artifact.json forge script scripts/L2Genesis.s.sol:L2Genesis --sig 'runWithStateDump()'
cp deployments/artifact.json ../../build/artifact.json
# generate the genesis files for op-geth and op-node
go run ../../op-node/cmd/main.go genesis l2 \
--deploy-config=deploy-config/devnetL1.json \
--l1-deployments=deployments/artifact.json \
--l2-allocs=deployments/state_dump.json \
--outfile.l2=../../build/genesis.json \
--outfile.rollup=../../build/rollup.json \
--l1-rpc=http://127.0.0.1:8545
openssl rand -hex 32 > /tmp/jwt.txt
git clone https://github.com/ethereum-optimism/op-geth.git
git checkout v1.101408.0
make all
# Prime the datadir with our genesis
./build/bin/geth --datadir=~/.op-geth/ --gcmode=archive init --state.scheme=hash ../optimism/build/genesis.json
# Run the node
./build/bin/geth \
--datadir ~/.op-geth \
--http \
--http.corsdomain="*" \
--http.vhosts="*" \
--http.port=7547 \
--http.addr=0.0.0.0 \
--http.api=web3,debug,eth,txpool,net,engine \
--ws \
--ws.addr=0.0.0.0 \
--ws.port=7546 \
--ws.origins="*" \
--ws.api=debug,eth,txpool,net,engine \
--syncmode=full \
--gcmode=archive \
--nodiscover \
--maxpeers=0 \
--networkid=901 \
--authrpc.vhosts="*" \
--authrpc.addr=0.0.0.0 \
--authrpc.port=8552 \
--authrpc.jwtsecret=/tmp/jwt.txt \
--rollup.disabletxpoolgossip=true
# erase ~/.op-geth and re-prime it with new genesis for a clean restart
Must be launched after op-geth
cd optimism
./op-node/bin/op-node --l2=http://localhost:8552 --l2.jwt-secret=/tmp/jwt.txt --sequencer.enabled --sequencer.l1-confs=5 --verifier.l1-confs=4 --rollup.config=build/rollup.json --rpc.addr=0.0.0.0 --p2p.disable --rpc.enable-admin --p2p.sequencer.key=0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba --l1=http://127.0.0.1:8545 --l1.beacon=http://127.0.0.1:3500 --l1.rpckind=standard
Must be launched after op-node
cd optimism
./op-batcher/bin/op-batcher \
--l2-eth-rpc=http://localhost:7547 \
--rollup-rpc=http://localhost:9545 \
--poll-interval=1s \
--sub-safety-margin=6 \
--num-confirmations=1 \
--safe-abort-nonce-too-low-count=3 \
--resubmission-timeout=30s \
--rpc.addr=0.0.0.0 \
--rpc.port=8548 \
--rpc.enable-admin \
--max-channel-duration=25 \
--l1-eth-rpc=http://127.0.0.1:8545 \
--private-key=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
9545 is a default port for op-node's RPC
Must be launched after op-node
cd optimism
./op-proposer/bin/op-proposer \
--poll-interval=12s \
--rpc.port=8560 \
--rollup-rpc=http://localhost:9545 \
--l2oo-address=$(cat ./build/artifact.json | jq -r .L2OutputOracleProxy) \
--private-key=0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d \
--l1-eth-rpc=http://127.0.0.1:8545
mkdir viem
cd viem
npm install viem
You may create this JS script which uses viem
library:
import {createPublicClient, http, createWalletClient, defineChain} from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
export const mychain = /*#__PURE__*/ defineChain({
id: 901,
name: 'Devnet',
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
rpcUrls: {
default: {
http: ['http://localhost:7547'],
},
},
})
const client = createPublicClient({
chain: mychain,
transport: http('http://localhost:7547'),
});
const acc = privateKeyToAccount('0xdf57089febbacf7ba0bc227dafbffa9fc08a93fdc68e1e42411a14efcf23656e')
const wallet = createWalletClient({
account: acc,
chain: mychain,
transport: http('http://localhost:7547'),
});
async function sendEth() {
const balance = await client.getBalance({ address: acc.address });
console.log(`Balance: ${balance} wei`);
const txHash = await wallet.sendTransaction({
to: '0x7626f6940e2eB28930efB4cEF49B2d1F2C9C1199',
value: 1n,
});
console.log('Transaction hash:', txHash);
}
sendEth();
And run it with node script.js
You can also use node
in REPL mode by typing node
and pasting the code in there, but it'll require a different syntax
Our current zk rollup setup consists of the following components:
Apr 24, 2025#n Executive Summary
Jan 8, 2025Service<_>, HTTPServer<> traits and structs
Nov 21, 2024Brainstorming: https://hackmd.io/FAXOf-PUTAOPβ2_kuNb-A
Oct 16, 2024or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up