Skip to content

feat(stellar): emit the v2 scheme id from announcement builders - #259

Merged
truthixify merged 4 commits into
wraith-protocol:developfrom
aratass:feat/234-stellar-v2-scheme-id
Oct 18, 2026
Merged

truthixify merged 4 commits into
wraith-protocol:developfrom
aratass:feat/234-stellar-v2-scheme-id

Conversation

@aratass

@aratass aratass commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Closes #234.

Summary

#231 found that buildStealthAnnouncement() sends scheme 1, while the deployed v2 announcer asserts scheme_id == 2 (STELLAR_V2_SCHEME_ID in wraith-protocol/contracts). The same default was in buildPathStealthPayment(), buildStellarSwapAndStealth(), buildAnnouncementData() and encodeAnnouncementData().

  1. One exported source of truth. New ACTIVE_SCHEME_ID (= SCHEME_ID_V2) in constants.ts, exported from @wraith-protocol/sdk/chains/stellar. All five builders read it.
  2. Builder-to-contract conformance fixture. test/chains/stellar/fixtures/stealth-announcer-v2.json vendors stellar/abi/stealth_announcer.json from contracts at 66273f2, plus the two rules announce() enforces in code: scheme id 2, and the view tag in metadata[0]. announcer-conformance.test.ts decodes the announce call each builder produces and checks the function name, argument count and Soroban types against the ABI, then the scheme id, stealth address, 32-byte ephemeral key and view tag. With ACTIVE_SCHEME_ID set back to 1, 6 of its 10 tests fail.
  3. Migration notes for v1 consumers in MIGRATING.md, the CHANGELOG and EVENT_FETCHING.md.

Compatibility

  • The v1 announcer accepts any scheme id (its announce() has no check), so the same calls keep working against a v1 deployment. Its events keep the 3-topic layout, now with scheme 2.
  • fetchAnnouncements() already reads v1 events with ("announce", *, *), and the parser picks v1 or v2 by topic count, so historical v1 events are never reinterpreted as v2, as the contract's migration note asks.
  • scanAnnouncements() and the stream and pool scanners already accept 1 and 2. scanAnnouncementsLegacySharedSecretTag() accepted only 1; it now accepts both, so conformance invariant 23 (it matches scanAnnouncements()) stays true for new announcements.
  • SCHEME_ID keeps its value 1 and is marked @deprecated, pointing to SCHEME_ID_V1 and ACTIVE_SCHEME_ID. No export is removed.

Semver

Behaviour change for code that compares a built announcement's scheme to 1, so the entry is under Changed in Upcoming: 2.0.0. Otherwise additive (ACTIVE_SCHEME_ID).

Checks run locally

pnpm format:check, pnpm build, pnpm test (1,551 SDK tests and the Svelte package), pnpm test:types, pnpm test:exports, pnpm size (Stellar ESM 30.82 kB of 31 kB), pnpm api:check (report updated in etc/sdk-stellar.api.md) and pnpm pack:check.

@drips-wave

drips-wave Bot commented Oct 17, 2026

Copy link
Copy Markdown

@aratass Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@truthixify truthixify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The v2 scheme activation preserves v1 scanning compatibility; 67 conformance, batch, and transaction builder tests pass. Approved.

The deployed v2 announcer accepts only scheme_id 2, but the builders sent
1. ACTIVE_SCHEME_ID (= SCHEME_ID_V2) is now the single source of truth for
buildStealthAnnouncement(), buildPathStealthPayment(),
buildStellarSwapAndStealth(), buildAnnouncementData() and
encodeAnnouncementData(). The legacy shared-secret scanner accepts v2
announcements like the other scanners, and SCHEME_ID is deprecated.

A conformance test checks every builder against the announcer ABI vendored
from wraith-protocol/contracts.

Refs wraith-protocol#234
@aratass
aratass force-pushed the feat/234-stellar-v2-scheme-id branch from c7a59ae to b8ddc9b Compare October 17, 2026 19:29
@aratass

aratass commented Oct 17, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on develop (after #256, #257, #258) to clear the CHANGELOG conflict. Locally: format:check, build, 1,574 tests plus the Svelte suite, test:types, size-limit and api:check all pass; the API reports are unchanged.

@truthixify truthixify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The builder changes correctly emit scheme 2, but scanAnnouncementsLegacySharedSecretTag now claims to accept scheme 2 while still comparing metadata with computeViewTag(sharedSecret), the legacy v1 algorithm. V2 announcements use computeAnnouncementViewTag(ephemeralPubKey, viewingPubKey), so this exported scanner silently misses roughly 255/256 valid v2 announcements. Keep the legacy scanner v1-only or branch to the v2 tag algorithm, and add a non-vacuous v2 regression test that requires one generated v2 announcement to match.

scanAnnouncementsLegacySharedSecretTag() compares the metadata tag with
computeViewTag(sharedSecret), the v1 algorithm. Scheme 2 announcements
carry the public tag from computeAnnouncementViewTag(), so accepting
them there missed about 255 of 256 valid v2 announcements. It reads
scheme 1 only again, as before this branch, and says so in its docs.

Tests: a v2 announcement from buildAnnouncementData() must match in
scanAnnouncements() and scanAnnouncementsStream(), and the legacy
scanner must not claim a scheme 2 announcement, including one that
carries the legacy tag. CHANGELOG, MIGRATING and the ACTIVE_SCHEME_ID
docs say which scanners read which schemes.
@aratass

aratass commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

@truthixify Thanks, fixed in de8c1e8.

  • scanAnnouncementsLegacySharedSecretTag() is v1-only again, as on develop. It checks the legacy shared-secret tag, so it now skips scheme 2 announcements instead of misreading them, and its doc comment points to scanAnnouncements() / scanAnnouncementsStream() for v2.
  • New tests in test/chains/stellar/scan.test.ts:
    • a v2 announcement from buildAnnouncementData() must match exactly once in scanAnnouncements() and in scanAnnouncementsStream(), with the same private scalar;
    • the legacy scanner must return nothing for a scheme 2 announcement, including one that carries the legacy tag. That case fails on the previous head.
  • CHANGELOG, MIGRATING and the ACTIVE_SCHEME_ID docs now say which scanners read which schemes.

Locally: format:check, build, 1,576 tests plus the Svelte suite, test:types, size-limit and api:check pass. The API reports are unchanged.

@truthixify truthixify left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The legacy shared-secret scanner is now explicitly v1-only, while the primary and streaming scanners retain scheme-2 support with regression coverage. Local verification passed 91 focused Stellar tests, the package build, and public type tests.

@truthixify
truthixify merged commit 3b3f774 into wraith-protocol:develop Oct 18, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Wave 10][Carryover] Emit the Stellar v2 scheme ID from announcement builders

3 participants