From 7d22923207ceb48c16f9213d56505976c2ba6dc2 Mon Sep 17 00:00:00 2001
From: joey <10592664+joey0612@users.noreply.github.com>
Date: Fri, 17 Jul 2026 17:15:32 +0800
Subject: [PATCH 01/29] doc: add payment lane bep
---
BEPs/BEP-703.md | 207 ++++++++++++++++++++++++++++++++++++++++++++++++
README.md | 1 +
2 files changed, 208 insertions(+)
create mode 100644 BEPs/BEP-703.md
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
new file mode 100644
index 00000000..ed178712
--- /dev/null
+++ b/BEPs/BEP-703.md
@@ -0,0 +1,207 @@
+
+ BEP: 703
+ Title: Payment Lane on BNB Smart Chain
+ Status: Draft
+ Type: Standards
+ Created: 2026-07-17
+ Description: Reserve a dynamically-sized portion of each block's gas for payment transactions, so basic value transfer stays available during congestion without changing how any transaction is ordered.
+
+
+# BEP-703: Payment Lane on BNB Smart Chain
+
+- [BEP-703: Payment Lane on BNB Smart Chain](#bep-703-payment-lane-on-bnb-smart-chain)
+ - [1. Summary](#1-summary)
+ - [2. Motivation](#2-motivation)
+ - [3. Specification](#3-specification)
+ - [3.1 Transaction Classification](#31-transaction-classification)
+ - [3.2 Reserved Gas Accounting Rule](#32-reserved-gas-accounting-rule)
+ - [3.3 Dynamic Quota Adjustment](#33-dynamic-quota-adjustment)
+ - [3.4 Quota Bounds](#34-quota-bounds)
+ - [3.5 Parameters, Invariants, and Governance](#35-parameters-invariants-and-governance)
+ - [3.6 Payment Contract List](#36-payment-contract-list)
+ - [4. Rationale](#4-rationale)
+ - [5. Backward Compatibility](#5-backward-compatibility)
+ - [6. Security Considerations](#6-security-considerations)
+ - [7. License](#7-license)
+
+## 1. Summary
+
+This BEP reserves a small, dynamically-sized amount of gas in every block — the **Payment Lane** — that only payment transactions may consume. The reservation is a per-block gas accounting rule, not a region of the block: payment and non-payment transactions remain freely interleaved, ordered, and priced exactly as today. During congestion, the reservation guarantees a minimum throughput floor for basic value transfer; at all other times it stays near its minimum and the mechanism is effectively dormant.
+
+## 2. Motivation
+
+BSC fixes the base fee at zero ([BEP-226](./BEP226.md)), so transaction inclusion is decided entirely by priority-fee bidding. This works well in the common case, but during demand pulses one class of traffic bids up inclusion prices for every other class. Payment transactions — stablecoin transfers, exchange deposits and withdrawals, remittances, merchant settlement — are the traffic hit hardest: they are individually small in gas, time-sensitive, present in the overwhelming majority of blocks, and yet the least able to re-price themselves block by block. When a pulse arrives they are the first traffic crowded out, and the chain's most basic function — moving funds — becomes its least reliable one.
+
+This is not a capacity problem. BSC's throughput is on a sustained upward path, and total block space comfortably exceeds payment demand at all times. The defect is structural: heterogeneous traffic shares one undifferentiated bidding dimension, so local congestion in one class propagates to unrelated classes. A bounded, protocol-level reservation for the payment class severs that propagation path at negligible cost to everything else — and does so without touching the fee market or the ordering rules that the rest of the ecosystem relies on.
+
+## 3. Specification
+
+### 3.1 Transaction Classification
+
+A transaction is a **payment transaction** if and only if it belongs to one of the following three categories, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**.
+
+| Category | Scope | Determination |
+|---|---|---|
+| ① Native BNB transfer | Pure value transfer that executes no contract code | Mechanical: `to` is non-nil, `data` is empty, and the account at `to` has no code |
+| ② Listed stablecoin contracts | Initially USDT and USDC only | Governance nomination ([§3.6](#36-payment-contract-list)) |
+| ③ Listed [BEP-702](./BEP-702.md) native tokens | Tokens created under the New Tokens on BNB Smart Chain standard | Protocol-native validity checks + governance nomination ([§3.6](#36-payment-contract-list)) |
+
+For category ①, the no-code requirement is checked against the parent block's final state. An account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator has code and is therefore excluded — a transfer to it triggers execution, and no execution-bearing transaction may enter the lane through the native-transfer category.
+
+For categories ② and ③, classification after list membership is settled is a static lookup on the `to` address. In all three categories, any node can classify a transaction without executing it, so classification adds no consensus overhead.
+
+Classification requires nothing from users or wallets: which address a transaction is sent to, and which asset it moves, are already determined by the underlying business action. The lane assignment is the protocol recognizing an existing fact, not a new field or declaration.
+
+### 3.2 Reserved Gas Accounting Rule
+
+For each block, let:
+
+```
+paymentGasUsed = total gas consumed by payment transactions in the block
+generalGasUsed = total gas consumed by general transactions in the block
+paymentLaneSize = the block's reserved payment quota (computed per 3.3 and 3.4)
+```
+
+The block MUST satisfy:
+
+```
+generalGasUsed + max(paymentGasUsed, paymentLaneSize) <= GasLimit
+```
+
+Blocks violating this rule MUST be rejected as invalid.
+
+The rule has exactly two regimes:
+
+- **Payment demand meets or exceeds the quota** (`paymentGasUsed >= paymentLaneSize`): the constraint reduces to the ordinary `paymentGasUsed + generalGasUsed <= GasLimit`. Payment gas beyond the quota competes for the remaining space under the existing priority-fee rules on equal terms with general transactions — the quota is a floor, never a ceiling.
+- **Payment demand falls short of the quota** (`paymentGasUsed < paymentLaneSize`): the shortfall reduces the gas available to general transactions one-for-one. The unused reservation is deliberately left idle for that block rather than released — this is what makes the guarantee real ([§4](#4-rationale)).
+
+The rule constrains only gas totals. It says nothing about where transactions sit inside the block: payment and general transactions may be interleaved arbitrarily, and block producers keep full freedom over transaction selection and ordering within the accounting constraint. No new ordering rule, priority rule, or fee rule is introduced.
+
+### 3.3 Dynamic Quota Adjustment
+
+`paymentLaneSize` for block `n` is a deterministic function of chain history, computed by every node from block `n−1`; no new header field is required. The adjustment reads a single signal:
+
+```
+signal(n−1) = generalGasUsed(n−1) / GasLimit(n−1)
+```
+
+- `signal >= EXPAND_TRIGGER_RATIO` — the chain is congested: the quota ratio increases by `EXPAND_STEP`, up to the effective maximum.
+- `signal < SHRINK_TRIGGER_RATIO` — the chain has slack: the quota ratio decreases by `SHRINK_STEP`, down to the effective minimum.
+- Otherwise — the hysteresis band: the quota is unchanged, absorbing fluctuation and preventing oscillation.
+
+Note that `generalGasUsed` includes payment gas consumed beyond the quota (that gas competed as general traffic), so the signal responds to both pressure sources: general demand squeezing available space, and payment demand overflowing its own floor.
+
+At the activation block, `paymentLaneSize` initializes to the effective minimum.
+
+### 3.4 Quota Bounds
+
+The quota is constrained by two independent boundaries:
+
+- **Ratio bounds** (`PAYMENT_LANE_MIN_RATIO`, `PAYMENT_LANE_MAX_RATIO`): the adjustment target range, expressed as a fraction of `GasLimit` so it scales automatically as block capacity grows.
+- **Absolute bounds** (`PAYMENT_LANE_MIN`, `PAYMENT_LANE_MAX`): fixed gas amounts that cap the quota's absolute size regardless of how large blocks become.
+
+The effective range is the intersection: lower bound = the larger of the two minimums, upper bound = the smaller of the two maximums. If an extreme `GasLimit` makes the intersection empty (e.g., the ratio minimum converts to more gas than the absolute maximum), **the absolute bounds prevail** and the quota range is `[PAYMENT_LANE_MIN, PAYMENT_LANE_MAX]` — behavior is defined in every configuration.
+
+### 3.5 Parameters, Invariants, and Governance
+
+The adjustment algorithm itself (the signal, the hysteresis structure, the accounting rule) is protocol logic and is not governable. The values that drive it are governable parameters, taking effect only through the standard BSC on-chain governance process:
+
+| Name | Meaning | Kind |
+|---|---|---|
+| `PAYMENT_LANE_MIN_RATIO` | Ratio lower bound | Governable |
+| `PAYMENT_LANE_MAX_RATIO` | Ratio upper bound | Governable |
+| `PAYMENT_LANE_MIN` | Absolute lower bound (gas) | Governable |
+| `PAYMENT_LANE_MAX` | Absolute upper bound (gas) | Governable |
+| `EXPAND_TRIGGER_RATIO` | Congestion threshold that triggers expansion | Governable |
+| `SHRINK_TRIGGER_RATIO` | Slack threshold that triggers contraction | Governable |
+| `EXPAND_STEP` | Per-block expansion step | Governable |
+| `SHRINK_STEP` | Per-block contraction step | Governable |
+| `TRIGGER_GAP_MIN` | Minimum hysteresis band width | Protocol constant |
+| `RATIO_GAP_MIN` | Minimum ratio range width | Protocol constant |
+
+Governable parameters are not free-form. The following invariants are validated by the protocol before any parameter change takes effect; **a governance proposal violating any of them is invalid** and never activates. The two gap constants are protocol constants, not governable — governance may move the ranges but can never collapse them:
+
+```
+(1) EXPAND_TRIGGER_RATIO − SHRINK_TRIGGER_RATIO >= TRIGGER_GAP_MIN
+ The expansion threshold must sit above the contraction threshold by at
+ least the hysteresis floor; otherwise usage hovering near one boundary
+ makes the quota thrash block by block.
+
+(2) EXPAND_STEP > SHRINK_STEP > 0
+ Fast expansion, slow contraction is a hard requirement, not advice:
+ protection must arrive before space is handed back, or a sawtooth
+ demand pattern contracts the quota faster than it can re-expand.
+
+(3) PAYMENT_LANE_MAX_RATIO − PAYMENT_LANE_MIN_RATIO >= RATIO_GAP_MIN
+ The ratio range must be genuinely wide; a collapsed range degrades the
+ dynamic mechanism into a fixed constant.
+
+(4) PAYMENT_LANE_MAX > PAYMENT_LANE_MIN > 0
+ The absolute range must be non-empty.
+```
+
+Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
+
+```
+PAYMENT_LANE_MIN_RATIO = 2% PAYMENT_LANE_MAX_RATIO = 8%
+PAYMENT_LANE_MIN = 2M gas PAYMENT_LANE_MAX = 8M gas
+EXPAND_TRIGGER_RATIO = 80% SHRINK_TRIGGER_RATIO = 70%
+EXPAND_STEP = +2pp/block SHRINK_STEP = -0.5pp/block
+TRIGGER_GAP_MIN = 10% RATIO_GAP_MIN = 5%
+
+Invariant check: 80−70 = 10 >= 10 ✓ | 2pp > 0.5pp > 0 ✓ | 8−2 = 6 >= 5 ✓ | 8M > 2M > 0 ✓
+
+Illustration at GasLimit = 70M, 0.45s blocks (effective range [2M, 5.6M]):
+ quiet: quota rests at 2M (~3% of the block); mechanism dormant
+ congestion: signal >= 80% → quota expands 2M → 3.4M → 4.8M → 5.6M
+ (3 blocks, ~1.35s); 5.6M ≈ 90+ transfers per block guaranteed
+ recovery: signal < 70% → quota returns to 2M over ~10 blocks (~4.5s)
+```
+
+### 3.6 Payment Contract List
+
+Categories ② and ③ are defined by a **payment contract list** maintained in a system contract and updatable only through the standard BSC governance process (validator voting). Classification reads list membership as of the parent block's final state, so a list change never affects the block that contains it.
+
+**Category ② — stablecoins.** Admission is decided entirely by governance nomination, on the strength of off-chain audit history and long-accumulated on-chain reputation. The initial list is USDT and USDC only: USDT's contract is non-upgradeable and its bytecode has been fixed since deployment; USDC, while an upgradeable proxy, undergoes rigorous off-chain audit for every upgrade with extensive reputational backing and market scrutiny. Because the protocol imposes no mechanical gate here, governance carries both the nomination and the ongoing-monitoring responsibility: if a listed contract's behavior materially changes, removal depends on governance acting, not on an automatic protocol trigger. This is an explicit, acknowledged trust extended to assets whose reputation is already thoroughly established — whether future additions receive the same treatment or stricter verification is for governance to decide case by case.
+
+**Category ③ — BEP-702 native tokens.** Tokens under [BEP-702](./BEP-702.md) are protocol-native: they deploy no bytecode, cannot self-destruct, expose a function surface fixed by the protocol standard, and have no upgradeable implementation to drift. The properties an arbitrary contract would need audits or reputation to establish hold for these tokens by construction. Admission therefore requires:
+
+1. **Protocol validity** — the address passes BEP-702's native-token address check and corresponds to a token actually created through its registry;
+2. **Off-chain audit** — review of the token's deployment parameters and operational configuration (admin custody, role assignments, transfer-policy settings, supply cap) for fitness as payment infrastructure — e.g., a token whose receiving policy is a narrow allowlist is not a general payment asset;
+3. **Governance nomination** — the same validator-voting process as category ②, answering one question: is this a genuine, significant payment asset.
+
+The initial category-③ list is empty; tokens are nominated individually as audits complete.
+
+**Removal is symmetric with admission.** Governance MAY at any time, through the same validator-voting process, remove any listed address from either category. Because classification reads the parent block's final state, a removal takes effect from the block after it lands on-chain; transactions to the removed address are simply classified as general transactions thereafter — they remain fully valid and are included under the ordinary rules, so removal strips lane eligibility and nothing else. For both categories the rollout pace rests entirely with governance, and governance's power is bounded: it can delay an asset's admission by not nominating it, but nomination and removal votes are public and accountable, and for category ③ governance cannot override or weaken the guarantees BEP-702 itself provides.
+
+## 4. Rationale
+
+**A quota, not a region.** Reserving a gas amount rather than partitioning the block preserves everything about how blocks are built today. Producers keep complete freedom of selection and ordering; transactions of both classes interleave arbitrarily; the existing priority-fee market operates untouched for all traffic, payment traffic included. The entire proposal is one additional accounting inequality checked at block validation.
+
+**Unused quota is idle, not reclaimable.** If the shortfall flowed back to general transactions, excluding payment transactions would cost a producer nothing — the space would simply be resold, and the floor would be a fiction precisely in the congested moments it exists for. Making the reservation binding regardless of realized payment demand inverts the economics: the reserved gas produces fees only when payment transactions fill it, so including them is the only way to monetize it, and excluding them yields nothing. The waste in quiet blocks is bounded (at most the quota minimum, a low single-digit percent of the block) and is the price of the guarantee being real.
+
+**Congestion-only signal, no motive judgment.** Any signal that tries to classify *why* the chain is congested — for example, the share of payment transactions among recent traffic — is written by whoever selects transactions, and can be steered at near-zero cost to keep the quota from ever expanding. Total general-transaction gas usage, by contrast, is aligned with fee revenue: a demand pulse produces high usage exactly because producers are including the paying transactions in front of them, and suppressing the signal means leaving those fees uncollected. Denying congestion is possible only at the cost of forgoing income. The rule is therefore deliberately reduced to *congestion expands the quota, regardless of cause*. The cost of this simplification — congestion unrelated to payments also triggers expansion — is bounded by the quota maximum and self-corrects within blocks once congestion clears.
+
+**Fast expansion, slow contraction, with hysteresis.** Expansion must outpace the demand pulse it protects against, while contraction can afford patience; the asymmetry (enforced as invariant 2) guarantees that under sawtooth pulses, protection is in place before space is returned. The hysteresis band (invariant 1) keeps boundary-hovering usage from thrashing the quota.
+
+**Ratio and absolute bounds together.** Ratio bounds let the quota scale automatically with block capacity so the mechanism never needs re-tuning as GasLimit grows; absolute bounds cap its footprint so growth in block size can never silently grow the reservation beyond an intended ceiling.
+
+**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, no user action, and no way to smuggle arbitrary execution into the lane: category ① admits no code execution at all, and categories ②/③ admit only contracts whose entire function surface is value transfer — vetted by governance with audit backing for ②, guaranteed by protocol construction for ③.
+
+## 5. Backward Compatibility
+
+This is a consensus-breaking change and requires a hard fork: it adds a new block validity rule and the associated quota computation. It changes no transaction format, no RPC interface, no fee mechanism, and no ordering rule — the existing transaction ordering and inclusion mechanics of the ecosystem are unaffected, for every class of transaction. Wallets, exchanges, and applications require no modification.
+
+Outside congestion (the overwhelming majority of blocks), the quota rests at its minimum and observable behavior is essentially identical to today. During congestion, general transactions have marginally less space available in exchange for payment traffic retaining a guaranteed floor; the reduction is bounded by the quota maximum and, as block capacity continues to grow, shrinks as a fraction of total block space.
+
+## 6. Security Considerations
+
+- **Spam within the lane.** The quota does not grant free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so flooding the lane costs fees like any other spam and displaces only other payment traffic, never the general market beyond the quota bound.
+- **Bounded waste.** Idle reserved gas is capped by `PAYMENT_LANE_MAX` per block and by the ratio ceiling as a fraction of block space; misjudged expansion self-corrects via contraction once the signal clears, and cannot accumulate.
+- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
+- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.6](#36-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
+- **Parameter safety.** The invariants in [§3.5](#35-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can configure a thrashing, inverted, or degenerate quota.
+
+## 7. License
+
+The content is licensed under [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
diff --git a/README.md b/README.md
index a7c3b346..73d03792 100644
--- a/README.md
+++ b/README.md
@@ -108,6 +108,7 @@ Here is the list of subjects of BEPs:
| [BEP-677](./BEPs/BEP-677.md) | Implement EIP-8056 Scaled UI Amount | Standards | Draft |
| [BEP-682](./BEPs/BEP-682.md) | Reject Duplicate Validators in CometBFT Light Block Validation | Standards | Draft |
| [BEP-695](./BEPs/BEP-695.md) | Staking and Governance Security Hardening | Standards | Draft |
+| [BEP-703](./BEPs/BEP-703.md) | Payment Lane on BNB Smart Chain | Standards | Draft |
# BAPs
BAP (BNB Application Proposal) defines standards for application layer interactions on BNB Chain. Unlike BEPs which govern core protocol changes, BAPs focus on establishing conventions and interfaces for how applications communicate and interact with each other within the BNB Chain ecosystem.
From 6c1406e1451536de5ede0b05ac63203d0eb67754 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 10:00:13 +0800
Subject: [PATCH 02/29] docs: refine signal gas
---
BEPs/BEP-703.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index ed178712..accebd6d 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -82,14 +82,14 @@ The rule constrains only gas totals. It says nothing about where transactions si
`paymentLaneSize` for block `n` is a deterministic function of chain history, computed by every node from block `n−1`; no new header field is required. The adjustment reads a single signal:
```
-signal(n−1) = generalGasUsed(n−1) / GasLimit(n−1)
+signal(n−1) = signalGasUsed(n−1) / GasLimit(n−1)
```
- `signal >= EXPAND_TRIGGER_RATIO` — the chain is congested: the quota ratio increases by `EXPAND_STEP`, up to the effective maximum.
- `signal < SHRINK_TRIGGER_RATIO` — the chain has slack: the quota ratio decreases by `SHRINK_STEP`, down to the effective minimum.
- Otherwise — the hysteresis band: the quota is unchanged, absorbing fluctuation and preventing oscillation.
-Note that `generalGasUsed` includes payment gas consumed beyond the quota (that gas competed as general traffic), so the signal responds to both pressure sources: general demand squeezing available space, and payment demand overflowing its own floor.
+Here `signalGasUsed` is general gas usage plus any payment gas consumed beyond the quota (that gas competed as general traffic), so the signal responds to both pressure sources: general demand squeezing available space, and payment demand overflowing its own floor.
At the activation block, `paymentLaneSize` initializes to the effective minimum.
From 907a5e1f55dc74a73b31ca8c4598f0fdcd4f49a1 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 10:52:03 +0800
Subject: [PATCH 03/29] bep-703: add block space model
---
BEPs/BEP-703.md | 81 ++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 64 insertions(+), 17 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index accebd6d..e2fb5ae5 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -13,12 +13,13 @@
- [1. Summary](#1-summary)
- [2. Motivation](#2-motivation)
- [3. Specification](#3-specification)
- - [3.1 Transaction Classification](#31-transaction-classification)
- - [3.2 Reserved Gas Accounting Rule](#32-reserved-gas-accounting-rule)
- - [3.3 Dynamic Quota Adjustment](#33-dynamic-quota-adjustment)
- - [3.4 Quota Bounds](#34-quota-bounds)
- - [3.5 Parameters, Invariants, and Governance](#35-parameters-invariants-and-governance)
- - [3.6 Payment Contract List](#36-payment-contract-list)
+ - [3.1 Block Space Model](#31-block-space-model)
+ - [3.2 Transaction Classification](#32-transaction-classification)
+ - [3.3 Reserved Gas Accounting Rule](#33-reserved-gas-accounting-rule)
+ - [3.4 Dynamic Quota Adjustment](#34-dynamic-quota-adjustment)
+ - [3.5 Quota Bounds](#35-quota-bounds)
+ - [3.6 Parameters, Invariants, and Governance](#36-parameters-invariants-and-governance)
+ - [3.7 Payment Contract List](#37-payment-contract-list)
- [4. Rationale](#4-rationale)
- [5. Backward Compatibility](#5-backward-compatibility)
- [6. Security Considerations](#6-security-considerations)
@@ -36,15 +37,61 @@ This is not a capacity problem. BSC's throughput is on a sustained upward path,
## 3. Specification
-### 3.1 Transaction Classification
+### 3.1 Block Space Model
+
+This section states the model in pictures; the rules that follow are its formalization. Every transaction is either a **payment transaction** or a **general transaction** — how that is decided is specified in [§3.2](#32-transaction-classification).
+
+```
+Legend # general tx gas = payment tx gas
+ : reserved for payment but unused - general may NOT take it
+ . block space nobody used - either class may take it
+
+Schematic, not to scale: the payment lane is about 3% of the block at rest
+and at most about 8% when fully expanded.
+
+
+Today, with no reservation
+
+ <---------------- GasLimit ---------------->
+ quiet [######====..................................]
+ congested [############################################]
+ general demand alone fills the block; payment
+ traffic arriving during the pulse is not included
+
+
+With the payment lane
+
+ <-------- general space --------->
+ quiet [######............................|====:::::]
+ the block is not full; the lane changes nothing
+
+ congested, [##################################|===::::::]
+ payment < paymentLaneSize general stops at the lane boundary; the unused
+ part of the lane stays idle, and is not returned
+ to general
+
+ congested, [############################======|=========]
+ payment > paymentLaneSize payment filled the lane and overflowed past it;
+ the overflow competed for general space under the
+ ordinary fee rules, so general got less
+```
+
+Two rules govern the boundary, and they are deliberately asymmetric:
+
+- **General transactions can never use the lane** — not even when it sits empty. This is where the guarantee comes from: reserved gas that could be resold to general traffic would not be a reservation at all.
+- **Payment transactions can use general space** — the lane is a floor, never a ceiling. Payment gas beyond the lane carries no privilege and bids for the remaining space on equal terms with everything else.
+
+The bar is a gas budget, not a layout: it says nothing about where transactions sit inside the block, and both classes remain freely interleaved and ordered exactly as today. The accounting rule in [§3.3](#33-reserved-gas-accounting-rule) is this picture written as a single inequality.
+
+### 3.2 Transaction Classification
A transaction is a **payment transaction** if and only if it belongs to one of the following three categories, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**.
| Category | Scope | Determination |
|---|---|---|
| ① Native BNB transfer | Pure value transfer that executes no contract code | Mechanical: `to` is non-nil, `data` is empty, and the account at `to` has no code |
-| ② Listed stablecoin contracts | Initially USDT and USDC only | Governance nomination ([§3.6](#36-payment-contract-list)) |
-| ③ Listed [BEP-702](./BEP-702.md) native tokens | Tokens created under the New Tokens on BNB Smart Chain standard | Protocol-native validity checks + governance nomination ([§3.6](#36-payment-contract-list)) |
+| ② Listed stablecoin contracts | Initially USDT and USDC only | Governance nomination ([§3.7](#37-payment-contract-list)) |
+| ③ Listed [BEP-702](./BEP-702.md) native tokens | Tokens created under the New Tokens on BNB Smart Chain standard | Protocol-native validity checks + governance nomination ([§3.7](#37-payment-contract-list)) |
For category ①, the no-code requirement is checked against the parent block's final state. An account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator has code and is therefore excluded — a transfer to it triggers execution, and no execution-bearing transaction may enter the lane through the native-transfer category.
@@ -52,14 +99,14 @@ For categories ② and ③, classification after list membership is settled is a
Classification requires nothing from users or wallets: which address a transaction is sent to, and which asset it moves, are already determined by the underlying business action. The lane assignment is the protocol recognizing an existing fact, not a new field or declaration.
-### 3.2 Reserved Gas Accounting Rule
+### 3.3 Reserved Gas Accounting Rule
For each block, let:
```
paymentGasUsed = total gas consumed by payment transactions in the block
generalGasUsed = total gas consumed by general transactions in the block
-paymentLaneSize = the block's reserved payment quota (computed per 3.3 and 3.4)
+paymentLaneSize = the block's reserved payment quota (computed per 3.4 and 3.5)
```
The block MUST satisfy:
@@ -77,7 +124,7 @@ The rule has exactly two regimes:
The rule constrains only gas totals. It says nothing about where transactions sit inside the block: payment and general transactions may be interleaved arbitrarily, and block producers keep full freedom over transaction selection and ordering within the accounting constraint. No new ordering rule, priority rule, or fee rule is introduced.
-### 3.3 Dynamic Quota Adjustment
+### 3.4 Dynamic Quota Adjustment
`paymentLaneSize` for block `n` is a deterministic function of chain history, computed by every node from block `n−1`; no new header field is required. The adjustment reads a single signal:
@@ -93,7 +140,7 @@ Here `signalGasUsed` is general gas usage plus any payment gas consumed beyond t
At the activation block, `paymentLaneSize` initializes to the effective minimum.
-### 3.4 Quota Bounds
+### 3.5 Quota Bounds
The quota is constrained by two independent boundaries:
@@ -102,7 +149,7 @@ The quota is constrained by two independent boundaries:
The effective range is the intersection: lower bound = the larger of the two minimums, upper bound = the smaller of the two maximums. If an extreme `GasLimit` makes the intersection empty (e.g., the ratio minimum converts to more gas than the absolute maximum), **the absolute bounds prevail** and the quota range is `[PAYMENT_LANE_MIN, PAYMENT_LANE_MAX]` — behavior is defined in every configuration.
-### 3.5 Parameters, Invariants, and Governance
+### 3.6 Parameters, Invariants, and Governance
The adjustment algorithm itself (the signal, the hysteresis structure, the accounting rule) is protocol logic and is not governable. The values that drive it are governable parameters, taking effect only through the standard BSC on-chain governance process:
@@ -158,7 +205,7 @@ Illustration at GasLimit = 70M, 0.45s blocks (effective range [2M, 5.6M]):
recovery: signal < 70% → quota returns to 2M over ~10 blocks (~4.5s)
```
-### 3.6 Payment Contract List
+### 3.7 Payment Contract List
Categories ② and ③ are defined by a **payment contract list** maintained in a system contract and updatable only through the standard BSC governance process (validator voting). Classification reads list membership as of the parent block's final state, so a list change never affects the block that contains it.
@@ -199,8 +246,8 @@ Outside congestion (the overwhelming majority of blocks), the quota rests at its
- **Spam within the lane.** The quota does not grant free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so flooding the lane costs fees like any other spam and displaces only other payment traffic, never the general market beyond the quota bound.
- **Bounded waste.** Idle reserved gas is capped by `PAYMENT_LANE_MAX` per block and by the ratio ceiling as a fraction of block space; misjudged expansion self-corrects via contraction once the signal clears, and cannot accumulate.
- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
-- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.6](#36-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
-- **Parameter safety.** The invariants in [§3.5](#35-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can configure a thrashing, inverted, or degenerate quota.
+- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.7](#37-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
+- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can configure a thrashing, inverted, or degenerate quota.
## 7. License
From daa6af1a58d6fb952a648acc59f24a0e09f032dd Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 11:50:45 +0800
Subject: [PATCH 04/29] bep-703: refine Dynamic Quota Adjustment
---
BEPs/BEP-703.md | 196 ++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 173 insertions(+), 23 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index e2fb5ae5..4e1d809c 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -17,7 +17,18 @@
- [3.2 Transaction Classification](#32-transaction-classification)
- [3.3 Reserved Gas Accounting Rule](#33-reserved-gas-accounting-rule)
- [3.4 Dynamic Quota Adjustment](#34-dynamic-quota-adjustment)
- - [3.5 Quota Bounds](#35-quota-bounds)
+ - [3.4.1 The Recurrence](#341-the-recurrence)
+ - [3.4.2 The Congestion Signal](#342-the-congestion-signal)
+ - [3.4.3 The Step](#343-the-step)
+ - [3.4.4 Bounds](#344-bounds)
+ - [3.4.5 Activation](#345-activation)
+ - [3.4.6 Worked Example](#346-worked-example)
+ - [3.5 Header Commitment](#35-header-commitment)
+ - [3.5.1 Why the State Must Be Committed](#351-why-the-state-must-be-committed)
+ - [3.5.2 What Is Committed](#352-what-is-committed)
+ - [3.5.3 Why UncleHash](#353-why-unclehash)
+ - [3.5.4 Validation](#354-validation)
+ - [3.5.5 What This Buys](#355-what-this-buys)
- [3.6 Parameters, Invariants, and Governance](#36-parameters-invariants-and-governance)
- [3.7 Payment Contract List](#37-payment-contract-list)
- [4. Rationale](#4-rationale)
@@ -106,7 +117,7 @@ For each block, let:
```
paymentGasUsed = total gas consumed by payment transactions in the block
generalGasUsed = total gas consumed by general transactions in the block
-paymentLaneSize = the block's reserved payment quota (computed per 3.4 and 3.5)
+paymentLaneSize = the block's reserved payment quota (computed per 3.4)
```
The block MUST satisfy:
@@ -126,28 +137,154 @@ The rule constrains only gas totals. It says nothing about where transactions si
### 3.4 Dynamic Quota Adjustment
-`paymentLaneSize` for block `n` is a deterministic function of chain history, computed by every node from block `n−1`; no new header field is required. The adjustment reads a single signal:
+`paymentLaneSize` is an accumulator, not a function of the current block. Each block moves it by one step or holds it, according to how congested its parent was; where it stands today is the sum of every step taken since activation. [§3.5](#35-header-commitment) explains why that memory cannot be avoided, and how a node obtains it without replaying history.
+
+Throughout, `h` is the block being built or validated and `h−1` is its parent. Every ratio-typed parameter is an integer in basis points against `RATIO_DENOM = 10000`. Conversions to gas multiply before they divide and truncate toward zero. No part of this computation uses floating point, and no comparison uses division.
+
+#### 3.4.1 The Recurrence
+
+```
+paymentLaneSize(h) = clamp( paymentLaneSize(h−1) + step(h), laneMin(h), laneMax(h) )
+```
+
+The clamp applies to the carried state, not merely to the value the current block uses. A quota allowed to accumulate past its bound through a long congestion episode would take just as long to unwind afterwards, and would stop tracking the signal entirely.
+
+#### 3.4.2 The Congestion Signal
+
+```
+signalGasUsed(h−1) = generalGasUsed(h−1) + max(0, paymentGasUsed(h−1) − paymentLaneSize(h−1))
+```
+
+`signalGasUsed` is the gas that competed for space on the open market: all general gas, plus any payment gas beyond the reservation, which bid for the remaining space on equal terms with general traffic. It excludes the payment gas the reservation actually covered — that gas competed for nothing.
+
+The exclusion is what keeps the lane from bootstrapping itself. Were reserved gas counted, an attacker could fill the lane with minimum-cost transfers, drive the signal up, and grow the reservation — using traffic that is sheltered from competition by the very reservation it is enlarging.
+
+Thresholds are compared without dividing:
+
+```
+signalGasUsed(h−1) × RATIO_DENOM vs trigger(h−1) × GasLimit(h−1)
+```
+
+`GasLimit` is bounded far below 2^40 and `RATIO_DENOM` is 10^4, so neither product can overflow 64 bits.
+
+One property follows from the accounting rule in [§3.3](#33-reserved-gas-accounting-rule) and is worth stating explicitly. That rule implies `signalGasUsed(h−1) <= GasLimit(h−1) − paymentLaneSize(h−1)`, so the signal can never exceed `1 − paymentLaneSize/GasLimit`: a larger quota mechanically depresses the very signal that grows it. Invariant (5) in [§3.6](#36-parameters-invariants-and-governance) keeps that ceiling above the expansion threshold.
+
+#### 3.4.3 The Step
```
-signal(n−1) = signalGasUsed(n−1) / GasLimit(n−1)
+step(h) =
+ + EXPAND_STEP × GasLimit(h) / RATIO_DENOM
+ if signalGasUsed(h−1) × RATIO_DENOM >= EXPAND_TRIGGER_RATIO × GasLimit(h−1)
+
+ − SHRINK_STEP × GasLimit(h) / RATIO_DENOM
+ if signalGasUsed(h−1) × RATIO_DENOM <= SHRINK_TRIGGER_RATIO × GasLimit(h−1)
+
+ 0 otherwise — the hysteresis band
```
-- `signal >= EXPAND_TRIGGER_RATIO` — the chain is congested: the quota ratio increases by `EXPAND_STEP`, up to the effective maximum.
-- `signal < SHRINK_TRIGGER_RATIO` — the chain has slack: the quota ratio decreases by `SHRINK_STEP`, down to the effective minimum.
-- Otherwise — the hysteresis band: the quota is unchanged, absorbing fluctuation and preventing oscillation.
+The three cases are exhaustive and mutually exclusive. Both thresholds are inclusive toward action, and invariant (1) keeps the expansion threshold strictly above the contraction threshold, so the band between them is where the quota holds and absorbs fluctuation.
+
+`EXPAND_STEP` and `SHRINK_STEP` are both positive; the direction is carried by the sign in the rule above, not by the parameter.
-Here `signalGasUsed` is general gas usage plus any payment gas consumed beyond the quota (that gas competed as general traffic), so the signal responds to both pressure sources: general demand squeezing available space, and payment demand overflowing its own floor.
+The signal is measured against `GasLimit(h−1)` because that is the block whose congestion is being read, while the step is scaled by `GasLimit(h)` because that is the block whose space is being reserved. On BSC `GasLimit` moves by at most 1/1024 per block, so the two differ only marginally; both are header fields, so every node derives the same step.
+
+#### 3.4.4 Bounds
+
+```
+laneMin(h) = max( PAYMENT_LANE_MIN_RATIO × GasLimit(h) / RATIO_DENOM, PAYMENT_LANE_MIN )
+laneMax(h) = min( PAYMENT_LANE_MAX_RATIO × GasLimit(h) / RATIO_DENOM, PAYMENT_LANE_MAX )
+```
-At the activation block, `paymentLaneSize` initializes to the effective minimum.
+Two independent boundaries meet here. The **ratio bounds** express the target range as a fraction of `GasLimit`, so the reservation scales automatically as block capacity grows and never needs re-tuning. The **absolute bounds** cap its size in gas regardless of how large blocks become, so capacity growth can never silently grow the reservation past an intended ceiling. The effective range is their intersection.
-### 3.5 Quota Bounds
+If an extreme `GasLimit` makes that intersection empty — the ratio minimum converting to more gas than the absolute maximum — **the absolute bounds prevail** and the range is `[PAYMENT_LANE_MIN, PAYMENT_LANE_MAX]`. Behaviour is defined in every configuration.
-The quota is constrained by two independent boundaries:
+Bounds are re-evaluated and the clamp re-applied on every block, including blocks where `step(h)` is zero. A governance change that narrows the range therefore takes effect on the next block, rather than waiting for the next step.
-- **Ratio bounds** (`PAYMENT_LANE_MIN_RATIO`, `PAYMENT_LANE_MAX_RATIO`): the adjustment target range, expressed as a fraction of `GasLimit` so it scales automatically as block capacity grows.
-- **Absolute bounds** (`PAYMENT_LANE_MIN`, `PAYMENT_LANE_MAX`): fixed gas amounts that cap the quota's absolute size regardless of how large blocks become.
+#### 3.4.5 Activation
-The effective range is the intersection: lower bound = the larger of the two minimums, upper bound = the smaller of the two maximums. If an extreme `GasLimit` makes the intersection empty (e.g., the ratio minimum converts to more gas than the absolute maximum), **the absolute bounds prevail** and the quota range is `[PAYMENT_LANE_MIN, PAYMENT_LANE_MAX]` — behavior is defined in every configuration.
+A system contract upgrade takes effect at the end of the block that carries it, so this BEP's governable parameters are first readable by the block after activation. The activation block is therefore exempt from the accounting rule in [§3.3](#33-reserved-gas-accounting-rule). It still carries a commitment ([§3.5](#35-header-commitment)), seeded as:
+
+```
+paymentLaneSize(activation) = PAYMENT_LANE_MIN
+paymentGasUsed(activation) = the true payment gas of that block's own transactions
+```
+
+From `activation + 1` onward the recurrence runs unchanged, deriving each block from its parent's commitment. Because the clamp is re-applied every block ([§3.4.4](#344-bounds)), the seed is brought inside `[laneMin, laneMax]` at the first adjustment.
+
+#### 3.4.6 Worked Example
+
+At `GasLimit = 70M` and a 0.45s block interval, with the suggested parameters of [§3.6](#36-parameters-invariants-and-governance):
+
+```
+laneMin = max(2% × 70M, 2M) = max(1.4M, 2M) = 2M <- absolute bound binds
+laneMax = min(8% × 70M, 8M) = min(5.6M, 8M) = 5.6M <- ratio bound binds
+expand = 2% × 70M = 1.4M per block
+shrink = 0.5% × 70M = 0.35M per block
+
+quiet the quota rests at 2M, 2.9% of the block; the mechanism is dormant
+
+congestion signal >= 80%: 2M -> 3.4M -> 4.8M -> 5.6M (clamped down from 6.2M)
+ 3 blocks, about 1.35s
+
+recovery signal <= 70%: 5.6M -> 2M in steps of 0.35M
+ 11 blocks, about 5s
+```
+
+At 5.6M the lane holds room for roughly 266 native transfers, or 86 stablecoin transfers, per block. Note that each boundary system binds on one side only at this `GasLimit`: the ratio minimum (1.4M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. Both become active at larger block sizes.
+
+### 3.5 Header Commitment
+
+#### 3.5.1 Why the State Must Be Committed
+
+To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. The split requires the state as of `h−2` to classify `h−1`'s transactions, and the quota chains back, block by block, to activation.
+
+Collapsing that recursion into a bounded window of `K` recent blocks does not work, and this BEP's own invariants are what rule it out. Each step is monotone and 1-Lipschitz, so a `K`-block window determines `paymentLaneSize(h)` only if two trajectories starting from opposite ends of the range converge within `K` steps. Invariant (1) guarantees a hysteresis band at least `TRIGGER_GAP_MIN` wide in which no step is taken, and invariant (3) guarantees the range is at least `RATIO_GAP_MIN` wide. A run of `K` blocks whose signal stays inside that band leaves the two trajectories exactly as far apart as they started, so two chains with byte-identical last `K` blocks would disagree about the quota. No finite `K` is sound.
+
+The recurrence state is therefore committed to every block header.
+
+#### 3.5.2 What Is Committed
+
+Two values, encoded into the 32 bytes of `header.UncleHash`:
+
+| Bytes | Field | Meaning |
+|---|---|---|
+| `[0:8]` | `paymentLaneSize` | uint64 big-endian — the quota in force for this block |
+| `[8:16]` | `paymentGasUsed` | uint64 big-endian — payment gas consumed by this block |
+| `[16]` | version | MUST equal `COMMITMENT_VERSION` |
+| `[17:32]` | reserved | MUST be zero |
+
+Two values suffice. The header already carries the block's total gas used, so committing `paymentGasUsed` fixes `generalGasUsed` as well, and with it the whole class split.
+
+The version byte is a correctness requirement rather than an extension point. Without it, a commitment of two zeros — the ordinary shape of an empty block sitting at the quota minimum — would encode to the all-zero hash, which existing client code treats as "this field was never set". Reserved bytes MUST be zero; a future extension requires a version bump.
+
+#### 3.5.3 Why `UncleHash`
+
+Parlia does not permit uncles, so `UncleHash` carries no information on BSC and is pinned to the empty-list hash in every block today. Reusing it adds no header field, no size increase, and no change to block encoding; and the field already sits inside the producer's seal, so authentication costs nothing.
+
+This BEP claims `header.UncleHash` exclusively — no other use of the field is defined. `ParentBeaconRoot` is unaffected.
+
+After activation:
+
+1. Clients MUST accept any 32-byte value in `UncleHash` when validating Parlia blocks.
+2. The uncle list in the block body MUST remain empty. Clients MUST verify this directly on the body, and MUST NOT derive the expected uncle list from `UncleHash`.
+3. Every path that recomputes the uncle-list hash from the body and compares it against the header MUST be gated on activation — block validation, block propagation, the block fetcher, and the downloader's body matching. A path left ungated makes committed blocks impossible to import, propagate, or sync.
+
+#### 3.5.4 Validation
+
+| Check | Where | Why there |
+|---|---|---|
+| Version byte and reserved bytes | Header verification | A pure function of the header; no state required |
+| `paymentLaneSize` matches the value derived from the parent | Block execution | The derivation reads governable parameters from the parent's post-state |
+| `paymentGasUsed` matches the value obtained by re-execution | Block execution | Requires running the block |
+
+The value checks are not optional. An accepted, incorrect `paymentLaneSize` becomes the base of the recurrence for every descendant, and because every node reads the same parent header the chain does not fork — it silently converges on a destroyed lane, or on a general market permanently starved by an oversized reservation.
+
+The same checks apply on the builder path: a block received under [BEP-675](./BEP-675.md) MUST be validated against these rules before a validator signs it. There the commitment arrives as 32 bytes chosen by the builder, so every sum a client derives from it MUST be checked for 64-bit overflow.
+
+#### 3.5.5 What This Buys
+
+A recursion depth of one: a node needs nothing beyond its parent's header. Snap sync, restart from disk, reorg, and history pruning all reduce to reading a single header, so none of them require replaying history or retaining it.
### 3.6 Parameters, Invariants, and Governance
@@ -165,6 +302,8 @@ The adjustment algorithm itself (the signal, the hysteresis structure, the accou
| `SHRINK_STEP` | Per-block contraction step | Governable |
| `TRIGGER_GAP_MIN` | Minimum hysteresis band width | Protocol constant |
| `RATIO_GAP_MIN` | Minimum ratio range width | Protocol constant |
+| `RATIO_DENOM` | Denominator of every ratio parameter, fixed at 10000 | Protocol constant |
+| `COMMITMENT_VERSION` | Version byte of the header commitment ([§3.5](#35-header-commitment)) | Protocol constant |
Governable parameters are not free-form. The following invariants are validated by the protocol before any parameter change takes effect; **a governance proposal violating any of them is invalid** and never activates. The two gap constants are protocol constants, not governable — governance may move the ranges but can never collapse them:
@@ -185,6 +324,13 @@ Governable parameters are not free-form. The following invariants are validated
(4) PAYMENT_LANE_MAX > PAYMENT_LANE_MIN > 0
The absolute range must be non-empty.
+
+(5) PAYMENT_LANE_MAX_RATIO <= RATIO_DENOM − EXPAND_TRIGGER_RATIO
+ The signal is capped at 1 − paymentLaneSize/GasLimit (3.4.2), so a quota
+ ceiling set too high puts the expansion threshold out of reach: the quota
+ stalls below its maximum under saturated demand, and higher still it
+ oscillates at the top. This invariant also keeps the reservation clear of
+ the gas a block must spend on its mandatory system transactions.
```
Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
@@ -193,18 +339,17 @@ Suggested initial values, for discussion rather than locked by this BEP — the
PAYMENT_LANE_MIN_RATIO = 2% PAYMENT_LANE_MAX_RATIO = 8%
PAYMENT_LANE_MIN = 2M gas PAYMENT_LANE_MAX = 8M gas
EXPAND_TRIGGER_RATIO = 80% SHRINK_TRIGGER_RATIO = 70%
-EXPAND_STEP = +2pp/block SHRINK_STEP = -0.5pp/block
+EXPAND_STEP = 2pp/block SHRINK_STEP = 0.5pp/block
TRIGGER_GAP_MIN = 10% RATIO_GAP_MIN = 5%
-Invariant check: 80−70 = 10 >= 10 ✓ | 2pp > 0.5pp > 0 ✓ | 8−2 = 6 >= 5 ✓ | 8M > 2M > 0 ✓
-
-Illustration at GasLimit = 70M, 0.45s blocks (effective range [2M, 5.6M]):
- quiet: quota rests at 2M (~3% of the block); mechanism dormant
- congestion: signal >= 80% → quota expands 2M → 3.4M → 4.8M → 5.6M
- (3 blocks, ~1.35s); 5.6M ≈ 90+ transfers per block guaranteed
- recovery: signal < 70% → quota returns to 2M over ~10 blocks (~4.5s)
+Invariant check:
+ (1) 80−70 = 10 >= 10 ✓ (2) 2pp > 0.5pp > 0 ✓
+ (3) 8−2 = 6 >= 5 ✓ (4) 8M > 2M > 0 ✓
+ (5) 8% <= 100−80 = 20% ✓
```
+[§3.4.6](#346-worked-example) works these values through a congestion episode.
+
### 3.7 Payment Contract List
Categories ② and ③ are defined by a **payment contract list** maintained in a system contract and updatable only through the standard BSC governance process (validator voting). Classification reads list membership as of the parent block's final state, so a list change never affects the block that contains it.
@@ -237,7 +382,12 @@ The initial category-③ list is empty; tokens are nominated individually as aud
## 5. Backward Compatibility
-This is a consensus-breaking change and requires a hard fork: it adds a new block validity rule and the associated quota computation. It changes no transaction format, no RPC interface, no fee mechanism, and no ordering rule — the existing transaction ordering and inclusion mechanics of the ecosystem are unaffected, for every class of transaction. Wallets, exchanges, and applications require no modification.
+This is a consensus-breaking change and requires a hard fork: it adds a new block validity rule, the associated quota computation, and a header commitment. It changes no transaction format, no fee mechanism, and no ordering rule — the existing transaction ordering and inclusion mechanics of the ecosystem are unaffected, for every class of transaction. Wallets, exchanges, and applications that submit and read transactions require no modification.
+
+Two observable values do change, and downstream tooling should account for both:
+
+- `sha3Uncles` is no longer the constant empty-list hash ([§3.5.3](#353-why-unclehash)). Any consumer that compares it against that constant, or derives the uncle list from it, must be updated.
+- During congestion, `gasUsed / GasLimit` understates how full a block really was, by up to the unused part of the reservation. Block explorers, gas-price oracles, and alerting that read that ratio as a congestion indicator will see values low by as much as the quota.
Outside congestion (the overwhelming majority of blocks), the quota rests at its minimum and observable behavior is essentially identical to today. During congestion, general transactions have marginally less space available in exchange for payment traffic retaining a guaranteed floor; the reduction is bounded by the quota maximum and, as block capacity continues to grow, shrinks as a fraction of total block space.
From faf7c35bd07210adc8d4ad89ccb397acc7cf99b8 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 14:55:48 +0800
Subject: [PATCH 05/29] bep-703: refine some trivals
---
BEPs/BEP-703.md | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 4e1d809c..cd55278b 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -137,7 +137,7 @@ The rule constrains only gas totals. It says nothing about where transactions si
### 3.4 Dynamic Quota Adjustment
-`paymentLaneSize` is an accumulator, not a function of the current block. Each block moves it by one step or holds it, according to how congested its parent was; where it stands today is the sum of every step taken since activation. [§3.5](#35-header-commitment) explains why that memory cannot be avoided, and how a node obtains it without replaying history.
+`paymentLaneSize` is an accumulator, not a function of the current block. Each block moves it by one step or holds it, according to how congested its parent was; where it stands today is the sum of every step taken since the lane took effect. [§3.5](#35-header-commitment) explains why that memory cannot be avoided, and how a node obtains it without replaying history.
Throughout, `h` is the block being built or validated and `h−1` is its parent. Every ratio-typed parameter is an integer in basis points against `RATIO_DENOM = 10000`. Conversions to gas multiply before they divide and truncate toward zero. No part of this computation uses floating point, and no comparison uses division.
@@ -203,14 +203,15 @@ Bounds are re-evaluated and the clamp re-applied on every block, including block
#### 3.4.5 Activation
-A system contract upgrade takes effect at the end of the block that carries it, so this BEP's governable parameters are first readable by the block after activation. The activation block is therefore exempt from the accounting rule in [§3.3](#33-reserved-gas-accounting-rule). It still carries a commitment ([§3.5](#35-header-commitment)), seeded as:
+A system contract upgrade takes effect at the end of the block that carries it, so this BEP's parameters are first readable by the block after activation. The activation block does nothing but deploy them: it is not subject to the accounting rule in [§3.3](#33-reserved-gas-accounting-rule), and it carries no commitment.
+
+The lane applies from `activation + 1`. That block has no parent commitment to derive from, so its quota is not produced by the recurrence but taken directly from the floor:
```
-paymentLaneSize(activation) = PAYMENT_LANE_MIN
-paymentGasUsed(activation) = the true payment gas of that block's own transactions
+paymentLaneSize(activation + 1) = laneMin(activation + 1)
```
-From `activation + 1` onward the recurrence runs unchanged, deriving each block from its parent's commitment. Because the clamp is re-applied every block ([§3.4.4](#344-bounds)), the seed is brought inside `[laneMin, laneMax]` at the first adjustment.
+It is subject to the accounting rule, and it carries the first commitment ([§3.5](#35-header-commitment)). From `activation + 2` onward the recurrence in [§3.4.1](#341-the-recurrence) runs unchanged, each block deriving its quota from its parent's commitment. No block before `activation + 1` is ever read by the recurrence, so no earlier block needs a class split it does not have.
#### 3.4.6 Worked Example
@@ -237,11 +238,11 @@ At 5.6M the lane holds room for roughly 266 native transfers, or 86 stablecoin t
#### 3.5.1 Why the State Must Be Committed
-To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. The split requires the state as of `h−2` to classify `h−1`'s transactions, and the quota chains back, block by block, to activation.
+To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. The split requires the state as of `h−2` to classify `h−1`'s transactions, and the quota chains back, block by block, to `activation + 1`.
Collapsing that recursion into a bounded window of `K` recent blocks does not work, and this BEP's own invariants are what rule it out. Each step is monotone and 1-Lipschitz, so a `K`-block window determines `paymentLaneSize(h)` only if two trajectories starting from opposite ends of the range converge within `K` steps. Invariant (1) guarantees a hysteresis band at least `TRIGGER_GAP_MIN` wide in which no step is taken, and invariant (3) guarantees the range is at least `RATIO_GAP_MIN` wide. A run of `K` blocks whose signal stays inside that band leaves the two trajectories exactly as far apart as they started, so two chains with byte-identical last `K` blocks would disagree about the quota. No finite `K` is sound.
-The recurrence state is therefore committed to every block header.
+The recurrence state is therefore committed to every block header from `activation + 1` onward.
#### 3.5.2 What Is Committed
@@ -251,12 +252,11 @@ Two values, encoded into the 32 bytes of `header.UncleHash`:
|---|---|---|
| `[0:8]` | `paymentLaneSize` | uint64 big-endian — the quota in force for this block |
| `[8:16]` | `paymentGasUsed` | uint64 big-endian — payment gas consumed by this block |
-| `[16]` | version | MUST equal `COMMITMENT_VERSION` |
-| `[17:32]` | reserved | MUST be zero |
+| `[16:32]` | reserved | MUST be zero |
Two values suffice. The header already carries the block's total gas used, so committing `paymentGasUsed` fixes `generalGasUsed` as well, and with it the whole class split.
-The version byte is a correctness requirement rather than an extension point. Without it, a commitment of two zeros — the ordinary shape of an empty block sitting at the quota minimum — would encode to the all-zero hash, which existing client code treats as "this field was never set". Reserved bytes MUST be zero; a future extension requires a version bump.
+Requiring the reserved bytes to be zero makes the encoding canonical — exactly one 32-byte value per pair — and rejects a header that still carries the pre-activation empty-list hash.
#### 3.5.3 Why `UncleHash`
@@ -264,7 +264,7 @@ Parlia does not permit uncles, so `UncleHash` carries no information on BSC and
This BEP claims `header.UncleHash` exclusively — no other use of the field is defined. `ParentBeaconRoot` is unaffected.
-After activation:
+From `activation + 1` onward:
1. Clients MUST accept any 32-byte value in `UncleHash` when validating Parlia blocks.
2. The uncle list in the block body MUST remain empty. Clients MUST verify this directly on the body, and MUST NOT derive the expected uncle list from `UncleHash`.
@@ -274,7 +274,7 @@ After activation:
| Check | Where | Why there |
|---|---|---|
-| Version byte and reserved bytes | Header verification | A pure function of the header; no state required |
+| Reserved bytes are zero | Header verification | A pure function of the header; no state required |
| `paymentLaneSize` matches the value derived from the parent | Block execution | The derivation reads governable parameters from the parent's post-state |
| `paymentGasUsed` matches the value obtained by re-execution | Block execution | Requires running the block |
@@ -303,7 +303,6 @@ The adjustment algorithm itself (the signal, the hysteresis structure, the accou
| `TRIGGER_GAP_MIN` | Minimum hysteresis band width | Protocol constant |
| `RATIO_GAP_MIN` | Minimum ratio range width | Protocol constant |
| `RATIO_DENOM` | Denominator of every ratio parameter, fixed at 10000 | Protocol constant |
-| `COMMITMENT_VERSION` | Version byte of the header commitment ([§3.5](#35-header-commitment)) | Protocol constant |
Governable parameters are not free-form. The following invariants are validated by the protocol before any parameter change takes effect; **a governance proposal violating any of them is invalid** and never activates. The two gap constants are protocol constants, not governable — governance may move the ranges but can never collapse them:
From 6c5f8d82d27640609ad173220cd540a406f4dd9c Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 15:14:34 +0800
Subject: [PATCH 06/29] chore: polish trivals
---
BEPs/BEP-703.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index cd55278b..e6c6ef46 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -89,8 +89,8 @@ With the payment lane
Two rules govern the boundary, and they are deliberately asymmetric:
-- **General transactions can never use the lane** — not even when it sits empty. This is where the guarantee comes from: reserved gas that could be resold to general traffic would not be a reservation at all.
-- **Payment transactions can use general space** — the lane is a floor, never a ceiling. Payment gas beyond the lane carries no privilege and bids for the remaining space on equal terms with everything else.
+- **General transactions can never use the payment lane** — not even when it sits empty. This is where the guarantee comes from: reserved gas that could be resold to general traffic would not be a reservation at all.
+- **Payment transactions can use general space** — the payment lane is a floor, never a ceiling. Payment gas beyond it carries no privilege and bids for the remaining space on equal terms with everything else.
The bar is a gas budget, not a layout: it says nothing about where transactions sit inside the block, and both classes remain freely interleaved and ordered exactly as today. The accounting rule in [§3.3](#33-reserved-gas-accounting-rule) is this picture written as a single inequality.
From 022745e434dd30c110561b2e671f2ef2fa2b880e Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 17:06:24 +0800
Subject: [PATCH 07/29] BEP-703: refine model
---
BEPs/BEP-703.md | 40 +++++++++++++++++++++++++++-------------
1 file changed, 27 insertions(+), 13 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index e6c6ef46..33aa1d71 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -38,7 +38,7 @@
## 1. Summary
-This BEP reserves a small, dynamically-sized amount of gas in every block — the **Payment Lane** — that only payment transactions may consume. The reservation is a per-block gas accounting rule, not a region of the block: payment and non-payment transactions remain freely interleaved, ordered, and priced exactly as today. During congestion, the reservation guarantees a minimum throughput floor for basic value transfer; at all other times it stays near its minimum and the mechanism is effectively dormant.
+This BEP reserves a small, dynamically-sized amount of gas in every block — the **Payment Lane** — that only payment transactions may consume. The reservation is a per-block gas accounting rule, not a region of the block: payment and non-payment transactions remain freely interleaved, ordered, and priced exactly as today. During congestion, the reservation guarantees the payment class a minimum amount of block gas — not the inclusion of any particular transaction; at all other times it stays near its minimum and the mechanism is effectively dormant.
## 2. Motivation
@@ -100,11 +100,13 @@ A transaction is a **payment transaction** if and only if it belongs to one of t
| Category | Scope | Determination |
|---|---|---|
-| ① Native BNB transfer | Pure value transfer that executes no contract code | Mechanical: `to` is non-nil, `data` is empty, and the account at `to` has no code |
+| ① Native BNB transfer | Pure value transfer that executes no contract code as of the parent state | Mechanical: the transaction type is `0x00`, `0x01`, or `0x02`; `to` is non-nil and is not a precompile address; `data` and `accessList` are empty; and the account at `to` has no code |
| ② Listed stablecoin contracts | Initially USDT and USDC only | Governance nomination ([§3.7](#37-payment-contract-list)) |
| ③ Listed [BEP-702](./BEP-702.md) native tokens | Tokens created under the New Tokens on BNB Smart Chain standard | Protocol-native validity checks + governance nomination ([§3.7](#37-payment-contract-list)) |
-For category ①, the no-code requirement is checked against the parent block's final state. An account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator has code and is therefore excluded — a transfer to it triggers execution, and no execution-bearing transaction may enter the lane through the native-transfer category.
+The three conditions beyond the no-code test each close a statically visible route to code execution or unbounded gas. The transaction-type allowlist excludes blob-carrying and code-setting types. The empty `accessList` requirement excludes access lists, which are charged 2400 gas per address and 1900 per storage key regardless of whether `data` is empty. The precompile exclusion is needed because a precompile address holds no code in state and so passes the no-code test, yet a call to one runs the precompile — and a precompile that rejects its input consumes every unit of gas the call was given. The precompile set is fixed by the fork schedule, so this is a static address check like the others. Together the four conditions pin a category-① transaction's intrinsic cost at exactly the 21000-gas transfer cost.
+
+For category ①, the no-code requirement is checked against the parent block's final state, so an account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator has code and is excluded. Reading the parent state does leave one gap: if the account at `to` acquires code earlier in the same block, through a deployment or a delegation authorisation, the transfer will call into it and execute code inside the lane. What that costs is bounded by the transaction's own gas limit, and it is accounted to the payment class like any other payment gas. [§4](#4-rationale) explains why classification is nevertheless not moved to execution time.
For categories ② and ③, classification after list membership is settled is a static lookup on the `to` address. In all three categories, any node can classify a transaction without executing it, so classification adds no consensus overhead.
@@ -159,6 +161,8 @@ signalGasUsed(h−1) = generalGasUsed(h−1) + max(0, paymentGasUsed(h−1) −
The exclusion is what keeps the lane from bootstrapping itself. Were reserved gas counted, an attacker could fill the lane with minimum-cost transfers, drive the signal up, and grow the reservation — using traffic that is sheltered from competition by the very reservation it is enlarging.
+Payment gas beyond the reservation is kept for the opposite reason: it did compete, outbidding general traffic for space that general could otherwise have used, so the open market really was contested. Keeping it does mean that sustained payment overflow expands the quota. That is intended, and its reach is narrow. Overflow is non-zero only when `paymentGasUsed >= paymentLaneSize`, and in exactly those blocks `max(paymentGasUsed, paymentLaneSize)` equals `paymentGasUsed`, so the quota constrains nothing. The two regimes do not overlap: the overflow term can only pre-position the floor for later blocks, never take space from general traffic in the block that raised it.
+
Thresholds are compared without dividing:
```
@@ -167,7 +171,13 @@ signalGasUsed(h−1) × RATIO_DENOM vs trigger(h−1) × GasLimit(h−1)
`GasLimit` is bounded far below 2^40 and `RATIO_DENOM` is 10^4, so neither product can overflow 64 bits.
-One property follows from the accounting rule in [§3.3](#33-reserved-gas-accounting-rule) and is worth stating explicitly. That rule implies `signalGasUsed(h−1) <= GasLimit(h−1) − paymentLaneSize(h−1)`, so the signal can never exceed `1 − paymentLaneSize/GasLimit`: a larger quota mechanically depresses the very signal that grows it. Invariant (5) in [§3.6](#36-parameters-invariants-and-governance) keeps that ceiling above the expansion threshold.
+The accounting rule in [§3.3](#33-reserved-gas-accounting-rule) caps this signal. Substituting `max(p, L) = L + max(0, p − L)` into that rule gives
+
+```
+signalGasUsed(h−1) <= GasLimit(h−1) − paymentLaneSize(h−1)
+```
+
+which a full block attains, so the bound is tight. The signal is therefore capped at `1 − paymentLaneSize/GasLimit` — a ceiling set by the controller's own output. Two things follow. Growth in the quota lowers every later reading and so damps further growth, which is stabilising; it also means a saturated block reads lower the larger the quota is, and the controller loses the ability to tell a barely full block from a heavily oversubscribed one. And expansion can only fire while the quota sits below `RATIO_DENOM − EXPAND_TRIGGER_RATIO` of the block, whatever maximum is configured; invariant (5) in [§3.6](#36-parameters-invariants-and-governance) keeps the configured maximum within that reach.
#### 3.4.3 The Step
@@ -232,7 +242,7 @@ recovery signal <= 70%: 5.6M -> 2M in steps of 0.35M
11 blocks, about 5s
```
-At 5.6M the lane holds room for roughly 266 native transfers, or 86 stablecoin transfers, per block. Note that each boundary system binds on one side only at this `GasLimit`: the ratio minimum (1.4M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. Both become active at larger block sizes.
+At 5.6M the reservation is large enough for roughly 266 native transfers, or 86 stablecoin transfers, per block — an illustration of capacity, not a guaranteed count. The rule reserves gas, and a single transaction may consume all of it. Note that each boundary system binds on one side only at this `GasLimit`: the ratio minimum (1.4M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. Both become active at larger block sizes. At the maximum the signal ceiling is `1 − 5.6M/70M = 92%`, twelve points clear of the 80% expansion threshold, so the quota does reach 5.6M under sustained congestion.
### 3.5 Header Commitment
@@ -325,11 +335,11 @@ Governable parameters are not free-form. The following invariants are validated
The absolute range must be non-empty.
(5) PAYMENT_LANE_MAX_RATIO <= RATIO_DENOM − EXPAND_TRIGGER_RATIO
- The signal is capped at 1 − paymentLaneSize/GasLimit (3.4.2), so a quota
- ceiling set too high puts the expansion threshold out of reach: the quota
- stalls below its maximum under saturated demand, and higher still it
- oscillates at the top. This invariant also keeps the reservation clear of
- the gas a block must spend on its mandatory system transactions.
+ Expansion only fires while the quota is below RATIO_DENOM −
+ EXPAND_TRIGGER_RATIO of the block (3.4.2). Without this bound the
+ configured maximum is unreachable: under saturated demand the quota
+ stalls just past that point and stays there, leaving governance with a
+ ceiling the mechanism can never use.
```
Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
@@ -377,7 +387,11 @@ The initial category-③ list is empty; tokens are nominated individually as aud
**Ratio and absolute bounds together.** Ratio bounds let the quota scale automatically with block capacity so the mechanism never needs re-tuning as GasLimit grows; absolute bounds cap its footprint so growth in block size can never silently grow the reservation beyond an intended ceiling.
-**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, no user action, and no way to smuggle arbitrary execution into the lane: category ① admits no code execution at all, and categories ②/③ admit only contracts whose entire function surface is value transfer — vetted by governance with audit backing for ②, guaranteed by protocol construction for ③.
+**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim. Categories ②/③ admit only contracts whose entire function surface is value transfer — vetted by governance with audit backing for ②, guaranteed by protocol construction for ③.
+
+The price of that choice is that a transaction is classified one state transition before it runs. Category ① rules out every statically visible route to code execution — code-setting and blob-carrying transaction types, access lists, precompile destinations, and accounts that already hold code — but it cannot see a deployment or a delegation authorisation that lands earlier in the same block. A transfer to such an account executes code inside the lane, consuming at most its own gas limit.
+
+Closing that gap would mean classifying against execution-time state, which opens a worse one. Whoever orders the block would then decide which users' transfers are lane-eligible, by placing one cheap deployment ahead of them; classification would stop being a fact the protocol recognises and become a lever the producer holds. The parent-state rule is therefore deliberate, and the residual exposure is bounded by the offending transaction's own gas limit.
## 5. Backward Compatibility
@@ -392,8 +406,8 @@ Outside congestion (the overwhelming majority of blocks), the quota rests at its
## 6. Security Considerations
-- **Spam within the lane.** The quota does not grant free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so flooding the lane costs fees like any other spam and displaces only other payment traffic, never the general market beyond the quota bound.
-- **Bounded waste.** Idle reserved gas is capped by `PAYMENT_LANE_MAX` per block and by the ratio ceiling as a fraction of block space; misjudged expansion self-corrects via contraction once the signal clears, and cannot accumulate.
+- **Spam within the lane.** The quota does not grant free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so flooding the lane costs fees like any other spam. Sustained payment traffic beyond the quota does raise the congestion signal and expand the reservation ([§3.4.2](#342-the-congestion-signal)), and general traffic bears that in later blocks. The exposure is bounded by `PAYMENT_LANE_MAX`, unwinds through the contraction path once the signal clears, and materialises at all only when general traffic is itself congested — in which case its own usage would have expanded the quota anyway. The flood is paid for at full fees throughout.
+- **Bounded waste.** Idle reserved gas is capped per block by `PAYMENT_LANE_MAX` and by the ratio ceiling, and the quota cannot grow past those bounds. The bound is per block, not cumulative over time: while the signal that raised the quota persists, so does the waste. It unwinds only through the contraction path, once that signal clears.
- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.7](#37-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can configure a thrashing, inverted, or degenerate quota.
From 71708ffc65d906c4f5b9fbdc5f0c1420b259c09d Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 17:47:04 +0800
Subject: [PATCH 08/29] chore: refine bep-703
---
BEPs/BEP-703.md | 51 ++++++++++++++++++++++++++++++++-----------------
1 file changed, 34 insertions(+), 17 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 33aa1d71..4721ffc5 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -141,7 +141,7 @@ The rule constrains only gas totals. It says nothing about where transactions si
`paymentLaneSize` is an accumulator, not a function of the current block. Each block moves it by one step or holds it, according to how congested its parent was; where it stands today is the sum of every step taken since the lane took effect. [§3.5](#35-header-commitment) explains why that memory cannot be avoided, and how a node obtains it without replaying history.
-Throughout, `h` is the block being built or validated and `h−1` is its parent. Every ratio-typed parameter is an integer in basis points against `RATIO_DENOM = 10000`. Conversions to gas multiply before they divide and truncate toward zero. No part of this computation uses floating point, and no comparison uses division.
+Throughout, `h` is the block being built or validated and `h−1` is its parent. Every ratio-typed parameter is an integer in basis points against `RATIO_DENOM = 10000` and MUST lie in `[0, RATIO_DENOM]`. Conversions to gas multiply before they divide and truncate toward zero. All arithmetic is on unsigned 64-bit integers and saturates: a subtraction that would fall below zero yields zero, and no sum may exceed `2^64 − 1`. No part of this computation uses floating point, and no comparison uses division.
#### 3.4.1 The Recurrence
@@ -201,13 +201,17 @@ The signal is measured against `GasLimit(h−1)` because that is the block whose
#### 3.4.4 Bounds
```
-laneMin(h) = max( PAYMENT_LANE_MIN_RATIO × GasLimit(h) / RATIO_DENOM, PAYMENT_LANE_MIN )
-laneMax(h) = min( PAYMENT_LANE_MAX_RATIO × GasLimit(h) / RATIO_DENOM, PAYMENT_LANE_MAX )
+laneMax(h) = min( PAYMENT_LANE_MAX_RATIO × GasLimit(h) / RATIO_DENOM,
+ PAYMENT_LANE_MAX )
+
+laneMin(h) = min( max( PAYMENT_LANE_MIN_RATIO × GasLimit(h) / RATIO_DENOM,
+ PAYMENT_LANE_MIN ),
+ laneMax(h) )
```
-Two independent boundaries meet here. The **ratio bounds** express the target range as a fraction of `GasLimit`, so the reservation scales automatically as block capacity grows and never needs re-tuning. The **absolute bounds** cap its size in gas regardless of how large blocks become, so capacity growth can never silently grow the reservation past an intended ceiling. The effective range is their intersection.
+Two limits meet in `laneMax`. The **ratio bound** expresses the ceiling as a fraction of `GasLimit`, so the reservation scales automatically as block capacity grows and never needs re-tuning — and shrinks with it, so the reservation stays proportionate however small blocks become. The **absolute bound** caps its size in gas regardless of how large blocks become, so capacity growth can never silently grow the reservation past an intended ceiling.
-If an extreme `GasLimit` makes that intersection empty — the ratio minimum converting to more gas than the absolute maximum — **the absolute bounds prevail** and the range is `[PAYMENT_LANE_MIN, PAYMENT_LANE_MAX]`. Behaviour is defined in every configuration.
+`laneMin` is the larger of its own two bounds, then capped at `laneMax`. That final cap is what makes the range well defined: `laneMin(h) <= laneMax(h)` holds by construction at every `GasLimit`, so there is no empty range to resolve by convention.
Bounds are re-evaluated and the clamp re-applied on every block, including blocks where `step(h)` is zero. A governance change that narrows the range therefore takes effect on the next block, rather than waiting for the next step.
@@ -228,10 +232,12 @@ It is subject to the accounting rule, and it carries the first commitment ([§3.
At `GasLimit = 70M` and a 0.45s block interval, with the suggested parameters of [§3.6](#36-parameters-invariants-and-governance):
```
-laneMin = max(2% × 70M, 2M) = max(1.4M, 2M) = 2M <- absolute bound binds
-laneMax = min(8% × 70M, 8M) = min(5.6M, 8M) = 5.6M <- ratio bound binds
-expand = 2% × 70M = 1.4M per block
-shrink = 0.5% × 70M = 0.35M per block
+2% × 70M = 1.4M 8% × 70M = 5.6M 0.5% × 70M = 0.35M
+
+laneMax = min(5.6M, 8M) = 5.6M <- set by the ratio bound
+laneMin = min(max(1.4M, 2M), 5.6M) = 2M <- set by the absolute bound
+expand = 1.4M per block
+shrink = 0.35M per block
quiet the quota rests at 2M, 2.9% of the block; the mechanism is dormant
@@ -242,7 +248,7 @@ recovery signal <= 70%: 5.6M -> 2M in steps of 0.35M
11 blocks, about 5s
```
-At 5.6M the reservation is large enough for roughly 266 native transfers, or 86 stablecoin transfers, per block — an illustration of capacity, not a guaranteed count. The rule reserves gas, and a single transaction may consume all of it. Note that each boundary system binds on one side only at this `GasLimit`: the ratio minimum (1.4M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. Both become active at larger block sizes. At the maximum the signal ceiling is `1 − 5.6M/70M = 92%`, twelve points clear of the 80% expansion threshold, so the quota does reach 5.6M under sustained congestion.
+At 5.6M the reservation is large enough for roughly 266 native transfers, or 86 stablecoin transfers, per block — an illustration of capacity, not a guaranteed count. The rule reserves gas, and a single transaction may consume all of it. Between those bounds the quota moves in 1.4M steps, so the range holds four distinct levels: 2M, 3.4M, 4.8M and 5.6M. Note also that each boundary binds on one side only at this `GasLimit`: the ratio minimum (1.4M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. At the maximum the signal ceiling is `1 − 5.6M/70M = 92%`, twelve points clear of the 80% expansion threshold, so the quota does reach 5.6M under sustained congestion.
### 3.5 Header Commitment
@@ -250,7 +256,9 @@ At 5.6M the reservation is large enough for roughly 266 native transfers, or 86
To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. The split requires the state as of `h−2` to classify `h−1`'s transactions, and the quota chains back, block by block, to `activation + 1`.
-Collapsing that recursion into a bounded window of `K` recent blocks does not work, and this BEP's own invariants are what rule it out. Each step is monotone and 1-Lipschitz, so a `K`-block window determines `paymentLaneSize(h)` only if two trajectories starting from opposite ends of the range converge within `K` steps. Invariant (1) guarantees a hysteresis band at least `TRIGGER_GAP_MIN` wide in which no step is taken, and invariant (3) guarantees the range is at least `RATIO_GAP_MIN` wide. A run of `K` blocks whose signal stays inside that band leaves the two trajectories exactly as far apart as they started, so two chains with byte-identical last `K` blocks would disagree about the quota. No finite `K` is sound.
+Collapsing that recursion into a bounded window of `K` recent blocks does not work, for any `K`. Take a window of `K` blocks in which every block has `paymentGasUsed` below `laneMin`, and `generalGasUsed` placing the signal strictly inside the hysteresis band — invariant (1) guarantees that band is not empty, and both conditions leave the block valid under [§3.3](#33-reserved-gas-accounting-rule).
+
+Under those conditions the overflow term `max(0, paymentGasUsed − paymentLaneSize)` vanishes for every quota in `[laneMin, laneMax]`. Each block in the window therefore yields the same signal whatever the quota was, that signal takes the hysteresis branch, and the quota is left untouched. Two chains whose last `K` blocks are byte-identical can thus end the window holding `laneMin` and `laneMax` respectively — and wherever those two differ, they disagree about whether the next block is valid. `K` was arbitrary, so no finite window is sound.
The recurrence state is therefore committed to every block header from `activation + 1` onward.
@@ -310,8 +318,8 @@ The adjustment algorithm itself (the signal, the hysteresis structure, the accou
| `SHRINK_TRIGGER_RATIO` | Slack threshold that triggers contraction | Governable |
| `EXPAND_STEP` | Per-block expansion step | Governable |
| `SHRINK_STEP` | Per-block contraction step | Governable |
-| `TRIGGER_GAP_MIN` | Minimum hysteresis band width | Protocol constant |
-| `RATIO_GAP_MIN` | Minimum ratio range width | Protocol constant |
+| `TRIGGER_GAP_MIN` | Minimum hysteresis band width, fixed at 1000 (10%) | Protocol constant |
+| `RATIO_GAP_MIN` | Minimum ratio range width, fixed at 500 (5%) | Protocol constant |
| `RATIO_DENOM` | Denominator of every ratio parameter, fixed at 10000 | Protocol constant |
Governable parameters are not free-form. The following invariants are validated by the protocol before any parameter change takes effect; **a governance proposal violating any of them is invalid** and never activates. The two gap constants are protocol constants, not governable — governance may move the ranges but can never collapse them:
@@ -328,8 +336,11 @@ Governable parameters are not free-form. The following invariants are validated
demand pattern contracts the quota faster than it can re-expand.
(3) PAYMENT_LANE_MAX_RATIO − PAYMENT_LANE_MIN_RATIO >= RATIO_GAP_MIN
- The ratio range must be genuinely wide; a collapsed range degrades the
- dynamic mechanism into a fixed constant.
+ Keeps the ratio range from collapsing. It does not guarantee a wide
+ effective range: the absolute bounds can narrow that independently, and
+ by how much depends on GasLimit, which is not known when a parameter
+ change is validated. A narrow effective range leaves the quota
+ near-constant — a loss of the dynamic behaviour, not a hazard.
(4) PAYMENT_LANE_MAX > PAYMENT_LANE_MIN > 0
The absolute range must be non-empty.
@@ -340,6 +351,13 @@ Governable parameters are not free-form. The following invariants are validated
configured maximum is unreachable: under saturated demand the quota
stalls just past that point and stays there, leaving governance with a
ceiling the mechanism can never use.
+
+(6) EXPAND_STEP <= EXPAND_TRIGGER_RATIO − SHRINK_TRIGGER_RATIO
+ Where the signal responds to the quota at all it does so one for one
+ (3.4.2), so a step wider than the hysteresis band would carry the signal
+ from one trigger straight past the other and the quota would alternate
+ between expanding and contracting every block. Invariant (2) makes this
+ bound SHRINK_STEP as well.
```
Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
@@ -349,12 +367,11 @@ PAYMENT_LANE_MIN_RATIO = 2% PAYMENT_LANE_MAX_RATIO = 8%
PAYMENT_LANE_MIN = 2M gas PAYMENT_LANE_MAX = 8M gas
EXPAND_TRIGGER_RATIO = 80% SHRINK_TRIGGER_RATIO = 70%
EXPAND_STEP = 2pp/block SHRINK_STEP = 0.5pp/block
-TRIGGER_GAP_MIN = 10% RATIO_GAP_MIN = 5%
Invariant check:
(1) 80−70 = 10 >= 10 ✓ (2) 2pp > 0.5pp > 0 ✓
(3) 8−2 = 6 >= 5 ✓ (4) 8M > 2M > 0 ✓
- (5) 8% <= 100−80 = 20% ✓
+ (5) 8% <= 100−80 = 20% ✓ (6) 2pp <= 80−70 = 10pp ✓
```
[§3.4.6](#346-worked-example) works these values through a congestion episode.
From 66ff3c3d13ce68279cf4ada18576e401ed997802 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Fri, 31 Jul 2026 18:32:52 +0800
Subject: [PATCH 09/29] chore: polish 703
---
BEPs/BEP-703.md | 58 ++++++++++++++++++++++++++-----------------------
1 file changed, 31 insertions(+), 27 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 4721ffc5..fb9e7613 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -46,6 +46,8 @@ BSC fixes the base fee at zero ([BEP-226](./BEP226.md)), so transaction inclusio
This is not a capacity problem. BSC's throughput is on a sustained upward path, and total block space comfortably exceeds payment demand at all times. The defect is structural: heterogeneous traffic shares one undifferentiated bidding dimension, so local congestion in one class propagates to unrelated classes. A bounded, protocol-level reservation for the payment class severs that propagation path at negligible cost to everything else — and does so without touching the fee market or the ordering rules that the rest of the ecosystem relies on.
+What that buys is precise, and worth stating before the rules that deliver it. Up to the reserved amount, payment traffic no longer bids against the pulse at all: the space is there whatever the general market is paying, so a transfer that could not have re-priced itself does not need to. Beyond the reserved amount nothing changes — payment traffic bids as it does today, and payment transactions compete among themselves for the reservation on the ordinary fee rules ([§6](#6-security-considerations)). The reservation therefore removes the *general* market as a source of payment crowd-out, up to its size; it does not make any individual transfer unconditionally includable.
+
## 3. Specification
### 3.1 Block Space Model
@@ -57,7 +59,7 @@ Legend # general tx gas = payment tx gas
: reserved for payment but unused - general may NOT take it
. block space nobody used - either class may take it
-Schematic, not to scale: the payment lane is about 3% of the block at rest
+Schematic, not to scale: the payment lane is about 4% of the block at rest
and at most about 8% when fully expanded.
@@ -104,7 +106,9 @@ A transaction is a **payment transaction** if and only if it belongs to one of t
| ② Listed stablecoin contracts | Initially USDT and USDC only | Governance nomination ([§3.7](#37-payment-contract-list)) |
| ③ Listed [BEP-702](./BEP-702.md) native tokens | Tokens created under the New Tokens on BNB Smart Chain standard | Protocol-native validity checks + governance nomination ([§3.7](#37-payment-contract-list)) |
-The three conditions beyond the no-code test each close a statically visible route to code execution or unbounded gas. The transaction-type allowlist excludes blob-carrying and code-setting types. The empty `accessList` requirement excludes access lists, which are charged 2400 gas per address and 1900 per storage key regardless of whether `data` is empty. The precompile exclusion is needed because a precompile address holds no code in state and so passes the no-code test, yet a call to one runs the precompile — and a precompile that rejects its input consumes every unit of gas the call was given. The precompile set is fixed by the fork schedule, so this is a static address check like the others. Together the four conditions pin a category-① transaction's intrinsic cost at exactly the 21000-gas transfer cost.
+The conditions fall into two groups. Four of them pin the transaction's intrinsic cost at exactly 21000 gas: `to` non-nil rules out contract creation, empty `data` rules out calldata cost, an empty `accessList` rules out the 2400 gas per address and 1900 per storage key that an access list is charged regardless of whether `data` is empty, and the type allowlist rules out the per-authorisation cost of a code-setting transaction. The allowlist also keeps blob-carrying transactions out of the class, which is a separate resource question rather than a gas one.
+
+The other two bar code execution. The no-code test is the obvious one. The precompile exclusion is needed because a precompile address holds no code in state and so passes that test, yet a call to one runs the precompile — and a precompile that rejects its input consumes every unit of gas the call was given. The precompile set is fixed by the fork schedule, so this is a static address check like the rest.
For category ①, the no-code requirement is checked against the parent block's final state, so an account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator has code and is excluded. Reading the parent state does leave one gap: if the account at `to` acquires code earlier in the same block, through a deployment or a delegation authorisation, the transfer will call into it and execute code inside the lane. What that costs is bounded by the transaction's own gas limit, and it is accounted to the payment class like any other payment gas. [§4](#4-rationale) explains why classification is nevertheless not moved to execution time.
@@ -139,9 +143,9 @@ The rule constrains only gas totals. It says nothing about where transactions si
### 3.4 Dynamic Quota Adjustment
-`paymentLaneSize` is an accumulator, not a function of the current block. Each block moves it by one step or holds it, according to how congested its parent was; where it stands today is the sum of every step taken since the lane took effect. [§3.5](#35-header-commitment) explains why that memory cannot be avoided, and how a node obtains it without replaying history.
+`paymentLaneSize` is an accumulator, not a function of the current block. Each block moves it by one step or holds it, according to how congested its parent was; where it stands today is the result of every step taken since the lane took effect, clamped back into range at each one. [§3.5](#35-header-commitment) explains why that memory cannot be avoided, and how a node obtains it without replaying history.
-Throughout, `h` is the block being built or validated and `h−1` is its parent. Every ratio-typed parameter is an integer in basis points against `RATIO_DENOM = 10000` and MUST lie in `[0, RATIO_DENOM]`. Conversions to gas multiply before they divide and truncate toward zero. All arithmetic is on unsigned 64-bit integers and saturates: a subtraction that would fall below zero yields zero, and no sum may exceed `2^64 − 1`. No part of this computation uses floating point, and no comparison uses division.
+Throughout, `h` is the block being built or validated and `h−1` is its parent. Every ratio-typed parameter is an integer in basis points against `RATIO_DENOM = 10000` and MUST lie in `[0, RATIO_DENOM]`. Conversions to gas multiply before they divide and truncate toward zero. Quantities are unsigned 64-bit integers and arithmetic on them saturates: a subtraction that would fall below zero yields zero. Products of a ratio and a gas amount MUST be computed with widened intermediates — BSC's consensus bounds `GasLimit` only by `2^63 − 1`, and `RATIO_DENOM × GasLimit` leaves 64 bits once `GasLimit` passes roughly `2^50.7`. No part of this computation uses floating point, and no comparison uses division.
#### 3.4.1 The Recurrence
@@ -149,6 +153,8 @@ Throughout, `h` is the block being built or validated and `h−1` is its parent.
paymentLaneSize(h) = clamp( paymentLaneSize(h−1) + step(h), laneMin(h), laneMax(h) )
```
+This governs every block from `activation + 2`; [§3.4.5](#345-activation) gives the two blocks before it.
+
The clamp applies to the carried state, not merely to the value the current block uses. A quota allowed to accumulate past its bound through a long congestion episode would take just as long to unwind afterwards, and would stop tracking the signal entirely.
#### 3.4.2 The Congestion Signal
@@ -161,7 +167,7 @@ signalGasUsed(h−1) = generalGasUsed(h−1) + max(0, paymentGasUsed(h−1) −
The exclusion is what keeps the lane from bootstrapping itself. Were reserved gas counted, an attacker could fill the lane with minimum-cost transfers, drive the signal up, and grow the reservation — using traffic that is sheltered from competition by the very reservation it is enlarging.
-Payment gas beyond the reservation is kept for the opposite reason: it did compete, outbidding general traffic for space that general could otherwise have used, so the open market really was contested. Keeping it does mean that sustained payment overflow expands the quota. That is intended, and its reach is narrow. Overflow is non-zero only when `paymentGasUsed >= paymentLaneSize`, and in exactly those blocks `max(paymentGasUsed, paymentLaneSize)` equals `paymentGasUsed`, so the quota constrains nothing. The two regimes do not overlap: the overflow term can only pre-position the floor for later blocks, never take space from general traffic in the block that raised it.
+Payment gas beyond the reservation is kept for the opposite reason: it did compete, outbidding general traffic for space that general could otherwise have used, so the open market really was contested. Keeping it does mean that sustained payment overflow expands the quota. That is intended, and its reach is narrow. Overflow is non-zero only when `paymentGasUsed > paymentLaneSize`, and in exactly those blocks `max(paymentGasUsed, paymentLaneSize)` equals `paymentGasUsed`, so the quota constrains nothing. The two regimes do not overlap: the overflow term can only pre-position the floor for later blocks, never take space from general traffic in the block that raised it.
Thresholds are compared without dividing:
@@ -169,8 +175,6 @@ Thresholds are compared without dividing:
signalGasUsed(h−1) × RATIO_DENOM vs trigger(h−1) × GasLimit(h−1)
```
-`GasLimit` is bounded far below 2^40 and `RATIO_DENOM` is 10^4, so neither product can overflow 64 bits.
-
The accounting rule in [§3.3](#33-reserved-gas-accounting-rule) caps this signal. Substituting `max(p, L) = L + max(0, p − L)` into that rule gives
```
@@ -229,26 +233,26 @@ It is subject to the accounting rule, and it carries the first commitment ([§3.
#### 3.4.6 Worked Example
-At `GasLimit = 70M` and a 0.45s block interval, with the suggested parameters of [§3.6](#36-parameters-invariants-and-governance):
+At `GasLimit = 55M`, BSC mainnet's current value, and a 0.45s block interval, with the suggested parameters of [§3.6](#36-parameters-invariants-and-governance):
```
-2% × 70M = 1.4M 8% × 70M = 5.6M 0.5% × 70M = 0.35M
+2% × 55M = 1.1M 8% × 55M = 4.4M 0.5% × 55M = 0.275M
-laneMax = min(5.6M, 8M) = 5.6M <- set by the ratio bound
-laneMin = min(max(1.4M, 2M), 5.6M) = 2M <- set by the absolute bound
-expand = 1.4M per block
-shrink = 0.35M per block
+laneMax = min(4.4M, 8M) = 4.4M <- set by the ratio bound
+laneMin = min(max(1.1M, 2M), 4.4M) = 2M <- set by the absolute bound
+expand = 1.1M per block
+shrink = 0.275M per block
-quiet the quota rests at 2M, 2.9% of the block; the mechanism is dormant
+quiet the quota rests at 2M, 3.6% of the block; the mechanism is dormant
-congestion signal >= 80%: 2M -> 3.4M -> 4.8M -> 5.6M (clamped down from 6.2M)
+congestion signal >= 80%: 2M -> 3.1M -> 4.2M -> 4.4M (clamped down from 5.3M)
3 blocks, about 1.35s
-recovery signal <= 70%: 5.6M -> 2M in steps of 0.35M
- 11 blocks, about 5s
+recovery signal <= 70%: 4.4M -> 2M in steps of 0.275M
+ 9 blocks, about 4s
```
-At 5.6M the reservation is large enough for roughly 266 native transfers, or 86 stablecoin transfers, per block — an illustration of capacity, not a guaranteed count. The rule reserves gas, and a single transaction may consume all of it. Between those bounds the quota moves in 1.4M steps, so the range holds four distinct levels: 2M, 3.4M, 4.8M and 5.6M. Note also that each boundary binds on one side only at this `GasLimit`: the ratio minimum (1.4M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. At the maximum the signal ceiling is `1 − 5.6M/70M = 92%`, twelve points clear of the 80% expansion threshold, so the quota does reach 5.6M under sustained congestion.
+At 4.4M the reservation is large enough for roughly 209 native transfers, or between 73 and 126 stablecoin transfers depending on the token and on whether the recipient already holds a balance — an illustration of capacity, not a guaranteed count. The rule reserves gas, and a single transaction may consume all of it. Between the bounds the quota moves in 1.1M steps, so the range holds four distinct levels: 2M, 3.1M, 4.2M and 4.4M. Note also that each boundary binds on one side only at this `GasLimit`: the ratio minimum (1.1M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. At the maximum the signal ceiling is `1 − 4.4M/55M = 92%`, twelve points clear of the 80% expansion threshold, so the quota does reach 4.4M under sustained congestion.
### 3.5 Header Commitment
@@ -256,11 +260,11 @@ At 5.6M the reservation is large enough for roughly 266 native transfers, or 86
To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. The split requires the state as of `h−2` to classify `h−1`'s transactions, and the quota chains back, block by block, to `activation + 1`.
-Collapsing that recursion into a bounded window of `K` recent blocks does not work, for any `K`. Take a window of `K` blocks in which every block has `paymentGasUsed` below `laneMin`, and `generalGasUsed` placing the signal strictly inside the hysteresis band — invariant (1) guarantees that band is not empty, and both conditions leave the block valid under [§3.3](#33-reserved-gas-accounting-rule).
+Suppose the quota were not committed, and a node derived it instead from a bounded window of the `K` most recent blocks. No `K` works. Fix one; hold `GasLimit` and the governable parameters constant, and take a range that is not degenerate (`laneMin < laneMax`). Now take `K + 1` consecutive blocks — one more than the window, because the window's earliest step reads the block before it — in which every block carries `paymentGasUsed` below `laneMin` and `generalGasUsed` strictly inside the hysteresis band. Such blocks exist: invariant (1) makes the band non-empty, and invariant (5) puts `GasLimit − laneMax` at or above the expansion threshold, so any general load inside the band satisfies [§3.3](#33-reserved-gas-accounting-rule) at every quota in the range.
-Under those conditions the overflow term `max(0, paymentGasUsed − paymentLaneSize)` vanishes for every quota in `[laneMin, laneMax]`. Each block in the window therefore yields the same signal whatever the quota was, that signal takes the hysteresis branch, and the quota is left untouched. Two chains whose last `K` blocks are byte-identical can thus end the window holding `laneMin` and `laneMax` respectively — and wherever those two differ, they disagree about whether the next block is valid. `K` was arbitrary, so no finite window is sound.
+Across that stretch the overflow term `max(0, paymentGasUsed − paymentLaneSize)` vanishes for every quota in the range. Each block therefore yields the same signal whatever the quota was, that signal takes the hysteresis branch, and — the bounds being unchanged — the clamp leaves the quota where it stood. One chain can enter the stretch holding `laneMin` and another holding `laneMax`, and both leave it still holding them. The two chains must have diverged at some earlier height, so their `ParentHash` and state root differ; but those are opaque digests of exactly the unbounded history the window was meant to replace, not quantities a windowed derivation can compute from. Every field such a derivation can read — gas limit, gas used, class split — agrees across both chains for all `K` blocks, and the quotas still differ. The difference is observable: a following block with no payment gas and `generalGasUsed = GasLimit − laneMin` is valid under the first quota and invalid under the second. `K` was arbitrary, so no finite window is sound.
-The recurrence state is therefore committed to every block header from `activation + 1` onward.
+The recurrence state must therefore be carried forward explicitly rather than rederived. It is committed to every block header from `activation + 1` onward — in the header rather than in state, so that the recursion never reaches past the parent ([§3.5.5](#355-what-this-buys)).
#### 3.5.2 What Is Committed
@@ -286,7 +290,7 @@ From `activation + 1` onward:
1. Clients MUST accept any 32-byte value in `UncleHash` when validating Parlia blocks.
2. The uncle list in the block body MUST remain empty. Clients MUST verify this directly on the body, and MUST NOT derive the expected uncle list from `UncleHash`.
-3. Every path that recomputes the uncle-list hash from the body and compares it against the header MUST be gated on activation — block validation, block propagation, the block fetcher, and the downloader's body matching. A path left ungated makes committed blocks impossible to import, propagate, or sync.
+3. Every path that recomputes the uncle-list hash from the body and compares it against the header MUST be gated on that same boundary — block validation, block propagation, the block fetcher, and the downloader's body matching. A path left ungated makes committed blocks impossible to import, propagate, or sync.
#### 3.5.4 Validation
@@ -298,11 +302,11 @@ From `activation + 1` onward:
The value checks are not optional. An accepted, incorrect `paymentLaneSize` becomes the base of the recurrence for every descendant, and because every node reads the same parent header the chain does not fork — it silently converges on a destroyed lane, or on a general market permanently starved by an oversized reservation.
-The same checks apply on the builder path: a block received under [BEP-675](./BEP-675.md) MUST be validated against these rules before a validator signs it. There the commitment arrives as 32 bytes chosen by the builder, so every sum a client derives from it MUST be checked for 64-bit overflow.
+The same checks apply on the builder path: a block received under [BEP-675](./BEP-675.md) MUST be validated against these rules before a validator signs it. There the commitment arrives as 32 bytes chosen by the builder. Values decoded from it are untrusted input, not quantities produced by the recurrence: a client MUST range-check them and reject the block — `paymentGasUsed` greater than the header's gas used, or any sum that would exceed 64 bits, is invalid, not saturated.
#### 3.5.5 What This Buys
-A recursion depth of one: a node needs nothing beyond its parent's header. Snap sync, restart from disk, reorg, and history pruning all reduce to reading a single header, so none of them require replaying history or retaining it.
+A recursion depth of one. Every input to the derivation comes from the parent header — its quota and payment gas from the commitment, its gas used and gas limit from the header proper — except the governable parameters, which are read from the parent's post-state like any other governed value. No block older than the parent is ever consulted. Snap sync, restart from disk, reorg, and history pruning therefore all reduce to reading one header against state the node already holds, with no history to replay and none to retain.
### 3.6 Parameters, Invariants, and Governance
@@ -398,13 +402,13 @@ The initial category-③ list is empty; tokens are nominated individually as aud
**Unused quota is idle, not reclaimable.** If the shortfall flowed back to general transactions, excluding payment transactions would cost a producer nothing — the space would simply be resold, and the floor would be a fiction precisely in the congested moments it exists for. Making the reservation binding regardless of realized payment demand inverts the economics: the reserved gas produces fees only when payment transactions fill it, so including them is the only way to monetize it, and excluding them yields nothing. The waste in quiet blocks is bounded (at most the quota minimum, a low single-digit percent of the block) and is the price of the guarantee being real.
-**Congestion-only signal, no motive judgment.** Any signal that tries to classify *why* the chain is congested — for example, the share of payment transactions among recent traffic — is written by whoever selects transactions, and can be steered at near-zero cost to keep the quota from ever expanding. Total general-transaction gas usage, by contrast, is aligned with fee revenue: a demand pulse produces high usage exactly because producers are including the paying transactions in front of them, and suppressing the signal means leaving those fees uncollected. Denying congestion is possible only at the cost of forgoing income. The rule is therefore deliberately reduced to *congestion expands the quota, regardless of cause*. The cost of this simplification — congestion unrelated to payments also triggers expansion — is bounded by the quota maximum and self-corrects within blocks once congestion clears.
+**Congestion-only signal, no motive judgment.** Any signal that tries to classify *why* the chain is congested — for example, the share of payment transactions among recent traffic — is written by whoever selects transactions, and can be steered at near-zero cost to keep the quota from ever expanding. `signalGasUsed` ([§3.4.2](#342-the-congestion-signal)), by contrast, counts only gas that competed on the open market, and every unit of it is aligned with fee revenue: a demand pulse produces high usage exactly because producers are including the paying transactions in front of them, and suppressing the signal means leaving those fees uncollected. Denying congestion is possible only at the cost of forgoing income. The rule is therefore deliberately reduced to *congestion expands the quota, regardless of cause*. The cost of this simplification — congestion unrelated to payments also triggers expansion — is bounded by the quota maximum, and unwinds through the contraction path once congestion clears, so it lasts as long as the congestion does and no longer.
**Fast expansion, slow contraction, with hysteresis.** Expansion must outpace the demand pulse it protects against, while contraction can afford patience; the asymmetry (enforced as invariant 2) guarantees that under sawtooth pulses, protection is in place before space is returned. The hysteresis band (invariant 1) keeps boundary-hovering usage from thrashing the quota.
**Ratio and absolute bounds together.** Ratio bounds let the quota scale automatically with block capacity so the mechanism never needs re-tuning as GasLimit grows; absolute bounds cap its footprint so growth in block size can never silently grow the reservation beyond an intended ceiling.
-**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim. Categories ②/③ admit only contracts whose entire function surface is value transfer — vetted by governance with audit backing for ②, guaranteed by protocol construction for ③.
+**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim. For category ③ the narrowness of the function surface is guaranteed by BEP-702's construction. For category ② nothing enforces it mechanically; it rests on governance vetting and continued monitoring, a trade [§3.7](#37-payment-contract-list) states in full.
The price of that choice is that a transaction is classified one state transition before it runs. Category ① rules out every statically visible route to code execution — code-setting and blob-carrying transaction types, access lists, precompile destinations, and accounts that already hold code — but it cannot see a deployment or a delegation authorisation that lands earlier in the same block. A transfer to such an account executes code inside the lane, consuming at most its own gas limit.
@@ -427,7 +431,7 @@ Outside congestion (the overwhelming majority of blocks), the quota rests at its
- **Bounded waste.** Idle reserved gas is capped per block by `PAYMENT_LANE_MAX` and by the ratio ceiling, and the quota cannot grow past those bounds. The bound is per block, not cumulative over time: while the signal that raised the quota persists, so does the waste. It unwinds only through the contraction path, once that signal clears.
- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.7](#37-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
-- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can configure a thrashing, inverted, or degenerate quota.
+- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can invert the two thresholds, invert the two steps, take a step wide enough to cross the hysteresis band, or set a maximum the quota could never reach. What they cannot guarantee is a wide effective range: the absolute and ratio bounds narrow it independently, and by how much depends on `GasLimit`, which is unknown at validation time (invariant (3)). A narrow range leaves the quota near-constant — the dynamic behaviour is lost, but no rule is violated.
## 7. License
From 5aac94eba8d4116d7b32e31fc6e95a5ed5fcee94 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 09:26:56 +0800
Subject: [PATCH 10/29] bep703: refine again
---
BEPs/BEP-703.md | 55 ++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 47 insertions(+), 8 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index fb9e7613..35415a9d 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -31,6 +31,7 @@
- [3.5.5 What This Buys](#355-what-this-buys)
- [3.6 Parameters, Invariants, and Governance](#36-parameters-invariants-and-governance)
- [3.7 Payment Contract List](#37-payment-contract-list)
+ - [3.8 System Contract](#38-system-contract)
- [4. Rationale](#4-rationale)
- [5. Backward Compatibility](#5-backward-compatibility)
- [6. Security Considerations](#6-security-considerations)
@@ -46,7 +47,11 @@ BSC fixes the base fee at zero ([BEP-226](./BEP226.md)), so transaction inclusio
This is not a capacity problem. BSC's throughput is on a sustained upward path, and total block space comfortably exceeds payment demand at all times. The defect is structural: heterogeneous traffic shares one undifferentiated bidding dimension, so local congestion in one class propagates to unrelated classes. A bounded, protocol-level reservation for the payment class severs that propagation path at negligible cost to everything else — and does so without touching the fee market or the ordering rules that the rest of the ecosystem relies on.
-What that buys is precise, and worth stating before the rules that deliver it. Up to the reserved amount, payment traffic no longer bids against the pulse at all: the space is there whatever the general market is paying, so a transfer that could not have re-priced itself does not need to. Beyond the reserved amount nothing changes — payment traffic bids as it does today, and payment transactions compete among themselves for the reservation on the ordinary fee rules ([§6](#6-security-considerations)). The reservation therefore removes the *general* market as a source of payment crowd-out, up to its size; it does not make any individual transfer unconditionally includable.
+What that buys is worth stating precisely, before the rules that deliver it.
+
+**Guaranteed.** Up to the reserved amount, payment traffic does not bid against the general market at all: the space is there whatever that market is paying, so a transfer that could not have re-priced itself does not need to.
+
+**Not guaranteed.** That any particular transaction is included; that any fixed number of transactions is included; that fees inside the reservation stay low. Beyond the reserved amount payment traffic bids exactly as it does today, and within it payment transactions compete among themselves on the ordinary fee rules ([§6](#6-security-considerations)).
## 3. Specification
@@ -114,6 +119,18 @@ For category ①, the no-code requirement is checked against the parent block's
For categories ② and ③, classification after list membership is settled is a static lookup on the `to` address. In all three categories, any node can classify a transaction without executing it, so classification adds no consensus overhead.
+In full:
+
+```
+classify(tx, parentState):
+ if tx.to in paymentContractList(parentState): return PAYMENT # 2 and 3
+ if tx.type in {0x00, 0x01, 0x02}
+ and tx.to != nil and not isPrecompile(tx.to)
+ and tx.data is empty and tx.accessList is empty
+ and parentState.codeAt(tx.to) is empty: return PAYMENT # 1
+ return GENERAL
+```
+
Classification requires nothing from users or wallets: which address a transaction is sent to, and which asset it moves, are already determined by the underlying business action. The lane assignment is the protocol recognizing an existing fact, not a new field or declaration.
### 3.3 Reserved Gas Accounting Rule
@@ -183,6 +200,8 @@ signalGasUsed(h−1) <= GasLimit(h−1) − paymentLaneSize(h−1)
which a full block attains, so the bound is tight. The signal is therefore capped at `1 − paymentLaneSize/GasLimit` — a ceiling set by the controller's own output. Two things follow. Growth in the quota lowers every later reading and so damps further growth, which is stabilising; it also means a saturated block reads lower the larger the quota is, and the controller loses the ability to tell a barely full block from a heavily oversubscribed one. And expansion can only fire while the quota sits below `RATIO_DENOM − EXPAND_TRIGGER_RATIO` of the block, whatever maximum is configured; invariant (5) in [§3.6](#36-parameters-invariants-and-governance) keeps the configured maximum within that reach.
+One block a day is unlike the others. Parlia's daily validator-set update is a system transaction of roughly 12.16M gas — about 22 points of signal on a 55M block — and it is general gas like any other, so it enters `signalGasUsed`. That block therefore reads higher than its market traffic alone would justify, and can cross the expansion threshold on its own where organic usage is already high. The effect is a single step, unwound by the contraction path over the blocks that follow.
+
#### 3.4.3 The Step
```
@@ -282,6 +301,8 @@ Requiring the reserved bytes to be zero makes the encoding canonical — exactly
#### 3.5.3 Why `UncleHash`
+That the state must be carried explicitly is a conclusion; which field carries it is not. The choice below is specific to BSC and is not forced by the argument above.
+
Parlia does not permit uncles, so `UncleHash` carries no information on BSC and is pinned to the empty-list hash in every block today. Reusing it adds no header field, no size increase, and no change to block encoding; and the field already sits inside the producer's seal, so authentication costs nothing.
This BEP claims `header.UncleHash` exclusively — no other use of the field is defined. `ParentBeaconRoot` is unaffected.
@@ -296,13 +317,18 @@ From `activation + 1` onward:
| Check | Where | Why there |
|---|---|---|
-| Reserved bytes are zero | Header verification | A pure function of the header; no state required |
-| `paymentLaneSize` matches the value derived from the parent | Block execution | The derivation reads governable parameters from the parent's post-state |
+| Reserved bytes are zero | Header verification | A pure function of the header |
+| The accounting rule of [§3.3](#33-reserved-gas-accounting-rule) holds on the committed values | Header verification | `generalGasUsed` is the header's gas used less `paymentGasUsed`, so the inequality needs no execution |
+| `paymentLaneSize` matches the value derived from the parent | Before execution, against the parent's post-state | The derivation reads governable parameters from that state, but nothing from this block beyond its header |
| `paymentGasUsed` matches the value obtained by re-execution | Block execution | Requires running the block |
+Only the last of these requires running the block.
+
The value checks are not optional. An accepted, incorrect `paymentLaneSize` becomes the base of the recurrence for every descendant, and because every node reads the same parent header the chain does not fork — it silently converges on a destroyed lane, or on a general market permanently starved by an oversized reservation.
-The same checks apply on the builder path: a block received under [BEP-675](./BEP-675.md) MUST be validated against these rules before a validator signs it. There the commitment arrives as 32 bytes chosen by the builder. Values decoded from it are untrusted input, not quantities produced by the recurrence: a client MUST range-check them and reject the block — `paymentGasUsed` greater than the header's gas used, or any sum that would exceed 64 bits, is invalid, not saturated.
+The split matters most on the builder path. Under [BEP-675](./BEP-675.md) a validator seals a builder-supplied block without executing it, and the commitment arrives as 32 bytes chosen by the builder. Everything decidable without running the block belongs with the pre-seal header checks a validator already performs on fields derived from the parent — including `paymentLaneSize`, since the validator holds the parent's post-state there. Values decoded from the commitment are untrusted input, not quantities produced by the recurrence: a client MUST range-check them and reject the block — `paymentGasUsed` greater than the header's gas used, or any sum that would exceed 64 bits, is invalid, not saturated.
+
+Only `paymentGasUsed` needs the block to be run, and it is checked where every other execution result is. That is not a weakening: the rule binds every node identically on import, so a false value yields a block no node accepts. It does carry one implementation consequence. The commitment sits outside execution, so a false `paymentGasUsed` leaves the state and receipts roots intact — the mismatch must fail import on its own account, or nothing catches it.
#### 3.5.5 What This Buys
@@ -310,7 +336,7 @@ A recursion depth of one. Every input to the derivation comes from the parent he
### 3.6 Parameters, Invariants, and Governance
-The adjustment algorithm itself (the signal, the hysteresis structure, the accounting rule) is protocol logic and is not governable. The values that drive it are governable parameters, taking effect only through the standard BSC on-chain governance process:
+The adjustment algorithm itself (the signal, the hysteresis structure, the accounting rule) is protocol logic and is not governable. The values that drive it are governable parameters, held in the system contract of [§3.8](#38-system-contract) and taking effect only through the standard BSC on-chain governance process:
| Name | Meaning | Kind |
|---|---|---|
@@ -382,9 +408,9 @@ Invariant check:
### 3.7 Payment Contract List
-Categories ② and ③ are defined by a **payment contract list** maintained in a system contract and updatable only through the standard BSC governance process (validator voting). Classification reads list membership as of the parent block's final state, so a list change never affects the block that contains it.
+Categories ② and ③ are defined by a **payment contract list** maintained in the system contract of [§3.8](#38-system-contract) and updatable only through the standard BSC governance process (validator voting). Classification reads list membership as of the parent block's final state, so a list change never affects the block that contains it. Listing is by address: any transaction whose `to` is a listed address is a payment transaction, whatever function it calls. The list curates assets, not operations.
-**Category ② — stablecoins.** Admission is decided entirely by governance nomination, on the strength of off-chain audit history and long-accumulated on-chain reputation. The initial list is USDT and USDC only: USDT's contract is non-upgradeable and its bytecode has been fixed since deployment; USDC, while an upgradeable proxy, undergoes rigorous off-chain audit for every upgrade with extensive reputational backing and market scrutiny. Because the protocol imposes no mechanical gate here, governance carries both the nomination and the ongoing-monitoring responsibility: if a listed contract's behavior materially changes, removal depends on governance acting, not on an automatic protocol trigger. This is an explicit, acknowledged trust extended to assets whose reputation is already thoroughly established — whether future additions receive the same treatment or stricter verification is for governance to decide case by case.
+**Category ② — stablecoins.** Admission is decided by governance nomination alone, on the strength of off-chain audit history and accumulated on-chain reputation. The initial list is USDT and USDC: USDT's contract is non-upgradeable and its bytecode fixed since deployment; USDC is an upgradeable proxy, audited on every upgrade under considerable market scrutiny. The protocol imposes no mechanical gate here, so governance carries the ongoing monitoring as well as the nomination — if a listed contract's behaviour materially changes, removal depends on governance acting. This is an explicit, acknowledged trust, extended to two assets whose reputation is already established; whether later additions get the same treatment is for governance to decide.
**Category ③ — BEP-702 native tokens.** Tokens under [BEP-702](./BEP-702.md) are protocol-native: they deploy no bytecode, cannot self-destruct, expose a function surface fixed by the protocol standard, and have no upgradeable implementation to drift. The properties an arbitrary contract would need audits or reputation to establish hold for these tokens by construction. Admission therefore requires:
@@ -396,6 +422,17 @@ The initial category-③ list is empty; tokens are nominated individually as aud
**Removal is symmetric with admission.** Governance MAY at any time, through the same validator-voting process, remove any listed address from either category. Because classification reads the parent block's final state, a removal takes effect from the block after it lands on-chain; transactions to the removed address are simply classified as general transactions thereafter — they remain fully valid and are included under the ordinary rules, so removal strips lane eligibility and nothing else. For both categories the rollout pace rests entirely with governance, and governance's power is bounded: it can delay an asset's admission by not nominating it, but nomination and removal votes are public and accountable, and for category ③ governance cannot override or weaken the guarantees BEP-702 itself provides.
+### 3.8 System Contract
+
+*TBD.*
+
+The governable parameters of [§3.6](#36-parameters-invariants-and-governance) and the payment contract list of [§3.7](#37-payment-contract-list) both live in a system contract, and both are read from the parent block's final state. This section will fix the parts an implementation cannot infer from the rules above:
+
+- the contract's address, and its storage layout for the parameter set and for a list entry;
+- the update interface, and which of BSC's existing governance paths reaches it;
+- when a change takes effect, stated against the same block boundary the rest of this specification uses;
+- how the invariants of [§3.6](#36-parameters-invariants-and-governance) are enforced on chain. In particular, what "a governance proposal violating any of them is invalid and never activates" means as contract behaviour: whether such a proposal is rejected at submission, reverts at execution, or is accepted and ignored — and what a node observes in each case.
+
## 4. Rationale
**A quota, not a region.** Reserving a gas amount rather than partitioning the block preserves everything about how blocks are built today. Producers keep complete freedom of selection and ordering; transactions of both classes interleave arbitrarily; the existing priority-fee market operates untouched for all traffic, payment traffic included. The entire proposal is one additional accounting inequality checked at block validation.
@@ -418,6 +455,8 @@ Closing that gap would mean classifying against execution-time state, which open
This is a consensus-breaking change and requires a hard fork: it adds a new block validity rule, the associated quota computation, and a header commitment. It changes no transaction format, no fee mechanism, and no ordering rule — the existing transaction ordering and inclusion mechanics of the ecosystem are unaffected, for every class of transaction. Wallets, exchanges, and applications that submit and read transactions require no modification.
+Node implementations, on the other hand, change substantially: the accounting rule, the quota recurrence, the commitment encoding, and the four uncle-validation paths named in [§3.5.3](#353-why-unclehash) all need fork-gated changes.
+
Two observable values do change, and downstream tooling should account for both:
- `sha3Uncles` is no longer the constant empty-list hash ([§3.5.3](#353-why-unclehash)). Any consumer that compares it against that constant, or derives the uncle list from it, must be updated.
@@ -427,7 +466,7 @@ Outside congestion (the overwhelming majority of blocks), the quota rests at its
## 6. Security Considerations
-- **Spam within the lane.** The quota does not grant free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so flooding the lane costs fees like any other spam. Sustained payment traffic beyond the quota does raise the congestion signal and expand the reservation ([§3.4.2](#342-the-congestion-signal)), and general traffic bears that in later blocks. The exposure is bounded by `PAYMENT_LANE_MAX`, unwinds through the contraction path once the signal clears, and materialises at all only when general traffic is itself congested — in which case its own usage would have expanded the quota anyway. The flood is paid for at full fees throughout.
+- **Spam within the lane.** The quota does not grant free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so flooding the lane costs fees like any other spam. Sustained payment traffic beyond the quota does raise the congestion signal and expand the reservation ([§3.4.2](#342-the-congestion-signal)), and general traffic bears that in later blocks. The exposure is bounded by `PAYMENT_LANE_MAX`, unwinds through the contraction path once the signal clears, and materialises at all only when general traffic is itself congested — in which case its own usage would have expanded the quota anyway. The flood is paid for at full fees throughout. Note that the reservation bounds volume, not the size of any one transaction: a single payment transaction may occupy all of it.
- **Bounded waste.** Idle reserved gas is capped per block by `PAYMENT_LANE_MAX` and by the ratio ceiling, and the quota cannot grow past those bounds. The bound is per block, not cumulative over time: while the signal that raised the quota persists, so does the waste. It unwinds only through the contraction path, once that signal clears.
- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.7](#37-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
From ae2ec5c192896e771dc463415a169ee852376376 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 14:01:06 +0800
Subject: [PATCH 11/29] chore: do some refine
---
BEPs/BEP-703.md | 66 ++++++++++++++++++++-----------------------------
1 file changed, 27 insertions(+), 39 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 35415a9d..21f0cf58 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -47,12 +47,6 @@ BSC fixes the base fee at zero ([BEP-226](./BEP226.md)), so transaction inclusio
This is not a capacity problem. BSC's throughput is on a sustained upward path, and total block space comfortably exceeds payment demand at all times. The defect is structural: heterogeneous traffic shares one undifferentiated bidding dimension, so local congestion in one class propagates to unrelated classes. A bounded, protocol-level reservation for the payment class severs that propagation path at negligible cost to everything else — and does so without touching the fee market or the ordering rules that the rest of the ecosystem relies on.
-What that buys is worth stating precisely, before the rules that deliver it.
-
-**Guaranteed.** Up to the reserved amount, payment traffic does not bid against the general market at all: the space is there whatever that market is paying, so a transfer that could not have re-priced itself does not need to.
-
-**Not guaranteed.** That any particular transaction is included; that any fixed number of transactions is included; that fees inside the reservation stay low. Beyond the reserved amount payment traffic bids exactly as it does today, and within it payment transactions compete among themselves on the ordinary fee rules ([§6](#6-security-considerations)).
-
## 3. Specification
### 3.1 Block Space Model
@@ -111,15 +105,9 @@ A transaction is a **payment transaction** if and only if it belongs to one of t
| ② Listed stablecoin contracts | Initially USDT and USDC only | Governance nomination ([§3.7](#37-payment-contract-list)) |
| ③ Listed [BEP-702](./BEP-702.md) native tokens | Tokens created under the New Tokens on BNB Smart Chain standard | Protocol-native validity checks + governance nomination ([§3.7](#37-payment-contract-list)) |
-The conditions fall into two groups. Four of them pin the transaction's intrinsic cost at exactly 21000 gas: `to` non-nil rules out contract creation, empty `data` rules out calldata cost, an empty `accessList` rules out the 2400 gas per address and 1900 per storage key that an access list is charged regardless of whether `data` is empty, and the type allowlist rules out the per-authorisation cost of a code-setting transaction. The allowlist also keeps blob-carrying transactions out of the class, which is a separate resource question rather than a gas one.
-
-The other two bar code execution. The no-code test is the obvious one. The precompile exclusion is needed because a precompile address holds no code in state and so passes that test, yet a call to one runs the precompile — and a precompile that rejects its input consumes every unit of gas the call was given. The precompile set is fixed by the fork schedule, so this is a static address check like the rest.
+Four of the category-① conditions pin the intrinsic cost at exactly 21000 gas: `to` non-nil rules out contract creation, empty `data` rules out calldata cost, an empty `accessList` rules out the 2400 gas per address and 1900 per storage key it would otherwise be charged, and the type allowlist rules out the per-authorisation cost of a code-setting transaction, and blob-carrying types with it. The other two bar code execution: the account at `to` holds no code, and `to` is not a precompile — a precompile holds no code either, so it passes the first test, yet a call to one runs it, and a precompile that rejects its input consumes every unit of gas the call was given. The precompile set is fixed by the fork schedule, so the check stays static.
-For category ①, the no-code requirement is checked against the parent block's final state, so an account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator has code and is excluded. Reading the parent state does leave one gap: if the account at `to` acquires code earlier in the same block, through a deployment or a delegation authorisation, the transfer will call into it and execute code inside the lane. What that costs is bounded by the transaction's own gas limit, and it is accounted to the payment class like any other payment gas. [§4](#4-rationale) explains why classification is nevertheless not moved to execution time.
-
-For categories ② and ③, classification after list membership is settled is a static lookup on the `to` address. In all three categories, any node can classify a transaction without executing it, so classification adds no consensus overhead.
-
-In full:
+Everything above reads static transaction fields and the parent block's final state, so any node can classify a transaction without executing it and classification adds no consensus overhead. An account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator holds code and so fails the no-code test. Reading the parent state has one consequence, though: an account that acquires code earlier in the same block, by deployment or by a delegation authorisation, is still classified as having none, and the transfer then executes that code inside the lane, bounded by its own gas limit. [§4](#4-rationale) explains why classification is nevertheless not moved to execution time.
```
classify(tx, parentState):
@@ -131,8 +119,6 @@ classify(tx, parentState):
return GENERAL
```
-Classification requires nothing from users or wallets: which address a transaction is sent to, and which asset it moves, are already determined by the underlying business action. The lane assignment is the protocol recognizing an existing fact, not a new field or declaration.
-
### 3.3 Reserved Gas Accounting Rule
For each block, let:
@@ -162,17 +148,25 @@ The rule constrains only gas totals. It says nothing about where transactions si
`paymentLaneSize` is an accumulator, not a function of the current block. Each block moves it by one step or holds it, according to how congested its parent was; where it stands today is the result of every step taken since the lane took effect, clamped back into range at each one. [§3.5](#35-header-commitment) explains why that memory cannot be avoided, and how a node obtains it without replaying history.
-Throughout, `h` is the block being built or validated and `h−1` is its parent. Every ratio-typed parameter is an integer in basis points against `RATIO_DENOM = 10000` and MUST lie in `[0, RATIO_DENOM]`. Conversions to gas multiply before they divide and truncate toward zero. Quantities are unsigned 64-bit integers and arithmetic on them saturates: a subtraction that would fall below zero yields zero. Products of a ratio and a gas amount MUST be computed with widened intermediates — BSC's consensus bounds `GasLimit` only by `2^63 − 1`, and `RATIO_DENOM × GasLimit` leaves 64 bits once `GasLimit` passes roughly `2^50.7`. No part of this computation uses floating point, and no comparison uses division.
+Throughout, `h` is the block being built or validated and `h−1` is its parent. The arithmetic below is consensus-critical, so each step is pinned:
+
+- **Ratios** are integers against `RATIO_DENOM = 10000`: a stored `N` means `N / 10000`, and MUST lie in `[0, RATIO_DENOM]`.
+- **Converting a ratio to gas** multiplies before dividing and truncates toward zero.
+- **Quantities** are unsigned 64-bit integers; subtraction saturates at zero.
+- **A ratio times a gas amount** MUST use widened intermediates: the product exceeds 64 bits above `GasLimit ≈ 2^50.7`, and consensus bounds `GasLimit` only by `2^63 − 1`.
+- **No floating point**, and no comparison done by division.
#### 3.4.1 The Recurrence
+For every block from `activation + 1`:
+
```
-paymentLaneSize(h) = clamp( paymentLaneSize(h−1) + step(h), laneMin(h), laneMax(h) )
+paymentLaneSize(h) =
+ laneMin(h) h = activation + 1
+ clamp( paymentLaneSize(h−1) + step(h), laneMin(h), laneMax(h) ) h > activation + 1
```
-This governs every block from `activation + 2`; [§3.4.5](#345-activation) gives the two blocks before it.
-
-The clamp applies to the carried state, not merely to the value the current block uses. A quota allowed to accumulate past its bound through a long congestion episode would take just as long to unwind afterwards, and would stop tracking the signal entirely.
+The base case needs no clamp: [§3.4.4](#344-bounds) puts `laneMin(h)` inside the range by construction.
#### 3.4.2 The Congestion Signal
@@ -242,13 +236,7 @@ Bounds are re-evaluated and the clamp re-applied on every block, including block
A system contract upgrade takes effect at the end of the block that carries it, so this BEP's parameters are first readable by the block after activation. The activation block does nothing but deploy them: it is not subject to the accounting rule in [§3.3](#33-reserved-gas-accounting-rule), and it carries no commitment.
-The lane applies from `activation + 1`. That block has no parent commitment to derive from, so its quota is not produced by the recurrence but taken directly from the floor:
-
-```
-paymentLaneSize(activation + 1) = laneMin(activation + 1)
-```
-
-It is subject to the accounting rule, and it carries the first commitment ([§3.5](#35-header-commitment)). From `activation + 2` onward the recurrence in [§3.4.1](#341-the-recurrence) runs unchanged, each block deriving its quota from its parent's commitment. No block before `activation + 1` is ever read by the recurrence, so no earlier block needs a class split it does not have.
+The lane applies from `activation + 1`. That block is subject to the accounting rule and carries the first commitment ([§3.5](#35-header-commitment)); having no parent commitment to derive from, it takes its quota from the floor — the base case of the recurrence in [§3.4.1](#341-the-recurrence). No block before `activation + 1` is ever read, so no earlier block needs a class split it does not have.
#### 3.4.6 Worked Example
@@ -344,10 +332,10 @@ The adjustment algorithm itself (the signal, the hysteresis structure, the accou
| `PAYMENT_LANE_MAX_RATIO` | Ratio upper bound | Governable |
| `PAYMENT_LANE_MIN` | Absolute lower bound (gas) | Governable |
| `PAYMENT_LANE_MAX` | Absolute upper bound (gas) | Governable |
-| `EXPAND_TRIGGER_RATIO` | Congestion threshold that triggers expansion | Governable |
-| `SHRINK_TRIGGER_RATIO` | Slack threshold that triggers contraction | Governable |
-| `EXPAND_STEP` | Per-block expansion step | Governable |
-| `SHRINK_STEP` | Per-block contraction step | Governable |
+| `EXPAND_TRIGGER_RATIO` | Congestion threshold that triggers expansion (ratio) | Governable |
+| `SHRINK_TRIGGER_RATIO` | Slack threshold that triggers contraction (ratio) | Governable |
+| `EXPAND_STEP` | Per-block expansion step (ratio) | Governable |
+| `SHRINK_STEP` | Per-block contraction step (ratio) | Governable |
| `TRIGGER_GAP_MIN` | Minimum hysteresis band width, fixed at 1000 (10%) | Protocol constant |
| `RATIO_GAP_MIN` | Minimum ratio range width, fixed at 500 (5%) | Protocol constant |
| `RATIO_DENOM` | Denominator of every ratio parameter, fixed at 10000 | Protocol constant |
@@ -393,15 +381,15 @@ Governable parameters are not free-form. The following invariants are validated
Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
```
-PAYMENT_LANE_MIN_RATIO = 2% PAYMENT_LANE_MAX_RATIO = 8%
-PAYMENT_LANE_MIN = 2M gas PAYMENT_LANE_MAX = 8M gas
-EXPAND_TRIGGER_RATIO = 80% SHRINK_TRIGGER_RATIO = 70%
-EXPAND_STEP = 2pp/block SHRINK_STEP = 0.5pp/block
+PAYMENT_LANE_MIN_RATIO = 200 (2%) PAYMENT_LANE_MAX_RATIO = 800 (8%)
+PAYMENT_LANE_MIN = 2M gas PAYMENT_LANE_MAX = 8M gas
+EXPAND_TRIGGER_RATIO = 8000 (80%) SHRINK_TRIGGER_RATIO = 7000 (70%)
+EXPAND_STEP = 200 (2%) SHRINK_STEP = 50 (0.5%)
Invariant check:
- (1) 80−70 = 10 >= 10 ✓ (2) 2pp > 0.5pp > 0 ✓
- (3) 8−2 = 6 >= 5 ✓ (4) 8M > 2M > 0 ✓
- (5) 8% <= 100−80 = 20% ✓ (6) 2pp <= 80−70 = 10pp ✓
+ (1) 8000−7000 = 1000 >= 1000 ✓ (2) 200 > 50 > 0 ✓
+ (3) 800−200 = 600 >= 500 ✓ (4) 8M > 2M > 0 ✓
+ (5) 800 <= 10000−8000 = 2000 ✓ (6) 200 <= 8000−7000 = 1000 ✓
```
[§3.4.6](#346-worked-example) works these values through a congestion episode.
From 28008007bc119fbfff642ba424a72b4871e6b134 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 17:37:34 +0800
Subject: [PATCH 12/29] bep703: refine The Congestion Signal
---
BEPs/BEP-703.md | 21 ++++-----------------
1 file changed, 4 insertions(+), 17 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 21f0cf58..ec2a6f79 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -174,11 +174,7 @@ The base case needs no clamp: [§3.4.4](#344-bounds) puts `laneMin(h)` inside th
signalGasUsed(h−1) = generalGasUsed(h−1) + max(0, paymentGasUsed(h−1) − paymentLaneSize(h−1))
```
-`signalGasUsed` is the gas that competed for space on the open market: all general gas, plus any payment gas beyond the reservation, which bid for the remaining space on equal terms with general traffic. It excludes the payment gas the reservation actually covered — that gas competed for nothing.
-
-The exclusion is what keeps the lane from bootstrapping itself. Were reserved gas counted, an attacker could fill the lane with minimum-cost transfers, drive the signal up, and grow the reservation — using traffic that is sheltered from competition by the very reservation it is enlarging.
-
-Payment gas beyond the reservation is kept for the opposite reason: it did compete, outbidding general traffic for space that general could otherwise have used, so the open market really was contested. Keeping it does mean that sustained payment overflow expands the quota. That is intended, and its reach is narrow. Overflow is non-zero only when `paymentGasUsed > paymentLaneSize`, and in exactly those blocks `max(paymentGasUsed, paymentLaneSize)` equals `paymentGasUsed`, so the quota constrains nothing. The two regimes do not overlap: the overflow term can only pre-position the floor for later blocks, never take space from general traffic in the block that raised it.
+`signalGasUsed` is the gas that competed on the open market: all general gas, plus payment gas beyond the reservation, which bid for the remaining space on equal terms. Gas the reservation covered is excluded — that space was closed to general traffic whether payment used it or not, so counting it would report contention that never happened, and would let the lane grow itself.
Thresholds are compared without dividing:
@@ -186,16 +182,6 @@ Thresholds are compared without dividing:
signalGasUsed(h−1) × RATIO_DENOM vs trigger(h−1) × GasLimit(h−1)
```
-The accounting rule in [§3.3](#33-reserved-gas-accounting-rule) caps this signal. Substituting `max(p, L) = L + max(0, p − L)` into that rule gives
-
-```
-signalGasUsed(h−1) <= GasLimit(h−1) − paymentLaneSize(h−1)
-```
-
-which a full block attains, so the bound is tight. The signal is therefore capped at `1 − paymentLaneSize/GasLimit` — a ceiling set by the controller's own output. Two things follow. Growth in the quota lowers every later reading and so damps further growth, which is stabilising; it also means a saturated block reads lower the larger the quota is, and the controller loses the ability to tell a barely full block from a heavily oversubscribed one. And expansion can only fire while the quota sits below `RATIO_DENOM − EXPAND_TRIGGER_RATIO` of the block, whatever maximum is configured; invariant (5) in [§3.6](#36-parameters-invariants-and-governance) keeps the configured maximum within that reach.
-
-One block a day is unlike the others. Parlia's daily validator-set update is a system transaction of roughly 12.16M gas — about 22 points of signal on a 55M block — and it is general gas like any other, so it enters `signalGasUsed`. That block therefore reads higher than its market traffic alone would justify, and can cross the expansion threshold on its own where organic usage is already high. The effect is a single step, unwound by the contraction path over the blocks that follow.
-
#### 3.4.3 The Step
```
@@ -364,8 +350,9 @@ Governable parameters are not free-form. The following invariants are validated
The absolute range must be non-empty.
(5) PAYMENT_LANE_MAX_RATIO <= RATIO_DENOM − EXPAND_TRIGGER_RATIO
- Expansion only fires while the quota is below RATIO_DENOM −
- EXPAND_TRIGGER_RATIO of the block (3.4.2). Without this bound the
+ Reserved gas never competes, so the signal cannot exceed the unreserved
+ part of the block and expansion cannot fire once the quota reaches
+ RATIO_DENOM − EXPAND_TRIGGER_RATIO of it. Without this bound the
configured maximum is unreachable: under saturated demand the quota
stalls just past that point and stays there, leaving governance with a
ceiling the mechanism can never use.
From 04dc1c1bfd54fef66cb55e8b61d60d0270973b11 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 18:01:39 +0800
Subject: [PATCH 13/29] bep-703: refine The Step
---
BEPs/BEP-703.md | 39 ++++++++++++++++++---------------------
1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index ec2a6f79..9397827b 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -154,6 +154,7 @@ Throughout, `h` is the block being built or validated and `h−1` is its parent.
- **Converting a ratio to gas** multiplies before dividing and truncates toward zero.
- **Quantities** are unsigned 64-bit integers; subtraction saturates at zero.
- **A ratio times a gas amount** MUST use widened intermediates: the product exceeds 64 bits above `GasLimit ≈ 2^50.7`, and consensus bounds `GasLimit` only by `2^63 − 1`.
+- **Governable parameters** are read from the parent's post-state and carry the index `(h−1)`; protocol constants carry none, because they never change.
- **No floating point**, and no comparison done by division.
#### 3.4.1 The Recurrence
@@ -186,29 +187,25 @@ signalGasUsed(h−1) × RATIO_DENOM vs trigger(h−1) × GasLimit(h−1)
```
step(h) =
- + EXPAND_STEP × GasLimit(h) / RATIO_DENOM
- if signalGasUsed(h−1) × RATIO_DENOM >= EXPAND_TRIGGER_RATIO × GasLimit(h−1)
+ + EXPAND_STEP_RATIO(h−1) × GasLimit(h) / RATIO_DENOM
+ if signalGasUsed(h−1) × RATIO_DENOM >= EXPAND_TRIGGER_RATIO(h−1) × GasLimit(h−1)
- − SHRINK_STEP × GasLimit(h) / RATIO_DENOM
- if signalGasUsed(h−1) × RATIO_DENOM <= SHRINK_TRIGGER_RATIO × GasLimit(h−1)
+ − SHRINK_STEP_RATIO(h−1) × GasLimit(h) / RATIO_DENOM
+ if signalGasUsed(h−1) × RATIO_DENOM <= SHRINK_TRIGGER_RATIO(h−1) × GasLimit(h−1)
0 otherwise — the hysteresis band
```
-The three cases are exhaustive and mutually exclusive. Both thresholds are inclusive toward action, and invariant (1) keeps the expansion threshold strictly above the contraction threshold, so the band between them is where the quota holds and absorbs fluctuation.
-
-`EXPAND_STEP` and `SHRINK_STEP` are both positive; the direction is carried by the sign in the rule above, not by the parameter.
-
-The signal is measured against `GasLimit(h−1)` because that is the block whose congestion is being read, while the step is scaled by `GasLimit(h)` because that is the block whose space is being reserved. On BSC `GasLimit` moves by at most 1/1024 per block, so the two differ only marginally; both are header fields, so every node derives the same step.
+The condition reads `GasLimit(h−1)` because that is the block whose congestion is being measured; the step scales by `GasLimit(h)` because that is the block whose space is being reserved.
#### 3.4.4 Bounds
```
-laneMax(h) = min( PAYMENT_LANE_MAX_RATIO × GasLimit(h) / RATIO_DENOM,
- PAYMENT_LANE_MAX )
+laneMax(h) = min( PAYMENT_LANE_MAX_RATIO(h−1) × GasLimit(h) / RATIO_DENOM,
+ PAYMENT_LANE_MAX(h−1) )
-laneMin(h) = min( max( PAYMENT_LANE_MIN_RATIO × GasLimit(h) / RATIO_DENOM,
- PAYMENT_LANE_MIN ),
+laneMin(h) = min( max( PAYMENT_LANE_MIN_RATIO(h−1) × GasLimit(h) / RATIO_DENOM,
+ PAYMENT_LANE_MIN(h−1) ),
laneMax(h) )
```
@@ -318,10 +315,10 @@ The adjustment algorithm itself (the signal, the hysteresis structure, the accou
| `PAYMENT_LANE_MAX_RATIO` | Ratio upper bound | Governable |
| `PAYMENT_LANE_MIN` | Absolute lower bound (gas) | Governable |
| `PAYMENT_LANE_MAX` | Absolute upper bound (gas) | Governable |
-| `EXPAND_TRIGGER_RATIO` | Congestion threshold that triggers expansion (ratio) | Governable |
-| `SHRINK_TRIGGER_RATIO` | Slack threshold that triggers contraction (ratio) | Governable |
-| `EXPAND_STEP` | Per-block expansion step (ratio) | Governable |
-| `SHRINK_STEP` | Per-block contraction step (ratio) | Governable |
+| `EXPAND_TRIGGER_RATIO` | Congestion threshold that triggers expansion | Governable |
+| `SHRINK_TRIGGER_RATIO` | Slack threshold that triggers contraction | Governable |
+| `EXPAND_STEP_RATIO` | Per-block expansion step | Governable |
+| `SHRINK_STEP_RATIO` | Per-block contraction step | Governable |
| `TRIGGER_GAP_MIN` | Minimum hysteresis band width, fixed at 1000 (10%) | Protocol constant |
| `RATIO_GAP_MIN` | Minimum ratio range width, fixed at 500 (5%) | Protocol constant |
| `RATIO_DENOM` | Denominator of every ratio parameter, fixed at 10000 | Protocol constant |
@@ -334,7 +331,7 @@ Governable parameters are not free-form. The following invariants are validated
least the hysteresis floor; otherwise usage hovering near one boundary
makes the quota thrash block by block.
-(2) EXPAND_STEP > SHRINK_STEP > 0
+(2) EXPAND_STEP_RATIO > SHRINK_STEP_RATIO > 0
Fast expansion, slow contraction is a hard requirement, not advice:
protection must arrive before space is handed back, or a sawtooth
demand pattern contracts the quota faster than it can re-expand.
@@ -357,12 +354,12 @@ Governable parameters are not free-form. The following invariants are validated
stalls just past that point and stays there, leaving governance with a
ceiling the mechanism can never use.
-(6) EXPAND_STEP <= EXPAND_TRIGGER_RATIO − SHRINK_TRIGGER_RATIO
+(6) EXPAND_STEP_RATIO <= EXPAND_TRIGGER_RATIO − SHRINK_TRIGGER_RATIO
Where the signal responds to the quota at all it does so one for one
(3.4.2), so a step wider than the hysteresis band would carry the signal
from one trigger straight past the other and the quota would alternate
between expanding and contracting every block. Invariant (2) makes this
- bound SHRINK_STEP as well.
+ bound SHRINK_STEP_RATIO as well.
```
Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
@@ -371,7 +368,7 @@ Suggested initial values, for discussion rather than locked by this BEP — the
PAYMENT_LANE_MIN_RATIO = 200 (2%) PAYMENT_LANE_MAX_RATIO = 800 (8%)
PAYMENT_LANE_MIN = 2M gas PAYMENT_LANE_MAX = 8M gas
EXPAND_TRIGGER_RATIO = 8000 (80%) SHRINK_TRIGGER_RATIO = 7000 (70%)
-EXPAND_STEP = 200 (2%) SHRINK_STEP = 50 (0.5%)
+EXPAND_STEP_RATIO = 200 (2%) SHRINK_STEP_RATIO = 50 (0.5%)
Invariant check:
(1) 8000−7000 = 1000 >= 1000 ✓ (2) 200 > 50 > 0 ✓
From f0158e1f68f2166e80da3f030bfcf68c32f0a742 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 20:43:31 +0800
Subject: [PATCH 14/29] bep-703: refine Bounds
---
BEPs/BEP-703.md | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 9397827b..1af2970d 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -206,14 +206,10 @@ laneMax(h) = min( PAYMENT_LANE_MAX_RATIO(h−1) × GasLimit(h) / RATIO_DENOM,
laneMin(h) = min( max( PAYMENT_LANE_MIN_RATIO(h−1) × GasLimit(h) / RATIO_DENOM,
PAYMENT_LANE_MIN(h−1) ),
- laneMax(h) )
+ laneMax(h) ) <- so laneMin(h) <= laneMax(h) at every GasLimit
```
-Two limits meet in `laneMax`. The **ratio bound** expresses the ceiling as a fraction of `GasLimit`, so the reservation scales automatically as block capacity grows and never needs re-tuning — and shrinks with it, so the reservation stays proportionate however small blocks become. The **absolute bound** caps its size in gas regardless of how large blocks become, so capacity growth can never silently grow the reservation past an intended ceiling.
-
-`laneMin` is the larger of its own two bounds, then capped at `laneMax`. That final cap is what makes the range well defined: `laneMin(h) <= laneMax(h)` holds by construction at every `GasLimit`, so there is no empty range to resolve by convention.
-
-Bounds are re-evaluated and the clamp re-applied on every block, including blocks where `step(h)` is zero. A governance change that narrows the range therefore takes effect on the next block, rather than waiting for the next step.
+Each bound is the tighter of a ratio limit that tracks `GasLimit` and an absolute limit in gas ([§4](#4-rationale)). Both are recomputed every block, so the clamp of [§3.4.1](#341-the-recurrence) applies even where `step(h)` is zero.
#### 3.4.5 Activation
From 8995677f368932520775f3bfd772570d12cfefd8 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 21:06:08 +0800
Subject: [PATCH 15/29] bep-703: refine Activation / Worked Example
---
BEPs/BEP-703.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 1af2970d..994805cd 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -213,9 +213,9 @@ Each bound is the tighter of a ratio limit that tracks `GasLimit` and an absolut
#### 3.4.5 Activation
-A system contract upgrade takes effect at the end of the block that carries it, so this BEP's parameters are first readable by the block after activation. The activation block does nothing but deploy them: it is not subject to the accounting rule in [§3.3](#33-reserved-gas-accounting-rule), and it carries no commitment.
+`activation` is the block at which this fork takes effect and the system contract of [§3.8](#38-system-contract) first holds the parameters. Every derivation reads them from the parent's post-state ([§3.4](#34-dynamic-quota-adjustment)), so `activation + 1` is the first block that can read them, and the first the lane applies to. Block `activation` is outside the mechanism: not subject to the accounting rule of [§3.3](#33-reserved-gas-accounting-rule), and carrying no commitment.
-The lane applies from `activation + 1`. That block is subject to the accounting rule and carries the first commitment ([§3.5](#35-header-commitment)); having no parent commitment to derive from, it takes its quota from the floor — the base case of the recurrence in [§3.4.1](#341-the-recurrence). No block before `activation + 1` is ever read, so no earlier block needs a class split it does not have.
+`activation + 1` therefore reads parameters from its parent, but no commitment and no class split. That is what the base case of [§3.4.1](#341-the-recurrence) covers, and it is why no pre-fork block is ever asked for a split it never recorded.
#### 3.4.6 Worked Example
@@ -238,7 +238,7 @@ recovery signal <= 70%: 4.4M -> 2M in steps of 0.275M
9 blocks, about 4s
```
-At 4.4M the reservation is large enough for roughly 209 native transfers, or between 73 and 126 stablecoin transfers depending on the token and on whether the recipient already holds a balance — an illustration of capacity, not a guaranteed count. The rule reserves gas, and a single transaction may consume all of it. Between the bounds the quota moves in 1.1M steps, so the range holds four distinct levels: 2M, 3.1M, 4.2M and 4.4M. Note also that each boundary binds on one side only at this `GasLimit`: the ratio minimum (1.1M) sits below the absolute minimum, and the absolute maximum (8M) sits above the ratio maximum. At the maximum the signal ceiling is `1 − 4.4M/55M = 92%`, twelve points clear of the 80% expansion threshold, so the quota does reach 4.4M under sustained congestion.
+At 4.4M the reservation holds roughly 209 native transfers, or between 73 and 126 stablecoin transfers depending on the token and on whether the recipient already holds a balance — an illustration of capacity, not a guaranteed count.
### 3.5 Header Commitment
From e78d908736b16eb5557d01175a6109613ffb8fe0 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 22:29:21 +0800
Subject: [PATCH 16/29] bep-703: refine Header Commitment
---
BEPs/BEP-703.md | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 994805cd..ebc88eea 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -246,11 +246,7 @@ At 4.4M the reservation holds roughly 209 native transfers, or between 73 and 12
To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. The split requires the state as of `h−2` to classify `h−1`'s transactions, and the quota chains back, block by block, to `activation + 1`.
-Suppose the quota were not committed, and a node derived it instead from a bounded window of the `K` most recent blocks. No `K` works. Fix one; hold `GasLimit` and the governable parameters constant, and take a range that is not degenerate (`laneMin < laneMax`). Now take `K + 1` consecutive blocks — one more than the window, because the window's earliest step reads the block before it — in which every block carries `paymentGasUsed` below `laneMin` and `generalGasUsed` strictly inside the hysteresis band. Such blocks exist: invariant (1) makes the band non-empty, and invariant (5) puts `GasLimit − laneMax` at or above the expansion threshold, so any general load inside the band satisfies [§3.3](#33-reserved-gas-accounting-rule) at every quota in the range.
-
-Across that stretch the overflow term `max(0, paymentGasUsed − paymentLaneSize)` vanishes for every quota in the range. Each block therefore yields the same signal whatever the quota was, that signal takes the hysteresis branch, and — the bounds being unchanged — the clamp leaves the quota where it stood. One chain can enter the stretch holding `laneMin` and another holding `laneMax`, and both leave it still holding them. The two chains must have diverged at some earlier height, so their `ParentHash` and state root differ; but those are opaque digests of exactly the unbounded history the window was meant to replace, not quantities a windowed derivation can compute from. Every field such a derivation can read — gas limit, gas used, class split — agrees across both chains for all `K` blocks, and the quotas still differ. The difference is observable: a following block with no payment gas and `generalGasUsed = GasLimit − laneMin` is valid under the first quota and invalid under the second. `K` was arbitrary, so no finite window is sound.
-
-The recurrence state must therefore be carried forward explicitly rather than rederived. It is committed to every block header from `activation + 1` onward — in the header rather than in state, so that the recursion never reaches past the parent ([§3.5.5](#355-what-this-buys)).
+The recurrence state is therefore committed rather than rederived, which bounds the recursion at the parent ([§3.5.5](#355-what-this-buys)).
#### 3.5.2 What Is Committed
@@ -262,17 +258,13 @@ Two values, encoded into the 32 bytes of `header.UncleHash`:
| `[8:16]` | `paymentGasUsed` | uint64 big-endian — payment gas consumed by this block |
| `[16:32]` | reserved | MUST be zero |
-Two values suffice. The header already carries the block's total gas used, so committing `paymentGasUsed` fixes `generalGasUsed` as well, and with it the whole class split.
-
-Requiring the reserved bytes to be zero makes the encoding canonical — exactly one 32-byte value per pair — and rejects a header that still carries the pre-activation empty-list hash.
+`generalGasUsed` needs no field of its own: it is the header's gas used less `paymentGasUsed`. Zeroing the reserved bytes makes the encoding canonical, and rejects a header still carrying the pre-activation empty-list hash.
#### 3.5.3 Why `UncleHash`
-That the state must be carried explicitly is a conclusion; which field carries it is not. The choice below is specific to BSC and is not forced by the argument above.
-
-Parlia does not permit uncles, so `UncleHash` carries no information on BSC and is pinned to the empty-list hash in every block today. Reusing it adds no header field, no size increase, and no change to block encoding; and the field already sits inside the producer's seal, so authentication costs nothing.
+Parlia permits no uncles, so `UncleHash` carries no consensus information on BSC and is pinned to the empty-list hash in every block today. Reusing it adds no header field, no size increase, and no change to block encoding — the header stays structurally identical to upstream Ethereum's. The field already sits inside the producer's seal, so authentication costs nothing.
-This BEP claims `header.UncleHash` exclusively — no other use of the field is defined. `ParentBeaconRoot` is unaffected.
+This BEP claims `header.UncleHash` exclusively; no other use of the field is defined.
From `activation + 1` onward:
From 385b9f501b3ebdfb6d71229de6f216319a088fa4 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 23:30:07 +0800
Subject: [PATCH 17/29] bep-703: refine Validation
---
BEPs/BEP-703.md | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index ebc88eea..1cef5933 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -274,20 +274,18 @@ From `activation + 1` onward:
#### 3.5.4 Validation
+Every check below is mandatory.
+
| Check | Where | Why there |
|---|---|---|
| Reserved bytes are zero | Header verification | A pure function of the header |
+| `paymentGasUsed` does not exceed the header's gas used | Header verification | A pure function of the header, and the rule below is evaluated on it |
+| `paymentLaneSize` does not exceed the header's gas limit | Header verification | Likewise; together the two bounds keep that rule's sum from wrapping |
| The accounting rule of [§3.3](#33-reserved-gas-accounting-rule) holds on the committed values | Header verification | `generalGasUsed` is the header's gas used less `paymentGasUsed`, so the inequality needs no execution |
| `paymentLaneSize` matches the value derived from the parent | Before execution, against the parent's post-state | The derivation reads governable parameters from that state, but nothing from this block beyond its header |
| `paymentGasUsed` matches the value obtained by re-execution | Block execution | Requires running the block |
-Only the last of these requires running the block.
-
-The value checks are not optional. An accepted, incorrect `paymentLaneSize` becomes the base of the recurrence for every descendant, and because every node reads the same parent header the chain does not fork — it silently converges on a destroyed lane, or on a general market permanently starved by an oversized reservation.
-
-The split matters most on the builder path. Under [BEP-675](./BEP-675.md) a validator seals a builder-supplied block without executing it, and the commitment arrives as 32 bytes chosen by the builder. Everything decidable without running the block belongs with the pre-seal header checks a validator already performs on fields derived from the parent — including `paymentLaneSize`, since the validator holds the parent's post-state there. Values decoded from the commitment are untrusted input, not quantities produced by the recurrence: a client MUST range-check them and reject the block — `paymentGasUsed` greater than the header's gas used, or any sum that would exceed 64 bits, is invalid, not saturated.
-
-Only `paymentGasUsed` needs the block to be run, and it is checked where every other execution result is. That is not a weakening: the rule binds every node identically on import, so a false value yields a block no node accepts. It does carry one implementation consequence. The commitment sits outside execution, so a false `paymentGasUsed` leaves the state and receipts roots intact — the mismatch must fail import on its own account, or nothing catches it.
+The pre-execution split keeps [BEP-675](./BEP-675.md) unchanged: everything a validator must check before blind-sealing a builder's block is decidable from the parent.
#### 3.5.5 What This Buys
From cc94bff30a5432c82179b6864ed5c2a41370503e Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sat, 1 Aug 2026 23:34:23 +0800
Subject: [PATCH 18/29] bep703: refine What This Buys
---
BEPs/BEP-703.md | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 1cef5933..9529504b 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -289,7 +289,13 @@ The pre-execution split keeps [BEP-675](./BEP-675.md) unchanged: everything a va
#### 3.5.5 What This Buys
-A recursion depth of one. Every input to the derivation comes from the parent header — its quota and payment gas from the commitment, its gas used and gas limit from the header proper — except the governable parameters, which are read from the parent's post-state like any other governed value. No block older than the parent is ever consulted. Snap sync, restart from disk, reorg, and history pruning therefore all reduce to reading one header against state the node already holds, with no history to replay and none to retain.
+A recursion depth of one. The derivation reads exactly three things:
+
+- the parent header — its committed quota and payment gas, its gas used and gas limit;
+- the parent's post-state — the governable parameters;
+- this block's own gas limit.
+
+Nothing older than the parent is ever consulted, so snap sync, restart from disk, reorg, and history pruning all reduce to reading the parent header against state the node already holds: no history to replay, and none to retain.
### 3.6 Parameters, Invariants, and Governance
From de02b54a42039ab6d3e6642ba131fde9ffd29747 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sun, 2 Aug 2026 11:18:03 +0800
Subject: [PATCH 19/29] bep-703: refine Parameters, Invariants, and Governance
---
BEPs/BEP-703.md | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 9529504b..600cd7b4 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -320,12 +320,11 @@ Governable parameters are not free-form. The following invariants are validated
```
(1) EXPAND_TRIGGER_RATIO − SHRINK_TRIGGER_RATIO >= TRIGGER_GAP_MIN
The expansion threshold must sit above the contraction threshold by at
- least the hysteresis floor; otherwise usage hovering near one boundary
+ least the minimum band width; otherwise usage hovering near one boundary
makes the quota thrash block by block.
(2) EXPAND_STEP_RATIO > SHRINK_STEP_RATIO > 0
- Fast expansion, slow contraction is a hard requirement, not advice:
- protection must arrive before space is handed back, or a sawtooth
+ Protection must arrive before space is handed back, or a sawtooth
demand pattern contracts the quota faster than it can re-expand.
(3) PAYMENT_LANE_MAX_RATIO − PAYMENT_LANE_MIN_RATIO >= RATIO_GAP_MIN
@@ -340,18 +339,16 @@ Governable parameters are not free-form. The following invariants are validated
(5) PAYMENT_LANE_MAX_RATIO <= RATIO_DENOM − EXPAND_TRIGGER_RATIO
Reserved gas never competes, so the signal cannot exceed the unreserved
- part of the block and expansion cannot fire once the quota reaches
- RATIO_DENOM − EXPAND_TRIGGER_RATIO of it. Without this bound the
- configured maximum is unreachable: under saturated demand the quota
- stalls just past that point and stays there, leaving governance with a
- ceiling the mechanism can never use.
+ part of the block: once the quota passes RATIO_DENOM − EXPAND_TRIGGER_RATIO
+ the signal can no longer reach the trigger and the quota stops growing.
+ A maximum above that point is one the mechanism can never reach.
(6) EXPAND_STEP_RATIO <= EXPAND_TRIGGER_RATIO − SHRINK_TRIGGER_RATIO
- Where the signal responds to the quota at all it does so one for one
- (3.4.2), so a step wider than the hysteresis band would carry the signal
- from one trigger straight past the other and the quota would alternate
- between expanding and contracting every block. Invariant (2) makes this
- bound SHRINK_STEP_RATIO as well.
+ The signal moves one for one with the quota where it responds at all
+ (3.4.2), so a step wider than the band jumps clean over it: expanding
+ at one trigger lands the signal past the other, and the quota reverses
+ the next block instead of settling. Invariant (2) bounds
+ SHRINK_STEP_RATIO the same way.
```
Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
@@ -434,7 +431,7 @@ Outside congestion (the overwhelming majority of blocks), the quota rests at its
- **Bounded waste.** Idle reserved gas is capped per block by `PAYMENT_LANE_MAX` and by the ratio ceiling, and the quota cannot grow past those bounds. The bound is per block, not cumulative over time: while the signal that raised the quota persists, so does the waste. It unwinds only through the contraction path, once that signal clears.
- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.7](#37-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
-- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can invert the two thresholds, invert the two steps, take a step wide enough to cross the hysteresis band, or set a maximum the quota could never reach. What they cannot guarantee is a wide effective range: the absolute and ratio bounds narrow it independently, and by how much depends on `GasLimit`, which is unknown at validation time (invariant (3)). A narrow range leaves the quota near-constant — the dynamic behaviour is lost, but no rule is violated.
+- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can invert the two thresholds, invert the two steps, take a step wide enough to cross the hysteresis band, or set a maximum the quota could never reach. What they cannot guarantee is a wide effective range (invariant (3)) — but a narrow one costs only the dynamic behaviour; no rule is violated.
## 7. License
From a6d1e1c12677439a43abc85b2a79c64d1908db31 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sun, 2 Aug 2026 11:39:27 +0800
Subject: [PATCH 20/29] bep-703: refine Payment Contract List
---
BEPs/BEP-703.md | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 600cd7b4..8dfa7f73 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -369,19 +369,19 @@ Invariant check:
### 3.7 Payment Contract List
-Categories ② and ③ are defined by a **payment contract list** maintained in the system contract of [§3.8](#38-system-contract) and updatable only through the standard BSC governance process (validator voting). Classification reads list membership as of the parent block's final state, so a list change never affects the block that contains it. Listing is by address: any transaction whose `to` is a listed address is a payment transaction, whatever function it calls. The list curates assets, not operations.
+Categories ② and ③ are defined by a **payment contract list** held in the system contract of [§3.8](#38-system-contract) and changed only through the standard BSC governance process (validator voting). Membership is read from the parent block's final state, so any change takes effect from the block after it lands. Listing is by address: every transaction whose `to` is listed is a payment transaction, whatever function it calls. The list curates assets, not operations.
-**Category ② — stablecoins.** Admission is decided by governance nomination alone, on the strength of off-chain audit history and accumulated on-chain reputation. The initial list is USDT and USDC: USDT's contract is non-upgradeable and its bytecode fixed since deployment; USDC is an upgradeable proxy, audited on every upgrade under considerable market scrutiny. The protocol imposes no mechanical gate here, so governance carries the ongoing monitoring as well as the nomination — if a listed contract's behaviour materially changes, removal depends on governance acting. This is an explicit, acknowledged trust, extended to two assets whose reputation is already established; whether later additions get the same treatment is for governance to decide.
+**Category ② — stablecoins.** Admission rests on governance judgement alone — off-chain audit history and on-chain reputation — with no mechanical gate behind it. The initial list is USDT and USDC: USDT is non-upgradeable, its bytecode fixed since deployment; USDC is an upgradeable proxy, audited on each upgrade under considerable market scrutiny. Governance therefore carries the ongoing monitoring as well as the nomination, and this trust is explicit.
-**Category ③ — BEP-702 native tokens.** Tokens under [BEP-702](./BEP-702.md) are protocol-native: they deploy no bytecode, cannot self-destruct, expose a function surface fixed by the protocol standard, and have no upgradeable implementation to drift. The properties an arbitrary contract would need audits or reputation to establish hold for these tokens by construction. Admission therefore requires:
+**Category ③ — [BEP-702](./BEP-702.md) native tokens.** These tokens deploy no bytecode, expose a function surface fixed by the protocol standard, and have no upgradeable implementation to drift, so what an ordinary contract needs an audit to establish holds here by construction. What still varies is the issuer's own configuration, so admission requires:
-1. **Protocol validity** — the address passes BEP-702's native-token address check and corresponds to a token actually created through its registry;
-2. **Off-chain audit** — review of the token's deployment parameters and operational configuration (admin custody, role assignments, transfer-policy settings, supply cap) for fitness as payment infrastructure — e.g., a token whose receiving policy is a narrow allowlist is not a general payment asset;
-3. **Governance nomination** — the same validator-voting process as category ②, answering one question: is this a genuine, significant payment asset.
+1. **Protocol validity** — the address lies in BEP-702's reserved native-token space, *and* a token has actually been created there;
+2. **Off-chain audit** — the token's configuration (admin custody, role assignments, transfer policies, supply cap) is fit for payment use; a token whose receiver policy is a narrow allowlist is not a general payment asset;
+3. **Governance nomination** — the same vote as category ②, on one question: is this a genuine, significant payment asset.
-The initial category-③ list is empty; tokens are nominated individually as audits complete.
+The initial category-③ list is empty.
-**Removal is symmetric with admission.** Governance MAY at any time, through the same validator-voting process, remove any listed address from either category. Because classification reads the parent block's final state, a removal takes effect from the block after it lands on-chain; transactions to the removed address are simply classified as general transactions thereafter — they remain fully valid and are included under the ordinary rules, so removal strips lane eligibility and nothing else. For both categories the rollout pace rests entirely with governance, and governance's power is bounded: it can delay an asset's admission by not nominating it, but nomination and removal votes are public and accountable, and for category ③ governance cannot override or weaken the guarantees BEP-702 itself provides.
+**Removal** uses the same vote, is available at any time for either category, and takes effect the same way. Transactions to a removed address are classified as general from the next block onward — fully valid, included under the ordinary rules. Removal strips lane eligibility and nothing else.
### 3.8 System Contract
From ce55956a7ab7c6ec35457f57ebb8271b9caefc00 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sun, 2 Aug 2026 11:48:46 +0800
Subject: [PATCH 21/29] bep-703: refine Rationale
---
BEPs/BEP-703.md | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 8dfa7f73..337ef821 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -396,21 +396,17 @@ The governable parameters of [§3.6](#36-parameters-invariants-and-governance) a
## 4. Rationale
-**A quota, not a region.** Reserving a gas amount rather than partitioning the block preserves everything about how blocks are built today. Producers keep complete freedom of selection and ordering; transactions of both classes interleave arbitrarily; the existing priority-fee market operates untouched for all traffic, payment traffic included. The entire proposal is one additional accounting inequality checked at block validation.
+**A quota, not a region.** A reserved region would have to sit somewhere in the block, which makes position part of the rule. A gas quota does not: the whole proposal is one accounting inequality checked at validation, with selection, ordering and pricing untouched.
-**Unused quota is idle, not reclaimable.** If the shortfall flowed back to general transactions, excluding payment transactions would cost a producer nothing — the space would simply be resold, and the floor would be a fiction precisely in the congested moments it exists for. Making the reservation binding regardless of realized payment demand inverts the economics: the reserved gas produces fees only when payment transactions fill it, so including them is the only way to monetize it, and excluding them yields nothing. The waste in quiet blocks is bounded (at most the quota minimum, a low single-digit percent of the block) and is the price of the guarantee being real.
+**Unused quota is idle, not reclaimable.** If the shortfall flowed back to general transactions, excluding payment transactions would cost a producer nothing — the space would simply be resold, and the floor would be a fiction precisely in the congested moments it exists for. Binding the reservation regardless of realized demand inverts the economics: reserved gas earns fees only when payment transactions fill it, so including them is the only way to monetize it.
-**Congestion-only signal, no motive judgment.** Any signal that tries to classify *why* the chain is congested — for example, the share of payment transactions among recent traffic — is written by whoever selects transactions, and can be steered at near-zero cost to keep the quota from ever expanding. `signalGasUsed` ([§3.4.2](#342-the-congestion-signal)), by contrast, counts only gas that competed on the open market, and every unit of it is aligned with fee revenue: a demand pulse produces high usage exactly because producers are including the paying transactions in front of them, and suppressing the signal means leaving those fees uncollected. Denying congestion is possible only at the cost of forgoing income. The rule is therefore deliberately reduced to *congestion expands the quota, regardless of cause*. The cost of this simplification — congestion unrelated to payments also triggers expansion — is bounded by the quota maximum, and unwinds through the contraction path once congestion clears, so it lasts as long as the congestion does and no longer.
-
-**Fast expansion, slow contraction, with hysteresis.** Expansion must outpace the demand pulse it protects against, while contraction can afford patience; the asymmetry (enforced as invariant 2) guarantees that under sawtooth pulses, protection is in place before space is returned. The hysteresis band (invariant 1) keeps boundary-hovering usage from thrashing the quota.
+**Congestion-only signal, no motive judgment.** A signal that tried to classify *why* the chain is congested — say, the share of payment transactions in recent traffic — would be written by whoever selects transactions, and steerable at near-zero cost. `signalGasUsed` ([§3.4.2](#342-the-congestion-signal)) instead counts only gas that competed on the open market, every unit of which is aligned with fee revenue: suppressing the signal means leaving paying transactions out, so denying congestion costs income. The rule reduces to *congestion expands the quota, regardless of cause*; the price — congestion unrelated to payments expands it too — is bounded by the quota maximum and unwinds once the congestion clears.
**Ratio and absolute bounds together.** Ratio bounds let the quota scale automatically with block capacity so the mechanism never needs re-tuning as GasLimit grows; absolute bounds cap its footprint so growth in block size can never silently grow the reservation beyond an intended ceiling.
-**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim. For category ③ the narrowness of the function surface is guaranteed by BEP-702's construction. For category ② nothing enforces it mechanically; it rests on governance vetting and continued monitoring, a trade [§3.7](#37-payment-contract-list) states in full.
-
-The price of that choice is that a transaction is classified one state transition before it runs. Category ① rules out every statically visible route to code execution — code-setting and blob-carrying transaction types, access lists, precompile destinations, and accounts that already hold code — but it cannot see a deployment or a delegation authorisation that lands earlier in the same block. A transfer to such an account executes code inside the lane, consuming at most its own gas limit.
+**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim. What backs a listed asset's behaviour differs by category — BEP-702's construction for ③, governance vetting for ② — a trade [§3.7](#37-payment-contract-list) states in full.
-Closing that gap would mean classifying against execution-time state, which opens a worse one. Whoever orders the block would then decide which users' transfers are lane-eligible, by placing one cheap deployment ahead of them; classification would stop being a fact the protocol recognises and become a lever the producer holds. The parent-state rule is therefore deliberate, and the residual exposure is bounded by the offending transaction's own gas limit.
+Reading the parent state costs one thing: an account that gains code earlier in the same block is still classified as having none ([§3.2](#32-transaction-classification)). Closing that gap would mean classifying against execution-time state, which opens a worse one — whoever orders the block would then decide which users' transfers are lane-eligible, by placing one cheap deployment ahead of them. Classification would stop being a fact the protocol recognises and become a lever the producer holds, so the parent-state rule is deliberate and the residual exposure is bounded by the offending transaction's own gas limit.
## 5. Backward Compatibility
From d216f9eff34f27c5f3cc4c5bf52b40e9cbd47f25 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sun, 2 Aug 2026 11:53:47 +0800
Subject: [PATCH 22/29] bep-703: refine Backward Compatibility
---
BEPs/BEP-703.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 337ef821..8fc75c0d 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -410,16 +410,16 @@ Reading the parent state costs one thing: an account that gains code earlier in
## 5. Backward Compatibility
-This is a consensus-breaking change and requires a hard fork: it adds a new block validity rule, the associated quota computation, and a header commitment. It changes no transaction format, no fee mechanism, and no ordering rule — the existing transaction ordering and inclusion mechanics of the ecosystem are unaffected, for every class of transaction. Wallets, exchanges, and applications that submit and read transactions require no modification.
+This is a consensus-breaking change and requires a hard fork: it adds a block validity rule, the quota computation behind it, and a header commitment. Transaction formats, the fee mechanism and ordering are untouched, so nothing that submits or handles transactions needs to change.
-Node implementations, on the other hand, change substantially: the accounting rule, the quota recurrence, the commitment encoding, and the four uncle-validation paths named in [§3.5.3](#353-why-unclehash) all need fork-gated changes.
+Node implementations change substantially: the accounting rule, the quota recurrence, the commitment encoding, and the four uncle-validation paths named in [§3.5.3](#353-why-unclehash) all need fork-gated changes.
Two observable values do change, and downstream tooling should account for both:
- `sha3Uncles` is no longer the constant empty-list hash ([§3.5.3](#353-why-unclehash)). Any consumer that compares it against that constant, or derives the uncle list from it, must be updated.
-- During congestion, `gasUsed / GasLimit` understates how full a block really was, by up to the unused part of the reservation. Block explorers, gas-price oracles, and alerting that read that ratio as a congestion indicator will see values low by as much as the quota.
+- A full block no longer shows `gasUsed / GasLimit` near 1: the ratio falls short by whatever part of the reservation payment traffic left unused. Explorers, gas-price oracles and alerting that read it as a congestion indicator will read low, by at most the quota.
-Outside congestion (the overwhelming majority of blocks), the quota rests at its minimum and observable behavior is essentially identical to today. During congestion, general transactions have marginally less space available in exchange for payment traffic retaining a guaranteed floor; the reduction is bounded by the quota maximum and, as block capacity continues to grow, shrinks as a fraction of total block space.
+Otherwise the quota rests at its minimum and behaviour is as it is today. Under congestion general traffic gives up at most `PAYMENT_LANE_MAX_RATIO` of the block, and gets it back through the contraction path once the congestion clears.
## 6. Security Considerations
From b11b4b89fb6343f14c28aa4ef6f515746d96cad5 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Sun, 2 Aug 2026 11:58:04 +0800
Subject: [PATCH 23/29] bep-703: refine Security Considerations
---
BEPs/BEP-703.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 8fc75c0d..7bedbf23 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -423,10 +423,10 @@ Otherwise the quota rests at its minimum and behaviour is as it is today. Under
## 6. Security Considerations
-- **Spam within the lane.** The quota does not grant free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so flooding the lane costs fees like any other spam. Sustained payment traffic beyond the quota does raise the congestion signal and expand the reservation ([§3.4.2](#342-the-congestion-signal)), and general traffic bears that in later blocks. The exposure is bounded by `PAYMENT_LANE_MAX`, unwinds through the contraction path once the signal clears, and materialises at all only when general traffic is itself congested — in which case its own usage would have expanded the quota anyway. The flood is paid for at full fees throughout. Note that the reservation bounds volume, not the size of any one transaction: a single payment transaction may occupy all of it.
-- **Bounded waste.** Idle reserved gas is capped per block by `PAYMENT_LANE_MAX` and by the ratio ceiling, and the quota cannot grow past those bounds. The bound is per block, not cumulative over time: while the signal that raised the quota persists, so does the waste. It unwinds only through the contraction path, once that signal clears.
+- **Spam within the lane.** The quota grants no free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so a flood pays full fees throughout. Sustained payment traffic beyond the quota does raise the signal and expand the reservation ([§3.4.2](#342-the-congestion-signal)), but general traffic feels that only when it is itself congested — at which point its own usage would have expanded the quota anyway. The reservation bounds volume, not the size of any one transaction: a single payment transaction may occupy all of it.
+- **Bounded waste.** Idle reserved gas is capped per block by `laneMax` ([§3.4.4](#344-bounds)). The bound is per block, not cumulative: while the signal that raised the quota persists so does the waste, and it unwinds only through the contraction path.
- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
-- **List governance.** Listing and delisting are ordinary governance votes in both categories ([§3.7](#37-payment-contract-list)). What differs is what stands behind a listed asset's safety: for category ②, the protocol enforces no mechanical gate, so the guarantee that listed contracts remain narrow value-transfer surfaces rests on governance's ongoing monitoring — a deliberate, disclosed trade made for two assets whose reputation is already extensively established; for category ③, the safety properties (no bytecode, fixed function surface, no upgrade path) are enforced by BEP-702's construction — a governance vote can remove a token's lane eligibility, but can never weaken or waive those protocol-level properties. In both categories, a governance failure's blast radius is confined to lane eligibility — a wrongly listed contract gains a bounded gas floor, never new execution powers.
+- **List governance.** Listing and delisting are ordinary governance votes ([§3.7](#37-payment-contract-list)), and a governance failure's blast radius is confined to lane eligibility: a wrongly listed contract gains a bounded gas floor, never new execution powers. For category ③ a vote can strip a token's eligibility but can never weaken the properties BEP-702 enforces on it.
- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can invert the two thresholds, invert the two steps, take a step wide enough to cross the hysteresis band, or set a maximum the quota could never reach. What they cannot guarantee is a wide effective range (invariant (3)) — but a narrow one costs only the dynamic behaviour; no rule is violated.
## 7. License
From 072070cff4c43c2956f25c087342a9bd3b79d4e5 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Mon, 10 Aug 2026 15:54:04 +0800
Subject: [PATCH 24/29] bep-703: refine some trivals (#705)
---
BEPs/BEP-703.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 7bedbf23..a17d3782 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -191,13 +191,15 @@ step(h) =
if signalGasUsed(h−1) × RATIO_DENOM >= EXPAND_TRIGGER_RATIO(h−1) × GasLimit(h−1)
− SHRINK_STEP_RATIO(h−1) × GasLimit(h) / RATIO_DENOM
- if signalGasUsed(h−1) × RATIO_DENOM <= SHRINK_TRIGGER_RATIO(h−1) × GasLimit(h−1)
+ if signalGasUsed(h−1) × RATIO_DENOM < SHRINK_TRIGGER_RATIO(h−1) × GasLimit(h−1)
0 otherwise — the hysteresis band
```
The condition reads `GasLimit(h−1)` because that is the block whose congestion is being measured; the step scales by `GasLimit(h)` because that is the block whose space is being reserved.
+Both operators are normative as written: `>=` above and `<` below, so the hysteresis band is `[SHRINK_TRIGGER_RATIO, EXPAND_TRIGGER_RATIO)` and a signal landing exactly on the shrink threshold holds instead of shrinking. Invariant (1) of [§3.6](#36-parameters-invariants-and-governance) is what keeps that band non-empty; it does not decide the operators. Since `paymentLaneSize` is an accumulator, two implementations disagreeing on a single boundary block never reconverge.
+
#### 3.4.4 Bounds
```
@@ -234,7 +236,7 @@ quiet the quota rests at 2M, 3.6% of the block; the mechanism is dormant
congestion signal >= 80%: 2M -> 3.1M -> 4.2M -> 4.4M (clamped down from 5.3M)
3 blocks, about 1.35s
-recovery signal <= 70%: 4.4M -> 2M in steps of 0.275M
+recovery signal < 70%: 4.4M -> 2M in steps of 0.275M
9 blocks, about 4s
```
From 689a67311b66e42397fdb13ef65ac47bc6313592 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Mon, 10 Aug 2026 19:00:43 +0800
Subject: [PATCH 25/29] chore: polish bep703
---
BEPs/BEP-703.md | 65 +++++++++++++++++++++++++------------------------
1 file changed, 33 insertions(+), 32 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index a17d3782..ae7c97a1 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -97,25 +97,29 @@ The bar is a gas budget, not a layout: it says nothing about where transactions
### 3.2 Transaction Classification
-A transaction is a **payment transaction** if and only if it belongs to one of the following three categories, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**.
+A transaction is a **payment transaction** if and only if it meets three conditions common to both rules below and then satisfies one of them, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**. Nothing is executed to decide this, so classification adds no consensus overhead.
-| Category | Scope | Determination |
-|---|---|---|
-| ① Native BNB transfer | Pure value transfer that executes no contract code as of the parent state | Mechanical: the transaction type is `0x00`, `0x01`, or `0x02`; `to` is non-nil and is not a precompile address; `data` and `accessList` are empty; and the account at `to` has no code |
-| ② Listed stablecoin contracts | Initially USDT and USDC only | Governance nomination ([§3.7](#37-payment-contract-list)) |
-| ③ Listed [BEP-702](./BEP-702.md) native tokens | Tokens created under the New Tokens on BNB Smart Chain standard | Protocol-native validity checks + governance nomination ([§3.7](#37-payment-contract-list)) |
+The common conditions are that `to` is non-nil, the transaction type is `0x00`, `0x01`, or `0x02`, and `accessList` is empty. They cap what a payment transaction can cost before either rule is consulted, and a transaction failing any of them is general whatever its destination. An access list is intrinsic gas that no destination can reduce — 2400 per address and 1900 per storage key — so at the 4.4M quota of [§3.4.6](#346-worked-example), 1833 addresses would fill the lane on intrinsic cost alone; the type allowlist rules out the per-authorisation cost of a code-setting transaction, and blob-carrying types with it.
-Four of the category-① conditions pin the intrinsic cost at exactly 21000 gas: `to` non-nil rules out contract creation, empty `data` rules out calldata cost, an empty `accessList` rules out the 2400 gas per address and 1900 per storage key it would otherwise be charged, and the type allowlist rules out the per-authorisation cost of a code-setting transaction, and blob-carrying types with it. The other two bar code execution: the account at `to` holds no code, and `to` is not a precompile — a precompile holds no code either, so it passes the first test, yet a call to one runs it, and a precompile that rejects its input consumes every unit of gas the call was given. The precompile set is fixed by the fork schedule, so the check stays static.
+| Rule | Payment when | Covers |
+|---|---|---|
+| Listed destination | `to` is on the payment contract list ([§3.7](#37-payment-contract-list)) | Stablecoins and [BEP-702](./BEP-702.md) native tokens, whatever function is called |
+| Bare transfer | `data` is empty, `value` is non-zero, and `to` has no code in the parent state | Native BNB payments between accounts |
-Everything above reads static transaction fields and the parent block's final state, so any node can classify a transaction without executing it and classification adds no consensus overhead. An account carrying an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designator holds code and so fails the no-code test. Reading the parent state has one consequence, though: an account that acquires code earlier in the same block, by deployment or by a delegation authorisation, is still classified as having none, and the transfer then executes that code inside the lane, bounded by its own gas limit. [§4](#4-rationale) explains why classification is nevertheless not moved to execution time.
+With the common conditions, a bare transfer costs exactly 21000 gas: `to` non-nil rules out contract creation, empty `data` rules out calldata cost, and the access-list and type restrictions rule out everything else chargeable before execution. Its other two tests are about substance rather than cost. A non-zero `value` is what makes the transaction a payment at all: a zero-value transfer moves nothing, so reserved gas would be protecting nothing. No code at `to` is a test against the parent state, and so bounds the intrinsic cost rather than guaranteeing that nothing executes — a precompile holds no code, and an account that acquires code earlier in the same block, by deployment or by an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) authorisation, is still classified as having none, though one already carrying a delegation designator holds code and fails the test. In both residual cases the transfer executes code inside the lane, bounded by its own gas limit; [§4](#4-rationale) says why neither is closed, and why classification is not moved to execution time.
```
classify(tx, parentState):
- if tx.to in paymentContractList(parentState): return PAYMENT # 2 and 3
- if tx.type in {0x00, 0x01, 0x02}
- and tx.to != nil and not isPrecompile(tx.to)
- and tx.data is empty and tx.accessList is empty
- and parentState.codeAt(tx.to) is empty: return PAYMENT # 1
+ if tx.to == nil: return GENERAL # common
+ if tx.type not in {0x00, 0x01, 0x02}: return GENERAL # common
+ if tx.accessList is not empty: return GENERAL # common
+
+ if tx.to in paymentContractList(parentState): return PAYMENT # listed
+
+ if tx.data is empty # bare transfer
+ and tx.value != 0
+ and parentState.codeAt(tx.to) is empty: return PAYMENT
+
return GENERAL
```
@@ -139,8 +143,8 @@ Blocks violating this rule MUST be rejected as invalid.
The rule has exactly two regimes:
-- **Payment demand meets or exceeds the quota** (`paymentGasUsed >= paymentLaneSize`): the constraint reduces to the ordinary `paymentGasUsed + generalGasUsed <= GasLimit`. Payment gas beyond the quota competes for the remaining space under the existing priority-fee rules on equal terms with general transactions — the quota is a floor, never a ceiling.
-- **Payment demand falls short of the quota** (`paymentGasUsed < paymentLaneSize`): the shortfall reduces the gas available to general transactions one-for-one. The unused reservation is deliberately left idle for that block rather than released — this is what makes the guarantee real ([§4](#4-rationale)).
+- **Payment demand meets or exceeds the quota** (`paymentGasUsed >= paymentLaneSize`): the constraint reduces to the ordinary `paymentGasUsed + generalGasUsed <= GasLimit`. Payment gas beyond the quota competes for the remaining space under the existing priority-fee rules on equal terms with general transactions.
+- **Payment demand falls short of the quota** (`paymentGasUsed < paymentLaneSize`): the shortfall reduces the gas available to general transactions one-for-one, the unused reservation staying idle for that block rather than being released ([§4](#4-rationale)).
The rule constrains only gas totals. It says nothing about where transactions sit inside the block: payment and general transactions may be interleaved arbitrarily, and block producers keep full freedom over transaction selection and ordering within the accounting constraint. No new ordering rule, priority rule, or fee rule is introduced.
@@ -215,7 +219,7 @@ Each bound is the tighter of a ratio limit that tracks `GasLimit` and an absolut
#### 3.4.5 Activation
-`activation` is the block at which this fork takes effect and the system contract of [§3.8](#38-system-contract) first holds the parameters. Every derivation reads them from the parent's post-state ([§3.4](#34-dynamic-quota-adjustment)), so `activation + 1` is the first block that can read them, and the first the lane applies to. Block `activation` is outside the mechanism: not subject to the accounting rule of [§3.3](#33-reserved-gas-accounting-rule), and carrying no commitment.
+`activation` is the block at which this fork takes effect and the system contract of [§3.8](#38-system-contract) first holds the parameters. Every derivation reads them from the parent's post-state ([§3.4](#34-dynamic-quota-adjustment)), so `activation + 1` is the first block that can read them, and the first the lane applies to. Block `activation` is outside the mechanism: not subject to the accounting rule of [§3.3](#33-reserved-gas-accounting-rule), and carrying no commitment — its `UncleHash` stays the empty-list hash, as in every block before it.
`activation + 1` therefore reads parameters from its parent, but no commitment and no class split. That is what the base case of [§3.4.1](#341-the-recurrence) covers, and it is why no pre-fork block is ever asked for a split it never recorded.
@@ -270,7 +274,7 @@ This BEP claims `header.UncleHash` exclusively; no other use of the field is def
From `activation + 1` onward:
-1. Clients MUST accept any 32-byte value in `UncleHash` when validating Parlia blocks.
+1. Clients MUST NOT reject a Parlia block because `UncleHash` differs from the empty-list hash. The only structural constraint on the field is the encoding of [§3.5.2](#352-what-is-committed), checked where [§3.5.4](#354-validation) requires.
2. The uncle list in the block body MUST remain empty. Clients MUST verify this directly on the body, and MUST NOT derive the expected uncle list from `UncleHash`.
3. Every path that recomputes the uncle-list hash from the body and compares it against the header MUST be gated on that same boundary — block validation, block propagation, the block fetcher, and the downloader's body matching. A path left ungated makes committed blocks impossible to import, propagate, or sync.
@@ -291,13 +295,16 @@ The pre-execution split keeps [BEP-675](./BEP-675.md) unchanged: everything a va
#### 3.5.5 What This Buys
-A recursion depth of one. The derivation reads exactly three things:
+A recursion depth of one. The derivation reads exactly four things, all of them available at the parent:
+- whether the parent carries a commitment at all — the base case of [§3.4.1](#341-the-recurrence) turns on this;
- the parent header — its committed quota and payment gas, its gas used and gas limit;
- the parent's post-state — the governable parameters;
- this block's own gas limit.
-Nothing older than the parent is ever consulted, so snap sync, restart from disk, reorg, and history pruning all reduce to reading the parent header against state the node already holds: no history to replay, and none to retain.
+The first MUST NOT be inferred from whether the parent's `UncleHash` decodes. A header unavailable or misread for any other reason would then be taken for a bootstrap seed, silently resetting the quota to `laneMin`, and the accumulator never reconverges from that. It is decidable from the parent header alone: a block outside the mechanism carries the empty-list hash ([§3.4.5](#345-activation)), and no commitment can equal it, since the reserved bytes of [§3.5.2](#352-what-is-committed) are zero and the empty-list hash's are not. A genesis parent is covered by the same test.
+
+Nothing older than the parent's own header is required, so snap sync, restart from disk, reorg, and history pruning all reduce to reading the parent header against state the node already holds: no history to replay, no bodies to fetch, and none to retain.
### 3.6 Parameters, Invariants, and Governance
@@ -371,19 +378,13 @@ Invariant check:
### 3.7 Payment Contract List
-Categories ② and ③ are defined by a **payment contract list** held in the system contract of [§3.8](#38-system-contract) and changed only through the standard BSC governance process (validator voting). Membership is read from the parent block's final state, so any change takes effect from the block after it lands. Listing is by address: every transaction whose `to` is listed is a payment transaction, whatever function it calls. The list curates assets, not operations.
-
-**Category ② — stablecoins.** Admission rests on governance judgement alone — off-chain audit history and on-chain reputation — with no mechanical gate behind it. The initial list is USDT and USDC: USDT is non-upgradeable, its bytecode fixed since deployment; USDC is an upgradeable proxy, audited on each upgrade under considerable market scrutiny. Governance therefore carries the ongoing monitoring as well as the nomination, and this trust is explicit.
-
-**Category ③ — [BEP-702](./BEP-702.md) native tokens.** These tokens deploy no bytecode, expose a function surface fixed by the protocol standard, and have no upgradeable implementation to drift, so what an ordinary contract needs an audit to establish holds here by construction. What still varies is the issuer's own configuration, so admission requires:
+The **payment contract list** is the first rule of [§3.2](#32-transaction-classification). It lives in the system contract of [§3.8](#38-system-contract) and changes only through the standard BSC governance process (validator voting), taking effect from the block after the change lands. It curates assets, not operations — listing is by address, whatever function a transaction calls — and it does not lift §3.2's common conditions. Two kinds of asset are eligible, on the same vote but different evidence. **The list starts empty: the fork lists nothing, and every entry arrives by governance afterwards.**
-1. **Protocol validity** — the address lies in BEP-702's reserved native-token space, *and* a token has actually been created there;
-2. **Off-chain audit** — the token's configuration (admin custody, role assignments, transfer policies, supply cap) is fit for payment use; a token whose receiver policy is a narrow allowlist is not a general payment asset;
-3. **Governance nomination** — the same vote as category ②, on one question: is this a genuine, significant payment asset.
+**Stablecoins.** Admission rests on governance judgement alone — off-chain audit history and on-chain reputation — with no mechanical gate behind it. The intended first entries are USDT and USDC: USDT is non-upgradeable, its bytecode fixed since deployment; USDC is an upgradeable proxy, audited on each upgrade under considerable market scrutiny. Governance therefore carries the ongoing monitoring as well as the nomination, and this trust is explicit.
-The initial category-③ list is empty.
+**[BEP-702](./BEP-702.md) native tokens.** These tokens deploy no bytecode, expose a function surface fixed by the protocol standard, and have no upgradeable implementation to drift, so what an ordinary contract needs an audit to establish holds here by construction. What still varies is the issuer's own configuration, so a voter must additionally establish that the address lies in BEP-702's reserved native-token space with a token actually created there, and that the token's configuration — admin custody, role assignments, transfer policies, supply cap — is fit for payment use; one whose receiver policy is a narrow allowlist is not a general payment asset. None of that is enforced on chain: the protocol reads membership and nothing else, so both kinds of listing are exactly as sound as the vote behind them.
-**Removal** uses the same vote, is available at any time for either category, and takes effect the same way. Transactions to a removed address are classified as general from the next block onward — fully valid, included under the ordinary rules. Removal strips lane eligibility and nothing else.
+**Removal** uses the same vote and takes effect the same way, at any time, for either kind. It strips lane eligibility and nothing else: transactions to a removed address are ordinary general transactions from the next block onward.
### 3.8 System Contract
@@ -406,9 +407,9 @@ The governable parameters of [§3.6](#36-parameters-invariants-and-governance) a
**Ratio and absolute bounds together.** Ratio bounds let the quota scale automatically with block capacity so the mechanism never needs re-tuning as GasLimit grows; absolute bounds cap its footprint so growth in block size can never silently grow the reservation beyond an intended ceiling.
-**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim. What backs a listed asset's behaviour differs by category — BEP-702's construction for ③, governance vetting for ② — a trade [§3.7](#37-payment-contract-list) states in full.
+**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim.
-Reading the parent state costs one thing: an account that gains code earlier in the same block is still classified as having none ([§3.2](#32-transaction-classification)). Closing that gap would mean classifying against execution-time state, which opens a worse one — whoever orders the block would then decide which users' transfers are lane-eligible, by placing one cheap deployment ahead of them. Classification would stop being a fact the protocol recognises and become a lever the producer holds, so the parent-state rule is deliberate and the residual exposure is bounded by the offending transaction's own gas limit.
+Classifying on code costs one thing: code can still run inside the lane, at a precompile or at an account that gains code earlier in the same block ([§3.2](#32-transaction-classification)). Neither is closed, for different reasons. Closing the same-block case would mean classifying against execution-time state, which opens a worse one — whoever orders the block would then decide which users' transfers are lane-eligible, by placing one cheap deployment ahead of them, and classification would stop being a fact the protocol recognises and become a lever the producer holds. No state test catches a precompile, which holds no code at any point, so only an address-set test would — and that set is fork- and chain-dependent: every client would have to carry it identically or diverge on classification, which the accumulator of [§3.4](#34-dynamic-quota-adjustment) never reconverges from. That is a wider divergence surface than the single case the test closes. Both residuals are bounded by the offending transaction's own gas limit, which is what makes leaving them open affordable.
## 5. Backward Compatibility
@@ -428,7 +429,7 @@ Otherwise the quota rests at its minimum and behaviour is as it is today. Under
- **Spam within the lane.** The quota grants no free inclusion: payment transactions compete among themselves for reserved gas under the ordinary priority-fee rules, so a flood pays full fees throughout. Sustained payment traffic beyond the quota does raise the signal and expand the reservation ([§3.4.2](#342-the-congestion-signal)), but general traffic feels that only when it is itself congested — at which point its own usage would have expanded the quota anyway. The reservation bounds volume, not the size of any one transaction: a single payment transaction may occupy all of it.
- **Bounded waste.** Idle reserved gas is capped per block by `laneMax` ([§3.4.4](#344-bounds)). The bound is per block, not cumulative: while the signal that raised the quota persists so does the waste, and it unwinds only through the contraction path.
- **Signal manipulation.** Suppressing the expansion signal requires producing under-filled blocks during peak fee demand — the manipulation is directly and continuously costly ([§4](#4-rationale)).
-- **List governance.** Listing and delisting are ordinary governance votes ([§3.7](#37-payment-contract-list)), and a governance failure's blast radius is confined to lane eligibility: a wrongly listed contract gains a bounded gas floor, never new execution powers. For category ③ a vote can strip a token's eligibility but can never weaken the properties BEP-702 enforces on it.
+- **List governance.** Listing and delisting are ordinary governance votes ([§3.7](#37-payment-contract-list)), and a governance failure's blast radius is confined to lane eligibility: a wrongly listed contract gains a bounded gas floor, never new execution powers. For a BEP-702 native token a vote can strip eligibility but can never weaken the properties BEP-702 enforces on it.
- **Parameter safety.** The invariants in [§3.6](#36-parameters-invariants-and-governance) are validated before any parameter change activates, so no governance action can invert the two thresholds, invert the two steps, take a step wide enough to cross the hysteresis band, or set a maximum the quota could never reach. What they cannot guarantee is a wide effective range (invariant (3)) — but a narrow one costs only the dynamic behaviour; no rule is violated.
## 7. License
From 89b89043609ff0da5e8694d8a2946cb6dd69358b Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Tue, 11 Aug 2026 09:20:06 +0800
Subject: [PATCH 26/29] chore: refine bep703
---
BEPs/BEP-703.md | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index ae7c97a1..5297cdb6 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -129,10 +129,12 @@ For each block, let:
```
paymentGasUsed = total gas consumed by payment transactions in the block
-generalGasUsed = total gas consumed by general transactions in the block
+generalGasUsed = the block's gas used less paymentGasUsed
paymentLaneSize = the block's reserved payment quota (computed per 3.4)
```
+`generalGasUsed` is a residual, not a sum over general transactions, and the difference is not cosmetic. Parlia appends unsigned system transactions to the end of every block — validator reward, slashing, finality reward, and on a breathe block a validator-set update that has reached 12M gas on mainnet — and their gas is in the header's gas used. Defining the residual puts that gas on the general side without asking [§3.2](#32-transaction-classification) to classify a transaction no user submitted; one of those system transactions is a bare value transfer, so the classification route would instead turn on its destination happening to hold code. The obligation to include them also bounds the quota, in [§3.4.4](#344-bounds).
+
The block MUST satisfy:
```
@@ -166,12 +168,14 @@ Throughout, `h` is the block being built or validated and `h−1` is its parent.
For every block from `activation + 1`:
```
-paymentLaneSize(h) =
+paymentLaneSize(h) = min( quota(h), laneCap(h) )
+
+quota(h) =
laneMin(h) h = activation + 1
clamp( paymentLaneSize(h−1) + step(h), laneMin(h), laneMax(h) ) h > activation + 1
```
-The base case needs no clamp: [§3.4.4](#344-bounds) puts `laneMin(h)` inside the range by construction.
+The base case needs no clamp: [§3.4.4](#344-bounds) puts `laneMin(h)` inside the range by construction. `laneCap(h)` is the system-transaction reserve, also [§3.4.4](#344-bounds); it is the outermost operation, and the recurrence feeds on `paymentLaneSize(h−1)` — the value the parent committed, after its own cap — never on `quota(h−1)`.
#### 3.4.2 The Congestion Signal
@@ -213,10 +217,16 @@ laneMax(h) = min( PAYMENT_LANE_MAX_RATIO(h−1) × GasLimit(h) / RATIO_DENOM,
laneMin(h) = min( max( PAYMENT_LANE_MIN_RATIO(h−1) × GasLimit(h) / RATIO_DENOM,
PAYMENT_LANE_MIN(h−1) ),
laneMax(h) ) <- so laneMin(h) <= laneMax(h) at every GasLimit
+
+laneCap(h) = GasLimit(h) − SYSTEM_TXS_GAS_RESERVE
```
Each bound is the tighter of a ratio limit that tracks `GasLimit` and an absolute limit in gas ([§4](#4-rationale)). Both are recomputed every block, so the clamp of [§3.4.1](#341-the-recurrence) applies even where `step(h)` is zero.
+`laneCap(h)` is the one place this specification lets the quota fall below `laneMin(h)`. Every block is obliged to include the system transactions of [§3.3](#33-reserved-gas-accounting-rule), so the quota must leave room for them, and `SYSTEM_TXS_GAS_RESERVE` is the gas Parlia reserves for its worst case — a breathe block carrying a validator-set update. A single constant is used rather than a per-block estimate so that both sides of a block agree on it without deriving anything.
+
+Falling below the floor is the point of the cap. Without it, a low enough `GasLimit` makes the quota exceed what a breathe block can hold, so no valid block exists — and that halt does not clear on its own, because a breathe block is one whose parent sits in the previous UTC day, so every later candidate is again a breathe block and fails identically. With the values of [§3.6](#36-parameters-invariants-and-governance) the cap binds only below a `GasLimit` of about 21.7M, a fraction of today's; raising `PAYMENT_LANE_MAX_RATIO` moves that threshold up.
+
#### 3.4.5 Activation
`activation` is the block at which this fork takes effect and the system contract of [§3.8](#38-system-contract) first holds the parameters. Every derivation reads them from the parent's post-state ([§3.4](#34-dynamic-quota-adjustment)), so `activation + 1` is the first block that can read them, and the first the lane applies to. Block `activation` is outside the mechanism: not subject to the accounting rule of [§3.3](#33-reserved-gas-accounting-rule), and carrying no commitment — its `UncleHash` stays the empty-list hash, as in every block before it.
@@ -225,13 +235,14 @@ Each bound is the tighter of a ratio limit that tracks `GasLimit` and an absolut
#### 3.4.6 Worked Example
-At `GasLimit = 55M`, BSC mainnet's current value, and a 0.45s block interval, with the suggested parameters of [§3.6](#36-parameters-invariants-and-governance):
+At `GasLimit = 55M`, BSC mainnet's current value, and a 0.45s block interval, with the parameters of [§3.6](#36-parameters-invariants-and-governance):
```
2% × 55M = 1.1M 8% × 55M = 4.4M 0.5% × 55M = 0.275M
laneMax = min(4.4M, 8M) = 4.4M <- set by the ratio bound
laneMin = min(max(1.1M, 2M), 4.4M) = 2M <- set by the absolute bound
+laneCap = 55M − 20M = 35M <- inert this far above laneMax
expand = 1.1M per block
shrink = 0.275M per block
@@ -264,7 +275,7 @@ Two values, encoded into the 32 bytes of `header.UncleHash`:
| `[8:16]` | `paymentGasUsed` | uint64 big-endian — payment gas consumed by this block |
| `[16:32]` | reserved | MUST be zero |
-`generalGasUsed` needs no field of its own: it is the header's gas used less `paymentGasUsed`. Zeroing the reserved bytes makes the encoding canonical, and rejects a header still carrying the pre-activation empty-list hash.
+`generalGasUsed` needs no field of its own — [§3.3](#33-reserved-gas-accounting-rule) already defines it as exactly that residual. Zeroing the reserved bytes makes the encoding canonical, and rejects a header still carrying the pre-activation empty-list hash.
#### 3.5.3 Why `UncleHash`
@@ -287,7 +298,7 @@ Every check below is mandatory.
| Reserved bytes are zero | Header verification | A pure function of the header |
| `paymentGasUsed` does not exceed the header's gas used | Header verification | A pure function of the header, and the rule below is evaluated on it |
| `paymentLaneSize` does not exceed the header's gas limit | Header verification | Likewise; together the two bounds keep that rule's sum from wrapping |
-| The accounting rule of [§3.3](#33-reserved-gas-accounting-rule) holds on the committed values | Header verification | `generalGasUsed` is the header's gas used less `paymentGasUsed`, so the inequality needs no execution |
+| The accounting rule of [§3.3](#33-reserved-gas-accounting-rule) holds on the committed values | Header verification | With `generalGasUsed` a residual, the inequality is a function of the header alone |
| `paymentLaneSize` matches the value derived from the parent | Before execution, against the parent's post-state | The derivation reads governable parameters from that state, but nothing from this block beyond its header |
| `paymentGasUsed` matches the value obtained by re-execution | Block execution | Requires running the block |
@@ -323,6 +334,7 @@ The adjustment algorithm itself (the signal, the hysteresis structure, the accou
| `TRIGGER_GAP_MIN` | Minimum hysteresis band width, fixed at 1000 (10%) | Protocol constant |
| `RATIO_GAP_MIN` | Minimum ratio range width, fixed at 500 (5%) | Protocol constant |
| `RATIO_DENOM` | Denominator of every ratio parameter, fixed at 10000 | Protocol constant |
+| `SYSTEM_TXS_GAS_RESERVE` | Gas the quota must leave for Parlia's system transactions ([§3.4.4](#344-bounds)), fixed at 20,000,000 | Protocol constant |
Governable parameters are not free-form. The following invariants are validated by the protocol before any parameter change takes effect; **a governance proposal violating any of them is invalid** and never activates. The two gap constants are protocol constants, not governable — governance may move the ranges but can never collapse them:
@@ -360,7 +372,7 @@ Governable parameters are not free-form. The following invariants are validated
SHRINK_STEP_RATIO the same way.
```
-Suggested initial values, for discussion rather than locked by this BEP — the mechanism's correctness does not depend on these specific numbers:
+The eight values below are normative, not suggestions: a parameter governance has never written reads as the value listed here, so from activation until the first governance change these *are* the parameters, and one never written keeps reading its listed value indefinitely — which also means revising one of these at a later fork revises every parameter governance has never written. Two clients disagreeing on a single digit derive different quotas from the first lane block onward, and the accumulator of [§3.4](#34-dynamic-quota-adjustment) never reconverges. What does not depend on the specific numbers is the mechanism: any tuple satisfying the invariants above behaves correctly. What every client must share is the same tuple.
```
PAYMENT_LANE_MIN_RATIO = 200 (2%) PAYMENT_LANE_MAX_RATIO = 800 (8%)
From f1ae816559ac0c09732c905c118a21bd4a0c1548 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Wed, 12 Aug 2026 09:29:54 +0800
Subject: [PATCH 27/29] chore: remove useless comments
---
BEPs/BEP-703.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 5297cdb6..8d32e8a3 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -99,7 +99,7 @@ The bar is a gas budget, not a layout: it says nothing about where transactions
A transaction is a **payment transaction** if and only if it meets three conditions common to both rules below and then satisfies one of them, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**. Nothing is executed to decide this, so classification adds no consensus overhead.
-The common conditions are that `to` is non-nil, the transaction type is `0x00`, `0x01`, or `0x02`, and `accessList` is empty. They cap what a payment transaction can cost before either rule is consulted, and a transaction failing any of them is general whatever its destination. An access list is intrinsic gas that no destination can reduce — 2400 per address and 1900 per storage key — so at the 4.4M quota of [§3.4.6](#346-worked-example), 1833 addresses would fill the lane on intrinsic cost alone; the type allowlist rules out the per-authorisation cost of a code-setting transaction, and blob-carrying types with it.
+The common conditions are that `to` is non-nil, the transaction type is `0x00`, `0x01`, or `0x02`, and `accessList` is empty. They cap what a payment transaction can cost before either rule is consulted, and a transaction failing any of them is general whatever its destination.
| Rule | Payment when | Covers |
|---|---|---|
From 20b885c8a1049257133cf8686ecd9fdcb894cd9f Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Wed, 12 Aug 2026 10:42:23 +0800
Subject: [PATCH 28/29] bep703: refine trivals
---
BEPs/BEP-703.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 8d32e8a3..46902200 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -97,9 +97,9 @@ The bar is a gas budget, not a layout: it says nothing about where transactions
### 3.2 Transaction Classification
-A transaction is a **payment transaction** if and only if it meets three conditions common to both rules below and then satisfies one of them, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**. Nothing is executed to decide this, so classification adds no consensus overhead.
+A transaction is a **payment transaction** if and only if it meets three conditions common to both rules below and then satisfies one of them, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**. Nothing is executed to decide this — the class follows from static fields and a bounded parent-state lookup, so it is known before the block runs rather than as a result of running it.
-The common conditions are that `to` is non-nil, the transaction type is `0x00`, `0x01`, or `0x02`, and `accessList` is empty. They cap what a payment transaction can cost before either rule is consulted, and a transaction failing any of them is general whatever its destination.
+The common conditions are that `to` is non-nil, the transaction type is `0x00`, `0x01`, or `0x02`, and `accessList` is empty. A transaction failing any of them is general whatever its destination.
| Rule | Payment when | Covers |
|---|---|---|
From fa7575b87020ba4327a1534cff775987d2102189 Mon Sep 17 00:00:00 2001
From: will-2012 <117156346+will-2012@users.noreply.github.com>
Date: Wed, 12 Aug 2026 16:35:16 +0800
Subject: [PATCH 29/29] chore: refine payment lane
---
BEPs/BEP-703.md | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/BEPs/BEP-703.md b/BEPs/BEP-703.md
index 46902200..df58a921 100644
--- a/BEPs/BEP-703.md
+++ b/BEPs/BEP-703.md
@@ -97,28 +97,30 @@ The bar is a gas budget, not a layout: it says nothing about where transactions
### 3.2 Transaction Classification
-A transaction is a **payment transaction** if and only if it meets three conditions common to both rules below and then satisfies one of them, evaluated against static transaction fields and the state as of the end of the parent block. Every other transaction is a **general transaction**. Nothing is executed to decide this — the class follows from static fields and a bounded parent-state lookup, so it is known before the block runs rather than as a result of running it.
+A transaction is a **payment transaction** if and only if it meets three conditions common to both rules below and then satisfies one of them. Every other transaction is a **general transaction**. Nothing is executed to decide this: the class follows from static transaction fields plus bounded state lookups, so it is settled before the transaction runs rather than as a result of running it.
+
+The two rules read two different states, and that is deliberate. The **listed-destination** rule reads the state as of the end of the parent block, because list membership is a governance fact that has to be settled before the block does anything — read live, whoever orders the block would decide who is on the list. The **bare-transfer** rule reads the state as it stands when the transaction is about to run, so that an address which gains code within this same block is recognised as holding it. Because the listed rule can only ever decide *payment* and stops there, no transaction's class is decided by both: a listed destination is decided by the parent state, and everything else by the live state.
The common conditions are that `to` is non-nil, the transaction type is `0x00`, `0x01`, or `0x02`, and `accessList` is empty. A transaction failing any of them is general whatever its destination.
| Rule | Payment when | Covers |
|---|---|---|
| Listed destination | `to` is on the payment contract list ([§3.7](#37-payment-contract-list)) | Stablecoins and [BEP-702](./BEP-702.md) native tokens, whatever function is called |
-| Bare transfer | `data` is empty, `value` is non-zero, and `to` has no code in the parent state | Native BNB payments between accounts |
+| Bare transfer | `data` is empty, `value` is non-zero, and `to` has no code in the state this transaction is about to run against | Native BNB payments between accounts |
-With the common conditions, a bare transfer costs exactly 21000 gas: `to` non-nil rules out contract creation, empty `data` rules out calldata cost, and the access-list and type restrictions rule out everything else chargeable before execution. Its other two tests are about substance rather than cost. A non-zero `value` is what makes the transaction a payment at all: a zero-value transfer moves nothing, so reserved gas would be protecting nothing. No code at `to` is a test against the parent state, and so bounds the intrinsic cost rather than guaranteeing that nothing executes — a precompile holds no code, and an account that acquires code earlier in the same block, by deployment or by an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) authorisation, is still classified as having none, though one already carrying a delegation designator holds code and fails the test. In both residual cases the transfer executes code inside the lane, bounded by its own gas limit; [§4](#4-rationale) says why neither is closed, and why classification is not moved to execution time.
+With the common conditions, a bare transfer's intrinsic cost is exactly 21000 gas: `to` non-nil rules out contract creation, empty `data` rules out calldata cost, and the access-list and type restrictions rule out everything else chargeable before execution. Its other two tests are about substance rather than cost. A non-zero `value` is what makes the transaction a payment at all: a zero-value transfer moves nothing, so reserved gas would be protecting nothing. No code at `to` is what keeps the transfer from running contract code: an account that gains code earlier in the same block, by deployment or by an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) authorisation, holds it by the time the transfer is classified and is general, as is one that already carried a delegation designator.
```
-classify(tx, parentState):
+classify(tx, parentState, liveState): # parentState: end of h-1. liveState: just before tx runs.
if tx.to == nil: return GENERAL # common
if tx.type not in {0x00, 0x01, 0x02}: return GENERAL # common
if tx.accessList is not empty: return GENERAL # common
- if tx.to in paymentContractList(parentState): return PAYMENT # listed
+ if tx.to in paymentContractList(parentState): return PAYMENT # listed, and stops here
if tx.data is empty # bare transfer
and tx.value != 0
- and parentState.codeAt(tx.to) is empty: return PAYMENT
+ and liveState.codeAt(tx.to) is empty: return PAYMENT
return GENERAL
```
@@ -261,7 +263,7 @@ At 4.4M the reservation holds roughly 209 native transfers, or between 73 and 12
#### 3.5.1 Why the State Must Be Committed
-To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. The split requires the state as of `h−2` to classify `h−1`'s transactions, and the quota chains back, block by block, to `activation + 1`.
+To derive `paymentLaneSize(h)`, a node needs two things about block `h−1`: the quota that was in force there, and the class split of its gas. Neither can be recovered from the header chain. Recovering the split means replaying `h−1` itself, because a bare transfer's class turns on the state at the moment it ran ([§3.2](#32-transaction-classification)); and the quota chains back, block by block, to `activation + 1`.
The recurrence state is therefore committed rather than rederived, which bounds the recursion at the parent ([§3.5.5](#355-what-this-buys)).
@@ -302,7 +304,7 @@ Every check below is mandatory.
| `paymentLaneSize` matches the value derived from the parent | Before execution, against the parent's post-state | The derivation reads governable parameters from that state, but nothing from this block beyond its header |
| `paymentGasUsed` matches the value obtained by re-execution | Block execution | Requires running the block |
-The pre-execution split keeps [BEP-675](./BEP-675.md) unchanged: everything a validator must check before blind-sealing a builder's block is decidable from the parent.
+This split is what [BEP-675](./BEP-675.md) needs: `paymentLaneSize` joins the checks a validator makes before blind-sealing a builder's block, and like the rest of them it is decidable from the parent alone. `paymentGasUsed` is not, and no partial substitute is defined for it — classification reads the live state of the block the transactions belong to, which a validator that has not replayed them does not have. It is adjudicated on import, where BEP-675 already places everything it cannot verify before sealing.
#### 3.5.5 What This Buys
@@ -419,9 +421,11 @@ The governable parameters of [§3.6](#36-parameters-invariants-and-governance) a
**Ratio and absolute bounds together.** Ratio bounds let the quota scale automatically with block capacity so the mechanism never needs re-tuning as GasLimit grows; absolute bounds cap its footprint so growth in block size can never silently grow the reservation beyond an intended ceiling.
-**Classification by destination, not declaration.** Deriving the class from `to` plus parent state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim.
+**Classification by destination, not declaration.** Deriving the class from `to` plus state means no new transaction field, no wallet changes, and no user action: the protocol recognises an existing fact rather than accepting a claim.
+
+**The code test reads the live state.** Read against the parent instead, it stops guaranteeing that nothing runs, and the gap is not academic: one transaction deploying code and a second, behind it in the same block, transferring to that address with a large gas limit puts arbitrary execution inside the quota — priced at the quota's clearing tip rather than the open market's, which is cheapest precisely when congestion makes the reservation matter. An [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) authorisation is the same attack without the deployment. Against the live state the destination holds code by the time the transfer is classified, and both are ordinary general transactions.
-Classifying on code costs one thing: code can still run inside the lane, at a precompile or at an account that gains code earlier in the same block ([§3.2](#32-transaction-classification)). Neither is closed, for different reasons. Closing the same-block case would mean classifying against execution-time state, which opens a worse one — whoever orders the block would then decide which users' transfers are lane-eligible, by placing one cheap deployment ahead of them, and classification would stop being a fact the protocol recognises and become a lever the producer holds. No state test catches a precompile, which holds no code at any point, so only an address-set test would — and that set is fork- and chain-dependent: every client would have to carry it identically or diverge on classification, which the accumulator of [§3.4](#34-dynamic-quota-adjustment) never reconverges from. That is a wider divergence surface than the single case the test closes. Both residuals are bounded by the offending transaction's own gas limit, which is what makes leaving them open affordable.
+What that hands the block producer is bounded and points the wrong way for them. They cannot put code at an address they do not control — a `CREATE` address follows from the deployer, and an authorisation needs the authority's own signature — so the only transfers whose class they can move are those to an address that gains code within their block, and the only direction they can move it is *out* of the lane. Code cannot be taken away again to move one in: [EIP-6780](https://eips.ethereum.org/EIPS/eip-6780) deletes only what the same transaction created, and clearing a delegation needs the account's signature. Moving a transfer out lowers `paymentGasUsed`, which raises the idle reservation and tightens [§3.3](#33-reserved-gas-accounting-rule) against the producer's own block: it costs them space and earns them nothing. The price paid for this is predictability rather than safety — for a bare transfer the class now depends on the transaction's position in a block, so it is no longer something a wallet or an explorer can settle from public state before the block exists, and a reorg can change it.
## 5. Backward Compatibility