toss-expo-sdk 0.1.2 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +368 -15
- package/lib/module/ble.js +59 -4
- package/lib/module/ble.js.map +1 -1
- package/lib/module/client/BLETransactionHandler.js +277 -0
- package/lib/module/client/BLETransactionHandler.js.map +1 -0
- package/lib/module/client/NonceAccountManager.js +364 -0
- package/lib/module/client/NonceAccountManager.js.map +1 -0
- package/lib/module/client/TossClient.js +1 -1
- package/lib/module/client/TossClient.js.map +1 -1
- package/lib/module/hooks/useOfflineBLETransactions.js +314 -0
- package/lib/module/hooks/useOfflineBLETransactions.js.map +1 -0
- package/lib/module/index.js +12 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/intent.js +129 -0
- package/lib/module/intent.js.map +1 -1
- package/lib/module/noise.js +175 -0
- package/lib/module/noise.js.map +1 -1
- package/lib/module/reconciliation.js +155 -0
- package/lib/module/reconciliation.js.map +1 -1
- package/lib/module/services/authService.js +164 -1
- package/lib/module/services/authService.js.map +1 -1
- package/lib/module/storage/secureStorage.js +102 -0
- package/lib/module/storage/secureStorage.js.map +1 -1
- package/lib/module/sync.js +25 -1
- package/lib/module/sync.js.map +1 -1
- package/lib/module/types/nonceAccount.js +2 -0
- package/lib/module/types/nonceAccount.js.map +1 -0
- package/lib/module/types/tossUser.js +16 -1
- package/lib/module/types/tossUser.js.map +1 -1
- package/lib/typescript/src/__tests__/solana-program-simple.test.d.ts +8 -0
- package/lib/typescript/src/__tests__/solana-program-simple.test.d.ts.map +1 -0
- package/lib/typescript/src/ble.d.ts +31 -2
- package/lib/typescript/src/ble.d.ts.map +1 -1
- package/lib/typescript/src/client/BLETransactionHandler.d.ts +98 -0
- package/lib/typescript/src/client/BLETransactionHandler.d.ts.map +1 -0
- package/lib/typescript/src/client/NonceAccountManager.d.ts +82 -0
- package/lib/typescript/src/client/NonceAccountManager.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useOfflineBLETransactions.d.ts +91 -0
- package/lib/typescript/src/hooks/useOfflineBLETransactions.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +9 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/intent.d.ts +15 -0
- package/lib/typescript/src/intent.d.ts.map +1 -1
- package/lib/typescript/src/noise.d.ts +62 -0
- package/lib/typescript/src/noise.d.ts.map +1 -1
- package/lib/typescript/src/reconciliation.d.ts +6 -0
- package/lib/typescript/src/reconciliation.d.ts.map +1 -1
- package/lib/typescript/src/services/authService.d.ts +26 -1
- package/lib/typescript/src/services/authService.d.ts.map +1 -1
- package/lib/typescript/src/storage/secureStorage.d.ts +16 -0
- package/lib/typescript/src/storage/secureStorage.d.ts.map +1 -1
- package/lib/typescript/src/sync.d.ts +6 -1
- package/lib/typescript/src/sync.d.ts.map +1 -1
- package/lib/typescript/src/types/nonceAccount.d.ts +59 -0
- package/lib/typescript/src/types/nonceAccount.d.ts.map +1 -0
- package/lib/typescript/src/types/tossUser.d.ts +16 -0
- package/lib/typescript/src/types/tossUser.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/solana-program-simple.test.ts +256 -0
- package/src/ble.ts +105 -4
- package/src/client/BLETransactionHandler.ts +364 -0
- package/src/client/NonceAccountManager.ts +444 -0
- package/src/client/TossClient.ts +1 -1
- package/src/hooks/useOfflineBLETransactions.ts +438 -0
- package/src/index.tsx +40 -6
- package/src/intent.ts +166 -0
- package/src/noise.ts +238 -0
- package/src/reconciliation.ts +184 -0
- package/src/services/authService.ts +188 -1
- package/src/storage/secureStorage.ts +138 -0
- package/src/sync.ts +40 -0
- package/src/types/nonceAccount.ts +75 -0
- package/src/types/tossUser.ts +35 -2
package/README.md
CHANGED
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
# TOSS Expo SDK
|
|
2
2
|
|
|
3
|
-
**TOSS (The Offline Solana Stack)**
|
|
3
|
+
**TOSS (The Offline Solana Stack)** implements the complete [TOSS Technical Paper](./TOSS_PAPER_IMPLEMENTATION_VERIFICATION.md) — a protocol-correct approach to building offline-first Solana applications without compromising security or finality guarantees.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/toss-expo-sdk)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
+
**Solana, extended.** TOSS introduces deterministic separation between transaction intent creation and onchain settlement, enabling applications to function seamlessly in disconnected environments while preserving Solana's security model.
|
|
9
|
+
|
|
8
10
|
## 🚀 Features
|
|
9
11
|
|
|
10
12
|
### Core Capabilities
|
|
11
13
|
|
|
12
14
|
- **Offline-First Architecture**: Create and process transactions without immediate network access
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
+
- **Durable Nonce Accounts**: Replay-protected offline transactions with automatic expiry handling
|
|
16
|
+
- **Secure Wallet Integration**: Built-in wallet management with biometric protection
|
|
17
|
+
- **BLE Transaction Transmission**: MTU-aware message fragmentation with automatic retry
|
|
18
|
+
- **End-to-End Encryption**: Noise Protocol integration for secure device-to-device communication
|
|
15
19
|
- **TypeScript Support**: Full TypeScript definitions for better developer experience
|
|
16
20
|
|
|
17
21
|
### Security
|
|
18
22
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
23
|
+
- ✅ Biometric-protected nonce accounts (mandatory)
|
|
24
|
+
- ✅ Hardware-backed secure key storage (Secure Enclave / Keymaster)
|
|
25
|
+
- ✅ Automatic replay protection with durable nonces
|
|
26
|
+
- ✅ Noise Protocol encryption for BLE transmission
|
|
27
|
+
- ✅ CRC32 checksums for fragment verification
|
|
28
|
+
- ✅ Non-custodial by design - users maintain control of their keys
|
|
22
29
|
|
|
23
30
|
### Developer Experience
|
|
24
31
|
|
|
25
|
-
- Simple, intuitive API for
|
|
26
|
-
-
|
|
32
|
+
- Simple, intuitive API for offline transactions
|
|
33
|
+
- Custom React hooks for easy integration (`useOfflineTransaction`, `useBLETransactionTransmission`)
|
|
34
|
+
- Comprehensive error handling with detailed messages
|
|
27
35
|
- Built-in retry mechanisms with exponential backoff
|
|
28
|
-
-
|
|
36
|
+
- Automatic MTU negotiation and fragmentation
|
|
29
37
|
|
|
30
38
|
## 📦 Installation
|
|
31
39
|
|
|
@@ -39,6 +47,27 @@ yarn add toss-expo-sdk
|
|
|
39
47
|
|
|
40
48
|
All dependencies (Solana Web3.js, Arcium, Noise Protocol, etc.) are automatically included.
|
|
41
49
|
|
|
50
|
+
## 📋 System Model & Design Principles
|
|
51
|
+
|
|
52
|
+
**TOSS operates under these assumptions:**
|
|
53
|
+
|
|
54
|
+
- Devices may be **offline for arbitrary durations**
|
|
55
|
+
- Transport channels are **unreliable and potentially adversarial**
|
|
56
|
+
- Devices are **not mutually trusted**
|
|
57
|
+
- **Onchain state is the sole authority** for settlement
|
|
58
|
+
- Offline execution is limited to **cryptographically verifiable intent generation only**
|
|
59
|
+
|
|
60
|
+
**TOSS maintains these invariants:**
|
|
61
|
+
|
|
62
|
+
- ✅ Onchain state is canonical
|
|
63
|
+
- ✅ Offline execution never mutates global state
|
|
64
|
+
- ✅ All offline artifacts are cryptographically verifiable onchain
|
|
65
|
+
- ✅ No trusted relayers or delegated signing
|
|
66
|
+
- ✅ Failure is deterministic and safe
|
|
67
|
+
- ✅ Privacy is preserved prior to settlement
|
|
68
|
+
|
|
69
|
+
**Violation of any invariant invalidates the offline model.**
|
|
70
|
+
|
|
42
71
|
## 🏁 Quick Start
|
|
43
72
|
|
|
44
73
|
### Initialize the Client
|
|
@@ -164,21 +193,295 @@ function PaymentScreen() {
|
|
|
164
193
|
|
|
165
194
|
## Core Idea: Intent, Not Transaction
|
|
166
195
|
|
|
167
|
-
TOSS uses an **intent-based model
|
|
196
|
+
TOSS uses an **intent-based model** that fundamentally separates cryptographic commitment from onchain execution.
|
|
168
197
|
|
|
169
198
|
An **intent** is:
|
|
170
199
|
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
-
|
|
200
|
+
- A **signed declaration** of what a user wants to do
|
|
201
|
+
- **Transferable offline** via BLE, NFC, QR, or local mesh
|
|
202
|
+
- **Verifiable locally** without network access (signature, expiry, nonce only)
|
|
203
|
+
- **Settled later on-chain** where Solana enforces final state transitions
|
|
204
|
+
|
|
205
|
+
This separation allows applications to function **without connectivity** while preserving Solana's security guarantees.
|
|
206
|
+
|
|
207
|
+
### The 4-Phase Intent Lifecycle
|
|
208
|
+
|
|
209
|
+
TOSS follows a deterministic 4-phase model (Section 4.3 of Technical Paper):
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
213
|
+
│ Phase 1: CREATION (Offline) │
|
|
214
|
+
│ • Sender constructs intent locally │
|
|
215
|
+
│ • Signs with native Solana keypair (Ed25519) │
|
|
216
|
+
│ • No network required │
|
|
217
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
218
|
+
↓
|
|
219
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
220
|
+
│ Phase 2: EXCHANGE (Offline) │
|
|
221
|
+
│ • Signed intent transmitted via proximity (BLE/NFC/QR) │
|
|
222
|
+
│ • Transport integrity not trusted │
|
|
223
|
+
│ • Peer receives intent in untrusted environment │
|
|
224
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
225
|
+
↓
|
|
226
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
227
|
+
│ Phase 3: OFFLINE VERIFICATION (Offline) │
|
|
228
|
+
│ • Verify signature correctness (Ed25519) │
|
|
229
|
+
│ • Check expiry bounds │
|
|
230
|
+
│ • Validate nonce (replay protection) │
|
|
231
|
+
│ • DEFERRED: Balance, program constraints (onchain only) │
|
|
232
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
233
|
+
↓
|
|
234
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
235
|
+
│ Phase 4: SETTLEMENT (Online) │
|
|
236
|
+
│ • Connectivity restored │
|
|
237
|
+
│ • Intent submitted to Solana │
|
|
238
|
+
│ • Program verifies signature + state │
|
|
239
|
+
│ • Settlement succeeds or fails deterministically │
|
|
240
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Key Invariant:** At no stage does offline execution bypass Solana's runtime or programs. Final state transitions occur **exclusively on Solana**.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 💾 Local State Management & Reconciliation
|
|
248
|
+
|
|
249
|
+
TOSS maintains an **encrypted, append-only local intent store** that enables offline operation while waiting for network connectivity.
|
|
250
|
+
|
|
251
|
+
### What Gets Stored Locally
|
|
252
|
+
|
|
253
|
+
Each device maintains:
|
|
254
|
+
|
|
255
|
+
- **Outbound pending intents** - Intents created but not yet settled
|
|
256
|
+
- **Inbound received intents** - Intents from peers, awaiting verification
|
|
257
|
+
- **Synchronization status** - Track which intents have been submitted
|
|
258
|
+
- **Expiry metadata** - Automatic cleanup of expired intents
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import {
|
|
262
|
+
secureStoreIntent,
|
|
263
|
+
getPendingIntents,
|
|
264
|
+
getAllSecureIntents,
|
|
265
|
+
} from 'toss-expo-sdk';
|
|
266
|
+
|
|
267
|
+
// Store an intent locally (encrypted in hardware secure enclave)
|
|
268
|
+
await secureStoreIntent(intent);
|
|
269
|
+
|
|
270
|
+
// Get all pending intents
|
|
271
|
+
const pending = await getPendingIntents();
|
|
272
|
+
console.log(`${pending.length} intents waiting for settlement`);
|
|
273
|
+
|
|
274
|
+
// Later, when online...
|
|
275
|
+
const allIntents = await getAllSecureIntents();
|
|
276
|
+
console.log(`Stored intents: ${allIntents.length}`);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Automatic Reconciliation
|
|
280
|
+
|
|
281
|
+
When connectivity is restored, TOSS initiates **deterministic reconciliation**:
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
import { syncToChain, reconcilePendingIntents } from 'toss-expo-sdk';
|
|
285
|
+
|
|
286
|
+
// Sync all pending intents to Solana
|
|
287
|
+
const syncResult = await syncToChain(connection);
|
|
288
|
+
|
|
289
|
+
console.log(`Settled: ${syncResult.successfulSettlements.length}`);
|
|
290
|
+
console.log(`Failed: ${syncResult.failedSettlements.length}`);
|
|
291
|
+
console.log(`Conflicts detected: ${syncResult.detectedConflicts.length}`);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Reconciliation Steps:**
|
|
295
|
+
|
|
296
|
+
1. ✅ Retrieve all pending intents from local storage
|
|
297
|
+
2. ✅ Submit to Solana
|
|
298
|
+
3. ✅ Verify signatures and state constraints onchain
|
|
299
|
+
4. ✅ Deterministically reject invalid or conflicting intents
|
|
300
|
+
5. ✅ Update local state with finality
|
|
301
|
+
|
|
302
|
+
**No offline state is treated as final.** Solana's verdict is authoritative.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## 🔐 Confidential Execution via Arcium (Optional)
|
|
307
|
+
|
|
308
|
+
TOSS integrates **Arcium** for confidential computation in pre-settlement stages, protecting sensitive transaction parameters before onchain execution.
|
|
309
|
+
|
|
310
|
+
### When to Use Private Transactions
|
|
311
|
+
|
|
312
|
+
By default, intents are created as regular transactions. Use `privateTransaction: true` when:
|
|
313
|
+
|
|
314
|
+
- You want to hide **transaction amounts** from peers during exchange
|
|
315
|
+
- You need to hide **recipient information** before settlement
|
|
316
|
+
- You're working with **sensitive business logic** (payments, transfers)
|
|
317
|
+
- You need **pre-settlement confidentiality** without revealing intent details
|
|
318
|
+
|
|
319
|
+
### Enabling Confidential Execution
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
import { createUserIntent, createIntent } from 'toss-expo-sdk';
|
|
323
|
+
import { Provider } from '@project-serum/anchor';
|
|
324
|
+
|
|
325
|
+
// Confidential intent creation
|
|
326
|
+
const confidentialIntent = await createUserIntent(
|
|
327
|
+
senderUser,
|
|
328
|
+
senderKeypair,
|
|
329
|
+
recipientUser,
|
|
330
|
+
amountInLamports,
|
|
331
|
+
connection,
|
|
332
|
+
{
|
|
333
|
+
privateTransaction: true,
|
|
334
|
+
mxeProgramId: new PublicKey('YOUR_MXE_PROGRAM_ID'),
|
|
335
|
+
provider: anchorProvider, // Anchor provider for MXE operations
|
|
336
|
+
expiresIn: 60 * 60, // 1 hour expiry
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
console.log('Intent created with Arcium encryption');
|
|
341
|
+
console.log(`Encrypted data: ${confidentialIntent.encrypted?.ciphertext}`);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### How It Works
|
|
175
345
|
|
|
176
|
-
|
|
346
|
+
1. **Pre-Creation:** Construct intent with plaintext values
|
|
347
|
+
2. **Encryption:** Amount and metadata encrypted with Arcium
|
|
348
|
+
3. **Storage:** Encrypted intent stored locally
|
|
349
|
+
4. **Exchange:** Encrypted parameters transmitted (peer cannot decrypt)
|
|
350
|
+
5. **Settlement:** Solana program decrypts and executes (onchain verification)
|
|
351
|
+
|
|
352
|
+
### Security Model
|
|
353
|
+
|
|
354
|
+
- **Encryption scope:** Optional (amount, metadata)
|
|
355
|
+
- **Key management:** Arcium handles encryption/decryption
|
|
356
|
+
- **Signature:** Intent signature covers plaintext (authenticity verified before decryption)
|
|
357
|
+
- **Onchain verification:** Only Solana MXE program can decrypt and validate
|
|
358
|
+
|
|
359
|
+
**Important:** Arcium encryption is **optional** and operates strictly before onchain execution. It does **not** alter Solana's trust model — the blockchain remains the final authority.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
TOSS now includes **production-ready offline transaction support** using Solana's durable nonce accounts with biometric protection.
|
|
364
|
+
|
|
365
|
+
### Quick Start: Offline Transactions
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
import {
|
|
369
|
+
useOfflineTransaction,
|
|
370
|
+
useBLETransactionTransmission,
|
|
371
|
+
useNonceAccountManagement,
|
|
372
|
+
createOfflineIntent,
|
|
373
|
+
AuthService,
|
|
374
|
+
} from 'toss-expo-sdk';
|
|
375
|
+
import { SystemProgram } from '@solana/web3.js';
|
|
376
|
+
|
|
377
|
+
// Step 1: Create nonce account (requires biometric)
|
|
378
|
+
const updatedUser = await AuthService.createSecureNonceAccount(
|
|
379
|
+
user,
|
|
380
|
+
connection,
|
|
381
|
+
userKeypair
|
|
382
|
+
);
|
|
383
|
+
|
|
384
|
+
// Step 2: Create offline transaction using custom hook
|
|
385
|
+
const { createOfflineTransaction } = useOfflineTransaction(user, connection);
|
|
386
|
+
|
|
387
|
+
const offlineTx = await createOfflineTransaction([
|
|
388
|
+
SystemProgram.transfer({
|
|
389
|
+
fromPubkey: user.wallet.publicKey,
|
|
390
|
+
toPubkey: recipientAddress,
|
|
391
|
+
lamports: amount,
|
|
392
|
+
}),
|
|
393
|
+
]);
|
|
394
|
+
|
|
395
|
+
// Step 3: Send via BLE with automatic fragmentation
|
|
396
|
+
const { sendTransactionBLE } = useBLETransactionTransmission('ios');
|
|
397
|
+
|
|
398
|
+
const result = await sendTransactionBLE(
|
|
399
|
+
bleDevice,
|
|
400
|
+
offlineTx,
|
|
401
|
+
noiseEncryptFn, // Optional Noise Protocol encryption
|
|
402
|
+
false // This is a transaction, not an intent
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
console.log(`Sent ${result.sentFragments}/${result.totalFragments} fragments`);
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Key Features
|
|
409
|
+
|
|
410
|
+
**Biometric Protection**
|
|
411
|
+
|
|
412
|
+
- ✅ All nonce operations require biometric authentication
|
|
413
|
+
- ✅ Private keys stored in device's secure enclave (iOS Secure Enclave / Android Keymaster)
|
|
414
|
+
- ✅ User cannot export or backup private keys
|
|
415
|
+
|
|
416
|
+
**Replay Protection**
|
|
417
|
+
|
|
418
|
+
- ✅ Each transaction uses a unique, incrementing nonce from the blockchain
|
|
419
|
+
- ✅ Nonce values automatically validated before transaction execution
|
|
420
|
+
- ✅ Expired nonces automatically detected and rejected
|
|
421
|
+
|
|
422
|
+
**BLE Transmission**
|
|
423
|
+
|
|
424
|
+
- ✅ Automatic MTU-aware message fragmentation
|
|
425
|
+
- ✅ CRC32 checksum verification for each fragment
|
|
426
|
+
- ✅ Automatic retry with exponential backoff
|
|
427
|
+
- ✅ Noise Protocol encryption support
|
|
428
|
+
|
|
429
|
+
**Storage & Renewal**
|
|
430
|
+
|
|
431
|
+
- ✅ Nonce accounts cached efficiently in memory
|
|
432
|
+
- ✅ Automatic renewal from blockchain
|
|
433
|
+
- ✅ Graceful expiry handling with status tracking
|
|
434
|
+
|
|
435
|
+
### Detailed Guide
|
|
436
|
+
|
|
437
|
+
For comprehensive documentation, guides, and advanced usage examples, see [OFFLINE_TRANSACTIONS_GUIDE.md](./OFFLINE_TRANSACTIONS_GUIDE.md).
|
|
438
|
+
|
|
439
|
+
Topics covered:
|
|
440
|
+
|
|
441
|
+
- Architecture overview
|
|
442
|
+
- Setup guide with step-by-step examples
|
|
443
|
+
- Custom React hooks API reference
|
|
444
|
+
- Noise Protocol integration
|
|
445
|
+
- Security considerations
|
|
446
|
+
- Error handling patterns
|
|
447
|
+
- Testing strategies
|
|
448
|
+
- Migration guide from previous versions
|
|
177
449
|
|
|
178
450
|
---
|
|
179
451
|
|
|
180
452
|
## 🔒 Security
|
|
181
453
|
|
|
454
|
+
### TOSS Security Guarantees
|
|
455
|
+
|
|
456
|
+
TOSS guarantees (per Technical Paper, Section 13):
|
|
457
|
+
|
|
458
|
+
1. **No Unauthorized Signing**
|
|
459
|
+
- Only users with access to their private keys can create intents
|
|
460
|
+
- Ed25519 signatures cannot be forged
|
|
461
|
+
- Biometric protection for nonce accounts (mandatory)
|
|
462
|
+
|
|
463
|
+
2. **No Offline State Mutation**
|
|
464
|
+
- Offline operations only create local intents (append-only store)
|
|
465
|
+
- No global state changes until onchain settlement
|
|
466
|
+
- Solana remains the sole authority for state transitions
|
|
467
|
+
|
|
468
|
+
3. **No Forced Execution**
|
|
469
|
+
- Signers can choose whether to submit intents
|
|
470
|
+
- Intents can be rejected before settlement
|
|
471
|
+
- Both parties must verify before committing to offline transfer
|
|
472
|
+
|
|
473
|
+
4. **Deterministic Settlement**
|
|
474
|
+
- Settlement outcomes are deterministic based on onchain state
|
|
475
|
+
- Conflict resolution is deterministic (nonce + timestamp)
|
|
476
|
+
- Failures are safe and recoverable
|
|
477
|
+
|
|
478
|
+
5. **Confidential Pre-Settlement Handling**
|
|
479
|
+
- Optional Arcium encryption before submission
|
|
480
|
+
- Private transaction metadata protected from peers
|
|
481
|
+
- Onchain verification ensures integrity
|
|
482
|
+
|
|
483
|
+
**Important:** Offline capability does **not** expand Solana's attack surface. All security guarantees come from cryptography and onchain verification, not the offline layer.
|
|
484
|
+
|
|
182
485
|
### Best Practices
|
|
183
486
|
|
|
184
487
|
1. Always verify transaction details before signing
|
|
@@ -330,6 +633,56 @@ const activePeers = discovery.getActivePeers();
|
|
|
330
633
|
console.log(`${activePeers.length} active peers nearby`);
|
|
331
634
|
```
|
|
332
635
|
|
|
636
|
+
## ⚠️ Understanding TOSS Limitations
|
|
637
|
+
|
|
638
|
+
TOSS is designed to fail safely. The following limitations are **by design** and fundamental to any offline system:
|
|
639
|
+
|
|
640
|
+
### What TOSS Does NOT Do
|
|
641
|
+
|
|
642
|
+
❌ **Does not resolve offline double-spend**
|
|
643
|
+
|
|
644
|
+
- Multiple devices can create conflicting intents offline
|
|
645
|
+
- Conflicts are resolved deterministically onchain (first valid intent wins)
|
|
646
|
+
- You must verify transaction details before committing to offline transfer
|
|
647
|
+
|
|
648
|
+
❌ **Does not guarantee settlement success**
|
|
649
|
+
|
|
650
|
+
- Intents may fail onchain due to insufficient balance, nonce violations, or expired intents
|
|
651
|
+
- Settlement is deterministic but failures can occur
|
|
652
|
+
- Always check sync results for failed intents
|
|
653
|
+
|
|
654
|
+
❌ **Does not replace Solana consensus**
|
|
655
|
+
|
|
656
|
+
- TOSS extends operational boundaries but does not modify Solana's execution semantics
|
|
657
|
+
- All final state transitions occur exclusively on Solana
|
|
658
|
+
- Transaction validity is determined by Solana's runtime, not TOSS
|
|
659
|
+
|
|
660
|
+
❌ **Does not eliminate finality dependency on network**
|
|
661
|
+
|
|
662
|
+
- Finality still requires network connectivity to Solana
|
|
663
|
+
- Offline operation defers settlement, not finality
|
|
664
|
+
- You cannot validate final state without connectivity
|
|
665
|
+
|
|
666
|
+
### Settlement Guarantees
|
|
667
|
+
|
|
668
|
+
TOSS **guarantees**:
|
|
669
|
+
|
|
670
|
+
- ✅ Signatures cannot be forged (Ed25519 cryptography)
|
|
671
|
+
- ✅ Offline state never mutates global state (local-only storage)
|
|
672
|
+
- ✅ All artifacts are verifiable onchain (deterministic settlement)
|
|
673
|
+
- ✅ Conflicts resolve deterministically (based on nonce and timestamp)
|
|
674
|
+
- ✅ Pre-settlement confidentiality via Arcium (optional)
|
|
675
|
+
|
|
676
|
+
But TOSS **does not guarantee**:
|
|
677
|
+
|
|
678
|
+
- ❌ That your intent will successfully settle (dependent on onchain state)
|
|
679
|
+
- ❌ Prevention of offline double-spend (conflicts detected onchain)
|
|
680
|
+
- ❌ Immediate finality (requires network connectivity)
|
|
681
|
+
|
|
682
|
+
**The distinction:** TOSS guarantees **protocol correctness**, not **settlement success**. These are different requirements.
|
|
683
|
+
|
|
684
|
+
---
|
|
685
|
+
|
|
333
686
|
## 🌐 Network Support
|
|
334
687
|
|
|
335
688
|
| Network | Status | RPC Endpoint |
|
package/lib/module/ble.js
CHANGED
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
// src/ble.ts
|
|
4
4
|
import { BleManager } from 'react-native-ble-plx';
|
|
5
5
|
import { PermissionsAndroid, Platform } from 'react-native';
|
|
6
|
+
import { BLETransactionHandler } from "./client/BLETransactionHandler.js";
|
|
6
7
|
const SERVICE_UUID = '0000ff00-0000-1000-8000-00805f9b34fb';
|
|
7
8
|
const USER_CHARACTERISTIC = '0000ff01-0000-1000-8000-00805f9b34fb';
|
|
8
9
|
const INTENT_CHARACTERISTIC = '0000ff02-0000-1000-8000-00805f9b34fb';
|
|
10
|
+
const OFFLINE_TX_CHARACTERISTIC = '0000ff03-0000-1000-8000-00805f9b34fb'; // New for offline transactions
|
|
11
|
+
|
|
9
12
|
const manager = new BleManager();
|
|
13
|
+
const bleTransactionHandler = new BLETransactionHandler(Platform.OS === 'ios' ? 'ios' : 'android');
|
|
10
14
|
export async function requestBLEPermissions() {
|
|
11
15
|
if (Platform.OS === 'android') {
|
|
12
16
|
await PermissionsAndroid.requestMultiple([PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN, PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT, PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION]);
|
|
@@ -21,7 +25,7 @@ async function connect(device) {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
// Scan for BLE devices advertising TOSS service
|
|
24
|
-
export function startTossScan(onUserFound, onIntentFound) {
|
|
28
|
+
export function startTossScan(onUserFound, onIntentFound, onOfflineTransactionFound) {
|
|
25
29
|
manager.startDeviceScan([SERVICE_UUID], null, async (error, device) => {
|
|
26
30
|
if (error) {
|
|
27
31
|
console.warn('BLE scan error', error.message);
|
|
@@ -45,6 +49,20 @@ export function startTossScan(onUserFound, onIntentFound) {
|
|
|
45
49
|
const intent = JSON.parse(intentData.value);
|
|
46
50
|
onIntentFound(intent, device);
|
|
47
51
|
}
|
|
52
|
+
|
|
53
|
+
// Check for offline transaction data (fragmented)
|
|
54
|
+
if (onOfflineTransactionFound) {
|
|
55
|
+
try {
|
|
56
|
+
const txData = await services.readCharacteristicForService(device.id, SERVICE_UUID, OFFLINE_TX_CHARACTERISTIC);
|
|
57
|
+
if (txData?.value) {
|
|
58
|
+
const tx = JSON.parse(txData.value);
|
|
59
|
+
onOfflineTransactionFound(tx, device);
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// Offline TX characteristic may not be available
|
|
63
|
+
console.debug('Offline transaction characteristic not found');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
48
66
|
} catch (err) {
|
|
49
67
|
console.warn('Error reading device data:', err);
|
|
50
68
|
}
|
|
@@ -96,8 +114,45 @@ export async function sendIntentToDevice(deviceId, intent) {
|
|
|
96
114
|
await device.cancelConnection();
|
|
97
115
|
}
|
|
98
116
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Send fragmented offline transaction over BLE with Noise Protocol encryption
|
|
119
|
+
* Automatically handles MTU limitations and retries
|
|
120
|
+
*/
|
|
121
|
+
export async function sendOfflineTransactionFragmented(device, transaction, noiseEncryptFn, isIntent = false) {
|
|
122
|
+
try {
|
|
123
|
+
const result = await bleTransactionHandler.sendFragmentedTransactionBLE(device, transaction, async (deviceId, charUUID, data) => {
|
|
124
|
+
const dev = await manager.connectToDevice(deviceId);
|
|
125
|
+
await dev.discoverAllServicesAndCharacteristics();
|
|
126
|
+
const characteristic = charUUID === OFFLINE_TX_CHARACTERISTIC ? OFFLINE_TX_CHARACTERISTIC : INTENT_CHARACTERISTIC;
|
|
127
|
+
await dev.writeCharacteristicWithResponseForService(deviceId, SERVICE_UUID, characteristic, data.toString('base64'));
|
|
128
|
+
await dev.cancelConnection();
|
|
129
|
+
}, noiseEncryptFn, isIntent);
|
|
130
|
+
return result;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
133
|
+
console.error('Failed to send offline transaction:', errorMessage);
|
|
134
|
+
throw new Error(`BLE transmission failed: ${errorMessage}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Receive and reassemble fragmented message from BLE
|
|
140
|
+
*/
|
|
141
|
+
export async function receiveOfflineTransactionFragment(fragment, noiseDecryptFn) {
|
|
142
|
+
return bleTransactionHandler.receiveFragmentedMessage(fragment, noiseDecryptFn);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get current BLE MTU configuration
|
|
147
|
+
*/
|
|
148
|
+
export function getBLEMTUConfig() {
|
|
149
|
+
return bleTransactionHandler.getMTUConfig();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Set custom BLE MTU configuration
|
|
154
|
+
*/
|
|
155
|
+
export function setBLEMTUConfig(config) {
|
|
156
|
+
bleTransactionHandler.setMTUConfig(config);
|
|
102
157
|
}
|
|
103
158
|
//# sourceMappingURL=ble.js.map
|
package/lib/module/ble.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["BleManager","PermissionsAndroid","Platform","SERVICE_UUID","USER_CHARACTERISTIC","INTENT_CHARACTERISTIC","manager","
|
|
1
|
+
{"version":3,"names":["BleManager","PermissionsAndroid","Platform","BLETransactionHandler","SERVICE_UUID","USER_CHARACTERISTIC","INTENT_CHARACTERISTIC","OFFLINE_TX_CHARACTERISTIC","manager","bleTransactionHandler","OS","requestBLEPermissions","requestMultiple","PERMISSIONS","BLUETOOTH_SCAN","BLUETOOTH_CONNECT","ACCESS_FINE_LOCATION","connect","device","connectedDevice","connectToDevice","id","discoverAllServicesAndCharacteristics","startTossScan","onUserFound","onIntentFound","onOfflineTransactionFound","startDeviceScan","error","console","warn","message","services","userData","readCharacteristicForService","value","user","JSON","parse","intentData","intent","txData","tx","debug","err","State","advertiseUser","subscription","onStateChange","state","PoweredOn","log","userId","remove","errorMessage","Error","String","stopAdvertising","stopDeviceScan","sendIntentToDevice","deviceId","jsonIntent","stringify","writeCharacteristicWithResponseForService","Buffer","from","toString","cancelConnection","sendOfflineTransactionFragmented","transaction","noiseEncryptFn","isIntent","result","sendFragmentedTransactionBLE","charUUID","data","dev","characteristic","receiveOfflineTransactionFragment","fragment","noiseDecryptFn","receiveFragmentedMessage","getBLEMTUConfig","getMTUConfig","setBLEMTUConfig","config","setMTUConfig"],"sourceRoot":"../../src","sources":["ble.ts"],"mappings":"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","ignoreList":[]}
|