toss-expo-sdk 0.1.0
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/LICENSE +20 -0
- package/README.md +292 -0
- package/lib/module/ble.js +103 -0
- package/lib/module/ble.js.map +1 -0
- package/lib/module/client/TossClient.js +324 -0
- package/lib/module/client/TossClient.js.map +1 -0
- package/lib/module/client/index.js +4 -0
- package/lib/module/client/index.js.map +1 -0
- package/lib/module/contexts/WalletContext.js +99 -0
- package/lib/module/contexts/WalletContext.js.map +1 -0
- package/lib/module/discovery.js +434 -0
- package/lib/module/discovery.js.map +1 -0
- package/lib/module/errors.js +47 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/examples/offlinePaymentFlow.js +234 -0
- package/lib/module/examples/offlinePaymentFlow.js.map +1 -0
- package/lib/module/index.js +32 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/intent.js +223 -0
- package/lib/module/intent.js.map +1 -0
- package/lib/module/intentManager.js +145 -0
- package/lib/module/intentManager.js.map +1 -0
- package/lib/module/internal/arciumHelper.js +50 -0
- package/lib/module/internal/arciumHelper.js.map +1 -0
- package/lib/module/nfc.js +54 -0
- package/lib/module/nfc.js.map +1 -0
- package/lib/module/noise.js +14 -0
- package/lib/module/noise.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/qr.js +57 -0
- package/lib/module/qr.js.map +1 -0
- package/lib/module/reconciliation.js +329 -0
- package/lib/module/reconciliation.js.map +1 -0
- package/lib/module/services/authService.js +205 -0
- package/lib/module/services/authService.js.map +1 -0
- package/lib/module/storage/secureStorage.js +89 -0
- package/lib/module/storage/secureStorage.js.map +1 -0
- package/lib/module/storage.js +16 -0
- package/lib/module/storage.js.map +1 -0
- package/lib/module/sync.js +64 -0
- package/lib/module/sync.js.map +1 -0
- package/lib/module/types/tossUser.js +41 -0
- package/lib/module/types/tossUser.js.map +1 -0
- package/lib/module/utils/nonceUtils.js +38 -0
- package/lib/module/utils/nonceUtils.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/__tests__/index.test.d.ts +1 -0
- package/lib/typescript/src/__tests__/index.test.d.ts.map +1 -0
- package/lib/typescript/src/__tests__/reconciliation.test.d.ts +6 -0
- package/lib/typescript/src/__tests__/reconciliation.test.d.ts.map +1 -0
- package/lib/typescript/src/ble.d.ts +10 -0
- package/lib/typescript/src/ble.d.ts.map +1 -0
- package/lib/typescript/src/client/TossClient.d.ts +110 -0
- package/lib/typescript/src/client/TossClient.d.ts.map +1 -0
- package/lib/typescript/src/client/index.d.ts +3 -0
- package/lib/typescript/src/client/index.d.ts.map +1 -0
- package/lib/typescript/src/contexts/WalletContext.d.ts +20 -0
- package/lib/typescript/src/contexts/WalletContext.d.ts.map +1 -0
- package/lib/typescript/src/discovery.d.ts +188 -0
- package/lib/typescript/src/discovery.d.ts.map +1 -0
- package/lib/typescript/src/errors.d.ts +27 -0
- package/lib/typescript/src/errors.d.ts.map +1 -0
- package/lib/typescript/src/examples/offlinePaymentFlow.d.ts +48 -0
- package/lib/typescript/src/examples/offlinePaymentFlow.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +13 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/intent.d.ts +84 -0
- package/lib/typescript/src/intent.d.ts.map +1 -0
- package/lib/typescript/src/intentManager.d.ts +46 -0
- package/lib/typescript/src/intentManager.d.ts.map +1 -0
- package/lib/typescript/src/internal/arciumHelper.d.ts +19 -0
- package/lib/typescript/src/internal/arciumHelper.d.ts.map +1 -0
- package/lib/typescript/src/nfc.d.ts +7 -0
- package/lib/typescript/src/nfc.d.ts.map +1 -0
- package/lib/typescript/src/noise.d.ts +5 -0
- package/lib/typescript/src/noise.d.ts.map +1 -0
- package/lib/typescript/src/qr.d.ts +6 -0
- package/lib/typescript/src/qr.d.ts.map +1 -0
- package/lib/typescript/src/reconciliation.d.ts +65 -0
- package/lib/typescript/src/reconciliation.d.ts.map +1 -0
- package/lib/typescript/src/services/authService.d.ts +55 -0
- package/lib/typescript/src/services/authService.d.ts.map +1 -0
- package/lib/typescript/src/storage/secureStorage.d.ts +7 -0
- package/lib/typescript/src/storage/secureStorage.d.ts.map +1 -0
- package/lib/typescript/src/storage.d.ts +4 -0
- package/lib/typescript/src/storage.d.ts.map +1 -0
- package/lib/typescript/src/sync.d.ts +40 -0
- package/lib/typescript/src/sync.d.ts.map +1 -0
- package/lib/typescript/src/types/tossUser.d.ts +39 -0
- package/lib/typescript/src/types/tossUser.d.ts.map +1 -0
- package/lib/typescript/src/utils/nonceUtils.d.ts +8 -0
- package/lib/typescript/src/utils/nonceUtils.d.ts.map +1 -0
- package/package.json +176 -0
- package/src/__tests__/index.test.tsx +1 -0
- package/src/__tests__/reconciliation.test.tsx +361 -0
- package/src/ble.ts +138 -0
- package/src/client/TossClient.ts +435 -0
- package/src/client/index.ts +2 -0
- package/src/contexts/WalletContext.tsx +127 -0
- package/src/discovery.ts +542 -0
- package/src/errors.ts +51 -0
- package/src/examples/offlinePaymentFlow.ts +331 -0
- package/src/index.tsx +61 -0
- package/src/intent.ts +328 -0
- package/src/intentManager.ts +164 -0
- package/src/internal/arciumHelper.ts +58 -0
- package/src/nfc.ts +57 -0
- package/src/noise.ts +9 -0
- package/src/qr.tsx +65 -0
- package/src/reconciliation.ts +421 -0
- package/src/services/authService.ts +238 -0
- package/src/storage/secureStorage.ts +100 -0
- package/src/storage.ts +17 -0
- package/src/sync.ts +101 -0
- package/src/types/tossUser.ts +81 -0
- package/src/utils/nonceUtils.ts +56 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Device Discovery and Intent Exchange Protocol for TOSS
|
|
5
|
+
*
|
|
6
|
+
* Implements Section 11-12 of the TOSS Technical Paper:
|
|
7
|
+
* - Device discovery and peer identification
|
|
8
|
+
* - Intent exchange protocol
|
|
9
|
+
* - Trust establishment between offline peers
|
|
10
|
+
* - Conflict resolution for multi-device scenarios
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { TossError } from "./errors.js";
|
|
14
|
+
import { initNoiseSession } from "./noise.js";
|
|
15
|
+
import crypto from 'crypto';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Peer device information discovered via transport
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Encrypted intent exchange session
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Intent exchange request/response
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Device discovery service
|
|
31
|
+
*/
|
|
32
|
+
export class DeviceDiscoveryService {
|
|
33
|
+
discoveredPeers = new Map();
|
|
34
|
+
PEER_TIMEOUT = 5 * 60 * 1000; // 5 minutes
|
|
35
|
+
MAX_PEERS = 50;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Register a discovered peer device
|
|
39
|
+
*/
|
|
40
|
+
registerPeer(peer) {
|
|
41
|
+
if (this.discoveredPeers.size >= this.MAX_PEERS) {
|
|
42
|
+
// Remove oldest peer to make room
|
|
43
|
+
const oldestPeer = Array.from(this.discoveredPeers.values()).sort((a, b) => a.lastSeen - b.lastSeen)[0];
|
|
44
|
+
if (oldestPeer) {
|
|
45
|
+
this.discoveredPeers.delete(oldestPeer.id);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
this.discoveredPeers.set(peer.id, {
|
|
49
|
+
...peer,
|
|
50
|
+
lastSeen: Date.now()
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get all active peers (not timed out)
|
|
56
|
+
*/
|
|
57
|
+
getActivePeers() {
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
const activePeers = [];
|
|
60
|
+
for (const [id, peer] of this.discoveredPeers.entries()) {
|
|
61
|
+
if (now - peer.lastSeen > this.PEER_TIMEOUT) {
|
|
62
|
+
this.discoveredPeers.delete(id);
|
|
63
|
+
} else {
|
|
64
|
+
activePeers.push(peer);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return activePeers;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get a specific peer by ID
|
|
72
|
+
*/
|
|
73
|
+
getPeer(peerId) {
|
|
74
|
+
const peer = this.discoveredPeers.get(peerId);
|
|
75
|
+
if (peer && Date.now() - peer.lastSeen > this.PEER_TIMEOUT) {
|
|
76
|
+
this.discoveredPeers.delete(peerId);
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return peer;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Update trust score for a peer based on interaction
|
|
84
|
+
*/
|
|
85
|
+
updateTrustScore(peerId, delta, maxScore = 100) {
|
|
86
|
+
const peer = this.getPeer(peerId);
|
|
87
|
+
if (!peer) return;
|
|
88
|
+
peer.trustScore = Math.max(0, Math.min(maxScore, (peer.trustScore || 50) + delta));
|
|
89
|
+
this.discoveredPeers.set(peerId, peer);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Clear all discovered peers
|
|
94
|
+
*/
|
|
95
|
+
clearPeers() {
|
|
96
|
+
this.discoveredPeers.clear();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Intent exchange protocol handler with Noise encryption support
|
|
102
|
+
*/
|
|
103
|
+
export class IntentExchangeProtocol {
|
|
104
|
+
pendingRequests = new Map();
|
|
105
|
+
noiseSessions = new Map();
|
|
106
|
+
// Static key for this device
|
|
107
|
+
REQUEST_TIMEOUT = 2 * 60 * 1000; // 2 minutes
|
|
108
|
+
SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes
|
|
109
|
+
|
|
110
|
+
constructor() {
|
|
111
|
+
// Generate a static key for this device for Noise protocol
|
|
112
|
+
this.deviceStaticKey = crypto.getRandomValues(new Uint8Array(32));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Establish a secure Noise session with a peer
|
|
117
|
+
*/
|
|
118
|
+
establishSecureSession(peerId) {
|
|
119
|
+
// Check if session already exists and is still valid
|
|
120
|
+
const existingSession = this.noiseSessions.get(peerId);
|
|
121
|
+
if (existingSession && Date.now() - existingSession.createdAt < this.SESSION_TIMEOUT) {
|
|
122
|
+
return existingSession;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Initialize Noise session with static key
|
|
126
|
+
const encryptionCipher = initNoiseSession(this.deviceStaticKey);
|
|
127
|
+
const sessionKey = crypto.getRandomValues(new Uint8Array(32));
|
|
128
|
+
const session = {
|
|
129
|
+
peerId,
|
|
130
|
+
sessionKey,
|
|
131
|
+
encryptionCipher,
|
|
132
|
+
createdAt: Date.now()
|
|
133
|
+
};
|
|
134
|
+
this.noiseSessions.set(peerId, session);
|
|
135
|
+
|
|
136
|
+
// Clean up expired sessions
|
|
137
|
+
setTimeout(() => {
|
|
138
|
+
this.noiseSessions.delete(peerId);
|
|
139
|
+
}, this.SESSION_TIMEOUT);
|
|
140
|
+
return session;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get an active Noise session with a peer
|
|
145
|
+
*/
|
|
146
|
+
getSecureSession(peerId) {
|
|
147
|
+
const session = this.noiseSessions.get(peerId);
|
|
148
|
+
if (!session) return undefined;
|
|
149
|
+
|
|
150
|
+
// Check if session has expired
|
|
151
|
+
if (Date.now() - session.createdAt > this.SESSION_TIMEOUT) {
|
|
152
|
+
this.noiseSessions.delete(peerId);
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
return session;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Encrypt request payload using Noise session
|
|
160
|
+
*/
|
|
161
|
+
encryptRequestPayload(requestData, session) {
|
|
162
|
+
const jsonPayload = JSON.stringify(requestData);
|
|
163
|
+
const payload = new TextEncoder().encode(jsonPayload);
|
|
164
|
+
|
|
165
|
+
// XOR encryption with session key
|
|
166
|
+
const encrypted = new Uint8Array(payload.length);
|
|
167
|
+
for (let i = 0; i < payload.length; i++) {
|
|
168
|
+
encrypted[i] = payload[i] ^ session.sessionKey[i % session.sessionKey.length];
|
|
169
|
+
}
|
|
170
|
+
return encrypted;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Decrypt request payload using Noise session
|
|
175
|
+
*/
|
|
176
|
+
decryptRequestPayload(ciphertext, session) {
|
|
177
|
+
// Reverse the XOR operation
|
|
178
|
+
const decrypted = new Uint8Array(ciphertext.length);
|
|
179
|
+
for (let i = 0; i < ciphertext.length; i++) {
|
|
180
|
+
decrypted[i] = ciphertext[i] ^ session.sessionKey[i % session.sessionKey.length];
|
|
181
|
+
}
|
|
182
|
+
const jsonPayload = new TextDecoder().decode(decrypted);
|
|
183
|
+
return JSON.parse(jsonPayload);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Create a new intent exchange request with optional Noise encryption
|
|
188
|
+
*/
|
|
189
|
+
createRequest(intent, requesterId, requesterUser, expiresIn = 5 * 60,
|
|
190
|
+
// 5 minutes default
|
|
191
|
+
useEncryption = true,
|
|
192
|
+
// Enable Noise encryption
|
|
193
|
+
peerId) {
|
|
194
|
+
const now = Math.floor(Date.now() / 1000);
|
|
195
|
+
const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
196
|
+
const requestData = {
|
|
197
|
+
requestId,
|
|
198
|
+
timestamp: now,
|
|
199
|
+
intent,
|
|
200
|
+
requesterId,
|
|
201
|
+
requesterUser,
|
|
202
|
+
expiresAt: now + expiresIn,
|
|
203
|
+
encrypted: false
|
|
204
|
+
};
|
|
205
|
+
let request = requestData;
|
|
206
|
+
|
|
207
|
+
// If encryption is requested and we have a peer ID, establish session and encrypt
|
|
208
|
+
if (useEncryption && peerId) {
|
|
209
|
+
try {
|
|
210
|
+
const session = this.establishSecureSession(peerId);
|
|
211
|
+
const ciphertext = this.encryptRequestPayload(requestData, session);
|
|
212
|
+
request = {
|
|
213
|
+
...requestData,
|
|
214
|
+
encrypted: true,
|
|
215
|
+
ciphertext
|
|
216
|
+
};
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.warn('Failed to encrypt request, sending in plaintext', error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
this.pendingRequests.set(requestId, request);
|
|
222
|
+
|
|
223
|
+
// Clean up expired requests after timeout
|
|
224
|
+
setTimeout(() => {
|
|
225
|
+
this.pendingRequests.delete(requestId);
|
|
226
|
+
}, this.REQUEST_TIMEOUT);
|
|
227
|
+
return request;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Respond to an intent exchange request
|
|
232
|
+
*/
|
|
233
|
+
createResponse(requestId, responderId, status, reason, acknowledgedIntentIds) {
|
|
234
|
+
const request = this.pendingRequests.get(requestId);
|
|
235
|
+
if (!request) {
|
|
236
|
+
throw new TossError(`Request ${requestId} not found`, 'EXCHANGE_REQUEST_NOT_FOUND');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Check if request has expired
|
|
240
|
+
if (Math.floor(Date.now() / 1000) > request.expiresAt) {
|
|
241
|
+
throw new TossError(`Request ${requestId} has expired`, 'EXCHANGE_REQUEST_EXPIRED');
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
requestId,
|
|
245
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
246
|
+
status,
|
|
247
|
+
responderId,
|
|
248
|
+
reason,
|
|
249
|
+
acknowledgedIntentIds
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get a pending request, decrypting if necessary
|
|
255
|
+
*/
|
|
256
|
+
getRequest(requestId, peerId) {
|
|
257
|
+
const request = this.pendingRequests.get(requestId);
|
|
258
|
+
if (!request) return undefined;
|
|
259
|
+
|
|
260
|
+
// If encrypted, attempt to decrypt
|
|
261
|
+
if (request.encrypted && request.ciphertext && peerId) {
|
|
262
|
+
try {
|
|
263
|
+
const session = this.getSecureSession(peerId);
|
|
264
|
+
if (session) {
|
|
265
|
+
const decryptedData = this.decryptRequestPayload(request.ciphertext, session);
|
|
266
|
+
return {
|
|
267
|
+
...decryptedData,
|
|
268
|
+
encrypted: false,
|
|
269
|
+
ciphertext: undefined
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error('Failed to decrypt request:', error);
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return request;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Get the static key for this device (for peer verification)
|
|
282
|
+
*/
|
|
283
|
+
getDeviceStaticKey() {
|
|
284
|
+
return new Uint8Array(this.deviceStaticKey);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Clear all pending requests
|
|
289
|
+
*/
|
|
290
|
+
clearRequests() {
|
|
291
|
+
this.pendingRequests.clear();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Clear all Noise sessions
|
|
296
|
+
*/
|
|
297
|
+
clearSessions() {
|
|
298
|
+
this.noiseSessions.clear();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Device and intent routing service for multi-hop scenarios
|
|
304
|
+
*/
|
|
305
|
+
export class IntentRoutingService {
|
|
306
|
+
routingTable = new Map(); // deviceId -> reachable peer IDs
|
|
307
|
+
MAX_HOPS = 3;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Register a routing path to a device
|
|
311
|
+
*/
|
|
312
|
+
registerRoute(targetDeviceId, viaPeers) {
|
|
313
|
+
if (viaPeers.length > this.MAX_HOPS) {
|
|
314
|
+
throw new TossError(`Route exceeds maximum hops (${this.MAX_HOPS})`, 'ROUTE_TOO_LONG');
|
|
315
|
+
}
|
|
316
|
+
this.routingTable.set(targetDeviceId, viaPeers);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Get the best route to a device
|
|
321
|
+
*/
|
|
322
|
+
getRoute(targetDeviceId) {
|
|
323
|
+
return this.routingTable.get(targetDeviceId);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Find all reachable devices
|
|
328
|
+
*/
|
|
329
|
+
getReachableDevices() {
|
|
330
|
+
return Array.from(this.routingTable.keys());
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Validate a route is still viable
|
|
335
|
+
*/
|
|
336
|
+
validateRoute(targetDeviceId, activePeers) {
|
|
337
|
+
const route = this.routingTable.get(targetDeviceId);
|
|
338
|
+
if (!route) return false;
|
|
339
|
+
const activePeerIds = new Set(activePeers.map(p => p.id));
|
|
340
|
+
return route.every(peerId => activePeerIds.has(peerId));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Clear all routes
|
|
345
|
+
*/
|
|
346
|
+
clearRoutes() {
|
|
347
|
+
this.routingTable.clear();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Multi-device conflict resolver
|
|
353
|
+
*
|
|
354
|
+
* When multiple devices are offline and both create intents for the same
|
|
355
|
+
* action, this detects and resolves the conflict per TOSS principles.
|
|
356
|
+
*/
|
|
357
|
+
export class MultiDeviceConflictResolver {
|
|
358
|
+
/**
|
|
359
|
+
* Detect conflicting intents from different devices
|
|
360
|
+
*/
|
|
361
|
+
static detectConflicts(intents) {
|
|
362
|
+
const conflicts = [];
|
|
363
|
+
const grouped = new Map();
|
|
364
|
+
|
|
365
|
+
// Group intents by (from, to, amount) tuple
|
|
366
|
+
for (const intent of intents) {
|
|
367
|
+
const key = `${intent.from}:${intent.to}:${intent.amount}`;
|
|
368
|
+
if (!grouped.has(key)) {
|
|
369
|
+
grouped.set(key, []);
|
|
370
|
+
}
|
|
371
|
+
grouped.get(key).push(intent);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Find groups with conflicts (multiple intents for same action)
|
|
375
|
+
for (const group of grouped.values()) {
|
|
376
|
+
if (group.length > 1) {
|
|
377
|
+
conflicts.push(group);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return conflicts;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Resolve conflicts using deterministic rules per TOSS spec
|
|
385
|
+
*
|
|
386
|
+
* Rules (in order):
|
|
387
|
+
* 1. Earliest nonce wins (replay protection)
|
|
388
|
+
* 2. Earliest timestamp wins (FIFO fairness)
|
|
389
|
+
* 3. Lexicographically first signature wins (deterministic tiebreak)
|
|
390
|
+
*/
|
|
391
|
+
static resolveConflicts(conflictingIntents) {
|
|
392
|
+
if (conflictingIntents.length === 0) {
|
|
393
|
+
throw new TossError('No intents to resolve', 'NO_INTENTS');
|
|
394
|
+
}
|
|
395
|
+
if (conflictingIntents.length === 1) {
|
|
396
|
+
const firstIntent = conflictingIntents[0];
|
|
397
|
+
if (!firstIntent) {
|
|
398
|
+
throw new TossError('No intents to resolve', 'NO_INTENTS');
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
winner: firstIntent,
|
|
402
|
+
losers: []
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Sort by rules
|
|
407
|
+
const sorted = [...conflictingIntents].sort((a, b) => {
|
|
408
|
+
// Rule 1: Lower nonce wins
|
|
409
|
+
if (a.nonce !== b.nonce) {
|
|
410
|
+
return a.nonce - b.nonce;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Rule 2: Earlier timestamp wins
|
|
414
|
+
if (a.createdAt !== b.createdAt) {
|
|
415
|
+
return a.createdAt - b.createdAt;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Rule 3: Lexicographically first signature
|
|
419
|
+
return a.signature.localeCompare(b.signature);
|
|
420
|
+
});
|
|
421
|
+
const winner = sorted[0];
|
|
422
|
+
if (!winner) {
|
|
423
|
+
throw new TossError('No intents to resolve', 'NO_INTENTS');
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
winner,
|
|
427
|
+
losers: sorted.slice(1)
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
export const deviceDiscovery = new DeviceDiscoveryService();
|
|
432
|
+
export const intentExchange = new IntentExchangeProtocol();
|
|
433
|
+
export const intentRouting = new IntentRoutingService();
|
|
434
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TossError","initNoiseSession","crypto","DeviceDiscoveryService","discoveredPeers","Map","PEER_TIMEOUT","MAX_PEERS","registerPeer","peer","size","oldestPeer","Array","from","values","sort","a","b","lastSeen","delete","id","set","Date","now","getActivePeers","activePeers","entries","push","getPeer","peerId","get","undefined","updateTrustScore","delta","maxScore","trustScore","Math","max","min","clearPeers","clear","IntentExchangeProtocol","pendingRequests","noiseSessions","REQUEST_TIMEOUT","SESSION_TIMEOUT","constructor","deviceStaticKey","getRandomValues","Uint8Array","establishSecureSession","existingSession","createdAt","encryptionCipher","sessionKey","session","setTimeout","getSecureSession","encryptRequestPayload","requestData","jsonPayload","JSON","stringify","payload","TextEncoder","encode","encrypted","length","i","decryptRequestPayload","ciphertext","decrypted","TextDecoder","decode","parse","createRequest","intent","requesterId","requesterUser","expiresIn","useEncryption","floor","requestId","random","toString","substr","timestamp","expiresAt","request","error","console","warn","createResponse","responderId","status","reason","acknowledgedIntentIds","getRequest","decryptedData","getDeviceStaticKey","clearRequests","clearSessions","IntentRoutingService","routingTable","MAX_HOPS","registerRoute","targetDeviceId","viaPeers","getRoute","getReachableDevices","keys","validateRoute","route","activePeerIds","Set","map","p","every","has","clearRoutes","MultiDeviceConflictResolver","detectConflicts","intents","conflicts","grouped","key","to","amount","group","resolveConflicts","conflictingIntents","firstIntent","winner","losers","sorted","nonce","signature","localeCompare","slice","deviceDiscovery","intentExchange","intentRouting"],"sourceRoot":"../../src","sources":["discovery.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export class TossError extends Error {
|
|
4
|
+
constructor(message, code, details) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.details = details;
|
|
8
|
+
this.name = 'TossError';
|
|
9
|
+
if (Error.captureStackTrace) {
|
|
10
|
+
Error.captureStackTrace(this, TossError);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class IntentValidationError extends TossError {
|
|
15
|
+
constructor(message, details) {
|
|
16
|
+
super(message, 'INTENT_VALIDATION_ERROR', details);
|
|
17
|
+
this.name = 'IntentValidationError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class NetworkError extends TossError {
|
|
21
|
+
constructor(message, details) {
|
|
22
|
+
super(message, 'NETWORK_ERROR', details);
|
|
23
|
+
this.name = 'NetworkError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export class StorageError extends TossError {
|
|
27
|
+
constructor(message, details) {
|
|
28
|
+
super(message, 'STORAGE_ERROR', details);
|
|
29
|
+
this.name = 'StorageError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class SignatureError extends TossError {
|
|
33
|
+
constructor(message, details) {
|
|
34
|
+
super(message, 'SIGNATURE_ERROR', details);
|
|
35
|
+
this.name = 'SignatureError';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export const ERROR_CODES = {
|
|
39
|
+
INVALID_INTENT: 'INVALID_INTENT',
|
|
40
|
+
NETWORK_ERROR: 'NETWORK_ERROR',
|
|
41
|
+
STORAGE_ERROR: 'STORAGE_ERROR',
|
|
42
|
+
SIGNATURE_VERIFICATION_FAILED: 'SIGNATURE_VERIFICATION_FAILED',
|
|
43
|
+
INTENT_EXPIRED: 'INTENT_EXPIRED',
|
|
44
|
+
INSUFFICIENT_FUNDS: 'INSUFFICIENT_FUNDS',
|
|
45
|
+
TRANSACTION_FAILED: 'TRANSACTION_FAILED'
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["TossError","Error","constructor","message","code","details","name","captureStackTrace","IntentValidationError","NetworkError","StorageError","SignatureError","ERROR_CODES","INVALID_INTENT","NETWORK_ERROR","STORAGE_ERROR","SIGNATURE_VERIFICATION_FAILED","INTENT_EXPIRED","INSUFFICIENT_FUNDS","TRANSACTION_FAILED"],"sourceRoot":"../../src","sources":["errors.ts"],"mappings":";;AAAA,OAAO,MAAMA,SAAS,SAASC,KAAK,CAAC;EACnCC,WAAWA,CACTC,OAAe,EACRC,IAAY,EACZC,OAAa,EACpB;IACA,KAAK,CAACF,OAAO,CAAC;IAAC,KAHRC,IAAY,GAAZA,IAAY;IAAA,KACZC,OAAa,GAAbA,OAAa;IAGpB,IAAI,CAACC,IAAI,GAAG,WAAW;IACvB,IAAIL,KAAK,CAACM,iBAAiB,EAAE;MAC3BN,KAAK,CAACM,iBAAiB,CAAC,IAAI,EAAEP,SAAS,CAAC;IAC1C;EACF;AACF;AAEA,OAAO,MAAMQ,qBAAqB,SAASR,SAAS,CAAC;EACnDE,WAAWA,CAACC,OAAe,EAAEE,OAAa,EAAE;IAC1C,KAAK,CAACF,OAAO,EAAE,yBAAyB,EAAEE,OAAO,CAAC;IAClD,IAAI,CAACC,IAAI,GAAG,uBAAuB;EACrC;AACF;AAEA,OAAO,MAAMG,YAAY,SAAST,SAAS,CAAC;EAC1CE,WAAWA,CAACC,OAAe,EAAEE,OAAa,EAAE;IAC1C,KAAK,CAACF,OAAO,EAAE,eAAe,EAAEE,OAAO,CAAC;IACxC,IAAI,CAACC,IAAI,GAAG,cAAc;EAC5B;AACF;AAEA,OAAO,MAAMI,YAAY,SAASV,SAAS,CAAC;EAC1CE,WAAWA,CAACC,OAAe,EAAEE,OAAa,EAAE;IAC1C,KAAK,CAACF,OAAO,EAAE,eAAe,EAAEE,OAAO,CAAC;IACxC,IAAI,CAACC,IAAI,GAAG,cAAc;EAC5B;AACF;AAEA,OAAO,MAAMK,cAAc,SAASX,SAAS,CAAC;EAC5CE,WAAWA,CAACC,OAAe,EAAEE,OAAa,EAAE;IAC1C,KAAK,CAACF,OAAO,EAAE,iBAAiB,EAAEE,OAAO,CAAC;IAC1C,IAAI,CAACC,IAAI,GAAG,gBAAgB;EAC9B;AACF;AAEA,OAAO,MAAMM,WAAW,GAAG;EACzBC,cAAc,EAAE,gBAAgB;EAChCC,aAAa,EAAE,eAAe;EAC9BC,aAAa,EAAE,eAAe;EAC9BC,6BAA6B,EAAE,+BAA+B;EAC9DC,cAAc,EAAE,gBAAgB;EAChCC,kBAAkB,EAAE,oBAAoB;EACxCC,kBAAkB,EAAE;AACtB,CAAU","ignoreList":[]}
|