fix(seismic-rpc): effective balance on eth_getAccountInfo (Veridise 1206)#412
Open
samlaf wants to merge 2 commits into
Open
fix(seismic-rpc): effective balance on eth_getAccountInfo (Veridise 1206)#412samlaf wants to merge 2 commits into
samlaf wants to merge 2 commits into
Conversation
Gas on Seismic can be paid in native token or USDC, but a transaction's `value` is always a native transfer. The validator collapsed both balances into `max(native, usdc_scaled)` and compared that to the full cost (gas + value), conflating the two: it admitted USDC-rich senders whose native balance can't cover `value` (the tx is then unminable and stuck), and rejected senders who could legitimately pay `value` from native and gas from USDC. Make affordability component-wise, with usdc.rs as the single source of truth: - can_afford(native, usdc, gas_cost, value): native must cover value; gas is paid from one token (remaining native or USDC), never split. - gas_allowance(...): the same rule for eth_estimateGas. - effective_balance is kept but redocumented as the display-only convention behind eth_getBalance, not an affordability check. Consumers: - validator: gate admission on can_afford instead of cost > max(...). - caller_gas_allowance in seismic-rpc (eth_estimateGas): delegate to gas_allowance, removing the duplicated inline max()-value recipe. The pool tracks a single balance scalar per sender and can't express the component-wise rule, so the validator's Valid outcome and SeismicBalanceHook now report native + usdc -- a sound upper bound (can_afford => cost <= native + usdc) that stops admitted split-balance txs from stranding in the Queued subpool. It over-approximates only when an account overcommits its native balance across multiple value-bearing txs; block building stays the exact gate. Add unit tests for can_afford/gas_allowance and validator tests for the accept/reject cases. Also tidies a drifted reth_provider import in seismic-rpc transaction.rs. Refs: Veridise 1224 (also resolves 1172 item 1: effective_balance now has a single documented purpose)
…206)
The account-surface RPCs split into two contracts, and the balance each
reports should follow that split:
- Spendability view ("what can this account spend"): eth_getBalance and
eth_getAccountInfo. Wallet-facing, so they report the effective balance,
max(native, usdc_scaled).
- Committed account record: eth_getProof and eth_getAccount. These expose
the raw trie leaf, so they report the raw native balance.
eth_getAccountInfo (balance, nonce, code) was inheriting the upstream default
and returning the raw native balance, so a USDC-only account showed zero
there while eth_getBalance reported it correctly. Override get_account_info
in SeismicEthApi to report the effective balance, mirroring the upstream
default and swapping only the balance field.
eth_getProof and eth_getAccount deliberately stay native:
- eth_getProof returns a Merkle proof against the state root; the balance is
part of the proven account leaf, so a synthetic value would make the proof
unverifiable (the leaf would no longer hash to the proven path).
- eth_getAccount mirrors the raw trie record (it also returns storage_root
and code_hash) and is kept consistent with eth_getProof, so the two
raw-state endpoints never disagree with each other or with the state root.
Swapping only its balance would leave the record self-inconsistent with
its own storage_root/code_hash.
The native-vs-effective divide is documented on the override so future
account-surface endpoints follow it deliberately rather than by accident.
Extends the e2e gas/call-variants test: for a USDC-only account,
eth_getAccountInfo balance matches eth_getBalance and is non-zero, while
eth_getAccount does not report the effective balance.
Partially fixed: getProof/getAccount kept native with documented rationale.
Contributor
|
Adds LGTM - this implementation follows established patterns and includes comprehensive test coverage. The distinction between effective balance for wallet-facing endpoints vs. raw native balance for trie-structural endpoints is well-documented and correctly implemented. |
Base automatically changed from
fix-usdc-value-affordability
to
veridise-audit-april-2026
June 16, 2026 10:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes Veridise-1206: Account inspection RPCs return native balance instead of Seismic effective balance
Built on top of #411 since we use its
effective_balancefunction. Should be merged intoveridise-auditbranch after that one is merged.The account-surface RPCs split into two contracts, and the balance each reports should follow that split:
eth_getAccountInfo (balance, nonce, code) was inheriting the upstream default and returning the raw native balance, so a USDC-only account showed zero there while eth_getBalance reported it correctly. Override get_account_info in SeismicEthApi to report the effective balance, mirroring the upstream default and swapping only the balance field.
eth_getProof and eth_getAccount deliberately stay native:
The native-vs-effective divide is documented on the override so future account-surface endpoints follow it deliberately rather than by accident.