Migrating from BNB Smart Chain¶
Same gas asset, same Parlia consensus family, same staking and governance contracts at the same addresses, unmodified EVM. Contracts deploy unchanged and standard tooling connects unchanged. The differences are almost all above the EVM: fees, mempool, block cadence, and how state is committed.
No public network yet
There is no public testnet or mainnet endpoint yet, so treat this as a porting checklist to work through ahead of one. A native New L1 ↔ BSC bridge is designed and under development but not live; the CrossChain address currently holds a placeholder (see System Contracts).
You Pay for Your Declared Gas Limit¶
New L1 charges the gas_limit you declare, not the gas the EVM actually spends. If a call needs 70,000 gas and you submit gas_limit = 500,000, you pay for 500,000.
New L1 orders blocks before execution, so declared gas is the block space reserved at ordering time. The node tracks each account’s in-flight fee/value exposure and caps cumulative declared gas and calldata. There is no fixed user reserve floor.
- Do not pad blindly.
estimate * 1.5, ethers’ default padding, and hardcoded500000waste money. eth_estimateGasstill returns simulated EVM usage. Add only the margin your call path needs.- Receipts report charged gas: user-transaction
gasUsednormally equals the declared limit. Use traces for actual EVM consumption. - Max per transaction: 16,777,216 gas (2²⁴, BEP-652).
- The same rule applies to
0x76AA transactions, including sponsors and session-key spend limits.
const estimated = await provider.estimateGas(tx);
tx.gasLimit = estimated + estimated / 10n; // example: 10% headroom
For one transaction, gasUsed should not exceed its declared limit. If it looks larger, you are probably reading header.gasUsed, cumulativeGasUsed, or an inner 0x76 call instead of the outer transaction. If execution needs more than the limit, it runs out of gas and fails.
Carries Over Unchanged¶
| Area | Notes |
|---|---|
| EVM semantics | Full Prague from genesis, no fork ramp. |
| Gas asset | BNB. |
| Staking & governance contracts | ValidatorSet, SlashIndicator, SystemReward, StakeHub, StakeCredit, Governor, GovToken, Timelock at their BSC addresses (details). |
| Consensus | Parlia + BLS fast finality, with parlia_getSnapshot / parlia_getValidators / parlia_getJustifiedNumber. |
| BSC-flavored RPC | eth_getFinalizedHeader, eth_getFinalizedBlock, eth_getTransactionReceiptsByBlockNumber, eth_getTransactionsByBlockNumber. |
| Millisecond timestamps | As on BSC: seconds in header.timestamp, milliseconds in the low 8 bytes of mixHash. |
Contracts¶
Bytecode runs as-is. What changes meaning is anything that reasons about time or block cadence.
block.numberadvances ~5×/second. Every block-count constant (vesting,blocksPerDay, TWAP windows, auction durations) is off by ~3.75× versus BSC. Recompute them, or switch to timestamp math.block.timestamprepeats across roughly five consecutive blocks.require(block.timestamp > lastUpdate), per-block rate limiting, and timestamp-as-unique-key all break.block.prevrandaois not randomness. It is the millisecond part of the timestamp,0–999.block.difficultyis Parlia’s2/1.- The fee payer may not be the sender. One transaction can also carry up to 64 atomic calls (
0x76). - EIP-7702 and EIP-4844 transactions are rejected. For smart accounts, use the native
0x76envelope and theAccountKeychainprecompile instead.
Submitting Transactions¶
- The base fee is pinned to zero (BEP-222), so the tip is the price:
min(maxFeePerGas, maxPriorityFeePerGas). Tipping0pays nothing and is rejected. Fees route through the system address toValidatorSet, with BEP-95 burning its share. - No global mempool. Transactions go straight to the current and next producer. No
txpool_*, andeth_subscribe("newPendingTransactions")shows only this node’s admissions. - Replace-by-fee needs a 10% bump and is local only. It displaces the incumbent just in the pools holding it.
- Pooled transactions expire after 3 hours by default, and that timeout is operator-configurable. A nonce more than 256 ahead is rejected at submission.
eth_getTransactionCount(addr, "latest")returns the ordered-tip nonce and does not look ahead. Track nonces client-side when pipelining.
Reading State and Receipts¶
This is where async execution shows up, and it is the biggest behavioral gap versus BSC.
latestmeans executed, not ordered. State reads trail the head you see on anewHeadssubscription. Expected, not a lagging node.-38004is retryable,-38001is not. Ordered-but-unexecuted versus no-such-block.eth_getTransactionReceiptuses-38004for “block not executed yet” andnullfor “unknown transaction”, so keep polling on the former.eth_getProofrejects with-32004. State is committed with an LtHash accumulator, not an MPT (State DB). Light clients, proof-based bridges, and similar need a different design; an accumulator-native proof scheme is planned.eth_syncingis alwaysfalse. Useeth_healthplus block-number progress. Snap sync doesn’t exist.
Indexers and Explorers¶
- System transactions are invisible in the block body. Slashing, deposits, finality rewards, validator-set updates, and shielded drains are not in the transaction list and not counted in
header.gasUsed. Read them vianewl1_getSystemReceiptsByBlock; they never appear ineth_getBlockReceipts. - Blocks carry
systemTransactionsRootandcommitments.stateRoot,receiptsRoot,logsBloom, andgasUsedarenullwhile a block is ordered but unexecuted, and strict deserializers fail at the tip. newl1_subscribeNewHeadsdelivers head, justified, and finalized numbers and hashes in one frame per canonical advance.
Once you’re ported, the Quick Guide covers what New L1 adds on top: pre-confirmation, Multi-Lane, native account abstraction, and the shielded pool.