@vue-solana/core 0.4.1 → 0.4.2
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/dist/ios-wallet.cjs +68 -27
- package/dist/ios-wallet.mjs +68 -27
- package/dist/wallet-standard.cjs +11 -3
- package/dist/wallet-standard.mjs +11 -3
- package/package.json +1 -1
package/dist/ios-wallet.cjs
CHANGED
|
@@ -29,6 +29,7 @@ function resolveTweetNaCl() {
|
|
|
29
29
|
}
|
|
30
30
|
const DEFAULT_IOS_WALLET_CHAINS = ["solana:mainnet", "solana:devnet"];
|
|
31
31
|
const PENDING_REQUEST_KEY = "vue-solana:ios-wallet:pending";
|
|
32
|
+
const PENDING_REQUEST_TTL_MS = 10 * 60 * 1e3;
|
|
32
33
|
const SESSION_PREFIX = "vue-solana:ios-wallet:session:";
|
|
33
34
|
const CALLBACK_PARAMS = /* @__PURE__ */ new Set([
|
|
34
35
|
"data",
|
|
@@ -160,6 +161,11 @@ function adaptSolanaIosWallet(walletInfo, options = {}) {
|
|
|
160
161
|
transactions,
|
|
161
162
|
options
|
|
162
163
|
);
|
|
164
|
+
if (signedTransactions.length !== transactions.length) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`iOS wallet returned ${signedTransactions.length} signed transactions for ${transactions.length} requested transactions`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
163
169
|
return signedTransactions.map(
|
|
164
170
|
(transaction, index) => deserializeTransaction(transactions[index], transaction)
|
|
165
171
|
);
|
|
@@ -187,36 +193,50 @@ function handleSolanaIosWalletCallback(options = {}) {
|
|
|
187
193
|
cleanCallbackUrl(url, options.clearUrl);
|
|
188
194
|
throw new Error("Received an iOS wallet callback without a pending request");
|
|
189
195
|
}
|
|
196
|
+
if (isPendingRequestExpired(pending)) {
|
|
197
|
+
clearPendingRequest();
|
|
198
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
199
|
+
throw new Error("Received an expired iOS wallet callback");
|
|
200
|
+
}
|
|
190
201
|
const definition = getIosWalletDefinitionById(pending.walletId);
|
|
191
202
|
const walletEncryptionPublicKey = url.searchParams.get(definition.encryptionPublicKeyParam);
|
|
192
203
|
const nonce = url.searchParams.get("nonce");
|
|
193
204
|
const data = url.searchParams.get("data");
|
|
194
205
|
if (!nonce || !data) {
|
|
206
|
+
clearPendingRequest();
|
|
207
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
195
208
|
throw new Error("Received an incomplete iOS wallet callback");
|
|
196
209
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
|
|
210
|
+
try {
|
|
211
|
+
const sharedSecret = getSharedSecret(
|
|
212
|
+
walletEncryptionPublicKey ?? getStoredSession(pending.walletId)?.walletEncryptionPublicKey,
|
|
213
|
+
pending.dappEncryptionSecretKey
|
|
214
|
+
);
|
|
215
|
+
const payload = decryptPayload(data, nonce, sharedSecret);
|
|
216
|
+
const result = createCallbackResult(pending, payload);
|
|
217
|
+
if (pending.method === "connect") {
|
|
218
|
+
if (!walletEncryptionPublicKey) {
|
|
219
|
+
throw new Error("iOS wallet connect callback did not include an encryption public key");
|
|
220
|
+
}
|
|
221
|
+
const publicKey = getPublicKeyField(payload, "public_key");
|
|
222
|
+
storeSession({
|
|
223
|
+
walletId: pending.walletId,
|
|
224
|
+
publicKey,
|
|
225
|
+
session: getStringField(payload, "session"),
|
|
226
|
+
dappEncryptionPublicKey: pending.dappEncryptionPublicKey,
|
|
227
|
+
dappEncryptionSecretKey: pending.dappEncryptionSecretKey,
|
|
228
|
+
walletEncryptionPublicKey,
|
|
229
|
+
sharedSecret: bs58__default.encode(sharedSecret)
|
|
230
|
+
});
|
|
206
231
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
clearPendingRequest();
|
|
218
|
-
cleanCallbackUrl(url, options.clearUrl);
|
|
219
|
-
return result;
|
|
232
|
+
clearPendingRequest();
|
|
233
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
234
|
+
return result;
|
|
235
|
+
} catch (cause) {
|
|
236
|
+
clearPendingRequest();
|
|
237
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
238
|
+
throw cause;
|
|
239
|
+
}
|
|
220
240
|
}
|
|
221
241
|
function isSolanaIosWalletInfo(walletInfo) {
|
|
222
242
|
return walletInfo.source === "deep-link" && isIosWalletDefinition(walletInfo.wallet);
|
|
@@ -316,7 +336,8 @@ async function launchEncryptedWalletRequest(definition, method, options, payload
|
|
|
316
336
|
publicKey: bs58__default.decode(session.dappEncryptionPublicKey),
|
|
317
337
|
secretKey: bs58__default.decode(session.dappEncryptionSecretKey)
|
|
318
338
|
},
|
|
319
|
-
options.redirectUrl
|
|
339
|
+
options.redirectUrl,
|
|
340
|
+
method === "signAllTransactions" && Array.isArray(payload.transactions) ? payload.transactions.length : void 0
|
|
320
341
|
);
|
|
321
342
|
const nonce = nacl.randomBytes(nacl.box.nonceLength);
|
|
322
343
|
const encryptedPayload = encryptPayload(
|
|
@@ -333,7 +354,7 @@ async function launchEncryptedWalletRequest(definition, method, options, payload
|
|
|
333
354
|
openIosWalletUrl(url.toString());
|
|
334
355
|
return waitForRedirect();
|
|
335
356
|
}
|
|
336
|
-
function createPendingRequest(walletId, method, keyPair, redirectUrl) {
|
|
357
|
+
function createPendingRequest(walletId, method, keyPair, redirectUrl, requestedTransactionCount) {
|
|
337
358
|
return {
|
|
338
359
|
id: createRequestId(),
|
|
339
360
|
walletId,
|
|
@@ -341,7 +362,8 @@ function createPendingRequest(walletId, method, keyPair, redirectUrl) {
|
|
|
341
362
|
dappEncryptionPublicKey: bs58__default.encode(keyPair.publicKey),
|
|
342
363
|
dappEncryptionSecretKey: bs58__default.encode(keyPair.secretKey),
|
|
343
364
|
redirectUrl: redirectUrl ?? getDefaultIosWalletRedirectUrl(),
|
|
344
|
-
createdAt: Date.now()
|
|
365
|
+
createdAt: Date.now(),
|
|
366
|
+
requestedTransactionCount
|
|
345
367
|
};
|
|
346
368
|
}
|
|
347
369
|
function createCallbackResult(pending, payload) {
|
|
@@ -349,7 +371,7 @@ function createCallbackResult(pending, payload) {
|
|
|
349
371
|
return {
|
|
350
372
|
walletId: pending.walletId,
|
|
351
373
|
method: pending.method,
|
|
352
|
-
publicKey:
|
|
374
|
+
publicKey: getPublicKeyField(payload, "public_key")
|
|
353
375
|
};
|
|
354
376
|
}
|
|
355
377
|
if (pending.method === "signTransaction") {
|
|
@@ -364,6 +386,11 @@ function createCallbackResult(pending, payload) {
|
|
|
364
386
|
if (!Array.isArray(transactions) || transactions.some((transaction) => typeof transaction !== "string")) {
|
|
365
387
|
throw new Error("iOS wallet returned invalid signed transactions");
|
|
366
388
|
}
|
|
389
|
+
if (typeof pending.requestedTransactionCount === "number" && transactions.length !== pending.requestedTransactionCount) {
|
|
390
|
+
throw new Error(
|
|
391
|
+
`iOS wallet returned ${transactions.length} signed transactions for ${pending.requestedTransactionCount} requested transactions`
|
|
392
|
+
);
|
|
393
|
+
}
|
|
367
394
|
return {
|
|
368
395
|
walletId: pending.walletId,
|
|
369
396
|
method: pending.method,
|
|
@@ -433,7 +460,9 @@ function getStoredSession(walletId) {
|
|
|
433
460
|
return null;
|
|
434
461
|
}
|
|
435
462
|
try {
|
|
436
|
-
|
|
463
|
+
const session = JSON.parse(value);
|
|
464
|
+
new web3Compat.PublicKey(session.publicKey);
|
|
465
|
+
return session;
|
|
437
466
|
} catch {
|
|
438
467
|
removeStoredSession(walletId);
|
|
439
468
|
return null;
|
|
@@ -510,6 +539,18 @@ function getStringField(payload, field) {
|
|
|
510
539
|
}
|
|
511
540
|
return value;
|
|
512
541
|
}
|
|
542
|
+
function getPublicKeyField(payload, field) {
|
|
543
|
+
const value = getStringField(payload, field);
|
|
544
|
+
try {
|
|
545
|
+
new web3Compat.PublicKey(value);
|
|
546
|
+
} catch {
|
|
547
|
+
throw new Error(`iOS wallet callback returned an invalid ${field}`);
|
|
548
|
+
}
|
|
549
|
+
return value;
|
|
550
|
+
}
|
|
551
|
+
function isPendingRequestExpired(request) {
|
|
552
|
+
return Date.now() - request.createdAt > PENDING_REQUEST_TTL_MS;
|
|
553
|
+
}
|
|
513
554
|
function getIosWalletDefinition(walletInfo) {
|
|
514
555
|
if (!isIosWalletDefinition(walletInfo.wallet)) {
|
|
515
556
|
throw new Error("Solana wallet info is not an iOS wallet");
|
package/dist/ios-wallet.mjs
CHANGED
|
@@ -10,6 +10,7 @@ function resolveTweetNaCl() {
|
|
|
10
10
|
}
|
|
11
11
|
const DEFAULT_IOS_WALLET_CHAINS = ["solana:mainnet", "solana:devnet"];
|
|
12
12
|
const PENDING_REQUEST_KEY = "vue-solana:ios-wallet:pending";
|
|
13
|
+
const PENDING_REQUEST_TTL_MS = 10 * 60 * 1e3;
|
|
13
14
|
const SESSION_PREFIX = "vue-solana:ios-wallet:session:";
|
|
14
15
|
const CALLBACK_PARAMS = /* @__PURE__ */ new Set([
|
|
15
16
|
"data",
|
|
@@ -141,6 +142,11 @@ function adaptSolanaIosWallet(walletInfo, options = {}) {
|
|
|
141
142
|
transactions,
|
|
142
143
|
options
|
|
143
144
|
);
|
|
145
|
+
if (signedTransactions.length !== transactions.length) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`iOS wallet returned ${signedTransactions.length} signed transactions for ${transactions.length} requested transactions`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
144
150
|
return signedTransactions.map(
|
|
145
151
|
(transaction, index) => deserializeTransaction(transactions[index], transaction)
|
|
146
152
|
);
|
|
@@ -168,36 +174,50 @@ function handleSolanaIosWalletCallback(options = {}) {
|
|
|
168
174
|
cleanCallbackUrl(url, options.clearUrl);
|
|
169
175
|
throw new Error("Received an iOS wallet callback without a pending request");
|
|
170
176
|
}
|
|
177
|
+
if (isPendingRequestExpired(pending)) {
|
|
178
|
+
clearPendingRequest();
|
|
179
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
180
|
+
throw new Error("Received an expired iOS wallet callback");
|
|
181
|
+
}
|
|
171
182
|
const definition = getIosWalletDefinitionById(pending.walletId);
|
|
172
183
|
const walletEncryptionPublicKey = url.searchParams.get(definition.encryptionPublicKeyParam);
|
|
173
184
|
const nonce = url.searchParams.get("nonce");
|
|
174
185
|
const data = url.searchParams.get("data");
|
|
175
186
|
if (!nonce || !data) {
|
|
187
|
+
clearPendingRequest();
|
|
188
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
176
189
|
throw new Error("Received an incomplete iOS wallet callback");
|
|
177
190
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
191
|
+
try {
|
|
192
|
+
const sharedSecret = getSharedSecret(
|
|
193
|
+
walletEncryptionPublicKey ?? getStoredSession(pending.walletId)?.walletEncryptionPublicKey,
|
|
194
|
+
pending.dappEncryptionSecretKey
|
|
195
|
+
);
|
|
196
|
+
const payload = decryptPayload(data, nonce, sharedSecret);
|
|
197
|
+
const result = createCallbackResult(pending, payload);
|
|
198
|
+
if (pending.method === "connect") {
|
|
199
|
+
if (!walletEncryptionPublicKey) {
|
|
200
|
+
throw new Error("iOS wallet connect callback did not include an encryption public key");
|
|
201
|
+
}
|
|
202
|
+
const publicKey = getPublicKeyField(payload, "public_key");
|
|
203
|
+
storeSession({
|
|
204
|
+
walletId: pending.walletId,
|
|
205
|
+
publicKey,
|
|
206
|
+
session: getStringField(payload, "session"),
|
|
207
|
+
dappEncryptionPublicKey: pending.dappEncryptionPublicKey,
|
|
208
|
+
dappEncryptionSecretKey: pending.dappEncryptionSecretKey,
|
|
209
|
+
walletEncryptionPublicKey,
|
|
210
|
+
sharedSecret: bs58.encode(sharedSecret)
|
|
211
|
+
});
|
|
187
212
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
clearPendingRequest();
|
|
199
|
-
cleanCallbackUrl(url, options.clearUrl);
|
|
200
|
-
return result;
|
|
213
|
+
clearPendingRequest();
|
|
214
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
215
|
+
return result;
|
|
216
|
+
} catch (cause) {
|
|
217
|
+
clearPendingRequest();
|
|
218
|
+
cleanCallbackUrl(url, options.clearUrl);
|
|
219
|
+
throw cause;
|
|
220
|
+
}
|
|
201
221
|
}
|
|
202
222
|
function isSolanaIosWalletInfo(walletInfo) {
|
|
203
223
|
return walletInfo.source === "deep-link" && isIosWalletDefinition(walletInfo.wallet);
|
|
@@ -297,7 +317,8 @@ async function launchEncryptedWalletRequest(definition, method, options, payload
|
|
|
297
317
|
publicKey: bs58.decode(session.dappEncryptionPublicKey),
|
|
298
318
|
secretKey: bs58.decode(session.dappEncryptionSecretKey)
|
|
299
319
|
},
|
|
300
|
-
options.redirectUrl
|
|
320
|
+
options.redirectUrl,
|
|
321
|
+
method === "signAllTransactions" && Array.isArray(payload.transactions) ? payload.transactions.length : void 0
|
|
301
322
|
);
|
|
302
323
|
const nonce = nacl.randomBytes(nacl.box.nonceLength);
|
|
303
324
|
const encryptedPayload = encryptPayload(
|
|
@@ -314,7 +335,7 @@ async function launchEncryptedWalletRequest(definition, method, options, payload
|
|
|
314
335
|
openIosWalletUrl(url.toString());
|
|
315
336
|
return waitForRedirect();
|
|
316
337
|
}
|
|
317
|
-
function createPendingRequest(walletId, method, keyPair, redirectUrl) {
|
|
338
|
+
function createPendingRequest(walletId, method, keyPair, redirectUrl, requestedTransactionCount) {
|
|
318
339
|
return {
|
|
319
340
|
id: createRequestId(),
|
|
320
341
|
walletId,
|
|
@@ -322,7 +343,8 @@ function createPendingRequest(walletId, method, keyPair, redirectUrl) {
|
|
|
322
343
|
dappEncryptionPublicKey: bs58.encode(keyPair.publicKey),
|
|
323
344
|
dappEncryptionSecretKey: bs58.encode(keyPair.secretKey),
|
|
324
345
|
redirectUrl: redirectUrl ?? getDefaultIosWalletRedirectUrl(),
|
|
325
|
-
createdAt: Date.now()
|
|
346
|
+
createdAt: Date.now(),
|
|
347
|
+
requestedTransactionCount
|
|
326
348
|
};
|
|
327
349
|
}
|
|
328
350
|
function createCallbackResult(pending, payload) {
|
|
@@ -330,7 +352,7 @@ function createCallbackResult(pending, payload) {
|
|
|
330
352
|
return {
|
|
331
353
|
walletId: pending.walletId,
|
|
332
354
|
method: pending.method,
|
|
333
|
-
publicKey:
|
|
355
|
+
publicKey: getPublicKeyField(payload, "public_key")
|
|
334
356
|
};
|
|
335
357
|
}
|
|
336
358
|
if (pending.method === "signTransaction") {
|
|
@@ -345,6 +367,11 @@ function createCallbackResult(pending, payload) {
|
|
|
345
367
|
if (!Array.isArray(transactions) || transactions.some((transaction) => typeof transaction !== "string")) {
|
|
346
368
|
throw new Error("iOS wallet returned invalid signed transactions");
|
|
347
369
|
}
|
|
370
|
+
if (typeof pending.requestedTransactionCount === "number" && transactions.length !== pending.requestedTransactionCount) {
|
|
371
|
+
throw new Error(
|
|
372
|
+
`iOS wallet returned ${transactions.length} signed transactions for ${pending.requestedTransactionCount} requested transactions`
|
|
373
|
+
);
|
|
374
|
+
}
|
|
348
375
|
return {
|
|
349
376
|
walletId: pending.walletId,
|
|
350
377
|
method: pending.method,
|
|
@@ -414,7 +441,9 @@ function getStoredSession(walletId) {
|
|
|
414
441
|
return null;
|
|
415
442
|
}
|
|
416
443
|
try {
|
|
417
|
-
|
|
444
|
+
const session = JSON.parse(value);
|
|
445
|
+
new PublicKey(session.publicKey);
|
|
446
|
+
return session;
|
|
418
447
|
} catch {
|
|
419
448
|
removeStoredSession(walletId);
|
|
420
449
|
return null;
|
|
@@ -491,6 +520,18 @@ function getStringField(payload, field) {
|
|
|
491
520
|
}
|
|
492
521
|
return value;
|
|
493
522
|
}
|
|
523
|
+
function getPublicKeyField(payload, field) {
|
|
524
|
+
const value = getStringField(payload, field);
|
|
525
|
+
try {
|
|
526
|
+
new PublicKey(value);
|
|
527
|
+
} catch {
|
|
528
|
+
throw new Error(`iOS wallet callback returned an invalid ${field}`);
|
|
529
|
+
}
|
|
530
|
+
return value;
|
|
531
|
+
}
|
|
532
|
+
function isPendingRequestExpired(request) {
|
|
533
|
+
return Date.now() - request.createdAt > PENDING_REQUEST_TTL_MS;
|
|
534
|
+
}
|
|
494
535
|
function getIosWalletDefinition(walletInfo) {
|
|
495
536
|
if (!isIosWalletDefinition(walletInfo.wallet)) {
|
|
496
537
|
throw new Error("Solana wallet info is not an iOS wallet");
|
package/dist/wallet-standard.cjs
CHANGED
|
@@ -136,9 +136,17 @@ function adaptSolanaStandardWallet(walletInfo, options = {}) {
|
|
|
136
136
|
chain: options.chain
|
|
137
137
|
}))
|
|
138
138
|
);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
if (results.length !== transactions.length) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Solana wallet returned ${results.length} signed transactions for ${transactions.length} requested transactions`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return results.map((result, index) => {
|
|
145
|
+
if (!result) {
|
|
146
|
+
throw new Error("Solana wallet did not return a signed transaction");
|
|
147
|
+
}
|
|
148
|
+
return deserializeTransaction(transactions[index], result.signedTransaction);
|
|
149
|
+
});
|
|
142
150
|
} : void 0,
|
|
143
151
|
signAndSendTransaction: hasSignAndSendTransaction(wallet) ? async (transaction, sendOptions) => {
|
|
144
152
|
const activeAccount = getActiveAccount(account);
|
package/dist/wallet-standard.mjs
CHANGED
|
@@ -130,9 +130,17 @@ function adaptSolanaStandardWallet(walletInfo, options = {}) {
|
|
|
130
130
|
chain: options.chain
|
|
131
131
|
}))
|
|
132
132
|
);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
if (results.length !== transactions.length) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Solana wallet returned ${results.length} signed transactions for ${transactions.length} requested transactions`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return results.map((result, index) => {
|
|
139
|
+
if (!result) {
|
|
140
|
+
throw new Error("Solana wallet did not return a signed transaction");
|
|
141
|
+
}
|
|
142
|
+
return deserializeTransaction(transactions[index], result.signedTransaction);
|
|
143
|
+
});
|
|
136
144
|
} : void 0,
|
|
137
145
|
signAndSendTransaction: hasSignAndSendTransaction(wallet) ? async (transaction, sendOptions) => {
|
|
138
146
|
const activeAccount = getActiveAccount(account);
|