event-gate erc20 balance reads#335
Open
mrq1911 wants to merge 1 commit into
Open
Conversation
🦋 Changeset detectedLatest commit: e0bca73 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
✅ Deploy Preview for galactic-apps ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
mrq1911
marked this pull request as ready for review
June 28, 2026 11:49
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.
Problem
BalanceClient.watchErc20Balanceis the #1 per-block RPC cost of an active sdk-next context. Today it does:→ re-reads every ERC20 id via
CurrenciesApi.account(achainHead_v1_call) on every block, unconditionally. ThedistinctUntilChangedonly suppresses emissions, not the RPC ops. Measured on a mainnet chainHead node (Treasury account, 64 pools / 43 ERC20 slots): ~84chainHead_v1_call/block, allCurrenciesApi_account.Fix (event-gated)
EVM.Log.watch(), decode ERC20Transfer(from,to,value)logs, map the emitting contract → asset id via the existingERC20.toAssetId(structural0x..01<id>precompile prefix — no RPC; same mappingAavePoolClientuses in reverse).(address, id)pairs where the watched account isfrom/to(account compared viaH160.fromAny).N=20blocks so a missed/unmapped log (e.g. a non-EVM mutation of an ERC20-typed asset) can't permanently stale a balance.Public
watchErc20Balance/watchBalancesignatures are unchanged (internal only).Benchmark (mainnet chainHead, same harness, only the lib changes)
CurrenciesApi_accountcalls per block, Treasury account, 64 pools / 43 ERC20 slots:CurrenciesApi_account/blockchainHead_v1_call/blockIdle blocks drop to 0
CurrenciesApi_accountcalls; the residual 0.43 is the unrelated router Aave-executor call from the spot-price loop. Storage ops unchanged → the change targets exactly the ERC20 call fan-out and nothing else.Regression
Erc20Log.spec.ts).getBalanceData → CurrenciesApi.accountis untouched; only the scheduling changed.)Erc20Logdecoder + the from/to gate are unit-tested against synthetic Transfer logs (sender match, receiver match, wrong-asset drop, unrelated-account drop, non-asset-contract → null). A real Transfer touching the account triggers a targeted re-read; the safety re-read backstops any missed log.Notes
packages/sdk-next/src/client/Erc20Log.spec.ts(10 cases) covering the pure decoder + the event-gate predicate.sdk-nextpatch).