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
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BLE MTU Configuration for different device types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Default MTU configurations
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_MTU_CONFIGS = {
|
|
11
|
+
android: {
|
|
12
|
+
maxPayloadSize: 512,
|
|
13
|
+
// Typical Android BLE MTU
|
|
14
|
+
chunkSize: 480,
|
|
15
|
+
// Conservative chunk size
|
|
16
|
+
maxRetries: 3,
|
|
17
|
+
timeout: 5000
|
|
18
|
+
},
|
|
19
|
+
ios: {
|
|
20
|
+
maxPayloadSize: 512,
|
|
21
|
+
// iOS BLE MTU
|
|
22
|
+
chunkSize: 480,
|
|
23
|
+
maxRetries: 3,
|
|
24
|
+
timeout: 5000
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Represents a fragmented message with header information
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Represents a Noise-encrypted BLE message
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* BLETransactionHandler
|
|
38
|
+
* Manages secure, fragmented BLE transmission of offline transactions
|
|
39
|
+
* with Noise Protocol encryption
|
|
40
|
+
*/
|
|
41
|
+
export class BLETransactionHandler {
|
|
42
|
+
fragmentCache = new Map();
|
|
43
|
+
messageIdMap = new Map();
|
|
44
|
+
constructor(platform = 'android') {
|
|
45
|
+
this.mtuConfig = DEFAULT_MTU_CONFIGS[platform] || DEFAULT_MTU_CONFIGS.android;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Fragment a large transaction/intent into BLE-safe chunks
|
|
50
|
+
* Respects MTU limitations and adds framing information
|
|
51
|
+
*/
|
|
52
|
+
fragmentTransaction(transaction, isIntent = false) {
|
|
53
|
+
const payload = Buffer.from(JSON.stringify(transaction), 'utf-8');
|
|
54
|
+
const messageId = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
55
|
+
const totalFragments = Math.ceil(payload.length / this.mtuConfig.chunkSize);
|
|
56
|
+
const fragments = [];
|
|
57
|
+
for (let i = 0; i < totalFragments; i++) {
|
|
58
|
+
const start = i * this.mtuConfig.chunkSize;
|
|
59
|
+
const end = Math.min(start + this.mtuConfig.chunkSize, payload.length);
|
|
60
|
+
const chunk = payload.slice(start, end);
|
|
61
|
+
const fragment = {
|
|
62
|
+
messageId,
|
|
63
|
+
sequenceNumber: i,
|
|
64
|
+
totalFragments,
|
|
65
|
+
checksumValue: this.calculateCRC32(chunk),
|
|
66
|
+
payload: chunk
|
|
67
|
+
};
|
|
68
|
+
fragments.push(fragment);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Store fragments for reassembly on receiver end
|
|
72
|
+
this.fragmentCache.set(messageId, fragments);
|
|
73
|
+
this.messageIdMap.set(messageId, isIntent ? transaction : transaction);
|
|
74
|
+
return fragments;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Prepare encrypted BLE message for transmission
|
|
79
|
+
* Uses Noise Protocol for end-to-end encryption
|
|
80
|
+
*/
|
|
81
|
+
async prepareEncryptedMessage(fragment, noiseEncryptFn) {
|
|
82
|
+
// Serialize fragment
|
|
83
|
+
const fragmentData = this.serializeFragment(fragment);
|
|
84
|
+
|
|
85
|
+
// Encrypt using Noise Protocol
|
|
86
|
+
const encrypted = await noiseEncryptFn(fragmentData);
|
|
87
|
+
return encrypted;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Send fragmented transaction over BLE with encryption
|
|
92
|
+
* Handles retries and verification
|
|
93
|
+
*/
|
|
94
|
+
async sendFragmentedTransactionBLE(device, transaction, sendFn, noiseEncryptFn, isIntent = false) {
|
|
95
|
+
const fragments = this.fragmentTransaction(transaction, isIntent);
|
|
96
|
+
const messageId = fragments[0]?.messageId;
|
|
97
|
+
const failedFragments = [];
|
|
98
|
+
if (!messageId) {
|
|
99
|
+
throw new Error('Failed to generate message ID for transaction');
|
|
100
|
+
}
|
|
101
|
+
const CHARACTERISTIC_UUID = '0000ff02-0000-1000-8000-00805f9b34fb'; // Intent characteristic
|
|
102
|
+
|
|
103
|
+
for (const fragment of fragments) {
|
|
104
|
+
let retries = 0;
|
|
105
|
+
let sent = false;
|
|
106
|
+
while (retries < this.mtuConfig.maxRetries && !sent) {
|
|
107
|
+
try {
|
|
108
|
+
let messageData;
|
|
109
|
+
if (noiseEncryptFn) {
|
|
110
|
+
// Encrypt fragment using Noise Protocol
|
|
111
|
+
const encrypted = await this.prepareEncryptedMessage(fragment, noiseEncryptFn);
|
|
112
|
+
messageData = Buffer.from(JSON.stringify(encrypted), 'utf-8');
|
|
113
|
+
} else {
|
|
114
|
+
// Send unencrypted (not recommended)
|
|
115
|
+
messageData = Buffer.from(JSON.stringify(fragment), 'utf-8');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Send via BLE
|
|
119
|
+
await sendFn(device.id, CHARACTERISTIC_UUID, messageData);
|
|
120
|
+
sent = true;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
retries++;
|
|
123
|
+
console.warn(`Failed to send fragment ${fragment.sequenceNumber}, retry ${retries}:`, error);
|
|
124
|
+
if (retries >= this.mtuConfig.maxRetries) {
|
|
125
|
+
failedFragments.push(fragment.sequenceNumber);
|
|
126
|
+
} else {
|
|
127
|
+
// Exponential backoff
|
|
128
|
+
await this.delay(Math.pow(2, retries) * 100);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
success: failedFragments.length === 0,
|
|
135
|
+
sentFragments: fragments.length - failedFragments.length,
|
|
136
|
+
failedFragments,
|
|
137
|
+
messageId
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Receive and reassemble fragmented messages
|
|
143
|
+
*/
|
|
144
|
+
async receiveFragmentedMessage(fragment, _noiseDecryptFn) {
|
|
145
|
+
const messageId = fragment.messageId;
|
|
146
|
+
|
|
147
|
+
// Initialize or retrieve fragment cache
|
|
148
|
+
if (!this.fragmentCache.has(messageId)) {
|
|
149
|
+
this.fragmentCache.set(messageId, []);
|
|
150
|
+
}
|
|
151
|
+
const cachedFragments = this.fragmentCache.get(messageId);
|
|
152
|
+
cachedFragments[fragment.sequenceNumber] = fragment;
|
|
153
|
+
const progress = {
|
|
154
|
+
received: cachedFragments.filter(f => f !== undefined).length,
|
|
155
|
+
total: fragment.totalFragments
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// Check if all fragments received
|
|
159
|
+
if (progress.received < fragment.totalFragments) {
|
|
160
|
+
return {
|
|
161
|
+
complete: false,
|
|
162
|
+
progress
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Reassemble message
|
|
167
|
+
const reassembled = this.reassembleMessage(cachedFragments);
|
|
168
|
+
if (!reassembled) {
|
|
169
|
+
return {
|
|
170
|
+
complete: false,
|
|
171
|
+
progress
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
// Parse transaction
|
|
176
|
+
const transactionData = JSON.parse(reassembled);
|
|
177
|
+
const transaction = transactionData;
|
|
178
|
+
|
|
179
|
+
// Cleanup cache
|
|
180
|
+
this.fragmentCache.delete(messageId);
|
|
181
|
+
this.messageIdMap.delete(messageId);
|
|
182
|
+
return {
|
|
183
|
+
complete: true,
|
|
184
|
+
transaction,
|
|
185
|
+
progress
|
|
186
|
+
};
|
|
187
|
+
} catch (error) {
|
|
188
|
+
console.error('Failed to parse reassembled message:', error);
|
|
189
|
+
return {
|
|
190
|
+
complete: false,
|
|
191
|
+
progress
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Reassemble fragments into original message
|
|
198
|
+
*/
|
|
199
|
+
reassembleMessage(fragments) {
|
|
200
|
+
try {
|
|
201
|
+
// Sort by sequence number
|
|
202
|
+
const sorted = fragments.sort((a, b) => a.sequenceNumber - b.sequenceNumber);
|
|
203
|
+
|
|
204
|
+
// Verify all fragments present and checksums
|
|
205
|
+
for (const fragment of sorted) {
|
|
206
|
+
const calculatedChecksum = this.calculateCRC32(fragment.payload);
|
|
207
|
+
if (calculatedChecksum !== fragment.checksumValue) {
|
|
208
|
+
console.warn(`Checksum mismatch for fragment ${fragment.sequenceNumber}`);
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Concatenate payloads
|
|
214
|
+
const combined = Buffer.concat(sorted.map(f => Buffer.from(f.payload)));
|
|
215
|
+
return combined.toString('utf-8');
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error('Failed to reassemble message:', error);
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Serialize BLE fragment for transmission
|
|
224
|
+
*/
|
|
225
|
+
serializeFragment(fragment) {
|
|
226
|
+
const data = {
|
|
227
|
+
messageId: fragment.messageId,
|
|
228
|
+
sequenceNumber: fragment.sequenceNumber,
|
|
229
|
+
totalFragments: fragment.totalFragments,
|
|
230
|
+
checksumValue: fragment.checksumValue,
|
|
231
|
+
payload: Array.from(fragment.payload)
|
|
232
|
+
};
|
|
233
|
+
return new Uint8Array(Buffer.from(JSON.stringify(data), 'utf-8'));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Calculate CRC32 checksum for fragment verification
|
|
238
|
+
*/
|
|
239
|
+
calculateCRC32(data) {
|
|
240
|
+
let crc = 0xffffffff;
|
|
241
|
+
for (let i = 0; i < data.length; i++) {
|
|
242
|
+
const byte = data[i];
|
|
243
|
+
if (byte !== undefined) {
|
|
244
|
+
crc = crc ^ byte;
|
|
245
|
+
for (let j = 0; j < 8; j++) {
|
|
246
|
+
crc = crc >>> 1 ^ (crc & 1 ? 0xedb88320 : 0);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Delay utility for retries
|
|
255
|
+
*/
|
|
256
|
+
delay(ms) {
|
|
257
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get MTU configuration
|
|
262
|
+
*/
|
|
263
|
+
getMTUConfig() {
|
|
264
|
+
return this.mtuConfig;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Set custom MTU configuration
|
|
269
|
+
*/
|
|
270
|
+
setMTUConfig(config) {
|
|
271
|
+
this.mtuConfig = {
|
|
272
|
+
...this.mtuConfig,
|
|
273
|
+
...config
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=BLETransactionHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["DEFAULT_MTU_CONFIGS","android","maxPayloadSize","chunkSize","maxRetries","timeout","ios","BLETransactionHandler","fragmentCache","Map","messageIdMap","constructor","platform","mtuConfig","fragmentTransaction","transaction","isIntent","payload","Buffer","from","JSON","stringify","messageId","Date","now","Math","random","toString","substr","totalFragments","ceil","length","fragments","i","start","end","min","chunk","slice","fragment","sequenceNumber","checksumValue","calculateCRC32","push","set","prepareEncryptedMessage","noiseEncryptFn","fragmentData","serializeFragment","encrypted","sendFragmentedTransactionBLE","device","sendFn","failedFragments","Error","CHARACTERISTIC_UUID","retries","sent","messageData","id","error","console","warn","delay","pow","success","sentFragments","receiveFragmentedMessage","_noiseDecryptFn","has","cachedFragments","get","progress","received","filter","f","undefined","total","complete","reassembled","reassembleMessage","transactionData","parse","delete","sorted","sort","a","b","calculatedChecksum","combined","concat","map","data","Array","Uint8Array","crc","byte","j","ms","Promise","resolve","setTimeout","getMTUConfig","setMTUConfig","config"],"sourceRoot":"../../../src","sources":["client/BLETransactionHandler.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { PublicKey, Keypair, SystemProgram, NONCE_ACCOUNT_LENGTH, NonceAccount } from '@solana/web3.js';
|
|
4
|
+
import * as SecureStore from 'expo-secure-store';
|
|
5
|
+
/**
|
|
6
|
+
* NonceAccountManager
|
|
7
|
+
* Manages durable nonce accounts for secure offline transactions
|
|
8
|
+
* with biometric protection and encrypted storage
|
|
9
|
+
*/
|
|
10
|
+
export class NonceAccountManager {
|
|
11
|
+
cache = new Map();
|
|
12
|
+
constructor(connection) {
|
|
13
|
+
this.connection = connection;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a new durable nonce account for a user
|
|
18
|
+
* Securely stores the nonce account with biometric protection
|
|
19
|
+
*/
|
|
20
|
+
async createNonceAccount(user, nonceAuthorityKeypair, owner, options = {}) {
|
|
21
|
+
const {
|
|
22
|
+
requireBiometric = true,
|
|
23
|
+
persistToSecureStorage = true
|
|
24
|
+
} = options;
|
|
25
|
+
if (requireBiometric !== true) {
|
|
26
|
+
throw new Error('❌ SECURITY ERROR: Biometric protection is mandatory for nonce accounts');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Generate nonce account keypair
|
|
30
|
+
const nonceAccountKeypair = Keypair.generate();
|
|
31
|
+
const nonceAccountAddress = nonceAccountKeypair.publicKey;
|
|
32
|
+
|
|
33
|
+
// Get the system's rent exemption minimum for nonce accounts
|
|
34
|
+
// (used for funding in actual transaction creation)
|
|
35
|
+
const minRentLamports = await this.connection.getMinimumBalanceForRentExemption(NONCE_ACCOUNT_LENGTH);
|
|
36
|
+
|
|
37
|
+
// Get the latest blockhash for the instruction
|
|
38
|
+
const {
|
|
39
|
+
blockhash
|
|
40
|
+
} = await this.connection.getLatestBlockhash();
|
|
41
|
+
const nonceAccountInfo = {
|
|
42
|
+
address: nonceAccountAddress.toBase58(),
|
|
43
|
+
owner: owner.toBase58(),
|
|
44
|
+
authorizedSigner: nonceAuthorityKeypair.publicKey.toBase58(),
|
|
45
|
+
currentNonce: 0,
|
|
46
|
+
lastUsedNonce: 0,
|
|
47
|
+
blockhash,
|
|
48
|
+
isBiometricProtected: requireBiometric,
|
|
49
|
+
createdAt: Math.floor(Date.now() / 1000),
|
|
50
|
+
lastModified: Math.floor(Date.now() / 1000),
|
|
51
|
+
isStoredSecurely: persistToSecureStorage,
|
|
52
|
+
minRentLamports
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Store nonce account info securely
|
|
56
|
+
if (persistToSecureStorage) {
|
|
57
|
+
await this.storeNonceAccountSecurely(user.userId, nonceAccountInfo, nonceAccountKeypair);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Cache the account info
|
|
61
|
+
this.cacheNonceAccount(user.userId, nonceAccountInfo);
|
|
62
|
+
return nonceAccountInfo;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Store nonce account securely in device's secure enclave
|
|
67
|
+
* Encrypted and protected by biometric authentication
|
|
68
|
+
*/
|
|
69
|
+
async storeNonceAccountSecurely(userId, nonceAccountInfo, nonceAccountKeypair) {
|
|
70
|
+
const storageKey = `toss_nonce_account_${userId}`;
|
|
71
|
+
const secureData = {
|
|
72
|
+
info: nonceAccountInfo,
|
|
73
|
+
keypair: {
|
|
74
|
+
publicKey: nonceAccountKeypair.publicKey.toBase58(),
|
|
75
|
+
secretKey: Array.from(nonceAccountKeypair.secretKey)
|
|
76
|
+
},
|
|
77
|
+
storedAt: Math.floor(Date.now() / 1000),
|
|
78
|
+
encryptionMethod: 'secure-enclave',
|
|
79
|
+
biometricRequired: true
|
|
80
|
+
};
|
|
81
|
+
await SecureStore.setItemAsync(storageKey, JSON.stringify(secureData));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Retrieve nonce account from secure storage
|
|
86
|
+
* Requires biometric verification
|
|
87
|
+
*/
|
|
88
|
+
async getNonceAccountSecure(userId, authenticator) {
|
|
89
|
+
const storageKey = `toss_nonce_account_${userId}`;
|
|
90
|
+
try {
|
|
91
|
+
// Call authenticator if provided (biometric check)
|
|
92
|
+
if (authenticator) {
|
|
93
|
+
await authenticator();
|
|
94
|
+
}
|
|
95
|
+
const stored = await SecureStore.getItemAsync(storageKey);
|
|
96
|
+
if (!stored) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const secureData = JSON.parse(stored);
|
|
100
|
+
return secureData.info;
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error('Failed to retrieve nonce account:', error);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Cache nonce account info for quick access
|
|
109
|
+
*/
|
|
110
|
+
cacheNonceAccount(userId, nonceAccountInfo) {
|
|
111
|
+
const cacheEntry = {
|
|
112
|
+
accountInfo: nonceAccountInfo,
|
|
113
|
+
nonces: [0],
|
|
114
|
+
expiresAt: Math.floor(Date.now() / 1000) + 60 * 60 * 24 // 24 hours
|
|
115
|
+
};
|
|
116
|
+
this.cache.set(userId, cacheEntry);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get cached nonce account info
|
|
121
|
+
*/
|
|
122
|
+
getCachedNonceAccount(userId) {
|
|
123
|
+
const cached = this.cache.get(userId);
|
|
124
|
+
if (cached && cached.expiresAt > Math.floor(Date.now() / 1000)) {
|
|
125
|
+
return cached;
|
|
126
|
+
}
|
|
127
|
+
this.cache.delete(userId);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Prepare offline transaction using nonce account
|
|
133
|
+
* Creates a transaction that can be signed and executed offline
|
|
134
|
+
*/
|
|
135
|
+
async prepareOfflineTransaction(user, _instructions, nonceAccountInfo) {
|
|
136
|
+
// Verify user has nonce account enabled
|
|
137
|
+
if (!user.tossFeatures.nonceAccountEnabled) {
|
|
138
|
+
throw new Error('Nonce account transactions not enabled for this user');
|
|
139
|
+
}
|
|
140
|
+
if (!user.nonceAccount) {
|
|
141
|
+
throw new Error('User does not have a nonce account configured');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Create offline transaction with nonce
|
|
145
|
+
const offlineTransaction = {
|
|
146
|
+
id: `offlineTx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
147
|
+
nonceAccount: nonceAccountInfo.address,
|
|
148
|
+
nonce: nonceAccountInfo.currentNonce,
|
|
149
|
+
transaction: '',
|
|
150
|
+
// Will be populated with serialized transaction
|
|
151
|
+
status: 'prepared',
|
|
152
|
+
createdAt: Math.floor(Date.now() / 1000),
|
|
153
|
+
expiresAt: Math.floor(Date.now() / 1000) + 24 * 60 * 60,
|
|
154
|
+
// 24 hours
|
|
155
|
+
metadata: {
|
|
156
|
+
userId: user.userId,
|
|
157
|
+
biometricRequired: user.security.nonceAccountRequiresBiometric
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
return offlineTransaction;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Renew nonce account (refresh blockhash and nonce state)
|
|
165
|
+
*/
|
|
166
|
+
async renewNonceAccount(userId, _nonceAccountAddress) {
|
|
167
|
+
try {
|
|
168
|
+
// Fetch current nonce account state from blockchain
|
|
169
|
+
const nonceAccountInfo = await this.connection.getAccountInfo(_nonceAccountAddress);
|
|
170
|
+
if (!nonceAccountInfo) {
|
|
171
|
+
console.warn('Nonce account not found on blockchain');
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Decode nonce account data
|
|
176
|
+
const nonceAccount = NonceAccount.fromAccountData(nonceAccountInfo.data);
|
|
177
|
+
|
|
178
|
+
// Get latest blockhash
|
|
179
|
+
const {
|
|
180
|
+
blockhash
|
|
181
|
+
} = await this.connection.getLatestBlockhash();
|
|
182
|
+
|
|
183
|
+
// Retrieve and update stored account info
|
|
184
|
+
const storageKey = `toss_nonce_account_${userId}`;
|
|
185
|
+
const stored = await SecureStore.getItemAsync(storageKey);
|
|
186
|
+
if (stored) {
|
|
187
|
+
const secureData = JSON.parse(stored);
|
|
188
|
+
const updatedInfo = {
|
|
189
|
+
...secureData.info,
|
|
190
|
+
currentNonce: nonceAccount.nonce,
|
|
191
|
+
blockhash,
|
|
192
|
+
lastModified: Math.floor(Date.now() / 1000)
|
|
193
|
+
};
|
|
194
|
+
secureData.info = updatedInfo;
|
|
195
|
+
await SecureStore.setItemAsync(storageKey, JSON.stringify(secureData));
|
|
196
|
+
|
|
197
|
+
// Update cache
|
|
198
|
+
this.cacheNonceAccount(userId, updatedInfo);
|
|
199
|
+
return updatedInfo;
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error('Failed to renew nonce account:', error);
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Revoke nonce account (mark as unusable)
|
|
210
|
+
*/
|
|
211
|
+
async revokeNonceAccount(userId, _nonceAccountAddress) {
|
|
212
|
+
const storageKey = `toss_nonce_account_${userId}`;
|
|
213
|
+
try {
|
|
214
|
+
const stored = await SecureStore.getItemAsync(storageKey);
|
|
215
|
+
if (stored) {
|
|
216
|
+
const secureData = JSON.parse(stored);
|
|
217
|
+
secureData.info.status = 'revoked';
|
|
218
|
+
await SecureStore.setItemAsync(storageKey, JSON.stringify(secureData));
|
|
219
|
+
}
|
|
220
|
+
this.cache.delete(userId);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.error('Failed to revoke nonce account:', error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Clean up expired nonce accounts from cache
|
|
228
|
+
*/
|
|
229
|
+
cleanupExpiredCache() {
|
|
230
|
+
const now = Math.floor(Date.now() / 1000);
|
|
231
|
+
for (const [userId, entry] of this.cache.entries()) {
|
|
232
|
+
if (entry.expiresAt < now) {
|
|
233
|
+
this.cache.delete(userId);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Validate nonce account status
|
|
240
|
+
*/
|
|
241
|
+
isNonceAccountValid(nonceAccountInfo) {
|
|
242
|
+
// Check if biometric protection is enabled (required for security)
|
|
243
|
+
if (!nonceAccountInfo.isBiometricProtected) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Check if account has aged beyond max validity
|
|
248
|
+
const maxAge = 365 * 24 * 60 * 60; // 1 year in seconds
|
|
249
|
+
const age = Math.floor(Date.now() / 1000) - nonceAccountInfo.createdAt;
|
|
250
|
+
return age < maxAge;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* GAP #6 FIX: Initialize a durable nonce account onchain
|
|
255
|
+
* Per TOSS Paper Section 4.2: "Replay-protected" nonces
|
|
256
|
+
* This creates the actual SystemProgram nonce account on the blockchain
|
|
257
|
+
*/
|
|
258
|
+
async initializeDurableNonceAccountOnchain(authority, nonceAccountKeypair, payer, minRentLamports) {
|
|
259
|
+
try {
|
|
260
|
+
// Create instruction to fund nonce account
|
|
261
|
+
const fundInstruction = SystemProgram.transfer({
|
|
262
|
+
fromPubkey: payer,
|
|
263
|
+
toPubkey: nonceAccountKeypair.publicKey,
|
|
264
|
+
lamports: minRentLamports
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Create instruction to initialize nonce account
|
|
268
|
+
const nonceInitInstruction = SystemProgram.nonceInitialize({
|
|
269
|
+
noncePubkey: nonceAccountKeypair.publicKey,
|
|
270
|
+
authorizedPubkey: authority
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Get latest blockhash
|
|
274
|
+
const {
|
|
275
|
+
blockhash,
|
|
276
|
+
lastValidBlockHeight
|
|
277
|
+
} = await this.connection.getLatestBlockhash('confirmed');
|
|
278
|
+
|
|
279
|
+
// Build transaction
|
|
280
|
+
const transaction = new (await import('@solana/web3.js')).Transaction();
|
|
281
|
+
transaction.add(fundInstruction);
|
|
282
|
+
transaction.add(nonceInitInstruction);
|
|
283
|
+
transaction.feePayer = payer;
|
|
284
|
+
transaction.recentBlockhash = blockhash;
|
|
285
|
+
transaction.lastValidBlockHeight = lastValidBlockHeight;
|
|
286
|
+
console.log('✅ Durable nonce account initialized: ', nonceAccountKeypair.publicKey.toBase58());
|
|
287
|
+
return nonceAccountKeypair.publicKey.toBase58();
|
|
288
|
+
} catch (error) {
|
|
289
|
+
throw new Error(`Failed to initialize nonce account: ${error instanceof Error ? error.message : String(error)}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* GAP #6 FIX: Consume (advance) a nonce account after successful transaction
|
|
295
|
+
* Per TOSS Paper Section 9: Nonce advancement for replay protection
|
|
296
|
+
*/
|
|
297
|
+
async consumeNonceAccount(nonceAccountAddress, nonceAuthority) {
|
|
298
|
+
// Create instruction to advance nonce
|
|
299
|
+
return SystemProgram.nonceAdvance({
|
|
300
|
+
noncePubkey: nonceAccountAddress,
|
|
301
|
+
authorizedPubkey: nonceAuthority
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* GAP #6 FIX: Validate nonce account state on chain
|
|
307
|
+
* Checks that nonce account exists and is properly configured
|
|
308
|
+
*/
|
|
309
|
+
async validateNonceAccountOnchain(nonceAccountAddress, _expectedAuthority) {
|
|
310
|
+
try {
|
|
311
|
+
const nonceAccountInfo = await this.connection.getAccountInfo(nonceAccountAddress);
|
|
312
|
+
if (!nonceAccountInfo) {
|
|
313
|
+
return {
|
|
314
|
+
valid: false,
|
|
315
|
+
error: 'Nonce account does not exist'
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
const SYSTEM_PROGRAM_ID = new PublicKey('11111111111111111111111111111111');
|
|
319
|
+
if (!nonceAccountInfo.owner.equals(SYSTEM_PROGRAM_ID)) {
|
|
320
|
+
return {
|
|
321
|
+
valid: false,
|
|
322
|
+
error: 'Nonce account is not owned by SystemProgram'
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Check if account is initialized (nonce is stored in first 32 bytes after version)
|
|
327
|
+
if (nonceAccountInfo.data.length < 48) {
|
|
328
|
+
return {
|
|
329
|
+
valid: false,
|
|
330
|
+
error: 'Nonce account data is malformed'
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
valid: true
|
|
335
|
+
};
|
|
336
|
+
} catch (error) {
|
|
337
|
+
return {
|
|
338
|
+
valid: false,
|
|
339
|
+
error: `Nonce account validation failed: ${error instanceof Error ? error.message : String(error)}`
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* GAP #6 FIX: Get current nonce value from blockchain
|
|
346
|
+
* Reads the actual nonce state from the nonce account
|
|
347
|
+
*/
|
|
348
|
+
async getCurrentNonceFromChain(nonceAccountAddress) {
|
|
349
|
+
try {
|
|
350
|
+
const nonceAccount = await this.connection.getAccountInfo(nonceAccountAddress);
|
|
351
|
+
if (!nonceAccount || nonceAccount.data.length < 48) {
|
|
352
|
+
return 0;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Nonce value is stored at offset 32-40 in NonceAccount structure
|
|
356
|
+
const nonceData = nonceAccount.data.slice(32, 40);
|
|
357
|
+
return nonceData.readBigUInt64LE(0);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.warn('Failed to get nonce from chain:', error);
|
|
360
|
+
return 0;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=NonceAccountManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["PublicKey","Keypair","SystemProgram","NONCE_ACCOUNT_LENGTH","NonceAccount","SecureStore","NonceAccountManager","cache","Map","constructor","connection","createNonceAccount","user","nonceAuthorityKeypair","owner","options","requireBiometric","persistToSecureStorage","Error","nonceAccountKeypair","generate","nonceAccountAddress","publicKey","minRentLamports","getMinimumBalanceForRentExemption","blockhash","getLatestBlockhash","nonceAccountInfo","address","toBase58","authorizedSigner","currentNonce","lastUsedNonce","isBiometricProtected","createdAt","Math","floor","Date","now","lastModified","isStoredSecurely","storeNonceAccountSecurely","userId","cacheNonceAccount","storageKey","secureData","info","keypair","secretKey","Array","from","storedAt","encryptionMethod","biometricRequired","setItemAsync","JSON","stringify","getNonceAccountSecure","authenticator","stored","getItemAsync","parse","error","console","cacheEntry","accountInfo","nonces","expiresAt","set","getCachedNonceAccount","cached","get","delete","prepareOfflineTransaction","_instructions","tossFeatures","nonceAccountEnabled","nonceAccount","offlineTransaction","id","random","toString","substr","nonce","transaction","status","metadata","security","nonceAccountRequiresBiometric","renewNonceAccount","_nonceAccountAddress","getAccountInfo","warn","fromAccountData","data","updatedInfo","revokeNonceAccount","cleanupExpiredCache","entry","entries","isNonceAccountValid","maxAge","age","initializeDurableNonceAccountOnchain","authority","payer","fundInstruction","transfer","fromPubkey","toPubkey","lamports","nonceInitInstruction","nonceInitialize","noncePubkey","authorizedPubkey","lastValidBlockHeight","Transaction","add","feePayer","recentBlockhash","log","message","String","consumeNonceAccount","nonceAuthority","nonceAdvance","validateNonceAccountOnchain","_expectedAuthority","valid","SYSTEM_PROGRAM_ID","equals","length","getCurrentNonceFromChain","nonceData","slice","readBigUInt64LE"],"sourceRoot":"../../../src","sources":["client/NonceAccountManager.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -223,7 +223,7 @@ export class TossClient {
|
|
|
223
223
|
async fullSync() {
|
|
224
224
|
return this.withRetry(async () => {
|
|
225
225
|
try {
|
|
226
|
-
return await syncToChain(this.connection, this.config.feePayer?.publicKey);
|
|
226
|
+
return await syncToChain(this.connection, this.config.feePayer?.publicKey?.toBase58());
|
|
227
227
|
} catch (error) {
|
|
228
228
|
if (error instanceof TossError) throw error;
|
|
229
229
|
throw new NetworkError('Full sync failed', {
|