@solana-mobile/mobile-wallet-adapter-protocol 2.2.5 → 2.2.6

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.
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var walletStandardUtil = require('@solana/wallet-standard-util');
6
4
  var codecsStrings = require('@solana/codecs-strings');
7
5
 
@@ -16,8 +14,12 @@ const SolanaMobileWalletAdapterErrorCode = {
16
14
  ERROR_WALLET_NOT_FOUND: 'ERROR_WALLET_NOT_FOUND',
17
15
  ERROR_INVALID_PROTOCOL_VERSION: 'ERROR_INVALID_PROTOCOL_VERSION',
18
16
  ERROR_BROWSER_NOT_SUPPORTED: 'ERROR_BROWSER_NOT_SUPPORTED',
17
+ ERROR_LOOPBACK_ACCESS_BLOCKED: 'ERROR_LOOPBACK_ACCESS_BLOCKED',
18
+ ERROR_ASSOCIATION_CANCELLED: 'ERROR_ASSOCIATION_CANCELLED',
19
19
  };
20
20
  class SolanaMobileWalletAdapterError extends Error {
21
+ data;
22
+ code;
21
23
  constructor(...args) {
22
24
  const [code, message, data] = args;
23
25
  super(message);
@@ -37,6 +39,9 @@ const SolanaMobileWalletAdapterProtocolErrorCode = {
37
39
  ERROR_ATTEST_ORIGIN_ANDROID: -100,
38
40
  };
39
41
  class SolanaMobileWalletAdapterProtocolError extends Error {
42
+ data;
43
+ code;
44
+ jsonRpcMessageId;
40
45
  constructor(...args) {
41
46
  const [jsonRpcMessageId, code, message, data] = args;
42
47
  super(message);
@@ -47,31 +52,6 @@ class SolanaMobileWalletAdapterProtocolError extends Error {
47
52
  }
48
53
  }
49
54
 
50
- /******************************************************************************
51
- Copyright (c) Microsoft Corporation.
52
-
53
- Permission to use, copy, modify, and/or distribute this software for any
54
- purpose with or without fee is hereby granted.
55
-
56
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
57
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
58
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
59
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
60
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
61
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
62
- PERFORMANCE OF THIS SOFTWARE.
63
- ***************************************************************************** */
64
-
65
- function __awaiter(thisArg, _arguments, P, generator) {
66
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
67
- return new (P || (P = Promise))(function (resolve, reject) {
68
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
69
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
70
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
71
- step((generator = generator.apply(thisArg, _arguments || [])).next());
72
- });
73
- }
74
-
75
55
  function encode(input) {
76
56
  return window.btoa(input);
77
57
  }
@@ -93,15 +73,13 @@ function toUint8Array(base64EncodedByteArray) {
93
73
  .map((c) => c.charCodeAt(0)));
94
74
  }
95
75
 
96
- function createHelloReq(ecdhPublicKey, associationKeypairPrivateKey) {
97
- return __awaiter(this, void 0, void 0, function* () {
98
- const publicKeyBuffer = yield crypto.subtle.exportKey('raw', ecdhPublicKey);
99
- const signatureBuffer = yield crypto.subtle.sign({ hash: 'SHA-256', name: 'ECDSA' }, associationKeypairPrivateKey, publicKeyBuffer);
100
- const response = new Uint8Array(publicKeyBuffer.byteLength + signatureBuffer.byteLength);
101
- response.set(new Uint8Array(publicKeyBuffer), 0);
102
- response.set(new Uint8Array(signatureBuffer), publicKeyBuffer.byteLength);
103
- return response;
104
- });
76
+ async function createHelloReq(ecdhPublicKey, associationKeypairPrivateKey) {
77
+ const publicKeyBuffer = await crypto.subtle.exportKey('raw', ecdhPublicKey);
78
+ const signatureBuffer = await crypto.subtle.sign({ hash: 'SHA-256', name: 'ECDSA' }, associationKeypairPrivateKey, publicKeyBuffer);
79
+ const response = new Uint8Array(publicKeyBuffer.byteLength + signatureBuffer.byteLength);
80
+ response.set(new Uint8Array(publicKeyBuffer), 0);
81
+ response.set(new Uint8Array(signatureBuffer), publicKeyBuffer.byteLength);
82
+ return response;
105
83
  }
106
84
 
107
85
  function createSIWSMessage(payload) {
@@ -144,16 +122,14 @@ function createMobileWalletProxy(protocolVersion, protocolRequestHandler) {
144
122
  return null;
145
123
  }
146
124
  if (target[p] == null) {
147
- target[p] = function (inputParams) {
148
- return __awaiter(this, void 0, void 0, function* () {
149
- const { method, params } = handleMobileWalletRequest(p, inputParams, protocolVersion);
150
- const result = yield protocolRequestHandler(method, params);
151
- // if the request tried to sign in but the wallet did not return a sign in result, fallback on message signing
152
- if (method === 'authorize' && params.sign_in_payload && !result.sign_in_result) {
153
- result['sign_in_result'] = yield signInFallback(params.sign_in_payload, result, protocolRequestHandler);
154
- }
155
- return handleMobileWalletResponse(p, result, protocolVersion);
156
- });
125
+ target[p] = async function (inputParams) {
126
+ const { method, params } = handleMobileWalletRequest(p, inputParams, protocolVersion);
127
+ const result = await protocolRequestHandler(method, params);
128
+ // if the request tried to sign in but the wallet did not return a sign in result, fallback on message signing
129
+ if (method === 'authorize' && params.sign_in_payload && !result.sign_in_result) {
130
+ result['sign_in_result'] = await signInFallback(params.sign_in_payload, result, protocolRequestHandler);
131
+ }
132
+ return handleMobileWalletResponse(p, result, protocolVersion);
157
133
  };
158
134
  }
159
135
  return target[p];
@@ -257,39 +233,43 @@ function handleMobileWalletResponse(method, response, protocolVersion) {
257
233
  if (capabilities.supports_clone_authorization === true) {
258
234
  features.push(SolanaCloneAuthorization);
259
235
  }
260
- return Object.assign(Object.assign({}, capabilities), { features: features });
236
+ return {
237
+ ...capabilities,
238
+ features: features,
239
+ };
261
240
  }
262
241
  case 'v1': {
263
- return Object.assign(Object.assign({}, capabilities), { supports_sign_and_send_transactions: true, supports_clone_authorization: capabilities.features.includes(SolanaCloneAuthorization) });
242
+ return {
243
+ ...capabilities,
244
+ supports_sign_and_send_transactions: true,
245
+ supports_clone_authorization: capabilities.features.includes(SolanaCloneAuthorization)
246
+ };
264
247
  }
265
248
  }
266
249
  }
267
250
  }
268
251
  return response;
269
252
  }
270
- function signInFallback(signInPayload, authorizationResult, protocolRequestHandler) {
271
- var _a;
272
- return __awaiter(this, void 0, void 0, function* () {
273
- const domain = (_a = signInPayload.domain) !== null && _a !== void 0 ? _a : window.location.host;
274
- const address = authorizationResult.accounts[0].address;
275
- const siwsMessage = createSIWSMessageBase64Url(Object.assign(Object.assign({}, signInPayload), { domain, address: base64ToBase58(address) }));
276
- const signMessageResult = yield protocolRequestHandler('sign_messages', {
277
- addresses: [address],
278
- payloads: [siwsMessage]
279
- });
280
- const signedPayload = toUint8Array(signMessageResult.signed_payloads[0]);
281
- const signedMessage = fromUint8Array$1(signedPayload.slice(0, signedPayload.length - 64));
282
- const signature = fromUint8Array$1(signedPayload.slice(signedPayload.length - 64));
283
- const signInResult = {
284
- address: address,
285
- // Workaround: some wallets have been observed to only reply with the message signature.
286
- // This is non-compliant with the spec, but in the interest of maximizing compatibility,
287
- // detect this case and reuse the original message.
288
- signed_message: signedMessage.length == 0 ? siwsMessage : signedMessage,
289
- signature
290
- };
291
- return signInResult;
253
+ async function signInFallback(signInPayload, authorizationResult, protocolRequestHandler) {
254
+ const domain = signInPayload.domain ?? window.location.host;
255
+ const address = authorizationResult.accounts[0].address;
256
+ const siwsMessage = createSIWSMessageBase64Url({ ...signInPayload, domain, address: base64ToBase58(address) });
257
+ const signMessageResult = await protocolRequestHandler('sign_messages', {
258
+ addresses: [address],
259
+ payloads: [siwsMessage]
292
260
  });
261
+ const signedPayload = toUint8Array(signMessageResult.signed_payloads[0]);
262
+ const signedMessage = fromUint8Array$1(signedPayload.slice(0, signedPayload.length - 64));
263
+ const signature = fromUint8Array$1(signedPayload.slice(signedPayload.length - 64));
264
+ const signInResult = {
265
+ address: address,
266
+ // Workaround: some wallets have been observed to only reply with the message signature.
267
+ // This is non-compliant with the spec, but in the interest of maximizing compatibility,
268
+ // detect this case and reuse the original message.
269
+ signed_message: signedMessage.length == 0 ? siwsMessage : signedMessage,
270
+ signature
271
+ };
272
+ return signInResult;
293
273
  }
294
274
 
295
275
  const SEQUENCE_NUMBER_BYTES = 4;
@@ -305,28 +285,24 @@ function createSequenceNumberVector(sequenceNumber) {
305
285
 
306
286
  const INITIALIZATION_VECTOR_BYTES = 12;
307
287
  const ENCODED_PUBLIC_KEY_LENGTH_BYTES = 65;
308
- function encryptMessage(plaintext, sequenceNumber, sharedSecret) {
309
- return __awaiter(this, void 0, void 0, function* () {
310
- const sequenceNumberVector = createSequenceNumberVector(sequenceNumber);
311
- const initializationVector = new Uint8Array(INITIALIZATION_VECTOR_BYTES);
312
- crypto.getRandomValues(initializationVector);
313
- const ciphertext = yield crypto.subtle.encrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, new TextEncoder().encode(plaintext));
314
- const response = new Uint8Array(sequenceNumberVector.byteLength + initializationVector.byteLength + ciphertext.byteLength);
315
- response.set(new Uint8Array(sequenceNumberVector), 0);
316
- response.set(new Uint8Array(initializationVector), sequenceNumberVector.byteLength);
317
- response.set(new Uint8Array(ciphertext), sequenceNumberVector.byteLength + initializationVector.byteLength);
318
- return response;
319
- });
288
+ async function encryptMessage(plaintext, sequenceNumber, sharedSecret) {
289
+ const sequenceNumberVector = createSequenceNumberVector(sequenceNumber);
290
+ const initializationVector = new Uint8Array(INITIALIZATION_VECTOR_BYTES);
291
+ crypto.getRandomValues(initializationVector);
292
+ const ciphertext = await crypto.subtle.encrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, new TextEncoder().encode(plaintext));
293
+ const response = new Uint8Array(sequenceNumberVector.byteLength + initializationVector.byteLength + ciphertext.byteLength);
294
+ response.set(new Uint8Array(sequenceNumberVector), 0);
295
+ response.set(new Uint8Array(initializationVector), sequenceNumberVector.byteLength);
296
+ response.set(new Uint8Array(ciphertext), sequenceNumberVector.byteLength + initializationVector.byteLength);
297
+ return response;
320
298
  }
321
- function decryptMessage(message, sharedSecret) {
322
- return __awaiter(this, void 0, void 0, function* () {
323
- const sequenceNumberVector = message.slice(0, SEQUENCE_NUMBER_BYTES);
324
- const initializationVector = message.slice(SEQUENCE_NUMBER_BYTES, SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
325
- const ciphertext = message.slice(SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
326
- const plaintextBuffer = yield crypto.subtle.decrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, ciphertext);
327
- const plaintext = getUtf8Decoder().decode(plaintextBuffer);
328
- return plaintext;
329
- });
299
+ async function decryptMessage(message, sharedSecret) {
300
+ const sequenceNumberVector = message.slice(0, SEQUENCE_NUMBER_BYTES);
301
+ const initializationVector = message.slice(SEQUENCE_NUMBER_BYTES, SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
302
+ const ciphertext = message.slice(SEQUENCE_NUMBER_BYTES + INITIALIZATION_VECTOR_BYTES);
303
+ const plaintextBuffer = await crypto.subtle.decrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, ciphertext);
304
+ const plaintext = getUtf8Decoder().decode(plaintextBuffer);
305
+ return plaintext;
330
306
  }
331
307
  function getAlgorithmParams(sequenceNumber, initializationVector) {
332
308
  return {
@@ -344,22 +320,18 @@ function getUtf8Decoder() {
344
320
  return _utf8Decoder;
345
321
  }
346
322
 
347
- function generateAssociationKeypair() {
348
- return __awaiter(this, void 0, void 0, function* () {
349
- return yield crypto.subtle.generateKey({
350
- name: 'ECDSA',
351
- namedCurve: 'P-256',
352
- }, false /* extractable */, ['sign'] /* keyUsages */);
353
- });
323
+ async function generateAssociationKeypair() {
324
+ return await crypto.subtle.generateKey({
325
+ name: 'ECDSA',
326
+ namedCurve: 'P-256',
327
+ }, false /* extractable */, ['sign'] /* keyUsages */);
354
328
  }
355
329
 
356
- function generateECDHKeypair() {
357
- return __awaiter(this, void 0, void 0, function* () {
358
- return yield crypto.subtle.generateKey({
359
- name: 'ECDH',
360
- namedCurve: 'P-256',
361
- }, false /* extractable */, ['deriveKey', 'deriveBits'] /* keyUsages */);
362
- });
330
+ async function generateECDHKeypair() {
331
+ return await crypto.subtle.generateKey({
332
+ name: 'ECDH',
333
+ namedCurve: 'P-256',
334
+ }, false /* extractable */, ['deriveKey', 'deriveBits'] /* keyUsages */);
363
335
  }
364
336
 
365
337
  // https://stackoverflow.com/a/9458996/802047
@@ -405,12 +377,12 @@ function getIntentURL(methodPathname, intentUrlBase) {
405
377
  try {
406
378
  baseUrl = new URL(intentUrlBase);
407
379
  }
408
- catch (_a) { } // eslint-disable-line no-empty
409
- if ((baseUrl === null || baseUrl === void 0 ? void 0 : baseUrl.protocol) !== 'https:') {
380
+ catch { } // eslint-disable-line no-empty
381
+ if (baseUrl?.protocol !== 'https:') {
410
382
  throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_FORBIDDEN_WALLET_BASE_URL, 'Base URLs supplied by wallets must be valid `https` URLs');
411
383
  }
412
384
  }
413
- baseUrl || (baseUrl = new URL(`${INTENT_NAME}:/`));
385
+ baseUrl ||= new URL(`${INTENT_NAME}:/`);
414
386
  const pathname = methodPathname.startsWith('/')
415
387
  ? // Method is an absolute path. Replace it wholesale.
416
388
  methodPathname
@@ -418,94 +390,82 @@ function getIntentURL(methodPathname, intentUrlBase) {
418
390
  [...getPathParts(baseUrl.pathname), ...getPathParts(methodPathname)].join('/');
419
391
  return new URL(pathname, baseUrl);
420
392
  }
421
- function getAssociateAndroidIntentURL(associationPublicKey, putativePort, associationURLBase, protocolVersions = ['v1']) {
422
- return __awaiter(this, void 0, void 0, function* () {
423
- const associationPort = assertAssociationPort(putativePort);
424
- const exportedKey = yield crypto.subtle.exportKey('raw', associationPublicKey);
425
- const encodedKey = arrayBufferToBase64String(exportedKey);
426
- const url = getIntentURL('v1/associate/local', associationURLBase);
427
- url.searchParams.set('association', getStringWithURLUnsafeCharactersReplaced(encodedKey));
428
- url.searchParams.set('port', `${associationPort}`);
429
- protocolVersions.forEach((version) => {
430
- url.searchParams.set('v', version);
431
- });
432
- return url;
393
+ async function getAssociateAndroidIntentURL(associationPublicKey, putativePort, associationURLBase, protocolVersions = ['v1']) {
394
+ const associationPort = assertAssociationPort(putativePort);
395
+ const exportedKey = await crypto.subtle.exportKey('raw', associationPublicKey);
396
+ const encodedKey = arrayBufferToBase64String(exportedKey);
397
+ const url = getIntentURL('v1/associate/local', associationURLBase);
398
+ url.searchParams.set('association', getStringWithURLUnsafeCharactersReplaced(encodedKey));
399
+ url.searchParams.set('port', `${associationPort}`);
400
+ protocolVersions.forEach((version) => {
401
+ url.searchParams.set('v', version);
433
402
  });
403
+ return url;
434
404
  }
435
- function getRemoteAssociateAndroidIntentURL(associationPublicKey, hostAuthority, reflectorId, associationURLBase, protocolVersions = ['v1']) {
436
- return __awaiter(this, void 0, void 0, function* () {
437
- const exportedKey = yield crypto.subtle.exportKey('raw', associationPublicKey);
438
- const encodedKey = arrayBufferToBase64String(exportedKey);
439
- const url = getIntentURL('v1/associate/remote', associationURLBase);
440
- url.searchParams.set('association', getStringWithURLUnsafeCharactersReplaced(encodedKey));
441
- url.searchParams.set('reflector', `${hostAuthority}`);
442
- url.searchParams.set('id', `${fromUint8Array$1(reflectorId, true)}`);
443
- protocolVersions.forEach((version) => {
444
- url.searchParams.set('v', version);
445
- });
446
- return url;
405
+ async function getRemoteAssociateAndroidIntentURL(associationPublicKey, hostAuthority, reflectorId, associationURLBase, protocolVersions = ['v1']) {
406
+ const exportedKey = await crypto.subtle.exportKey('raw', associationPublicKey);
407
+ const encodedKey = arrayBufferToBase64String(exportedKey);
408
+ const url = getIntentURL('v1/associate/remote', associationURLBase);
409
+ url.searchParams.set('association', getStringWithURLUnsafeCharactersReplaced(encodedKey));
410
+ url.searchParams.set('reflector', `${hostAuthority}`);
411
+ url.searchParams.set('id', `${fromUint8Array$1(reflectorId, true)}`);
412
+ protocolVersions.forEach((version) => {
413
+ url.searchParams.set('v', version);
447
414
  });
415
+ return url;
448
416
  }
449
417
 
450
- function encryptJsonRpcMessage(jsonRpcMessage, sharedSecret) {
451
- return __awaiter(this, void 0, void 0, function* () {
452
- const plaintext = JSON.stringify(jsonRpcMessage);
453
- const sequenceNumber = jsonRpcMessage.id;
454
- return encryptMessage(plaintext, sequenceNumber, sharedSecret);
455
- });
418
+ async function encryptJsonRpcMessage(jsonRpcMessage, sharedSecret) {
419
+ const plaintext = JSON.stringify(jsonRpcMessage);
420
+ const sequenceNumber = jsonRpcMessage.id;
421
+ return encryptMessage(plaintext, sequenceNumber, sharedSecret);
456
422
  }
457
- function decryptJsonRpcMessage(message, sharedSecret) {
458
- return __awaiter(this, void 0, void 0, function* () {
459
- const plaintext = yield decryptMessage(message, sharedSecret);
460
- const jsonRpcMessage = JSON.parse(plaintext);
461
- if (Object.hasOwnProperty.call(jsonRpcMessage, 'error')) {
462
- throw new SolanaMobileWalletAdapterProtocolError(jsonRpcMessage.id, jsonRpcMessage.error.code, jsonRpcMessage.error.message);
463
- }
464
- return jsonRpcMessage;
465
- });
423
+ async function decryptJsonRpcMessage(message, sharedSecret) {
424
+ const plaintext = await decryptMessage(message, sharedSecret);
425
+ const jsonRpcMessage = JSON.parse(plaintext);
426
+ if (Object.hasOwnProperty.call(jsonRpcMessage, 'error')) {
427
+ throw new SolanaMobileWalletAdapterProtocolError(jsonRpcMessage.id, jsonRpcMessage.error.code, jsonRpcMessage.error.message);
428
+ }
429
+ return jsonRpcMessage;
466
430
  }
467
431
 
468
- function parseHelloRsp(payloadBuffer, // The X9.62-encoded wallet endpoint ephemeral ECDH public keypoint.
432
+ async function parseHelloRsp(payloadBuffer, // The X9.62-encoded wallet endpoint ephemeral ECDH public keypoint.
469
433
  associationPublicKey, ecdhPrivateKey) {
470
- return __awaiter(this, void 0, void 0, function* () {
471
- const [associationPublicKeyBuffer, walletPublicKey] = yield Promise.all([
472
- crypto.subtle.exportKey('raw', associationPublicKey),
473
- crypto.subtle.importKey('raw', payloadBuffer.slice(0, ENCODED_PUBLIC_KEY_LENGTH_BYTES), { name: 'ECDH', namedCurve: 'P-256' }, false /* extractable */, [] /* keyUsages */),
474
- ]);
475
- const sharedSecret = yield crypto.subtle.deriveBits({ name: 'ECDH', public: walletPublicKey }, ecdhPrivateKey, 256);
476
- const ecdhSecretKey = yield crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false /* extractable */, ['deriveKey'] /* keyUsages */);
477
- const aesKeyMaterialVal = yield crypto.subtle.deriveKey({
478
- name: 'HKDF',
479
- hash: 'SHA-256',
480
- salt: new Uint8Array(associationPublicKeyBuffer),
481
- info: new Uint8Array(),
482
- }, ecdhSecretKey, { name: 'AES-GCM', length: 128 }, false /* extractable */, ['encrypt', 'decrypt']);
483
- return aesKeyMaterialVal;
484
- });
434
+ const [associationPublicKeyBuffer, walletPublicKey] = await Promise.all([
435
+ crypto.subtle.exportKey('raw', associationPublicKey),
436
+ crypto.subtle.importKey('raw', payloadBuffer.slice(0, ENCODED_PUBLIC_KEY_LENGTH_BYTES), { name: 'ECDH', namedCurve: 'P-256' }, false /* extractable */, [] /* keyUsages */),
437
+ ]);
438
+ const sharedSecret = await crypto.subtle.deriveBits({ name: 'ECDH', public: walletPublicKey }, ecdhPrivateKey, 256);
439
+ const ecdhSecretKey = await crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false /* extractable */, ['deriveKey'] /* keyUsages */);
440
+ const aesKeyMaterialVal = await crypto.subtle.deriveKey({
441
+ name: 'HKDF',
442
+ hash: 'SHA-256',
443
+ salt: new Uint8Array(associationPublicKeyBuffer),
444
+ info: new Uint8Array(),
445
+ }, ecdhSecretKey, { name: 'AES-GCM', length: 128 }, false /* extractable */, ['encrypt', 'decrypt']);
446
+ return aesKeyMaterialVal;
485
447
  }
486
448
 
487
- function parseSessionProps(message, sharedSecret) {
488
- return __awaiter(this, void 0, void 0, function* () {
489
- const plaintext = yield decryptMessage(message, sharedSecret);
490
- const jsonProperties = JSON.parse(plaintext);
491
- let protocolVersion = 'legacy';
492
- if (Object.hasOwnProperty.call(jsonProperties, 'v')) {
493
- switch (jsonProperties.v) {
494
- case 1:
495
- case '1':
496
- case 'v1':
497
- protocolVersion = 'v1';
498
- break;
499
- case 'legacy':
500
- protocolVersion = 'legacy';
501
- break;
502
- default:
503
- throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION, `Unknown/unsupported protocol version: ${jsonProperties.v}`);
504
- }
449
+ async function parseSessionProps(message, sharedSecret) {
450
+ const plaintext = await decryptMessage(message, sharedSecret);
451
+ const jsonProperties = JSON.parse(plaintext);
452
+ let protocolVersion = 'legacy';
453
+ if (Object.hasOwnProperty.call(jsonProperties, 'v')) {
454
+ switch (jsonProperties.v) {
455
+ case 1:
456
+ case '1':
457
+ case 'v1':
458
+ protocolVersion = 'v1';
459
+ break;
460
+ case 'legacy':
461
+ protocolVersion = 'legacy';
462
+ break;
463
+ default:
464
+ throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION, `Unknown/unsupported protocol version: ${jsonProperties.v}`);
505
465
  }
506
- return ({
507
- protocol_version: protocolVersion
508
- });
466
+ }
467
+ return ({
468
+ protocol_version: protocolVersion
509
469
  });
510
470
  }
511
471
 
@@ -550,47 +510,43 @@ function launchUrlThroughHiddenFrame(url) {
550
510
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
551
511
  _frame.contentWindow.location.href = url.toString();
552
512
  }
553
- function launchAssociation(associationUrl) {
554
- return __awaiter(this, void 0, void 0, function* () {
555
- if (associationUrl.protocol === 'https:') {
556
- // The association URL is an Android 'App Link' or iOS 'Universal Link'.
557
- // These are regular web URLs that are designed to launch an app if it
558
- // is installed or load the actual target webpage if not.
559
- window.location.assign(associationUrl);
560
- }
561
- else {
562
- // The association URL has a custom protocol (eg. `solana-wallet:`)
563
- try {
564
- const browser = getBrowser();
565
- switch (browser) {
566
- case Browser.Firefox:
567
- // If a custom protocol is not supported in Firefox, it throws.
568
- launchUrlThroughHiddenFrame(associationUrl);
569
- // If we reached this line, it's supported.
570
- break;
571
- case Browser.Other: {
572
- const detectionPromise = getDetectionPromise();
573
- window.location.assign(associationUrl);
574
- yield detectionPromise;
575
- break;
576
- }
577
- default:
578
- assertUnreachable(browser);
513
+ async function launchAssociation(associationUrl) {
514
+ if (associationUrl.protocol === 'https:') {
515
+ // The association URL is an Android 'App Link' or iOS 'Universal Link'.
516
+ // These are regular web URLs that are designed to launch an app if it
517
+ // is installed or load the actual target webpage if not.
518
+ window.location.assign(associationUrl);
519
+ }
520
+ else {
521
+ // The association URL has a custom protocol (eg. `solana-wallet:`)
522
+ try {
523
+ const browser = getBrowser();
524
+ switch (browser) {
525
+ case Browser.Firefox:
526
+ // If a custom protocol is not supported in Firefox, it throws.
527
+ launchUrlThroughHiddenFrame(associationUrl);
528
+ // If we reached this line, it's supported.
529
+ break;
530
+ case Browser.Other: {
531
+ const detectionPromise = getDetectionPromise();
532
+ window.location.assign(associationUrl);
533
+ await detectionPromise;
534
+ break;
579
535
  }
580
- }
581
- catch (e) {
582
- throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_WALLET_NOT_FOUND, 'Found no installed wallet that supports the mobile wallet protocol.');
536
+ default:
537
+ assertUnreachable(browser);
583
538
  }
584
539
  }
585
- });
540
+ catch (e) {
541
+ throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_WALLET_NOT_FOUND, 'Found no installed wallet that supports the mobile wallet protocol.');
542
+ }
543
+ }
586
544
  }
587
- function startSession(associationPublicKey, associationURLBase) {
588
- return __awaiter(this, void 0, void 0, function* () {
589
- const randomAssociationPort = getRandomAssociationPort();
590
- const associationUrl = yield getAssociateAndroidIntentURL(associationPublicKey, randomAssociationPort, associationURLBase);
591
- yield launchAssociation(associationUrl);
592
- return randomAssociationPort;
593
- });
545
+ async function startSession(associationPublicKey, associationURLBase) {
546
+ const randomAssociationPort = getRandomAssociationPort();
547
+ const associationUrl = await getAssociateAndroidIntentURL(associationPublicKey, randomAssociationPort, associationURLBase);
548
+ await launchAssociation(associationUrl);
549
+ return randomAssociationPort;
594
550
  }
595
551
 
596
552
  const WEBSOCKET_CONNECTION_CONFIG = {
@@ -619,7 +575,7 @@ function assertSecureEndpointSpecificURI(walletUriBase) {
619
575
  try {
620
576
  url = new URL(walletUriBase);
621
577
  }
622
- catch (_a) {
578
+ catch {
623
579
  throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_FORBIDDEN_WALLET_BASE_URL, 'Invalid base URL supplied by wallet');
624
580
  }
625
581
  if (url.protocol !== 'https:') {
@@ -644,25 +600,38 @@ function getReflectorIdFromByteArray(byteArray) {
644
600
  let { value: length, offset } = decodeVarLong(byteArray);
645
601
  return new Uint8Array(byteArray.slice(offset, offset + length));
646
602
  }
647
- function transact(callback, config) {
648
- return __awaiter(this, void 0, void 0, function* () {
649
- assertSecureContext();
650
- const associationKeypair = yield generateAssociationKeypair();
651
- const sessionPort = yield startSession(associationKeypair.publicKey, config === null || config === void 0 ? void 0 : config.baseUri);
652
- const websocketURL = `ws://localhost:${sessionPort}/solana-wallet`;
653
- let connectionStartTime;
654
- const getNextRetryDelayMs = (() => {
655
- const schedule = [...WEBSOCKET_CONNECTION_CONFIG.retryDelayScheduleMs];
656
- return () => (schedule.length > 1 ? schedule.shift() : schedule[0]);
657
- })();
658
- let nextJsonRpcMessageId = 1;
659
- let lastKnownInboundSequenceNumber = 0;
660
- let state = { __type: 'disconnected' };
661
- return new Promise((resolve, reject) => {
662
- let socket;
603
+ async function transact(callback, config) {
604
+ const { wallet, close } = await startScenario(config);
605
+ try {
606
+ return await callback(await wallet);
607
+ }
608
+ finally {
609
+ close();
610
+ }
611
+ }
612
+ async function startScenario(config) {
613
+ assertSecureContext();
614
+ const associationKeypair = await generateAssociationKeypair();
615
+ const sessionPort = await startSession(associationKeypair.publicKey, config?.baseUri);
616
+ const websocketURL = `ws://localhost:${sessionPort}/solana-wallet`;
617
+ let connectionStartTime;
618
+ const getNextRetryDelayMs = (() => {
619
+ const schedule = [...WEBSOCKET_CONNECTION_CONFIG.retryDelayScheduleMs];
620
+ return () => (schedule.length > 1 ? schedule.shift() : schedule[0]);
621
+ })();
622
+ let nextJsonRpcMessageId = 1;
623
+ let lastKnownInboundSequenceNumber = 0;
624
+ let state = { __type: 'disconnected' };
625
+ let socket;
626
+ let sessionEstablished = false;
627
+ let handleForceClose;
628
+ return { close: () => {
629
+ socket.close();
630
+ handleForceClose();
631
+ }, wallet: new Promise((resolve, reject) => {
663
632
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
664
633
  const jsonRpcResponsePromises = {};
665
- const handleOpen = () => __awaiter(this, void 0, void 0, function* () {
634
+ const handleOpen = async () => {
666
635
  if (state.__type !== 'connecting') {
667
636
  console.warn('Expected adapter state to be `connecting` at the moment the websocket opens. ' +
668
637
  `Got \`${state.__type}\`.`);
@@ -676,14 +645,14 @@ function transact(callback, config) {
676
645
  // APP_PING was sent by the wallet/websocket server. We must continue to support this behavior
677
646
  // in case the user is using a wallet that has not updated their walletlib implementation.
678
647
  const { associationKeypair } = state;
679
- const ecdhKeypair = yield generateECDHKeypair();
680
- socket.send(yield createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
648
+ const ecdhKeypair = await generateECDHKeypair();
649
+ socket.send(await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
681
650
  state = {
682
651
  __type: 'hello_req_sent',
683
652
  associationPublicKey: associationKeypair.publicKey,
684
653
  ecdhPrivateKey: ecdhKeypair.privateKey,
685
654
  };
686
- });
655
+ };
687
656
  const handleClose = (evt) => {
688
657
  if (evt.wasClean) {
689
658
  state = { __type: 'disconnected' };
@@ -693,28 +662,28 @@ function transact(callback, config) {
693
662
  }
694
663
  disposeSocket();
695
664
  };
696
- const handleError = (_evt) => __awaiter(this, void 0, void 0, function* () {
665
+ const handleError = async (_evt) => {
697
666
  disposeSocket();
698
667
  if (Date.now() - connectionStartTime >= WEBSOCKET_CONNECTION_CONFIG.timeoutMs) {
699
668
  reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT, `Failed to connect to the wallet websocket at ${websocketURL}.`));
700
669
  }
701
670
  else {
702
- yield new Promise((resolve) => {
671
+ await new Promise((resolve) => {
703
672
  const retryDelayMs = getNextRetryDelayMs();
704
673
  retryWaitTimeoutId = window.setTimeout(resolve, retryDelayMs);
705
674
  });
706
675
  attemptSocketConnection();
707
676
  }
708
- });
709
- const handleMessage = (evt) => __awaiter(this, void 0, void 0, function* () {
710
- const responseBuffer = yield evt.data.arrayBuffer();
677
+ };
678
+ const handleMessage = async (evt) => {
679
+ const responseBuffer = await evt.data.arrayBuffer();
711
680
  switch (state.__type) {
712
681
  case 'connecting':
713
682
  if (responseBuffer.byteLength !== 0) {
714
683
  throw new Error('Encountered unexpected message while connecting');
715
684
  }
716
- const ecdhKeypair = yield generateECDHKeypair();
717
- socket.send(yield createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
685
+ const ecdhKeypair = await generateECDHKeypair();
686
+ socket.send(await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
718
687
  state = {
719
688
  __type: 'hello_req_sent',
720
689
  associationPublicKey: associationKeypair.publicKey,
@@ -729,7 +698,7 @@ function transact(callback, config) {
729
698
  throw new Error('Encrypted message has invalid sequence number');
730
699
  }
731
700
  lastKnownInboundSequenceNumber = sequenceNumber;
732
- const jsonRpcMessage = yield decryptJsonRpcMessage(responseBuffer, state.sharedSecret);
701
+ const jsonRpcMessage = await decryptJsonRpcMessage(responseBuffer, state.sharedSecret);
733
702
  const responsePromise = jsonRpcResponsePromises[jsonRpcMessage.id];
734
703
  delete jsonRpcResponsePromises[jsonRpcMessage.id];
735
704
  responsePromise.resolve(jsonRpcMessage.result);
@@ -748,8 +717,8 @@ function transact(callback, config) {
748
717
  case 'hello_req_sent': {
749
718
  // if we receive an APP_PING message (empty message), resend the HELLO_REQ (see above)
750
719
  if (responseBuffer.byteLength === 0) {
751
- const ecdhKeypair = yield generateECDHKeypair();
752
- socket.send(yield createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
720
+ const ecdhKeypair = await generateECDHKeypair();
721
+ socket.send(await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
753
722
  state = {
754
723
  __type: 'hello_req_sent',
755
724
  associationPublicKey: associationKeypair.publicKey,
@@ -757,10 +726,10 @@ function transact(callback, config) {
757
726
  };
758
727
  break;
759
728
  }
760
- const sharedSecret = yield parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
729
+ const sharedSecret = await parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
761
730
  const sessionPropertiesBuffer = responseBuffer.slice(ENCODED_PUBLIC_KEY_LENGTH_BYTES);
762
731
  const sessionProperties = sessionPropertiesBuffer.byteLength !== 0
763
- ? yield (() => __awaiter(this, void 0, void 0, function* () {
732
+ ? await (async () => {
764
733
  const sequenceNumberVector = sessionPropertiesBuffer.slice(0, SEQUENCE_NUMBER_BYTES);
765
734
  const sequenceNumber = getSequenceNumberFromByteArray(sequenceNumberVector);
766
735
  if (sequenceNumber !== (lastKnownInboundSequenceNumber + 1)) {
@@ -768,15 +737,15 @@ function transact(callback, config) {
768
737
  }
769
738
  lastKnownInboundSequenceNumber = sequenceNumber;
770
739
  return parseSessionProps(sessionPropertiesBuffer, sharedSecret);
771
- }))() : { protocol_version: 'legacy' };
740
+ })() : { protocol_version: 'legacy' };
772
741
  state = { __type: 'connected', sharedSecret, sessionProperties };
773
- const wallet = createMobileWalletProxy(sessionProperties.protocol_version, (method, params) => __awaiter(this, void 0, void 0, function* () {
742
+ const wallet = createMobileWalletProxy(sessionProperties.protocol_version, async (method, params) => {
774
743
  const id = nextJsonRpcMessageId++;
775
- socket.send(yield encryptJsonRpcMessage({
744
+ socket.send(await encryptJsonRpcMessage({
776
745
  id,
777
746
  jsonrpc: '2.0',
778
747
  method,
779
- params: params !== null && params !== void 0 ? params : {},
748
+ params: params ?? {},
780
749
  }, sharedSecret));
781
750
  return new Promise((resolve, reject) => {
782
751
  jsonRpcResponsePromises[id] = {
@@ -802,21 +771,25 @@ function transact(callback, config) {
802
771
  reject,
803
772
  };
804
773
  });
805
- }));
774
+ });
775
+ sessionEstablished = true;
806
776
  try {
807
- resolve(yield callback(wallet));
777
+ resolve(wallet);
808
778
  }
809
779
  catch (e) {
810
780
  reject(e);
811
781
  }
812
- finally {
813
- disposeSocket();
814
- socket.close();
815
- }
816
782
  break;
817
783
  }
818
784
  }
819
- });
785
+ };
786
+ handleForceClose = () => {
787
+ socket.removeEventListener('message', handleMessage);
788
+ disposeSocket();
789
+ if (!sessionEstablished) {
790
+ reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session was closed before connection.`, { closeEvent: new CloseEvent('socket was closed before connection') }));
791
+ }
792
+ };
820
793
  let disposeSocket;
821
794
  let retryWaitTimeoutId;
822
795
  const attemptSocketConnection = () => {
@@ -841,244 +814,241 @@ function transact(callback, config) {
841
814
  };
842
815
  };
843
816
  attemptSocketConnection();
844
- });
845
- });
817
+ }) };
846
818
  }
847
- function startRemoteScenario(config) {
848
- return __awaiter(this, void 0, void 0, function* () {
849
- assertSecureContext();
850
- const associationKeypair = yield generateAssociationKeypair();
851
- const websocketURL = `wss://${config === null || config === void 0 ? void 0 : config.remoteHostAuthority}/reflect`;
852
- let connectionStartTime;
853
- const getNextRetryDelayMs = (() => {
854
- const schedule = [...WEBSOCKET_CONNECTION_CONFIG.retryDelayScheduleMs];
855
- return () => (schedule.length > 1 ? schedule.shift() : schedule[0]);
856
- })();
857
- let nextJsonRpcMessageId = 1;
858
- let lastKnownInboundSequenceNumber = 0;
859
- let encoding;
860
- let state = { __type: 'disconnected' };
861
- let socket;
862
- let disposeSocket;
863
- let decodeBytes = (evt) => __awaiter(this, void 0, void 0, function* () {
864
- if (encoding == 'base64') { // base64 encoding
865
- const message = yield evt.data;
866
- return toUint8Array(message).buffer;
819
+ async function startRemoteScenario(config) {
820
+ assertSecureContext();
821
+ const associationKeypair = await generateAssociationKeypair();
822
+ const websocketURL = `wss://${config?.remoteHostAuthority}/reflect`;
823
+ let connectionStartTime;
824
+ const getNextRetryDelayMs = (() => {
825
+ const schedule = [...WEBSOCKET_CONNECTION_CONFIG.retryDelayScheduleMs];
826
+ return () => (schedule.length > 1 ? schedule.shift() : schedule[0]);
827
+ })();
828
+ let nextJsonRpcMessageId = 1;
829
+ let lastKnownInboundSequenceNumber = 0;
830
+ let encoding;
831
+ let state = { __type: 'disconnected' };
832
+ let socket;
833
+ let disposeSocket;
834
+ let decodeBytes = async (evt) => {
835
+ if (encoding == 'base64') { // base64 encoding
836
+ const message = await evt.data;
837
+ return toUint8Array(message).buffer;
838
+ }
839
+ else {
840
+ return await evt.data.arrayBuffer();
841
+ }
842
+ };
843
+ // Reflector Connection Phase
844
+ // here we connect to the reflector and wait for the REFLECTOR_ID message
845
+ // so we build the association URL and return that back to the caller
846
+ const associationUrl = await new Promise((resolve, reject) => {
847
+ const handleOpen = async () => {
848
+ if (state.__type !== 'connecting') {
849
+ console.warn('Expected adapter state to be `connecting` at the moment the websocket opens. ' +
850
+ `Got \`${state.__type}\`.`);
851
+ return;
852
+ }
853
+ if (socket.protocol.includes(WEBSOCKET_PROTOCOL_BASE64)) {
854
+ encoding = 'base64';
867
855
  }
868
856
  else {
869
- return yield evt.data.arrayBuffer();
857
+ encoding = 'binary';
870
858
  }
871
- });
872
- // Reflector Connection Phase
873
- // here we connect to the reflector and wait for the REFLECTOR_ID message
874
- // so we build the association URL and return that back to the caller
875
- const associationUrl = yield new Promise((resolve, reject) => {
876
- const handleOpen = () => __awaiter(this, void 0, void 0, function* () {
877
- if (state.__type !== 'connecting') {
878
- console.warn('Expected adapter state to be `connecting` at the moment the websocket opens. ' +
879
- `Got \`${state.__type}\`.`);
880
- return;
881
- }
882
- if (socket.protocol.includes(WEBSOCKET_PROTOCOL_BASE64)) {
883
- encoding = 'base64';
884
- }
885
- else {
886
- encoding = 'binary';
887
- }
888
- socket.removeEventListener('open', handleOpen);
889
- });
890
- const handleClose = (evt) => {
891
- if (evt.wasClean) {
892
- state = { __type: 'disconnected' };
893
- }
894
- else {
895
- reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session dropped unexpectedly (${evt.code}: ${evt.reason}).`, { closeEvent: evt }));
896
- }
897
- disposeSocket();
898
- };
899
- const handleError = (_evt) => __awaiter(this, void 0, void 0, function* () {
900
- disposeSocket();
901
- if (Date.now() - connectionStartTime >= WEBSOCKET_CONNECTION_CONFIG.timeoutMs) {
902
- reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT, `Failed to connect to the wallet websocket at ${websocketURL}.`));
903
- }
904
- else {
905
- yield new Promise((resolve) => {
906
- const retryDelayMs = getNextRetryDelayMs();
907
- retryWaitTimeoutId = window.setTimeout(resolve, retryDelayMs);
908
- });
909
- attemptSocketConnection();
910
- }
911
- });
912
- const handleReflectorIdMessage = (evt) => __awaiter(this, void 0, void 0, function* () {
913
- const responseBuffer = yield decodeBytes(evt);
914
- if (state.__type === 'connecting') {
915
- if (responseBuffer.byteLength == 0) {
916
- throw new Error('Encountered unexpected message while connecting');
917
- }
918
- const reflectorId = getReflectorIdFromByteArray(responseBuffer);
919
- state = {
920
- __type: 'reflector_id_received',
921
- reflectorId: reflectorId
922
- };
923
- const associationUrl = yield getRemoteAssociateAndroidIntentURL(associationKeypair.publicKey, config.remoteHostAuthority, reflectorId, config === null || config === void 0 ? void 0 : config.baseUri);
924
- socket.removeEventListener('message', handleReflectorIdMessage);
925
- resolve(associationUrl);
926
- }
927
- });
928
- let retryWaitTimeoutId;
929
- const attemptSocketConnection = () => {
930
- if (disposeSocket) {
931
- disposeSocket();
932
- }
933
- state = { __type: 'connecting', associationKeypair };
934
- if (connectionStartTime === undefined) {
935
- connectionStartTime = Date.now();
859
+ socket.removeEventListener('open', handleOpen);
860
+ };
861
+ const handleClose = (evt) => {
862
+ if (evt.wasClean) {
863
+ state = { __type: 'disconnected' };
864
+ }
865
+ else {
866
+ reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session dropped unexpectedly (${evt.code}: ${evt.reason}).`, { closeEvent: evt }));
867
+ }
868
+ disposeSocket();
869
+ };
870
+ const handleError = async (_evt) => {
871
+ disposeSocket();
872
+ if (Date.now() - connectionStartTime >= WEBSOCKET_CONNECTION_CONFIG.timeoutMs) {
873
+ reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT, `Failed to connect to the wallet websocket at ${websocketURL}.`));
874
+ }
875
+ else {
876
+ await new Promise((resolve) => {
877
+ const retryDelayMs = getNextRetryDelayMs();
878
+ retryWaitTimeoutId = window.setTimeout(resolve, retryDelayMs);
879
+ });
880
+ attemptSocketConnection();
881
+ }
882
+ };
883
+ const handleReflectorIdMessage = async (evt) => {
884
+ const responseBuffer = await decodeBytes(evt);
885
+ if (state.__type === 'connecting') {
886
+ if (responseBuffer.byteLength == 0) {
887
+ throw new Error('Encountered unexpected message while connecting');
936
888
  }
937
- socket = new WebSocket(websocketURL, [WEBSOCKET_PROTOCOL_BINARY, WEBSOCKET_PROTOCOL_BASE64]);
938
- socket.addEventListener('open', handleOpen);
939
- socket.addEventListener('close', handleClose);
940
- socket.addEventListener('error', handleError);
941
- socket.addEventListener('message', handleReflectorIdMessage);
942
- disposeSocket = () => {
943
- window.clearTimeout(retryWaitTimeoutId);
944
- socket.removeEventListener('open', handleOpen);
945
- socket.removeEventListener('close', handleClose);
946
- socket.removeEventListener('error', handleError);
947
- socket.removeEventListener('message', handleReflectorIdMessage);
889
+ const reflectorId = getReflectorIdFromByteArray(responseBuffer);
890
+ state = {
891
+ __type: 'reflector_id_received',
892
+ reflectorId: reflectorId
948
893
  };
894
+ const associationUrl = await getRemoteAssociateAndroidIntentURL(associationKeypair.publicKey, config.remoteHostAuthority, reflectorId, config?.baseUri);
895
+ socket.removeEventListener('message', handleReflectorIdMessage);
896
+ resolve(associationUrl);
897
+ }
898
+ };
899
+ let retryWaitTimeoutId;
900
+ const attemptSocketConnection = () => {
901
+ if (disposeSocket) {
902
+ disposeSocket();
903
+ }
904
+ state = { __type: 'connecting', associationKeypair };
905
+ if (connectionStartTime === undefined) {
906
+ connectionStartTime = Date.now();
907
+ }
908
+ socket = new WebSocket(websocketURL, [WEBSOCKET_PROTOCOL_BINARY, WEBSOCKET_PROTOCOL_BASE64]);
909
+ socket.addEventListener('open', handleOpen);
910
+ socket.addEventListener('close', handleClose);
911
+ socket.addEventListener('error', handleError);
912
+ socket.addEventListener('message', handleReflectorIdMessage);
913
+ disposeSocket = () => {
914
+ window.clearTimeout(retryWaitTimeoutId);
915
+ socket.removeEventListener('open', handleOpen);
916
+ socket.removeEventListener('close', handleClose);
917
+ socket.removeEventListener('error', handleError);
918
+ socket.removeEventListener('message', handleReflectorIdMessage);
949
919
  };
950
- attemptSocketConnection();
951
- });
952
- // Wallet Connection Phase
953
- // here we return the association URL (containing the reflector ID) to the caller +
954
- // a promise that will resolve the MobileWallet object once the wallet connects.
955
- let sessionEstablished = false;
956
- let handleClose;
957
- return { associationUrl, close: () => {
958
- socket.close();
959
- handleClose();
960
- }, wallet: new Promise((resolve, reject) => {
961
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
962
- const jsonRpcResponsePromises = {};
963
- const handleMessage = (evt) => __awaiter(this, void 0, void 0, function* () {
964
- const responseBuffer = yield decodeBytes(evt);
965
- switch (state.__type) {
966
- case 'reflector_id_received':
967
- if (responseBuffer.byteLength !== 0) {
968
- throw new Error('Encountered unexpected message while awaiting reflection');
920
+ };
921
+ attemptSocketConnection();
922
+ });
923
+ // Wallet Connection Phase
924
+ // here we return the association URL (containing the reflector ID) to the caller +
925
+ // a promise that will resolve the MobileWallet object once the wallet connects.
926
+ let sessionEstablished = false;
927
+ let handleClose;
928
+ return { associationUrl, close: () => {
929
+ socket.close();
930
+ handleClose();
931
+ }, wallet: new Promise((resolve, reject) => {
932
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
933
+ const jsonRpcResponsePromises = {};
934
+ const handleMessage = async (evt) => {
935
+ const responseBuffer = await decodeBytes(evt);
936
+ switch (state.__type) {
937
+ case 'reflector_id_received':
938
+ if (responseBuffer.byteLength !== 0) {
939
+ throw new Error('Encountered unexpected message while awaiting reflection');
940
+ }
941
+ const ecdhKeypair = await generateECDHKeypair();
942
+ const binaryMsg = await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey);
943
+ if (encoding == 'base64') {
944
+ socket.send(fromUint8Array$1(binaryMsg));
945
+ }
946
+ else {
947
+ socket.send(binaryMsg);
948
+ }
949
+ state = {
950
+ __type: 'hello_req_sent',
951
+ associationPublicKey: associationKeypair.publicKey,
952
+ ecdhPrivateKey: ecdhKeypair.privateKey,
953
+ };
954
+ break;
955
+ case 'connected':
956
+ try {
957
+ const sequenceNumberVector = responseBuffer.slice(0, SEQUENCE_NUMBER_BYTES);
958
+ const sequenceNumber = getSequenceNumberFromByteArray(sequenceNumberVector);
959
+ if (sequenceNumber !== (lastKnownInboundSequenceNumber + 1)) {
960
+ throw new Error('Encrypted message has invalid sequence number');
969
961
  }
970
- const ecdhKeypair = yield generateECDHKeypair();
971
- const binaryMsg = yield createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey);
972
- if (encoding == 'base64') {
973
- socket.send(fromUint8Array$1(binaryMsg));
962
+ lastKnownInboundSequenceNumber = sequenceNumber;
963
+ const jsonRpcMessage = await decryptJsonRpcMessage(responseBuffer, state.sharedSecret);
964
+ const responsePromise = jsonRpcResponsePromises[jsonRpcMessage.id];
965
+ delete jsonRpcResponsePromises[jsonRpcMessage.id];
966
+ responsePromise.resolve(jsonRpcMessage.result);
967
+ }
968
+ catch (e) {
969
+ if (e instanceof SolanaMobileWalletAdapterProtocolError) {
970
+ const responsePromise = jsonRpcResponsePromises[e.jsonRpcMessageId];
971
+ delete jsonRpcResponsePromises[e.jsonRpcMessageId];
972
+ responsePromise.reject(e);
974
973
  }
975
974
  else {
976
- socket.send(binaryMsg);
975
+ throw e;
977
976
  }
978
- state = {
979
- __type: 'hello_req_sent',
980
- associationPublicKey: associationKeypair.publicKey,
981
- ecdhPrivateKey: ecdhKeypair.privateKey,
982
- };
983
- break;
984
- case 'connected':
985
- try {
986
- const sequenceNumberVector = responseBuffer.slice(0, SEQUENCE_NUMBER_BYTES);
977
+ }
978
+ break;
979
+ case 'hello_req_sent': {
980
+ const sharedSecret = await parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
981
+ const sessionPropertiesBuffer = responseBuffer.slice(ENCODED_PUBLIC_KEY_LENGTH_BYTES);
982
+ const sessionProperties = sessionPropertiesBuffer.byteLength !== 0
983
+ ? await (async () => {
984
+ const sequenceNumberVector = sessionPropertiesBuffer.slice(0, SEQUENCE_NUMBER_BYTES);
987
985
  const sequenceNumber = getSequenceNumberFromByteArray(sequenceNumberVector);
988
986
  if (sequenceNumber !== (lastKnownInboundSequenceNumber + 1)) {
989
987
  throw new Error('Encrypted message has invalid sequence number');
990
988
  }
991
989
  lastKnownInboundSequenceNumber = sequenceNumber;
992
- const jsonRpcMessage = yield decryptJsonRpcMessage(responseBuffer, state.sharedSecret);
993
- const responsePromise = jsonRpcResponsePromises[jsonRpcMessage.id];
994
- delete jsonRpcResponsePromises[jsonRpcMessage.id];
995
- responsePromise.resolve(jsonRpcMessage.result);
990
+ return parseSessionProps(sessionPropertiesBuffer, sharedSecret);
991
+ })() : { protocol_version: 'legacy' };
992
+ state = { __type: 'connected', sharedSecret, sessionProperties };
993
+ const wallet = createMobileWalletProxy(sessionProperties.protocol_version, async (method, params) => {
994
+ const id = nextJsonRpcMessageId++;
995
+ const binaryMsg = await encryptJsonRpcMessage({
996
+ id,
997
+ jsonrpc: '2.0',
998
+ method,
999
+ params: params ?? {},
1000
+ }, sharedSecret);
1001
+ if (encoding == 'base64') {
1002
+ socket.send(fromUint8Array$1(binaryMsg));
996
1003
  }
997
- catch (e) {
998
- if (e instanceof SolanaMobileWalletAdapterProtocolError) {
999
- const responsePromise = jsonRpcResponsePromises[e.jsonRpcMessageId];
1000
- delete jsonRpcResponsePromises[e.jsonRpcMessageId];
1001
- responsePromise.reject(e);
1002
- }
1003
- else {
1004
- throw e;
1005
- }
1004
+ else {
1005
+ socket.send(binaryMsg);
1006
1006
  }
1007
- break;
1008
- case 'hello_req_sent': {
1009
- const sharedSecret = yield parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
1010
- const sessionPropertiesBuffer = responseBuffer.slice(ENCODED_PUBLIC_KEY_LENGTH_BYTES);
1011
- const sessionProperties = sessionPropertiesBuffer.byteLength !== 0
1012
- ? yield (() => __awaiter(this, void 0, void 0, function* () {
1013
- const sequenceNumberVector = sessionPropertiesBuffer.slice(0, SEQUENCE_NUMBER_BYTES);
1014
- const sequenceNumber = getSequenceNumberFromByteArray(sequenceNumberVector);
1015
- if (sequenceNumber !== (lastKnownInboundSequenceNumber + 1)) {
1016
- throw new Error('Encrypted message has invalid sequence number');
1017
- }
1018
- lastKnownInboundSequenceNumber = sequenceNumber;
1019
- return parseSessionProps(sessionPropertiesBuffer, sharedSecret);
1020
- }))() : { protocol_version: 'legacy' };
1021
- state = { __type: 'connected', sharedSecret, sessionProperties };
1022
- const wallet = createMobileWalletProxy(sessionProperties.protocol_version, (method, params) => __awaiter(this, void 0, void 0, function* () {
1023
- const id = nextJsonRpcMessageId++;
1024
- const binaryMsg = yield encryptJsonRpcMessage({
1025
- id,
1026
- jsonrpc: '2.0',
1027
- method,
1028
- params: params !== null && params !== void 0 ? params : {},
1029
- }, sharedSecret);
1030
- if (encoding == 'base64') {
1031
- socket.send(fromUint8Array$1(binaryMsg));
1032
- }
1033
- else {
1034
- socket.send(binaryMsg);
1035
- }
1036
- return new Promise((resolve, reject) => {
1037
- jsonRpcResponsePromises[id] = {
1038
- resolve(result) {
1039
- switch (method) {
1040
- case 'authorize':
1041
- case 'reauthorize': {
1042
- const { wallet_uri_base } = result;
1043
- if (wallet_uri_base != null) {
1044
- try {
1045
- assertSecureEndpointSpecificURI(wallet_uri_base);
1046
- }
1047
- catch (e) {
1048
- reject(e);
1049
- return;
1050
- }
1007
+ return new Promise((resolve, reject) => {
1008
+ jsonRpcResponsePromises[id] = {
1009
+ resolve(result) {
1010
+ switch (method) {
1011
+ case 'authorize':
1012
+ case 'reauthorize': {
1013
+ const { wallet_uri_base } = result;
1014
+ if (wallet_uri_base != null) {
1015
+ try {
1016
+ assertSecureEndpointSpecificURI(wallet_uri_base);
1017
+ }
1018
+ catch (e) {
1019
+ reject(e);
1020
+ return;
1051
1021
  }
1052
- break;
1053
1022
  }
1023
+ break;
1054
1024
  }
1055
- resolve(result);
1056
- },
1057
- reject,
1058
- };
1059
- });
1060
- }));
1061
- sessionEstablished = true;
1062
- try {
1063
- resolve(wallet);
1064
- }
1065
- catch (e) {
1066
- reject(e);
1067
- }
1068
- break;
1025
+ }
1026
+ resolve(result);
1027
+ },
1028
+ reject,
1029
+ };
1030
+ });
1031
+ });
1032
+ sessionEstablished = true;
1033
+ try {
1034
+ resolve(wallet);
1069
1035
  }
1036
+ catch (e) {
1037
+ reject(e);
1038
+ }
1039
+ break;
1070
1040
  }
1071
- });
1072
- socket.addEventListener('message', handleMessage);
1073
- handleClose = () => {
1074
- socket.removeEventListener('message', handleMessage);
1075
- disposeSocket();
1076
- if (!sessionEstablished) {
1077
- reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session was closed before connection.`, { closeEvent: new CloseEvent('socket was closed before connection') }));
1078
- }
1079
- };
1080
- }) };
1081
- });
1041
+ }
1042
+ };
1043
+ socket.addEventListener('message', handleMessage);
1044
+ handleClose = () => {
1045
+ socket.removeEventListener('message', handleMessage);
1046
+ disposeSocket();
1047
+ if (!sessionEstablished) {
1048
+ reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session was closed before connection.`, { closeEvent: new CloseEvent('socket was closed before connection') }));
1049
+ }
1050
+ };
1051
+ }) };
1082
1052
  }
1083
1053
 
1084
1054
  exports.SolanaCloneAuthorization = SolanaCloneAuthorization;
@@ -1089,4 +1059,5 @@ exports.SolanaMobileWalletAdapterProtocolErrorCode = SolanaMobileWalletAdapterPr
1089
1059
  exports.SolanaSignInWithSolana = SolanaSignInWithSolana;
1090
1060
  exports.SolanaSignTransactions = SolanaSignTransactions;
1091
1061
  exports.startRemoteScenario = startRemoteScenario;
1062
+ exports.startScenario = startScenario;
1092
1063
  exports.transact = transact;