event-mapper: decode CAP-67 muxed transfer values and full-range i128 amounts - #17
Merged
Merged
Conversation
… amounts. SAC transfer events since protocol 23 can carry their data as a map with amount and to_muxed_id; those deposits mapped to a null amount and never reached volume or asset-breakdown aggregates. decodeI128 also emitted an unparseable hi:lo string for amounts at or above 2^64.
AquiGorka
force-pushed
the
fix/sac-transfer-amount-decode
branch
from
July 31, 2026 12:39
5930df8 to
36787ec
Compare
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.
Root cause (with decoded on-chain evidence)
The empty volume / asset-breakdown tiles were investigated against live testnet data. Findings:
The plain-i128 path works. The two real channel money-flow events on testnet decode correctly with the current code:
0016589233871425536-0000000000(ledger 3862482):transferGDKSTZ...OBEF -> channel CD5MZC...KPF2, valuescvI128XDRAAAACgAAAAAAAAAAAAAAADuiayA== 1000500000 stroops0016589324065746944-0000000000(ledger 3862503): channel -> GBCDUL...QXU7, valuescvI128XDRAAAACgAAAAAAAAAAAAAAAAvrwgA== 200000000 stroopsBoth amounts appear intact in the live WS snapshot's
recentpayloads. The tiles are empty right now because no deposit/settlement has occurred inside the 24h / 60-min windows since 2026-07-29 13:25 UTC, not because these two events lost their amounts.Two real decode defects existed regardless:
transferevents whose destination carries a muxed id put their data in anscvMap{"amount": i128, "to_muxed_id": bytes}instead of a bare i128. Real example on testnet: event0016589229576450048-0000000000(ledger 3862481).decodeI128only acceptedscvI128, so any muxed deposit/settlement mapped toamount: nulland could never reach volume or asset-breakdown aggregates.decodeI128returned"<hi>:<lo>"wheneverhi != 0; the store'sparseAmountrejects that, silently dropping large amounts (and all negative amounts, sincehi = -1for those).Fix
decodeTransferAmountaccepts both on-chain shapes: barescvI128, and the CAP-67 map (extracts theamountentry).decodeI128does real signed reassembly (hi * 2^64 + lo) and returns a plain decimal string across the full i128 range.Tests
Five new vectors, the on-chain ones using the verbatim ScVal XDR captured from testnet RPC:
channel_depositwith amount1000500000channel_settlementwith amount200000000hi=1, lo=1->18446744073709551617(pre-fix:"1:1")mapChainEvent->recordEvent-> sparkline volume bucket100.05and 24h asset breakdown row1000500000stroops / 100%deno task test: 51 passed, 0 failed.check,lint,fmt:checkclean.Live verification (2026-07-31)
Ran local-dev testnet suite 1 through the events-capture harness against the deployed testnet platforms: 5/5 network WS events matched, including channel_deposit amount 100500000 and channel_settlement amount 40000000. Post-run snapshot shows volume sparkline 14.05 XLM, 24h asset breakdown XLM 140500000 stroops (100%), and live latency samples. The plain-i128 path is confirmed live end-to-end; the muxed-map and >=2^64 paths this PR adds are covered by the unit vectors and can get the same live check after deploy.