fix(scan): parse versioned SIP:1/SIP:2 announcements via SDK parseAnnouncement (#313)#314
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ouncement
The /v1/scan/payments and /scan/payments/batch routes parsed stealth
announcements with `.replace('SIP:', '').split(':')`, assuming an unversioned
`SIP:<eph>:<viewTag>:<stealth>` memo. But the SIP SDK has always emitted
versioned announcements — `SIP:1:` (legacy) and, since the EIP-5564 canonical
flip (sdk 0.10/0.11), `SIP:2:`. The naive parse leaves the version digit as
parts[0], so `new PublicKey('1'|'2')` throws and the announcement is silently
skipped. The route therefore missed every real on-chain announcement, not just
SIP:2.
Replace both parse sites with the SDK's canonical, version-aware
`parseAnnouncement`, which resolves SIP:1 + SIP:2 and validates the
ephemeral/viewTag/stealth components. The unversioned form is a fictional format
no producer emits and is intentionally no longer matched.
The `SIP:` log pre-filter uses a local constant because the SDK's
`SIP_MEMO_PREFIX_ANY` currently exists only in the SDK's CJS runtime bundle —
absent from the ESM build and from both type-declaration files, so an ESM/TS
consumer can't import it; `parseAnnouncement` does the authoritative parsing.
Tests: SIP:2 view-only round-trips for both routes + a guard that the legacy
unversioned form is ignored.
Closes #313
225ed1d to
5638dfc
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.
Closes #313.
The bug (broader than the issue framed)
Both
/v1/scan/paymentsand/v1/scan/payments/batchparsed stealth announcements with:This assumes an unversioned
SIP:<eph>:<viewTag>:<stealth>memo. But git history shows the SIP SDK has always emitted versioned announcements:createAnnouncementMemo→SIP:1:<eph>:<viewTag>,parseAnnouncementrequiredstartsWith('SIP:1:')SIP:2:<eph>:<viewTag>[:<stealth>]For a real memo,
.replace('SIP:', '')leaves the version digit asparts[0]→new PublicKey('1'|'2')throws → the announcement is silently skipped. So the route missed every real on-chain announcement (SIP:1 and SIP:2), not just SIP:2 as the issue estimated. The unversioned form the code parsed is fictional — nothing in the SIP ecosystem emits it (verified: sipher writes noSIP:memos; the SDK always versions).The fix
Adopt the SDK's canonical, version-aware
parseAnnouncementat both parse sites. It resolvesSIP:1:+SIP:2:and validates the ephemeral/viewTag/stealth components. The fictional unversioned form is intentionally no longer matched (a test documents this). Downstream logic (PublicKey→hex, viewTag range,checkEd25519StealthAddress, response shape) is unchanged — no API contract change.SDK ESM-export gap (found en route — filed separately)
parseAnnouncement/createAnnouncementMemoare exported from the SDK's ESM build, but the constantsSIP_MEMO_PREFIX_ANY/SIP_MEMO_PREFIX_V2exist only in the SDK's CJS runtime bundle (dist/index.js) — they're absent from the ESM bundle (dist/index.mjs) and from both type-declaration files (dist/index.d.ts,dist/index.d.mts). So no ESM/TS consumer can import them: tsc errors ("no exported member"), and a bundler that tolerates missing named ESM imports yieldsundefinedat runtime (caught here during TDD). TheSIP:pre-filter therefore uses a local constant;parseAnnouncementdoes the authoritative parsing. Filed upstream: sip-protocol/sip-protocol#1123.Tests (TDD — red first)
POST /v1/scan/payments— SIP:2 view-only round-trip (built via the SDK'screateAnnouncementMemo)POST /v1/scan/payments/batch— SIP:2 view-only round-trip (the batch route has the same bug)SIP:memo is ignoredVerification
pnpm exec vitest run tests/scan.test.ts→ 15/15pnpm exec vitest run(root) → 558/558 (+2 net new)pnpm typecheck→ clean (app + packages/sdk + packages/agent)Notes
SIP:1:) parse but won't match the canonical view-only check — the accepted data-compat behavior from the #1099 flip.src/routes/scan.tswas untouched by fix!: migrate to @sip-protocol/sdk 0.11.0 (canonical EIP-5564 view-only) #312, so this is pre-existing.