Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/snippets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,33 @@ jobs:

- name: Validate Stellar testnet snippets
run: pnpm run check:stellar-testnet

playground-smoke:
name: Playground smoke test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Verify playground fixtures are in sync
run: pnpm run check:playground-fixtures

- name: Install Playwright browser
run: pnpm exec playwright install --with-deps chromium

- name: Run playground smoke tests
run: pnpm run test:playground
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules/
.npm/
.npm/
test-results/
playwright-report/
19 changes: 19 additions & 0 deletions api-reference/fetch-announcements-stream.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,25 @@ for await (const announcement of stream) {
}
```

---

## Try It: Scan Announcements in Your Browser

The playground below parses a batch of Horizon-shaped fixture events — the same `topic`/`value` shape `fetchAnnouncementsStream` yields on Stellar — and scans them client-side with the view-tag fast filter and Ed25519 point math. No wallet, no network calls.

<iframe
src="/scripts/playground/index.html?step=scan"
sandbox="allow-scripts allow-same-origin"
width="100%"
height="760"
style={{ border: "1px solid #2a2f3d", borderRadius: "8px" }}
title="Wraith stealth playground — scan step"
/>

<Note>
Two of the five fixture announcements match the demo keys (pre-filled via **Load demo keys**); the other three are noise with the wrong view tag. You can also construct your own announcement in the [Send step](/guides/stellar-quickstart) and scan it here.
</Note>

### Resilient Stream with Retention Fallback

```typescript
Expand Down
23 changes: 22 additions & 1 deletion api-reference/stealth-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,25 @@ const keys = await deriveStealthKeysFromPasskey({
});
```

For a complete walkthrough on setting up passkey authentication with stealth transactions, refer to our [Passkey Signing Guide](../guides/stellar/passkey-signing.mdx).
For a complete walkthrough on setting up passkey authentication with stealth transactions, refer to our [Passkey Signing Guide](../guides/stellar/passkey-signing.mdx).

---

## Try It: Derive Keys in Your Browser

The playground below runs the same derivation the SDK performs, entirely client-side against canned fixtures — no wallet, no network calls. Paste any 64-byte signature (the demo one is pre-filled), and watch the two seeds split into a scan key, a spend key, and your stealth meta-address.

<iframe
src="/scripts/playground/index.html?step=derive"
sandbox="allow-scripts allow-same-origin"
width="100%"
height="660"
style={{ border: "1px solid #2a2f3d", borderRadius: "8px" }}
title="Wraith stealth playground — derive step"
/>

<Note>
The demo signature is deterministic and the derived keys are not connected to any real wallet. The meta-address it produces matches the fixtures used by the [scan step](/api-reference/fetch-announcements-stream).
</Note>

Continue through the guided flow by opening the same playground on the [Send](/guides/stellar-quickstart), [Scan](/api-reference/fetch-announcements-stream), and [Withdraw](/guides/stellar-quickstart) steps.
38 changes: 38 additions & 0 deletions guides/stellar/stellar-quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ By the end of this tutorial you will have:

**Prerequisites:** Node.js 18+, a Wraith API key ([sign up at usewraith.xyz](https://usewraith.xyz)), and the Freighter browser extension installed ([get it here](https://www.freighter.app)).

<Tip>
Every stage below can be run interactively in your browser. The [Send](#send-a-stealth-payment) and [Withdraw](#withdraw-to-your-wallet) sections embed a client-side playground that runs the exact same flow against canned fixtures — no wallet or network calls needed. Continue the full guided flow on the [derive](/api-reference/stealth-keys) and [scan](/api-reference/fetch-announcements-stream) pages.
</Tip>

---

## 1. Install Dependencies
Expand Down Expand Up @@ -328,6 +332,23 @@ Alice's agent scans for announcements, matches them using her viewing key, and d
A view tag is the first byte of `SHA-256("wraith:tag:" || sharedSecret)`. It allows scanners to reject ~255/256 non-matching announcements with a single byte comparison — no expensive Ed25519 point operations needed. This makes scanning fast even over thousands of announcements.
</Accordion>

### Try It: Construct an Announcement

Construct a mock stealth payment in your browser — the playground generates the one-time ephemeral keypair, derives the stealth address, and builds the Horizon announcement event the `stealth-announcer` contract would emit. The announcement lands in the scan batch, so it shows up in the [scan step](/api-reference/fetch-announcements-stream).

<iframe
src="/scripts/playground/index.html?step=send"
sandbox="allow-scripts allow-same-origin"
width="100%"
height="640"
style={{ border: "1px solid #2a2f3d", borderRadius: "8px" }}
title="Wraith stealth playground — send step"
/>

<Note>
The demo recipient meta-address is pre-filled and deterministic; the payment it produces is a simulation, not an on-chain transaction.
</Note>

---

## 8. Scan for Incoming Payments
Expand Down Expand Up @@ -395,6 +416,23 @@ console.log(privacy.response);
To protect your privacy, space withdrawals at least **1 hour apart** and avoid withdrawing uniform round amounts. The agent's privacy scoring algorithm checks for timing patterns, address correlation, and dust amounts. See [Privacy Best Practices](/guides/privacy-best-practices) for details.
</Info>

### Try It: Withdraw a Stealth Balance

The playground below derives the withdrawable balances from the fixture announcements with the demo keys, then shows the simulated withdrawal transaction each one would sign with its stealth private scalar.

<iframe
src="/scripts/playground/index.html?step=withdraw"
sandbox="allow-scripts allow-same-origin"
width="100%"
height="640"
style={{ border: "1px solid #2a2f3d", borderRadius: "8px" }}
title="Wraith stealth playground — withdraw step"
/>

<Note>
This is a simulation — the destination wallet is a deterministic demo address. The private scalar shown is what your own agent would use to sign a real withdrawal.
</Note>

### Withdrawing to Any Destination

```typescript
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"check:stellar-testnet": "tsx scripts/check-stellar-testnet-snippets.ts",
"generate:stellar-reference": "tsx scripts/generate-stellar-reference.ts",
"check:stellar-reference": "tsx scripts/generate-stellar-reference.ts --check --allow-missing",
"generate:playground-fixtures": "node scripts/playground/generate-fixtures.mjs",
"check:playground-fixtures": "node scripts/playground/generate-fixtures.mjs --check",
"test:playground": "playwright test --config scripts/playground/tests/playwright.config.ts",
"mint:validate": "mint validate",
"mint:broken-links": "mint broken-links",
"test": "npm run check:snippets && npm run check:nav-coverage"
Expand All @@ -18,6 +21,7 @@
"@wraith-protocol/sdk": "^1.4.5"
},
"devDependencies": {
"@playwright/test": "^1.49.1",
"@types/node": "^22.10.2",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
Expand Down
38 changes: 38 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 91 additions & 0 deletions scripts/playground/fixtures.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"recipient": {
"signature": "98822231bc29a7b7fa05b22cb955271eb091952cdc574040833e8710c21a57febc8a29ac3a269ecf90a8000ba429a629f7a03475bcf0727f3862099bbc3b97bc",
"spendingKey": "8abc3ca12f1ea7d8a035035b30495dab4580312cda2ddc408bfcb0f05a4aeadf",
"viewingKey": "0d474ed106c31d9be5e40d23987e05e7e7f250f618abee45e78ce8a5a89d5c16",
"spendingScalar": "44210394736376739873962455346134452853705630680662457980493046177521038273944",
"viewingScalar": "48307637337068610111822068508286914851033825534515029969832724895260692015208",
"spendingPubKey": "eb8452e938d04e9a56ef69c47dacd8224464b030b5ca569d5b4e4399f8d0fb55",
"viewingPubKey": "29a8dd877a3803289ab3a62ac39cce4a99021a3cd0fac6ad982e051c8fa769dc",
"metaAddress": "st:xlm:eb8452e938d04e9a56ef69c47dacd8224464b030b5ca569d5b4e4399f8d0fb5529a8dd877a3803289ab3a62ac39cce4a99021a3cd0fac6ad982e051c8fa769dc",
"walletAddress": "GB4X7TDIRWAXKYRAYRXSTY27DZUTQKEMJKV7GBKZ3RVJJS5XCHAELUZI"
},
"announcerContractId": "CCJLJ2QRBJAAKIG6ELNQVXLLWMKKWVN5O2FKWUETHZGMPAD4MHK7WVWL",
"events": [
{
"type": "contract",
"contract_id": "CCJLJ2QRBJAAKIG6ELNQVXLLWMKKWVN5O2FKWUETHZGMPAD4MHK7WVWL",
"ledger": 51234000,
"ledger_close_time": "2026-08-20T12:00:00.000Z",
"id": "0000000000000000030dc4d00000000000000000",
"paging_token": "51234000-0",
"topic": [
"AAAADwAAAAhhbm5vdW5jZQ==",
"AAAAAwAAAAE=",
"AAAAEgAAAAAAAAAAIqtRXPL2GmdCP+bde4hGNCoXiH+wKZAxd3/TheC3t/0="
],
"value": "AAAAEAAAAAEAAAADAAAAEgAAAAAAAAAAFjM5gVlCLWe12ocr2Z56+SK0zkRi5WgaOs8iFHUi6d4AAAANAAAAIBYzOYFZQi1ntdqHK9meevkitM5EYuVoGjrPIhR1IuneAAAADQAAACBfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"_yours": true
},
{
"type": "contract",
"contract_id": "CCJLJ2QRBJAAKIG6ELNQVXLLWMKKWVN5O2FKWUETHZGMPAD4MHK7WVWL",
"ledger": 51234001,
"ledger_close_time": "2026-08-21T12:00:00.000Z",
"id": "0000000000000000030dc4d10000000000000000",
"paging_token": "51234001-1",
"topic": [
"AAAADwAAAAhhbm5vdW5jZQ==",
"AAAAAwAAAAE=",
"AAAAEgAAAAAAAAAAbwoxfo1UleU30uxYWjsBtQpSXMVYCGBkney2/oqlwWU="
],
"value": "AAAAEAAAAAEAAAADAAAAEgAAAAAAAAAAYaeYyrc6YoZo7/DMSlz1HVaHyUe/xnQQAIBTgEnhNjoAAAANAAAAIGGnmMq3OmKGaO/wzEpc9R1Wh8lHv8Z0EACAU4BJ4TY6AAAADQAAACCFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"_yours": false
},
{
"type": "contract",
"contract_id": "CCJLJ2QRBJAAKIG6ELNQVXLLWMKKWVN5O2FKWUETHZGMPAD4MHK7WVWL",
"ledger": 51234002,
"ledger_close_time": "2026-08-22T12:00:00.000Z",
"id": "0000000000000000030dc4d20000000000000000",
"paging_token": "51234002-2",
"topic": [
"AAAADwAAAAhhbm5vdW5jZQ==",
"AAAAAwAAAAE=",
"AAAAEgAAAAAAAAAAfLtYHQxZk09xS3vObXcVqtYviB7UFT3OGORCXiSOlGA="
],
"value": "AAAAEAAAAAEAAAADAAAAEgAAAAAAAAAAUhyk20jvoleCDbryfv10BQMOIOreUmtoALmC+gpGy/AAAAANAAAAIFIcpNtI76JXgg268n79dAUDDiDq3lJraAC5gvoKRsvwAAAADQAAACBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"_yours": true
},
{
"type": "contract",
"contract_id": "CCJLJ2QRBJAAKIG6ELNQVXLLWMKKWVN5O2FKWUETHZGMPAD4MHK7WVWL",
"ledger": 51234003,
"ledger_close_time": "2026-08-23T12:00:00.000Z",
"id": "0000000000000000030dc4d30000000000000000",
"paging_token": "51234003-3",
"topic": [
"AAAADwAAAAhhbm5vdW5jZQ==",
"AAAAAwAAAAE=",
"AAAAEgAAAAAAAAAATam9D4M2xhWIQ6h03y9kOlcHQ2aFMOJ8w42VdMJRWgM="
],
"value": "AAAAEAAAAAEAAAADAAAAEgAAAAAAAAAA3FLnwEKlqKFW90zpyt/IdNo0SGTTkrCClOXAzD45dYkAAAANAAAAINxS58BCpaihVvdM6crfyHTaNEhk05KwgpTlwMw+OXWJAAAADQAAACCVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"_yours": false
},
{
"type": "contract",
"contract_id": "CCJLJ2QRBJAAKIG6ELNQVXLLWMKKWVN5O2FKWUETHZGMPAD4MHK7WVWL",
"ledger": 51234004,
"ledger_close_time": "2026-08-24T12:00:00.000Z",
"id": "0000000000000000030dc4d40000000000000000",
"paging_token": "51234004-4",
"topic": [
"AAAADwAAAAhhbm5vdW5jZQ==",
"AAAAAwAAAAE=",
"AAAAEgAAAAAAAAAAjsBTk06PWenk4B0q3B5BtX+fPfEsJXehKsCI42TzQ30="
],
"value": "AAAAEAAAAAEAAAADAAAAEgAAAAAAAAAAsbT/rDG0eoPrT66DUFMJ4AqhkAUfk08F/td0yuN1INwAAAANAAAAILG0/6wxtHqD60+ug1BTCeAKoZAFH5NPBf7XdMrjdSDcAAAADQAAACD6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"_yours": false
}
]
}
Loading
Loading