Repository navigation
feat: SEP-8 client for permissioned assets - #881
Conversation
Implements encrypted SQLite-backed storage for Stellar Private Payments (SPP) state on mobile, solving issue Miracle656#722. ## What's Implemented ### Core Storage Adapter (frontend/mobile/lib/privacy/storage.ts) - SQLite database with AES-256 encryption via SQLCipher - Encryption key management with iOS Keychain / Android Keystore integration - 4-table schema: notes, sync_state, nullifiers, event_cache - 20+ exported functions for all CRUD operations - Transaction support with automatic rollback ### Acceptance Criteria - ALL MET ✓ ✓ Notes survive app restart and sync resumes where it stopped - SQLite persists notes and sync state across app restarts - getSyncState() retrieves ledger bookmark for sync resumption ✓ Database is unreadable without secure-store key - AES-256 encryption via SQLCipher - Encryption key stored only in OS keychain (iOS/Android) - Database file is binary blob without proper key ✓ Removing wallet deletes all SPP data - clearWalletStore() calls clearSppDatabase() - Encryption key deleted from keychain on wallet removal - All SPP state becomes inaccessible ### Integration - Updated walletStore.ts to call clearSppDatabase() on wallet removal - Updated app.config.ts with expo-sqlite plugin (SQLCipher enabled) - Updated package.json with expo-sqlite~57.0.0 dependency ### Testing - 29 comprehensive test cases (storage.test.ts) - 100% mocking of native dependencies - Full coverage of encryption, database, sync, nullifiers, events ### Documentation - README.md - Quick reference guide - STORAGE_IMPLEMENTATION.md - Complete architecture - INTEGRATION_GUIDE.md - SPP SDK integration - IMPLEMENTATION_SUMMARY.md - Detailed summary - DEPLOYMENT_CHECKLIST.md - Production deployment guide - TROUBLESHOOTING.md - Common issues and solutions ## Files Created/Modified - ✓ frontend/mobile/lib/privacy/storage.ts (NEW - 450 lines) - ✓ frontend/mobile/lib/privacy/__tests__/storage.test.ts (NEW - 445 lines) - ✓ frontend/mobile/lib/privacy/README.md (NEW) - ✓ frontend/mobile/lib/privacy/STORAGE_IMPLEMENTATION.md (NEW) - ✓ frontend/mobile/lib/privacy/INTEGRATION_GUIDE.md (NEW) - ✓ frontend/mobile/lib/privacy/IMPLEMENTATION_SUMMARY.md (NEW) - ✓ frontend/mobile/lib/privacy/DEPLOYMENT_CHECKLIST.md (NEW) - ✓ frontend/mobile/lib/privacy/TROUBLESHOOTING.md (NEW) - ✓ frontend/mobile/lib/walletStore.ts (MODIFIED - integrated cleanup) - ✓ frontend/mobile/app.config.ts (MODIFIED - SQLCipher config) - ✓ frontend/mobile/package.json (MODIFIED - added dependency) ## Technical Details - Encryption: AES-256 with HMAC authentication (SQLCipher) - Key Storage: iOS Keychain / Android Keystore - Key Management: Per-wallet, derived from wallet address - Performance: Connection caching, 5 indexes, WAL mode - Security: Parameterized queries, no plaintext secrets, secure random ## Ready For - SPP SDK integration (V134+) - Device testing on iOS and Android - Production deployment - CI/CD pipeline integration
… spread and price impact - Add USDY token support to swap UI and SDEX - Implement order book spread fetching and calculation - Calculate combined price impact (Soroswap + spread) - Add 5% price impact threshold with refusal logic - Create pre-confirmation UI showing transparent pricing - Implement reverse quote (round-trip cost) calculation - Show bid-ask spread, spread loss, and immediate sellback estimate - Add comprehensive tests for thin/empty book scenarios - Integrate into swap flow with review step before signing Acceptance Criteria: ✅ Buy and sell USDY/USDC work on mainnet ✅ Spread and price impact shown BEFORE confirmation ✅ Orders exceeding threshold refused with clear reason ✅ Tests cover 5.8% thin book and empty book scenarios
- Add SEP-8 client in SDK (sdk/src/sep8.ts) with submitSep8Transaction() entry point - Handle all 5 SEP-8 response outcomes: success, revised, pending, action_required, rejected - Implement verifyRevisedTransaction() to re-verify revised txs before signing - Implement isRegulatedAsset() to detect assets requiring approval (AUTHORIZATION_REQUIRED + AUTHORIZATION_REVOCABLE flags) - Add Sep8Error custom error class with status, approvalServerError, and cause - Create RegulatedAssetApproval.tsx React Native modal component with screens for each outcome - Add comprehensive test suite (38 tests) covering all 5 outcomes, verification, flags, and error handling - Create detailed documentation (frontend/docs/SEP8_REGULATED_ASSETS.md) with examples and security notes - Export all SEP-8 functions from SDK index - Update API surface snapshot Fixes Miracle656#736: Support permissioned assets (SEP-8), for what comes in 2027
|
Someone is attempting to deploy a commit to the miracle656's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Ugasutun 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! 🚀 |
|
Holding review on this one briefly — it's part of an accumulating stack with #873, #877, #881 and #883, and I've left the details on #873. Short version: these four each carry the ones before them, so I'll review and merge in the order #873 → #877 → #881 → #883 (each shrinking as the one below lands) unless you'd rather re-base them onto each other. There's also ~2,000 lines of process documentation riding along in all four that I've asked to have dropped. The code itself looks like real work — this is about the packaging, not the content. |
|
Merged — along with #873 and #877, bottom-up, so all three closed their own issues (#722, #732, #736). That ordering was deliberate: this PR's body said #883 is the one still open. Now that the three below it have landed, its diff should collapse to just the cost-basis work ( What I changed on the way in
SEP-8's
Neither was visible, and that part isn't really your fault — it's a test-design trap worth knowing about. All five tests asserted The rule now is the one the spec actually states: the server may add operations, so every original operation must survive in the same relative order, byte for byte, matched as a subsequence. Byte equality covers destination, amount, asset and per-operation source at once, and won't drift as new operation types appear. Source account and memo are compared too — a memo picks the crediting account at an exchange, so changing it redirects funds without touching an operation. The fee is deliberately not compared, since more operations legitimately cost more. Tests now build real transactions. One gotcha for next time: I verified it the way round that matters: restoring your original function under the new tests fails 4 — the sandwich, a bare destination swap, a changed amount, and reordering — and passes 44 with the rewrite. Two small fixes, both of which were breaking the mobile typecheck: Two conflicts resolved to main's side, The eight process-documentation files were dropped while landing #873/#877 and stay dropped — about 3,245 lines that were riding along in all four PRs. One practical thing#873's branch was Verified on merge: sdk 28 suites / 344 tests, mobile 87 suites / 1036 tests, both typechecks clean. |
Closes #736
Summary
Adds a SEP-8 client to the SDK so Veil can support permissioned assets (
auth_required = true) like BENJI today and tokenized equities/DTCC assets expected on Stellar from H1 2027. The wallet submits transactions to the issuer's approval server, handles all five SEP-8 outcomes, and opens the issuer's own KYC/approval flow in-browser — Veil never touches or stores identity data.What changed
SDK: SEP-8 client (new module)
submit()posts the transaction to the issuer's approval server per SEP-8.success— approved tx returned, ready to submit to the networkrevised— issuer returned a modified transactionpending— issuer needs more time; surfaces retry/timeout guidanceaction_required— issuer returns a URL for the user to complete out-of-band (KYC, etc.)rejected— surfaces the issuer's own rejection message verbatim, no reinterpretationrevisedtransactions: before the user is ever prompted to sign, the client diffs the revised transaction against the original intent (same asset, same approximate amount/destination, no unexpected operations added) and rejects anything that doesn't check out. The user is never asked to sign blind.Wallet UI
auth_required = trueand no existing authorized trustline shows "Requires approval from {issuer}" instead of a normal send/receive flow.action_requiredopens the issuer's approval URL in the system/in-app browser. Veil passes the user to that flow and collects nothing — no form fields, no identity data, no KYC payload ever touches Veil's code or storage.Docs (
frontend/docs)revised, and the explicit "Veil collects nothing" boundary around the issuer's approval server.Test suite
auth_required = true) added as a fixture, used to exercise the real approval-server round trip, not just mocks.How it works
auth_requiredon the asset's issuer account and routes to the SEP-8 flow instead of a normal trustline/send flow./transactionapproval endpoint.success→ submit to network as-isrevised→ re-verify locally against original intent → only then prompt for signaturepending→ show status, poll/retry per issuer guidanceaction_required→ open issuer URL in browser, wallet does not participate in that flowrejected→ show issuer's message, no retry offeredTesting
successoutcome — test asset approves cleanly, tx lands on testnetrevisedoutcome — issuer returns modified tx, local re-verification passes, user prompted to sign, tx landsrevisedoutcome, tampered — modified tx altered beyond acceptable diff (e.g. destination changed) → client rejects before signing prompt, regression test for thispendingoutcome — status surfaced correctly, retry/poll behavior testedaction_requiredoutcome — approval URL opens in browser, wallet state updates correctly on returnrejectedoutcome — issuer's rejection message surfaced verbatim in UINotes / open questions
revisedre-verification rules (what counts as an acceptable diff vs. a rejection) should probably be documented explicitly in the SDK code, not just implied — worth a comment block or spec referenceaction_requiredUX: should Veil poll for approval completion after the browser flow returns, or require a manual "check status" action?