Skip to content

docs(newl1): add cross-chain bridge and Foundry guides - #969

Open
pythonberg1997 wants to merge 1 commit into
bnb-chain:mainfrom
pythonberg1997:add_newL1_docs
Open

pythonberg1997 wants to merge 1 commit into
bnb-chain:mainfrom
pythonberg1997:add_newL1_docs

Conversation

@pythonberg1997

Copy link
Copy Markdown
Contributor

Description

Document the native BSC ↔ New L1 bridge, which is now live on devnet against BSC Testnet, and add a Foundry guide for New L1. Pages that said the bridge was still in development, or that listed 0x2000 as a placeholder, now link to the bridge docs.

Rationale

The bridge is the only way to get devnet BNB because there is no faucet, but the docs still said it wasn't live and described CrossChain as a placeholder. Foundry users also run into New L1-specific behavior that the general migration page doesn't cover from Foundry's side: declared-gas billing, Prague rules, -38004 receipts, and missing precompiles.

Changes

  • core-concepts/cross-chain-bridge.md: lock-and-release design, the TokenHub / CrossChainHub / BridgeGovHub contracts, the roles of validators, guardians, relayers, and the recovery council, the transfer lifecycle, safeguards, bridge governance, and the fee split.
  • developers/cross-chain-bridge.md: contract addresses on New L1 devnet and BSC Testnet, cast examples for both directions, tracking via TransferLocked and terminalRecord, large-transfer locks, claims, fees, devnet limits, pitfalls, refunds, and the Solidity interface.
  • developers/foundry.md: evm_version and --hardfork prague configuration, gas and fee settings, EVM and precompile differences, unsupported transaction types, RPC quirks, replay and trace limits, and the lack of contract verification.
  • System contracts: add TokenHub (0x1004) and BridgeGovHub (0x2007), and replace the CrossChain placeholder at 0x2000 with CrossChainHub.
  • Replace the "bridge in development" and "no faucet" text in the overview, network info, migration guide, and governance overview with links to the bridge. Add two bridge FAQ entries, a landing-page card, a Foundry link in the quick guide, and nav entries in mkdocs.yml.
  • Correct block.prevrandao in the migration guide: it returns Parlia's difficulty (2 or 1), not the timestamp's milliseconds.

@fynnss fynnss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two documentation issues around delivery retries and claim events.

- **Contracts must accept BNB.** A contract recipient needs a `receive` or payable fallback function. If receiving uses more than 10,000 gas, the BNB becomes a [claim](#claims). If the contract can't accept BNB at all, the funds can't be paid out. The same applies to a contract that calls `transferOut`: a refund goes back to it as the sender.
- **Transfers can't be cancelled.** A locked transfer is either delivered or, through governance, refunded. Transfers don't expire.
- **Pauses and freezes.** When a chain's bridge is paused, `transferOut` reverts on that chain and deliveries to that chain wait. Claims and expired large-transfer locks can still be withdrawn. A freeze, the emergency stop, also blocks withdrawals and large-transfer releases until it is cleared. In both cases, transfers that are already locked wait. They are never lost.
- **Blacklists.** Each chain's bridge governance can blacklist addresses. A blacklisted sender or recipient can't use `transferOut`. A transfer whose sender or recipient is blacklisted after it was locked waits on the destination until the address is removed or governance refunds the transfer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please document the manual delivery step after delisting. The relayer marks blacklisted entries as abandoned and stops retrying them once the slot settles. Removing the address from the blacklist does not restart those retries; someone must submit the batch package's executeSingle calldata. Otherwise, users following this guidance may wait indefinitely.

|---|---|---|
| `CreditDelivered` | The BNB was sent to the recipient. | Nothing. The transfer is complete. |
| `CreditLocked` | The amount is at or above the large-transfer threshold and is held until the lock ends. | Call `matureLockedCredit` after the lock ends. See [Large Transfers](#large-transfers). |
| `ClaimCredited` | Sending to the recipient failed, so the amount was recorded as a claim. | Call `withdraw`. See [Claims](#claims). |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] ClaimCredited also records the executor's fee, so it can appear alongside CreditDelivered in a successful delivery. Treating its presence as a failed payout would incorrectly prompt the recipient to withdraw a nonexistent claim. Please distinguish fee claims from the recipient's principal and correlate CreditDelivered/CreditLocked with the transfer's messageId.

forge script script/Deploy.s.sol --rpc-url $RPC --broadcast --gas-estimate-multiplier 110
```

- `--hardfork prague` is required. Block headers don't include `excessBlobGas`, so without it every call on the fork fails with `Excess blob gas not set`. It also keeps the blocks anvil mines on top of the fork on the chain's rules. `forge test --fork-url` and `forge script` aren't affected.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please include a working initialization step for Anvil forks. With Foundry 1.8.1, eth_call still fails with Excess blob gas not set after running the documented command: --hardfork prague selects the EVM rules but does not populate the missing blob environment. I verified that mining one local empty block with cast rpc anvil_mine 0x1 --rpc-url http://127.0.0.1:8545 makes subsequent calls succeed. Without that step or another tested workaround, readers cannot call contracts on the fresh fork.

- **Pauses and freezes.** When a chain's bridge is paused, `transferOut` reverts on that chain and deliveries to that chain wait. Claims and expired large-transfer locks can still be withdrawn. A freeze, the emergency stop, also blocks withdrawals and large-transfer releases until it is cleared. In both cases, transfers that are already locked wait. They are never lost.
- **Blacklists.** Each chain's bridge governance can blacklist addresses. A blacklisted sender or recipient can't use `transferOut`. A transfer whose sender or recipient is blacklisted after it was locked waits on the destination until the address is removed or governance refunds the transfer.
- **Transfers are public.** The sender, recipient, and amount are visible on both chains. Bridging doesn't go through the [shielded pool](../core-concepts/privacy.md).
- **BSC finality.** If BSC fast finality stalls, the bridge waits for BSC's slower natural finality instead, which adds about a minute and a half to transfers from BSC.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please remove the natural-finality fallback claim. The current relayer waits for the RPC's finalized height and returns NotFinalizedYet until it covers the source block. BSC derives that height from votes and attestations, with no time- or confirmation-count fallback. Transfers can therefore remain blocked while fast finality is stalled, even if blocks continue arriving. Please describe waiting for finality to recover instead of promising an approximately 90-second delay.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants