fix(swap): post-swap on-chain reconcile for EVM token outputs + tracker hardening#377
Merged
Merged
Conversation
Recorded as an unresolved REST-layer issue on the strength of a single observation. It was a stuck emulator. /hive/sign-operations is in SIGNING_ROUTES and does get server.timeout(req, 0), so a pending confirm holds the socket open as designed. Rewritten so the next agent restarts the emulator instead of going hunting in rest-api.ts.
…t malformed tracker rows
Two fixes for the stale-USDT-after-swap incident (85.6 USDT delivered, dashboard
kept a dust balance and the tracker stored received=0.604399 with a zeroed
outbound hash):
1. Post-swap targeted refresh now forces a direct on-chain balanceOf for the
swap's destination token. The swap-completed event carries the output CAIP;
when it is an EVM token (/erc20:) the Dashboard forwards it through
getBalances (swapDestCaips) and the bun backend appends an extraContracts
entry ({networkId, contractAddress, symbol, decimals}) to the Pioneer
POST /portfolio body — bypassing the indexed (Zapper) source, which lags a
few blocks after a swap and can return a stale pre-swap balance marked
fresh. Decimals/symbol come from pioneer-discovery assetData, falling back
to a previously cached token row; unknown tokens are skipped with a warning.
2. swap-tracker hardening: an all-zero (or empty) outbound tx hash in a
provider status response is treated as not-yet-known instead of being
stored, and the received amount from such a malformed row is rejected
(amounts <= 0 were already rejected) — a later poll carries the real values.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Why
After a swap delivered 85.643286 USDT, all three post-swap refreshes (immediate/+30s/+90s) re-queried the same indexed source (Zapper via Pioneer), got back the stale pre-swap dust balance marked fresh, and persisted it. Separately, the swap tracker accepted a malformed provider response (received 0.604399 with an all-zeros outbound tx hash) as final.
What
Post-swap targeted refresh reconciles the destination contract on-chain
keepkey-swap-completedevent (SwapTracker/ActivityTracker) now carriestoCaip.refreshBalances→getBalancesRPC (swapDestCaips, new optional param in rpc-schema).extraContractsentry on the PioneerGetPortfolioBalancesbody — networkId/contract parsed from the caip, decimals/symbol/name from pioneer-discoveryassetDatawith cached-token-row fallback; entries with unresolvable decimals are skipped (never guessed). Deduped against existing custom-token extraContracts. Rides all three refreshes.balanceOfnow upserts over stale indexer rows.Swap-tracker hardening (
src/bun/swap-tracker.ts)> 0guard keeps rejecting non-positive amounts. A later poll with real data fills in the correct values.Verified
bun scripts/bundle-backend.tsOK (7.60 MB),bunx vite buildOK (4.03s) — the compile stepsmake buildruns.tscoutput for the six touched files: zero new errors (repo has ~1576 pre-existing).🤖 Generated with Claude Code