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,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Complete Offline Payment Flow Example
|
|
5
|
+
*
|
|
6
|
+
* Demonstrates the full TOSS lifecycle per Section 12 of the Technical Paper:
|
|
7
|
+
* 1. Sender constructs and signs payment intent
|
|
8
|
+
* 2. Intent is exchanged offline via BLE/NFC/QR
|
|
9
|
+
* 3. Both devices store pending intent
|
|
10
|
+
* 4. When connectivity is restored, devices reconcile
|
|
11
|
+
* 5. Intent is submitted onchain with deterministic outcome
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { Keypair, PublicKey } from '@solana/web3.js';
|
|
15
|
+
import { createIntent, verifyIntent } from "../intent.js";
|
|
16
|
+
import { secureStoreIntent, getAllSecureIntents } from "../storage/secureStorage.js";
|
|
17
|
+
import { deviceDiscovery, intentExchange, MultiDeviceConflictResolver } from "../discovery.js";
|
|
18
|
+
import { syncToChain } from "../sync.js";
|
|
19
|
+
import { TossError } from "../errors.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Example: Sender initiates offline payment
|
|
23
|
+
*
|
|
24
|
+
* This simulates a sender who wants to send lamports to a recipient
|
|
25
|
+
* while offline. The intent is created, signed, and stored locally.
|
|
26
|
+
*/
|
|
27
|
+
export async function exampleInitiateOfflinePayment(senderKeypair, recipientAddress, amountLamports, connection) {
|
|
28
|
+
console.log('📝 Creating offline payment intent...');
|
|
29
|
+
|
|
30
|
+
// Create the intent (this is done offline, no network needed)
|
|
31
|
+
const intent = await createIntent(senderKeypair, new PublicKey(recipientAddress), amountLamports, connection, {
|
|
32
|
+
expiresIn: 24 * 60 * 60 // Valid for 24 hours
|
|
33
|
+
});
|
|
34
|
+
console.log(`✅ Intent created: ${intent.id}`);
|
|
35
|
+
console.log(` From: ${intent.from}`);
|
|
36
|
+
console.log(` To: ${intent.to}`);
|
|
37
|
+
console.log(` Amount: ${intent.amount} lamports`);
|
|
38
|
+
console.log(` Expires at: ${new Date(intent.expiry * 1000).toISOString()}`);
|
|
39
|
+
|
|
40
|
+
// Store locally
|
|
41
|
+
await secureStoreIntent(intent);
|
|
42
|
+
console.log('💾 Intent stored securely locally\n');
|
|
43
|
+
return intent;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Example: Intent exchange via proximity (BLE/NFC)
|
|
48
|
+
*
|
|
49
|
+
* One device has an intent it wants to share with a nearby peer.
|
|
50
|
+
* This demonstrates the intent exchange protocol.
|
|
51
|
+
*/
|
|
52
|
+
export async function exampleExchangeIntentWithPeer(intent, localDeviceId, peerDeviceId, peerDevice) {
|
|
53
|
+
console.log('📡 Initiating intent exchange with peer...');
|
|
54
|
+
console.log(` Local Device: ${localDeviceId}`);
|
|
55
|
+
console.log(` Peer Device: ${peerDeviceId}`);
|
|
56
|
+
|
|
57
|
+
// Register the peer
|
|
58
|
+
deviceDiscovery.registerPeer(peerDevice);
|
|
59
|
+
console.log(`✅ Peer registered: ${peerDevice.id}`);
|
|
60
|
+
|
|
61
|
+
// Create an exchange request
|
|
62
|
+
const exchangeRequest = intentExchange.createRequest(intent, localDeviceId, undefined, 5 * 60 // 5 minute expiry
|
|
63
|
+
);
|
|
64
|
+
console.log(`📨 Exchange request created: ${exchangeRequest.requestId}`);
|
|
65
|
+
console.log(` Intent ID: ${intent.id}`);
|
|
66
|
+
console.log(` Amount: ${intent.amount} lamports`);
|
|
67
|
+
|
|
68
|
+
// In a real scenario, this request would be transmitted via BLE/NFC/QR
|
|
69
|
+
// For this example, we'll simulate the peer receiving and accepting it
|
|
70
|
+
|
|
71
|
+
// Simulate peer accepting the request
|
|
72
|
+
const response = intentExchange.createResponse(exchangeRequest.requestId, peerDeviceId, 'accepted', undefined, [intent.id]);
|
|
73
|
+
console.log(`\n✅ Peer accepted exchange`);
|
|
74
|
+
console.log(` Status: ${response.status}`);
|
|
75
|
+
console.log(` Acknowledged intents: ${response.acknowledgedIntentIds?.join(', ')}\n`);
|
|
76
|
+
|
|
77
|
+
// In a real app, the peer would now have the intent in their local storage
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Example: Multiple devices create conflicting intents
|
|
82
|
+
*
|
|
83
|
+
* Demonstrates TOSS's deterministic conflict resolution when
|
|
84
|
+
* multiple offline devices create intents for the same action.
|
|
85
|
+
*/
|
|
86
|
+
export async function exampleMultiDeviceConflict(connection) {
|
|
87
|
+
console.log('🔄 Simulating multi-device conflict scenario...\n');
|
|
88
|
+
|
|
89
|
+
// Create keypair for "Device A"
|
|
90
|
+
const senderKeypair = Keypair.generate();
|
|
91
|
+
const recipient = new PublicKey('11111111111111111111111111111111');
|
|
92
|
+
const amount = 1000000; // 0.001 SOL
|
|
93
|
+
|
|
94
|
+
// Both devices create identical intents (same sender, recipient, amount)
|
|
95
|
+
// but at slightly different times
|
|
96
|
+
const intentA = await createIntent(senderKeypair, recipient, amount, connection, {
|
|
97
|
+
expiresIn: 3600
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Simulate Device B creating same intent 1 second later
|
|
101
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
102
|
+
const intentB = await createIntent(senderKeypair,
|
|
103
|
+
// Same sender!
|
|
104
|
+
recipient, amount, connection, {
|
|
105
|
+
expiresIn: 3600
|
|
106
|
+
});
|
|
107
|
+
console.log('❌ Conflict Detected!');
|
|
108
|
+
console.log(` Device A created intent: ${intentA.id} at ${intentA.createdAt}`);
|
|
109
|
+
console.log(` Device B created intent: ${intentB.id} at ${intentB.createdAt}`);
|
|
110
|
+
console.log(` Both intents: Same sender, same recipient, same amount\n`);
|
|
111
|
+
|
|
112
|
+
// Use the conflict resolver
|
|
113
|
+
const conflictingIntents = [intentA, intentB];
|
|
114
|
+
const resolution = MultiDeviceConflictResolver.resolveConflicts(conflictingIntents);
|
|
115
|
+
console.log('⚖️ Deterministic Resolution Applied:');
|
|
116
|
+
console.log(` Winner: ${resolution.winner.id}`);
|
|
117
|
+
console.log(` Winner nonce: ${resolution.winner.nonce}`);
|
|
118
|
+
console.log(` Winner timestamp: ${new Date(resolution.winner.createdAt * 1000).toISOString()}`);
|
|
119
|
+
console.log(`\n Losers: ${resolution.losers.map(i => i.id).join(', ')}`);
|
|
120
|
+
console.log(` (These intents will be marked failed during settlement)\n`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Example: Full offline-to-settlement flow
|
|
125
|
+
*
|
|
126
|
+
* Shows the complete journey of an intent from creation to onchain settlement.
|
|
127
|
+
*/
|
|
128
|
+
export async function exampleCompleteOfflineFlow(senderKeypair, recipientAddress, amountLamports, connection) {
|
|
129
|
+
console.log('='.repeat(60));
|
|
130
|
+
console.log('🚀 TOSS Complete Offline Payment Flow');
|
|
131
|
+
console.log('='.repeat(60) + '\n');
|
|
132
|
+
try {
|
|
133
|
+
// Step 1: Create intent offline
|
|
134
|
+
console.log('STEP 1: Offline Intent Creation');
|
|
135
|
+
console.log('-'.repeat(60));
|
|
136
|
+
const intent = await exampleInitiateOfflinePayment(senderKeypair, recipientAddress, amountLamports, connection);
|
|
137
|
+
|
|
138
|
+
// Step 2: Simulate peer device discovery and exchange
|
|
139
|
+
console.log('STEP 2: Peer Discovery & Intent Exchange');
|
|
140
|
+
console.log('-'.repeat(60));
|
|
141
|
+
const peerDevice = {
|
|
142
|
+
id: 'device_peer_001',
|
|
143
|
+
lastSeen: Date.now(),
|
|
144
|
+
transport: 'ble',
|
|
145
|
+
signalStrength: -45,
|
|
146
|
+
// dBm
|
|
147
|
+
trustScore: 75
|
|
148
|
+
};
|
|
149
|
+
await exampleExchangeIntentWithPeer(intent, 'device_local_001', 'device_peer_001', peerDevice);
|
|
150
|
+
|
|
151
|
+
// Step 3: Device reconnects and initiates synchronisation
|
|
152
|
+
console.log('STEP 3: Synchronisation with Solana');
|
|
153
|
+
console.log('-'.repeat(60));
|
|
154
|
+
console.log('📱 Device reconnected to network...');
|
|
155
|
+
console.log('🔄 Initiating sync with Solana blockchain...\n');
|
|
156
|
+
|
|
157
|
+
// Check sync status
|
|
158
|
+
const syncResult = await syncToChain(connection);
|
|
159
|
+
console.log('📊 Sync Results:');
|
|
160
|
+
console.log(` Successful settlements: ${syncResult.successfulSettlements.length}`);
|
|
161
|
+
console.log(` Failed settlements: ${syncResult.failedSettlements.length}`);
|
|
162
|
+
console.log(` Detected conflicts: ${syncResult.detectedConflicts.length}`);
|
|
163
|
+
console.log(` Overall complete: ${syncResult.isComplete}\n`);
|
|
164
|
+
if (syncResult.successfulSettlements.length > 0) {
|
|
165
|
+
console.log('✅ Successful Settlements:');
|
|
166
|
+
for (const settlement of syncResult.successfulSettlements) {
|
|
167
|
+
console.log(` Intent ${settlement.intentId}`);
|
|
168
|
+
console.log(` Signature: ${settlement.signature}`);
|
|
169
|
+
console.log(` Timestamp: ${new Date(settlement.timestamp * 1000).toISOString()}`);
|
|
170
|
+
}
|
|
171
|
+
console.log();
|
|
172
|
+
}
|
|
173
|
+
if (syncResult.failedSettlements.length > 0) {
|
|
174
|
+
console.log('❌ Failed Settlements:');
|
|
175
|
+
for (const settlement of syncResult.failedSettlements) {
|
|
176
|
+
console.log(` Intent ${settlement.intentId}`);
|
|
177
|
+
console.log(` Reason: ${settlement.error}`);
|
|
178
|
+
}
|
|
179
|
+
console.log();
|
|
180
|
+
}
|
|
181
|
+
if (syncResult.detectedConflicts.length > 0) {
|
|
182
|
+
console.log('⚠️ Detected Conflicts:');
|
|
183
|
+
for (const conflict of syncResult.detectedConflicts) {
|
|
184
|
+
console.log(` Intent ${conflict.intentId}: ${conflict.conflict}`);
|
|
185
|
+
}
|
|
186
|
+
console.log();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Step 4: Verify final state
|
|
190
|
+
console.log('STEP 4: Final State Verification');
|
|
191
|
+
console.log('-'.repeat(60));
|
|
192
|
+
const allIntents = await getAllSecureIntents();
|
|
193
|
+
const settledIntents = allIntents.filter(i => i.status === 'settled');
|
|
194
|
+
const failedIntents = allIntents.filter(i => i.status === 'failed');
|
|
195
|
+
console.log(`📦 Intent Storage:
|
|
196
|
+
Total intents: ${allIntents.length}
|
|
197
|
+
Settled: ${settledIntents.length}
|
|
198
|
+
Failed: ${failedIntents.length}\n`);
|
|
199
|
+
console.log('✨ Flow complete!\n');
|
|
200
|
+
console.log('='.repeat(60));
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error('❌ Error during offline flow:', error);
|
|
203
|
+
if (error instanceof TossError) {
|
|
204
|
+
console.error(` Error code: ${error.code}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Example: Verify intent before exchange
|
|
211
|
+
*
|
|
212
|
+
* Good practice: receivers should verify intent signatures
|
|
213
|
+
* before accepting and storing them.
|
|
214
|
+
*/
|
|
215
|
+
export async function exampleVerifyIntentBeforeAcceptance(intent, connection) {
|
|
216
|
+
console.log('🔐 Verifying intent signature...');
|
|
217
|
+
try {
|
|
218
|
+
const isValid = await verifyIntent(intent, connection);
|
|
219
|
+
if (isValid) {
|
|
220
|
+
console.log('✅ Intent signature is valid');
|
|
221
|
+
console.log(` From: ${intent.from}`);
|
|
222
|
+
console.log(` To: ${intent.to}`);
|
|
223
|
+
console.log(` Amount: ${intent.amount} lamports`);
|
|
224
|
+
return true;
|
|
225
|
+
} else {
|
|
226
|
+
console.log('❌ Intent signature is invalid');
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
} catch (error) {
|
|
230
|
+
console.error('❌ Verification failed:', error);
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=offlinePaymentFlow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Keypair","PublicKey","createIntent","verifyIntent","secureStoreIntent","getAllSecureIntents","deviceDiscovery","intentExchange","MultiDeviceConflictResolver","syncToChain","TossError","exampleInitiateOfflinePayment","senderKeypair","recipientAddress","amountLamports","connection","console","log","intent","expiresIn","id","from","to","amount","Date","expiry","toISOString","exampleExchangeIntentWithPeer","localDeviceId","peerDeviceId","peerDevice","registerPeer","exchangeRequest","createRequest","undefined","requestId","response","createResponse","status","acknowledgedIntentIds","join","exampleMultiDeviceConflict","generate","recipient","intentA","Promise","resolve","setTimeout","intentB","createdAt","conflictingIntents","resolution","resolveConflicts","winner","nonce","losers","map","i","exampleCompleteOfflineFlow","repeat","lastSeen","now","transport","signalStrength","trustScore","syncResult","successfulSettlements","length","failedSettlements","detectedConflicts","isComplete","settlement","intentId","signature","timestamp","error","conflict","allIntents","settledIntents","filter","failedIntents","code","exampleVerifyIntentBeforeAcceptance","isValid"],"sourceRoot":"../../../src","sources":["examples/offlinePaymentFlow.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Core types and intents
|
|
4
|
+
export { createIntent } from "./intent.js";
|
|
5
|
+
|
|
6
|
+
// Intent management
|
|
7
|
+
export { verifyIntentSignature, isIntentExpired, updateIntentStatus, validateIntent, processIntentsForSync, filterExpiredIntents } from "./intentManager.js";
|
|
8
|
+
|
|
9
|
+
// Storage
|
|
10
|
+
export { storePendingIntent, getPendingIntents, clearPendingIntents } from "./storage.js";
|
|
11
|
+
|
|
12
|
+
// Transport methods
|
|
13
|
+
export { startTossScan, requestBLEPermissions } from "./ble.js";
|
|
14
|
+
export { initNFC, readNFCUser, writeUserToNFC, writeIntentToNFC } from "./nfc.js";
|
|
15
|
+
export { QRScanner } from "./qr.js";
|
|
16
|
+
|
|
17
|
+
// Client
|
|
18
|
+
export { TossClient } from "./client/TossClient.js";
|
|
19
|
+
|
|
20
|
+
// Create client instance
|
|
21
|
+
import { TossClient } from "./client/TossClient.js";
|
|
22
|
+
export const createClient = TossClient.createClient;
|
|
23
|
+
|
|
24
|
+
// Sync and settlement
|
|
25
|
+
export { syncToChain, checkSyncStatus } from "./sync.js";
|
|
26
|
+
|
|
27
|
+
// Reconciliation and conflict detection
|
|
28
|
+
export { reconcilePendingIntents, settleIntent, validateIntentOnchain, buildTransactionFromIntent, submitTransactionToChain, detectConflicts, getReconciliationState } from "./reconciliation.js";
|
|
29
|
+
|
|
30
|
+
// Device discovery and intent exchange
|
|
31
|
+
export { DeviceDiscoveryService, IntentExchangeProtocol, IntentRoutingService, MultiDeviceConflictResolver, deviceDiscovery, intentExchange, intentRouting } from "./discovery.js";
|
|
32
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["createIntent","verifyIntentSignature","isIntentExpired","updateIntentStatus","validateIntent","processIntentsForSync","filterExpiredIntents","storePendingIntent","getPendingIntents","clearPendingIntents","startTossScan","requestBLEPermissions","initNFC","readNFCUser","writeUserToNFC","writeIntentToNFC","QRScanner","TossClient","createClient","syncToChain","checkSyncStatus","reconcilePendingIntents","settleIntent","validateIntentOnchain","buildTransactionFromIntent","submitTransactionToChain","detectConflicts","getReconciliationState","DeviceDiscoveryService","IntentExchangeProtocol","IntentRoutingService","MultiDeviceConflictResolver","deviceDiscovery","intentExchange","intentRouting"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA;AACA,SAASA,YAAY,QAA8C,aAAU;;AAE7E;AACA,SACEC,qBAAqB,EACrBC,eAAe,EACfC,kBAAkB,EAClBC,cAAc,EACdC,qBAAqB,EACrBC,oBAAoB,QACf,oBAAiB;;AAExB;AACA,SACEC,kBAAkB,EAClBC,iBAAiB,EACjBC,mBAAmB,QACd,cAAW;;AAElB;AACA,SAASC,aAAa,EAAEC,qBAAqB,QAAQ,UAAO;AAC5D,SAASC,OAAO,EAAEC,WAAW,EAAEC,cAAc,EAAEC,gBAAgB,QAAQ,UAAO;AAC9E,SAASC,SAAS,QAAQ,SAAM;;AAEhC;AACA,SAASC,UAAU,QAAyB,wBAAqB;;AAEjE;AACA,SAASA,UAAU,QAAQ,wBAAqB;AAChD,OAAO,MAAMC,YAAY,GAAGD,UAAU,CAACC,YAAY;;AAEnD;AACA,SAASC,WAAW,EAAEC,eAAe,QAAyB,WAAQ;;AAEtE;AACA,SACEC,uBAAuB,EACvBC,YAAY,EACZC,qBAAqB,EACrBC,0BAA0B,EAC1BC,wBAAwB,EACxBC,eAAe,EACfC,sBAAsB,QAGjB,qBAAkB;;AAEzB;AACA,SACEC,sBAAsB,EACtBC,sBAAsB,EACtBC,oBAAoB,EACpBC,2BAA2B,EAC3BC,eAAe,EACfC,cAAc,EACdC,aAAa,QAIR,gBAAa","ignoreList":[]}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { PublicKey } from '@solana/web3.js';
|
|
4
|
+
import bs58 from 'bs58';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
6
|
+
import { sign } from 'tweetnacl';
|
|
7
|
+
import nacl from 'tweetnacl';
|
|
8
|
+
import { encryptForArciumInternal } from "./internal/arciumHelper.js";
|
|
9
|
+
// Nonce management now handled internally
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Status of an intent in its lifecycle
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Core type for an offline intent following TOSS specification
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Options for creating a new intent
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Manages nonce values for transaction replay protection
|
|
25
|
+
*/
|
|
26
|
+
class NonceManager {
|
|
27
|
+
nonceStore = new Map();
|
|
28
|
+
NONCE_EXPIRY = 5 * 60 * 1000; // 5 minutes
|
|
29
|
+
|
|
30
|
+
async getNextNonce(publicKey, connection) {
|
|
31
|
+
const key = publicKey.toBase58();
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
|
|
34
|
+
// Clean up old nonces
|
|
35
|
+
this.cleanupNonces();
|
|
36
|
+
try {
|
|
37
|
+
// Get nonce from chain
|
|
38
|
+
const accountInfo = await connection.getAccountInfo(publicKey);
|
|
39
|
+
const chainNonce = accountInfo ? this.extractNonceFromAccountInfo(accountInfo) : 0;
|
|
40
|
+
|
|
41
|
+
// Get or initialize stored nonce
|
|
42
|
+
const stored = this.nonceStore.get(key) || {
|
|
43
|
+
nonce: chainNonce,
|
|
44
|
+
lastUsed: now
|
|
45
|
+
};
|
|
46
|
+
const nextNonce = Math.max(stored.nonce + 1, chainNonce + 1);
|
|
47
|
+
|
|
48
|
+
// Update store
|
|
49
|
+
this.nonceStore.set(key, {
|
|
50
|
+
nonce: nextNonce,
|
|
51
|
+
lastUsed: now
|
|
52
|
+
});
|
|
53
|
+
return nextNonce;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.warn('Failed to get nonce from chain, using in-memory nonce', error);
|
|
56
|
+
const stored = this.nonceStore.get(key) || {
|
|
57
|
+
nonce: 0,
|
|
58
|
+
lastUsed: now
|
|
59
|
+
};
|
|
60
|
+
const nextNonce = stored.nonce + 1;
|
|
61
|
+
this.nonceStore.set(key, {
|
|
62
|
+
nonce: nextNonce,
|
|
63
|
+
lastUsed: now
|
|
64
|
+
});
|
|
65
|
+
return nextNonce;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
extractNonceFromAccountInfo(accountInfo) {
|
|
69
|
+
// For SystemProgram accounts, nonce is typically stored in the first 8 bytes
|
|
70
|
+
const data = accountInfo.data;
|
|
71
|
+
return data?.length >= 8 ? data.readUInt32LE(0) : 0;
|
|
72
|
+
}
|
|
73
|
+
cleanupNonces() {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
for (const [key, value] of this.nonceStore.entries()) {
|
|
76
|
+
if (now - value.lastUsed > this.NONCE_EXPIRY) {
|
|
77
|
+
this.nonceStore.delete(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export const nonceManager = new NonceManager();
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Creates a signed intent that can be verified offline
|
|
86
|
+
*/
|
|
87
|
+
export async function createSignedIntent(sender, recipient, amount, connection, options = {}) {
|
|
88
|
+
const now = Math.floor(Date.now() / 1000);
|
|
89
|
+
const defaultExpiry = 24 * 60 * 60; // 24 hours default
|
|
90
|
+
|
|
91
|
+
// Get latest blockhash and nonce
|
|
92
|
+
const [{
|
|
93
|
+
blockhash
|
|
94
|
+
}, nonce] = await Promise.all([connection.getLatestBlockhash(), options.nonce !== undefined ? Promise.resolve(options.nonce) : nonceManager.getNextNonce(sender.publicKey, connection)]);
|
|
95
|
+
|
|
96
|
+
// Create base intent
|
|
97
|
+
const baseIntent = {
|
|
98
|
+
id: uuidv4(),
|
|
99
|
+
from: sender.publicKey.toBase58(),
|
|
100
|
+
to: recipient.toBase58(),
|
|
101
|
+
amount,
|
|
102
|
+
nonce,
|
|
103
|
+
expiry: now + (options.expiresIn || defaultExpiry),
|
|
104
|
+
blockhash,
|
|
105
|
+
feePayer: options.nonceAuth?.toBase58() || sender.publicKey.toBase58(),
|
|
106
|
+
status: 'pending',
|
|
107
|
+
createdAt: now,
|
|
108
|
+
updatedAt: now,
|
|
109
|
+
...(options.nonceAccount && options.nonceAuth ? {
|
|
110
|
+
nonceAccount: options.nonceAccount.publicKey.toBase58(),
|
|
111
|
+
nonceAuth: options.nonceAuth.toBase58()
|
|
112
|
+
} : {})
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Sign the intent
|
|
116
|
+
const signature = sign(Buffer.from(JSON.stringify(baseIntent)), sender.secretKey);
|
|
117
|
+
return {
|
|
118
|
+
...baseIntent,
|
|
119
|
+
signature: bs58.encode(signature)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Verifies the signature, nonce, and expiry of an intent
|
|
125
|
+
*/
|
|
126
|
+
export async function verifyIntent(intent, connection) {
|
|
127
|
+
try {
|
|
128
|
+
// Basic validation
|
|
129
|
+
if (!intent.signature || !intent.from || !intent.to) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check if intent is expired
|
|
134
|
+
if (isIntentExpired(intent)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Verify signature
|
|
139
|
+
const signature = bs58.decode(intent.signature);
|
|
140
|
+
const message = Buffer.from(JSON.stringify({
|
|
141
|
+
...intent,
|
|
142
|
+
signature: undefined
|
|
143
|
+
}));
|
|
144
|
+
const publicKey = new PublicKey(intent.from).toBytes();
|
|
145
|
+
try {
|
|
146
|
+
// Use nacl.sign.detached.verify for detached signature verification
|
|
147
|
+
// Requires: message, detached signature, public key
|
|
148
|
+
const publicKeyUint8 = new Uint8Array(publicKey);
|
|
149
|
+
const signatureUint8 = new Uint8Array(signature);
|
|
150
|
+
const verified = nacl.sign.detached.verify(Buffer.from(message), signatureUint8, publicKeyUint8);
|
|
151
|
+
if (!verified) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error('Signature verification failed:', error);
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Verify nonce if connection is provided
|
|
160
|
+
if (connection) {
|
|
161
|
+
try {
|
|
162
|
+
const accountInfo = await connection.getAccountInfo(new PublicKey(intent.from));
|
|
163
|
+
if (accountInfo) {
|
|
164
|
+
const currentNonce = accountInfo.data?.length >= 8 ? accountInfo.data.readUInt32LE(0) : 0;
|
|
165
|
+
if (intent.nonce <= currentNonce) {
|
|
166
|
+
return false; // Nonce too low or reused
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.warn('Failed to verify nonce:', error);
|
|
171
|
+
// Continue without nonce verification if we can't check the chain
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('Intent verification failed:', error);
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Creates an offline Solana intent following TOSS specification.
|
|
183
|
+
* If privateTransaction is true, encrypts internal data with Arcium.
|
|
184
|
+
*/
|
|
185
|
+
export async function createIntent(sender, recipient, amount, connection, options = {}) {
|
|
186
|
+
// First create and sign the intent
|
|
187
|
+
const intent = await createSignedIntent(sender, recipient, amount, connection, options);
|
|
188
|
+
|
|
189
|
+
// If private transaction, encrypt the intent data
|
|
190
|
+
if (options.privateTransaction) {
|
|
191
|
+
if (!options.mxeProgramId) {
|
|
192
|
+
throw new Error('MXE Program ID is required for private transactions');
|
|
193
|
+
}
|
|
194
|
+
if (!options.provider) {
|
|
195
|
+
throw new Error('Provider is required for private transactions');
|
|
196
|
+
}
|
|
197
|
+
const plaintextValues = [BigInt(amount)
|
|
198
|
+
// Include additional fields for privacy as needed
|
|
199
|
+
];
|
|
200
|
+
intent.encrypted = await encryptForArciumInternal(options.mxeProgramId, plaintextValues, options.provider);
|
|
201
|
+
}
|
|
202
|
+
return intent;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Checks if an intent has expired
|
|
207
|
+
*/
|
|
208
|
+
export function isIntentExpired(intent) {
|
|
209
|
+
return intent.expiry <= Math.floor(Date.now() / 1000);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Updates the status of an intent
|
|
214
|
+
*/
|
|
215
|
+
export function updateIntentStatus(intent, status, error) {
|
|
216
|
+
return {
|
|
217
|
+
...intent,
|
|
218
|
+
status,
|
|
219
|
+
error,
|
|
220
|
+
updatedAt: Math.floor(Date.now() / 1000)
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["PublicKey","bs58","v4","uuidv4","sign","nacl","encryptForArciumInternal","NonceManager","nonceStore","Map","NONCE_EXPIRY","getNextNonce","publicKey","connection","key","toBase58","now","Date","cleanupNonces","accountInfo","getAccountInfo","chainNonce","extractNonceFromAccountInfo","stored","get","nonce","lastUsed","nextNonce","Math","max","set","error","console","warn","data","length","readUInt32LE","value","entries","delete","nonceManager","createSignedIntent","sender","recipient","amount","options","floor","defaultExpiry","blockhash","Promise","all","getLatestBlockhash","undefined","resolve","baseIntent","id","from","to","expiry","expiresIn","feePayer","nonceAuth","status","createdAt","updatedAt","nonceAccount","signature","Buffer","JSON","stringify","secretKey","encode","verifyIntent","intent","isIntentExpired","decode","message","toBytes","publicKeyUint8","Uint8Array","signatureUint8","verified","detached","verify","currentNonce","createIntent","privateTransaction","mxeProgramId","Error","provider","plaintextValues","BigInt","encrypted","updateIntentStatus"],"sourceRoot":"../../src","sources":["intent.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Transaction } from '@solana/web3.js';
|
|
4
|
+
import bs58 from 'bs58';
|
|
5
|
+
/**
|
|
6
|
+
* Verifies the signature of a Solana intent
|
|
7
|
+
* @param intent The intent to verify
|
|
8
|
+
* @returns boolean indicating if the signature is valid
|
|
9
|
+
*/
|
|
10
|
+
export function verifyIntentSignature(intent) {
|
|
11
|
+
try {
|
|
12
|
+
// Check if serialized transaction exists
|
|
13
|
+
if (!intent.serialized) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Reconstruct the transaction to verify signatures
|
|
18
|
+
const tx = Transaction.from(Buffer.from(bs58.decode(intent.serialized)));
|
|
19
|
+
|
|
20
|
+
// Verify all signatures in the transaction
|
|
21
|
+
return tx.verifySignatures();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Error verifying intent signature:', error);
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Checks if an intent has expired
|
|
30
|
+
* @param intent The intent to check
|
|
31
|
+
* @returns boolean indicating if the intent has expired
|
|
32
|
+
*/
|
|
33
|
+
export function isIntentExpired(intent) {
|
|
34
|
+
return Date.now() / 1000 > intent.expiry;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Updates the status of an intent
|
|
39
|
+
* @param intent The intent to update
|
|
40
|
+
* @param status The new status
|
|
41
|
+
* @param error Optional error message if status is 'failed'
|
|
42
|
+
* @returns A new intent with updated status
|
|
43
|
+
*/
|
|
44
|
+
export function updateIntentStatus(intent, status, error) {
|
|
45
|
+
return {
|
|
46
|
+
...intent,
|
|
47
|
+
status,
|
|
48
|
+
updatedAt: Math.floor(Date.now() / 1000),
|
|
49
|
+
...(error && {
|
|
50
|
+
error
|
|
51
|
+
})
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Validates an intent against current blockchain state
|
|
57
|
+
* Note: This is a placeholder - actual implementation would check against a Solana node
|
|
58
|
+
* @param intent The intent to validate
|
|
59
|
+
* @param currentBlockhash Current network blockhash
|
|
60
|
+
* @returns Validation result with success status and optional error message
|
|
61
|
+
*/
|
|
62
|
+
export async function validateIntent(intent, currentBlockhash) {
|
|
63
|
+
// Check if intent has expired
|
|
64
|
+
if (isIntentExpired(intent)) {
|
|
65
|
+
return {
|
|
66
|
+
valid: false,
|
|
67
|
+
error: 'Intent has expired'
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Verify signatures
|
|
72
|
+
if (!verifyIntentSignature(intent)) {
|
|
73
|
+
return {
|
|
74
|
+
valid: false,
|
|
75
|
+
error: 'Invalid transaction signature'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check if blockhash is still valid
|
|
80
|
+
// In a real implementation, we'd check against the Solana cluster
|
|
81
|
+
// This is a simplified check
|
|
82
|
+
if (intent.blockhash !== currentBlockhash) {
|
|
83
|
+
return {
|
|
84
|
+
valid: false,
|
|
85
|
+
error: 'Stale blockhash'
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Additional validation logic would go here
|
|
90
|
+
// - Check account balances
|
|
91
|
+
// - Verify program-specific logic
|
|
92
|
+
// - Check for double-spend attempts
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
valid: true
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Processes a batch of intents for synchronization
|
|
101
|
+
* @param intents Array of intents to process
|
|
102
|
+
* @param connection Connection to Solana network
|
|
103
|
+
* @returns Processed intents with updated statuses
|
|
104
|
+
*/
|
|
105
|
+
export async function processIntentsForSync(intents, connection) {
|
|
106
|
+
const currentBlockhash = (await connection.getRecentBlockhash()).blockhash;
|
|
107
|
+
return Promise.all(intents.map(async intent => {
|
|
108
|
+
// Skip already processed intents
|
|
109
|
+
if (intent.status !== 'pending') return intent;
|
|
110
|
+
const validation = await validateIntent(intent, currentBlockhash);
|
|
111
|
+
if (!validation.valid) {
|
|
112
|
+
return updateIntentStatus(intent, 'failed', validation.error);
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
// In a real implementation, we would submit the transaction here
|
|
116
|
+
// const signature = await connection.sendRawTransaction(
|
|
117
|
+
// Buffer.from(bs58.decode(intent.serialized))
|
|
118
|
+
// );
|
|
119
|
+
// await connection.confirmTransaction(signature);
|
|
120
|
+
|
|
121
|
+
return updateIntentStatus(intent, 'settled');
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return updateIntentStatus(intent, 'failed', error instanceof Error ? error.message : 'Unknown error');
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Filters out expired intents and updates their status
|
|
130
|
+
* @param intents Array of intents to check
|
|
131
|
+
* @returns Tuple of [validIntents, expiredIntents]
|
|
132
|
+
*/
|
|
133
|
+
export function filterExpiredIntents(intents) {
|
|
134
|
+
const valid = [];
|
|
135
|
+
const expired = [];
|
|
136
|
+
for (const intent of intents) {
|
|
137
|
+
if (isIntentExpired(intent)) {
|
|
138
|
+
expired.push(updateIntentStatus(intent, 'expired'));
|
|
139
|
+
} else {
|
|
140
|
+
valid.push(intent);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return [valid, expired];
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=intentManager.js.map
|