@pooflabs/web 0.0.84 → 0.0.85-rc2

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.
Files changed (67) hide show
  1. package/dist/auth/providers/solana-mobile-wallet-provider.d.ts +47 -20
  2. package/dist/{index-BM6hgCdH.js → index-B1_Q49qQ.js} +2 -2
  3. package/dist/{index-BM6hgCdH.js.map → index-B1_Q49qQ.js.map} +1 -1
  4. package/dist/{index-CH2G5Y9i.esm.js → index-B7tJ8TAn.esm.js} +2 -2
  5. package/dist/{index-CH2G5Y9i.esm.js.map → index-B7tJ8TAn.esm.js.map} +1 -1
  6. package/dist/{index-BPlF6-PQ.js → index-BeFR3-cf.js} +522 -289
  7. package/dist/{index-BPlF6-PQ.js.map → index-BeFR3-cf.js.map} +1 -1
  8. package/dist/index-DbJCCvVN.esm.js +6 -0
  9. package/dist/index-DbJCCvVN.esm.js.map +1 -0
  10. package/dist/{index-CSeN3jbG.js → index-DflG_JAB.js} +3 -3
  11. package/dist/{index-CSeN3jbG.js.map → index-DflG_JAB.js.map} +1 -1
  12. package/dist/{index-Bp4b5LXs.js → index-DyRIXw-l.js} +2 -2
  13. package/dist/index-DyRIXw-l.js.map +1 -0
  14. package/dist/{index-XHbmzFFO.esm.js → index-QukWgaIi.esm.js} +523 -290
  15. package/dist/{index-XHbmzFFO.esm.js.map → index-QukWgaIi.esm.js.map} +1 -1
  16. package/dist/{index-ep10Sw82.esm.js → index-agGmWBn4.esm.js} +3 -3
  17. package/dist/{index-ep10Sw82.esm.js.map → index-agGmWBn4.esm.js.map} +1 -1
  18. package/dist/{index.browser-C1QL04xM.js → index.browser-BJmFjY2f.js} +1006 -15
  19. package/dist/index.browser-BJmFjY2f.js.map +1 -0
  20. package/dist/index.browser-DZtZWdul.js +4994 -0
  21. package/dist/index.browser-DZtZWdul.js.map +1 -0
  22. package/dist/index.browser-lHP9glAW.esm.js +6060 -0
  23. package/dist/index.browser-lHP9glAW.esm.js.map +1 -0
  24. package/dist/{index.browser-Cgj7Hs6n.esm.js → index.browser-p-pgsxxW.esm.js} +836 -916
  25. package/dist/index.browser-p-pgsxxW.esm.js.map +1 -0
  26. package/dist/index.esm.js +1 -1
  27. package/dist/index.js +1 -1
  28. package/dist/{index.native-BmtuyGXs.js → index.native-ANhb4jEB.js} +4 -4
  29. package/dist/{index.native-BmtuyGXs.js.map → index.native-ANhb4jEB.js.map} +1 -1
  30. package/dist/{index.native-X01vlukI.esm.js → index.native-a3mhu9HP.esm.js} +4 -4
  31. package/dist/{index.native-X01vlukI.esm.js.map → index.native-a3mhu9HP.esm.js.map} +1 -1
  32. package/dist/index.native.esm.js +1 -1
  33. package/dist/index.native.js +1 -1
  34. package/dist/{phantom-wallet-provider-C_LPU6Ns.js → phantom-wallet-provider-BOdn0D1Q.js} +4 -4
  35. package/dist/{phantom-wallet-provider-C_LPU6Ns.js.map → phantom-wallet-provider-BOdn0D1Q.js.map} +1 -1
  36. package/dist/{phantom-wallet-provider-DRvhBbbR.esm.js → phantom-wallet-provider-Dsza6TBv.esm.js} +4 -4
  37. package/dist/{phantom-wallet-provider-DRvhBbbR.esm.js.map → phantom-wallet-provider-Dsza6TBv.esm.js.map} +1 -1
  38. package/dist/{privy-wallet-provider-DQM8xO38.js → privy-wallet-provider-BlPh3Gn_.js} +3 -3
  39. package/dist/{privy-wallet-provider-DQM8xO38.js.map → privy-wallet-provider-BlPh3Gn_.js.map} +1 -1
  40. package/dist/{privy-wallet-provider-ZGu8q5T5.esm.js → privy-wallet-provider-bwwhkFjL.esm.js} +3 -3
  41. package/dist/{privy-wallet-provider-ZGu8q5T5.esm.js.map → privy-wallet-provider-bwwhkFjL.esm.js.map} +1 -1
  42. package/dist/solana-mobile-wallet-provider-S8yWHG6i.js +841 -0
  43. package/dist/solana-mobile-wallet-provider-S8yWHG6i.js.map +1 -0
  44. package/dist/solana-mobile-wallet-provider-fzLIgJBf.esm.js +820 -0
  45. package/dist/solana-mobile-wallet-provider-fzLIgJBf.esm.js.map +1 -0
  46. package/package.json +2 -1
  47. package/dist/index-Bp4b5LXs.js.map +0 -1
  48. package/dist/index-C80kRxWk.esm.js +0 -6
  49. package/dist/index-C80kRxWk.esm.js.map +0 -1
  50. package/dist/index.browser-BvNsUWjt.js +0 -105
  51. package/dist/index.browser-BvNsUWjt.js.map +0 -1
  52. package/dist/index.browser-BwIqqM4U.js +0 -1099
  53. package/dist/index.browser-BwIqqM4U.js.map +0 -1
  54. package/dist/index.browser-C1QL04xM.js.map +0 -1
  55. package/dist/index.browser-Cgj7Hs6n.esm.js.map +0 -1
  56. package/dist/index.browser-CifFI7Ju.esm.js +0 -1096
  57. package/dist/index.browser-CifFI7Ju.esm.js.map +0 -1
  58. package/dist/index.browser-D8VWPXTZ.esm.js +0 -102
  59. package/dist/index.browser-D8VWPXTZ.esm.js.map +0 -1
  60. package/dist/index.browser-OvGNsMPu.esm.js +0 -1002
  61. package/dist/index.browser-OvGNsMPu.esm.js.map +0 -1
  62. package/dist/index.browser-vuTr40so.js +0 -1008
  63. package/dist/index.browser-vuTr40so.js.map +0 -1
  64. package/dist/solana-mobile-wallet-provider-6gNw2_bX.js +0 -608
  65. package/dist/solana-mobile-wallet-provider-6gNw2_bX.js.map +0 -1
  66. package/dist/solana-mobile-wallet-provider-B65A7abd.esm.js +0 -587
  67. package/dist/solana-mobile-wallet-provider-B65A7abd.esm.js.map +0 -1
@@ -1,15 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var index_browser = require('./index.browser-vuTr40so.js');
4
- var index = require('./index-BPlF6-PQ.js');
3
+ var index = require('./index-BeFR3-cf.js');
5
4
  require('axios');
6
5
  require('@solana/web3.js');
7
6
  require('@coral-xyz/anchor');
8
7
  require('react');
9
8
 
10
- /** Solana Mainnet (beta) cluster, e.g. https://api.mainnet-beta.solana.com */
11
- const SOLANA_MAINNET_CHAIN = 'solana:mainnet';
12
-
13
9
  /** Name of the feature. */
14
10
  const SolanaSignAndSendTransaction = 'solana:signAndSendTransaction';
15
11
 
@@ -22,6 +18,1001 @@ const SolanaSignMessage = 'solana:signMessage';
22
18
  /** Name of the feature. */
23
19
  const SolanaSignTransaction = 'solana:signTransaction';
24
20
 
21
+ function createDecoder(decoder) {
22
+ return Object.freeze({
23
+ ...decoder,
24
+ decode: (bytes, offset = 0) => decoder.read(bytes, offset)[0]
25
+ });
26
+ }
27
+
28
+ var getBaseXDecoder = (alphabet4) => {
29
+ return createDecoder({
30
+ read(rawBytes, offset) {
31
+ const bytes = offset === 0 || offset <= -rawBytes.byteLength ? rawBytes : rawBytes.slice(offset);
32
+ if (bytes.length === 0) return ["", 0];
33
+ let trailIndex = bytes.findIndex((n) => n !== 0);
34
+ trailIndex = trailIndex === -1 ? bytes.length : trailIndex;
35
+ const leadingZeroes = alphabet4[0].repeat(trailIndex);
36
+ if (trailIndex === bytes.length) return [leadingZeroes, rawBytes.length];
37
+ const base10Number = bytes.slice(trailIndex).reduce((sum, byte) => sum * 256n + BigInt(byte), 0n);
38
+ const tailChars = getBaseXFromBigInt(base10Number, alphabet4);
39
+ return [leadingZeroes + tailChars, rawBytes.length];
40
+ }
41
+ });
42
+ };
43
+ function getBaseXFromBigInt(value, alphabet4) {
44
+ const base = BigInt(alphabet4.length);
45
+ const tailChars = [];
46
+ while (value > 0n) {
47
+ tailChars.unshift(alphabet4[Number(value % base)]);
48
+ value /= base;
49
+ }
50
+ return tailChars.join("");
51
+ }
52
+
53
+ // src/base58.ts
54
+ var alphabet2 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
55
+ var getBase58Decoder = () => getBaseXDecoder(alphabet2);
56
+
57
+ /** Solana Mainnet (beta) cluster, e.g. https://api.mainnet-beta.solana.com */
58
+ const SOLANA_MAINNET_CHAIN = 'solana:mainnet';
59
+
60
+ /**
61
+ * TODO: docs
62
+ */
63
+ function createSignInMessageText(input) {
64
+ // ${domain} wants you to sign in with your Solana account:
65
+ // ${address}
66
+ //
67
+ // ${statement}
68
+ //
69
+ // URI: ${uri}
70
+ // Version: ${version}
71
+ // Chain ID: ${chain}
72
+ // Nonce: ${nonce}
73
+ // Issued At: ${issued-at}
74
+ // Expiration Time: ${expiration-time}
75
+ // Not Before: ${not-before}
76
+ // Request ID: ${request-id}
77
+ // Resources:
78
+ // - ${resources[0]}
79
+ // - ${resources[1]}
80
+ // ...
81
+ // - ${resources[n]}
82
+ let message = `${input.domain} wants you to sign in with your Solana account:\n`;
83
+ message += `${input.address}`;
84
+ if (input.statement) {
85
+ message += `\n\n${input.statement}`;
86
+ }
87
+ const fields = [];
88
+ if (input.uri) {
89
+ fields.push(`URI: ${input.uri}`);
90
+ }
91
+ if (input.version) {
92
+ fields.push(`Version: ${input.version}`);
93
+ }
94
+ if (input.chainId) {
95
+ fields.push(`Chain ID: ${input.chainId}`);
96
+ }
97
+ if (input.nonce) {
98
+ fields.push(`Nonce: ${input.nonce}`);
99
+ }
100
+ if (input.issuedAt) {
101
+ fields.push(`Issued At: ${input.issuedAt}`);
102
+ }
103
+ if (input.expirationTime) {
104
+ fields.push(`Expiration Time: ${input.expirationTime}`);
105
+ }
106
+ if (input.notBefore) {
107
+ fields.push(`Not Before: ${input.notBefore}`);
108
+ }
109
+ if (input.requestId) {
110
+ fields.push(`Request ID: ${input.requestId}`);
111
+ }
112
+ if (input.resources) {
113
+ fields.push(`Resources:`);
114
+ for (const resource of input.resources) {
115
+ fields.push(`- ${resource}`);
116
+ }
117
+ }
118
+ if (fields.length) {
119
+ message += `\n\n${fields.join('\n')}`;
120
+ }
121
+ return message;
122
+ }
123
+
124
+ //#region src/errors.ts
125
+ const SolanaMobileWalletAdapterErrorCode = {
126
+ ERROR_ASSOCIATION_PORT_OUT_OF_RANGE: "ERROR_ASSOCIATION_PORT_OUT_OF_RANGE",
127
+ ERROR_REFLECTOR_ID_OUT_OF_RANGE: "ERROR_REFLECTOR_ID_OUT_OF_RANGE",
128
+ ERROR_FORBIDDEN_WALLET_BASE_URL: "ERROR_FORBIDDEN_WALLET_BASE_URL",
129
+ ERROR_SECURE_CONTEXT_REQUIRED: "ERROR_SECURE_CONTEXT_REQUIRED",
130
+ ERROR_SESSION_CLOSED: "ERROR_SESSION_CLOSED",
131
+ ERROR_SESSION_TIMEOUT: "ERROR_SESSION_TIMEOUT",
132
+ ERROR_WALLET_NOT_FOUND: "ERROR_WALLET_NOT_FOUND",
133
+ ERROR_INVALID_PROTOCOL_VERSION: "ERROR_INVALID_PROTOCOL_VERSION",
134
+ ERROR_BROWSER_NOT_SUPPORTED: "ERROR_BROWSER_NOT_SUPPORTED",
135
+ ERROR_LOOPBACK_ACCESS_BLOCKED: "ERROR_LOOPBACK_ACCESS_BLOCKED",
136
+ ERROR_ASSOCIATION_CANCELLED: "ERROR_ASSOCIATION_CANCELLED"
137
+ };
138
+ var SolanaMobileWalletAdapterError = class extends Error {
139
+ data;
140
+ code;
141
+ constructor(...args) {
142
+ const [code, message, data] = args;
143
+ super(message);
144
+ this.code = code;
145
+ this.data = data;
146
+ this.name = "SolanaMobileWalletAdapterError";
147
+ }
148
+ };
149
+ var SolanaMobileWalletAdapterProtocolError = class extends Error {
150
+ data;
151
+ code;
152
+ jsonRpcMessageId;
153
+ constructor(...args) {
154
+ const [jsonRpcMessageId, code, message, data] = args;
155
+ super(message);
156
+ this.code = code;
157
+ this.data = data;
158
+ this.jsonRpcMessageId = jsonRpcMessageId;
159
+ this.name = "SolanaMobileWalletAdapterProtocolError";
160
+ }
161
+ };
162
+ //#endregion
163
+ //#region src/base64Utils.ts
164
+ function encode(input) {
165
+ return window.btoa(input);
166
+ }
167
+ function fromUint8Array$1(byteArray, urlsafe) {
168
+ const base64 = window.btoa(String.fromCharCode.call(null, ...byteArray));
169
+ if (urlsafe) return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
170
+ else return base64;
171
+ }
172
+ function toUint8Array$1(base64EncodedByteArray) {
173
+ return new Uint8Array(window.atob(base64EncodedByteArray).split("").map((c) => c.charCodeAt(0)));
174
+ }
175
+ //#endregion
176
+ //#region src/createHelloReq.ts
177
+ async function createHelloReq(ecdhPublicKey, associationKeypairPrivateKey) {
178
+ const publicKeyBuffer = await crypto.subtle.exportKey("raw", ecdhPublicKey);
179
+ const signatureBuffer = await crypto.subtle.sign({
180
+ hash: "SHA-256",
181
+ name: "ECDSA"
182
+ }, associationKeypairPrivateKey, publicKeyBuffer);
183
+ const response = new Uint8Array(publicKeyBuffer.byteLength + signatureBuffer.byteLength);
184
+ response.set(new Uint8Array(publicKeyBuffer), 0);
185
+ response.set(new Uint8Array(signatureBuffer), publicKeyBuffer.byteLength);
186
+ return response;
187
+ }
188
+ //#endregion
189
+ //#region src/base58Utils.ts
190
+ function fromUint8Array$2(byteArray) {
191
+ return getBase58Decoder().decode(byteArray);
192
+ }
193
+ function base64ToBase58(base64EncodedString) {
194
+ return fromUint8Array$2(toUint8Array$1(base64EncodedString));
195
+ }
196
+ //#endregion
197
+ //#region src/createSIWSMessage.ts
198
+ function createSIWSMessage(payload) {
199
+ return createSignInMessageText(payload);
200
+ }
201
+ function createSIWSMessageBase64Url(payload) {
202
+ return encode(createSIWSMessage(payload)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
203
+ }
204
+ //#endregion
205
+ //#region src/types.ts
206
+ const SolanaSignTransactions = "solana:signTransactions";
207
+ const SolanaCloneAuthorization = "solana:cloneAuthorization";
208
+ //#endregion
209
+ //#region src/createMobileWalletProxy.ts
210
+ /**
211
+ * Creates a {@link MobileWallet} proxy that handles backwards compatibility and API to RPC conversion.
212
+ *
213
+ * @param protocolVersion the protocol version in use for this session/request
214
+ * @param protocolRequestHandler callback function that handles sending the RPC request to the wallet endpoint.
215
+ * @returns a {@link MobileWallet} proxy
216
+ */
217
+ function createMobileWalletProxy(protocolVersion, protocolRequestHandler) {
218
+ return new Proxy({}, {
219
+ get(target, p) {
220
+ if (p === "then") return null;
221
+ if (target[p] == null) target[p] = async function(inputParams) {
222
+ const { method, params } = handleMobileWalletRequest(p, inputParams, protocolVersion);
223
+ const result = await protocolRequestHandler(method, params);
224
+ if (method === "authorize" && params.sign_in_payload && !result.sign_in_result) result.sign_in_result = await signInFallback(params.sign_in_payload, result, protocolRequestHandler);
225
+ return handleMobileWalletResponse(p, result, protocolVersion);
226
+ };
227
+ return target[p];
228
+ },
229
+ defineProperty() {
230
+ return false;
231
+ },
232
+ deleteProperty() {
233
+ return false;
234
+ }
235
+ });
236
+ }
237
+ /**
238
+ * Handles all {@link MobileWallet} API requests and determines the correct MWA RPC method and params to call.
239
+ * This handles backwards compatibility, based on the provided @protocolVersion.
240
+ *
241
+ * @param methodName the name of {@link MobileWallet} method that was called
242
+ * @param methodParams the parameters that were passed to the method
243
+ * @param protocolVersion the protocol version in use for this session/request
244
+ * @returns the RPC request method and params that should be sent to the wallet endpoint
245
+ */
246
+ function handleMobileWalletRequest(methodName, methodParams, protocolVersion) {
247
+ let params = methodParams;
248
+ let method = methodName.toString().replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`).toLowerCase();
249
+ switch (methodName) {
250
+ case "authorize": {
251
+ const authorizeParams = params;
252
+ let { chain } = authorizeParams;
253
+ if (protocolVersion === "legacy") {
254
+ switch (chain) {
255
+ case "solana:testnet":
256
+ chain = "testnet";
257
+ break;
258
+ case "solana:devnet":
259
+ chain = "devnet";
260
+ break;
261
+ case "solana:mainnet":
262
+ chain = "mainnet-beta";
263
+ break;
264
+ default: chain = authorizeParams.cluster;
265
+ }
266
+ authorizeParams.cluster = chain;
267
+ params = authorizeParams;
268
+ } else {
269
+ switch (chain) {
270
+ case "testnet":
271
+ case "devnet":
272
+ chain = `solana:${chain}`;
273
+ break;
274
+ case "mainnet-beta":
275
+ chain = "solana:mainnet";
276
+ break;
277
+ }
278
+ authorizeParams.chain = chain;
279
+ params = authorizeParams;
280
+ }
281
+ }
282
+ case "reauthorize": {
283
+ const { auth_token, identity } = params;
284
+ if (auth_token) switch (protocolVersion) {
285
+ case "legacy":
286
+ method = "reauthorize";
287
+ params = {
288
+ auth_token,
289
+ identity
290
+ };
291
+ break;
292
+ default:
293
+ method = "authorize";
294
+ break;
295
+ }
296
+ break;
297
+ }
298
+ }
299
+ return {
300
+ method,
301
+ params
302
+ };
303
+ }
304
+ /**
305
+ * Handles all {@link MobileWallet} API responses and modifies the response for backwards compatibility, if needed
306
+ *
307
+ * @param method the {@link MobileWallet} method that was called
308
+ * @param response the original response that was returned by the method call
309
+ * @param protocolVersion the protocol version in use for this session/request
310
+ * @returns the possibly modified response
311
+ */
312
+ function handleMobileWalletResponse(method, response, protocolVersion) {
313
+ switch (method) {
314
+ case "getCapabilities": {
315
+ const capabilities = response;
316
+ switch (protocolVersion) {
317
+ case "legacy": {
318
+ const features = [SolanaSignTransactions];
319
+ if (capabilities.supports_clone_authorization === true) features.push(SolanaCloneAuthorization);
320
+ return {
321
+ ...capabilities,
322
+ features
323
+ };
324
+ }
325
+ case "v1": return {
326
+ ...capabilities,
327
+ supports_sign_and_send_transactions: true,
328
+ supports_clone_authorization: capabilities.features.includes(SolanaCloneAuthorization)
329
+ };
330
+ }
331
+ }
332
+ }
333
+ return response;
334
+ }
335
+ async function signInFallback(signInPayload, authorizationResult, protocolRequestHandler) {
336
+ const domain = signInPayload.domain ?? window.location.host;
337
+ const address = authorizationResult.accounts[0].address;
338
+ const siwsMessage = createSIWSMessageBase64Url({
339
+ ...signInPayload,
340
+ domain,
341
+ address: base64ToBase58(address)
342
+ });
343
+ const signedPayload = toUint8Array$1((await protocolRequestHandler("sign_messages", {
344
+ addresses: [address],
345
+ payloads: [siwsMessage]
346
+ })).signed_payloads[0]);
347
+ const signedMessage = fromUint8Array$1(signedPayload.slice(0, signedPayload.length - 64));
348
+ const signature = fromUint8Array$1(signedPayload.slice(signedPayload.length - 64));
349
+ return {
350
+ address,
351
+ signed_message: signedMessage.length == 0 ? siwsMessage : signedMessage,
352
+ signature
353
+ };
354
+ }
355
+ function createSequenceNumberVector(sequenceNumber) {
356
+ if (sequenceNumber >= 4294967296) throw new Error("Outbound sequence number overflow. The maximum sequence number is 32-bytes.");
357
+ const byteArray = /* @__PURE__ */ new ArrayBuffer(4);
358
+ new DataView(byteArray).setUint32(0, sequenceNumber, false);
359
+ return new Uint8Array(byteArray);
360
+ }
361
+ //#endregion
362
+ //#region src/encryptedMessage.ts
363
+ const INITIALIZATION_VECTOR_BYTES = 12;
364
+ async function encryptMessage(plaintext, sequenceNumber, sharedSecret) {
365
+ const sequenceNumberVector = createSequenceNumberVector(sequenceNumber);
366
+ const initializationVector = new Uint8Array(INITIALIZATION_VECTOR_BYTES);
367
+ crypto.getRandomValues(initializationVector);
368
+ const ciphertext = await crypto.subtle.encrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, new TextEncoder().encode(plaintext));
369
+ const response = new Uint8Array(sequenceNumberVector.byteLength + initializationVector.byteLength + ciphertext.byteLength);
370
+ response.set(new Uint8Array(sequenceNumberVector), 0);
371
+ response.set(new Uint8Array(initializationVector), sequenceNumberVector.byteLength);
372
+ response.set(new Uint8Array(ciphertext), sequenceNumberVector.byteLength + initializationVector.byteLength);
373
+ return response;
374
+ }
375
+ async function decryptMessage(message, sharedSecret) {
376
+ const sequenceNumberVector = message.slice(0, 4);
377
+ const initializationVector = message.slice(4, 4 + INITIALIZATION_VECTOR_BYTES);
378
+ const ciphertext = message.slice(4 + INITIALIZATION_VECTOR_BYTES);
379
+ const plaintextBuffer = await crypto.subtle.decrypt(getAlgorithmParams(sequenceNumberVector, initializationVector), sharedSecret, ciphertext);
380
+ return getUtf8Decoder().decode(plaintextBuffer);
381
+ }
382
+ function getAlgorithmParams(sequenceNumber, initializationVector) {
383
+ return {
384
+ additionalData: sequenceNumber,
385
+ iv: initializationVector,
386
+ name: "AES-GCM",
387
+ tagLength: 128
388
+ };
389
+ }
390
+ let _utf8Decoder;
391
+ function getUtf8Decoder() {
392
+ if (_utf8Decoder === void 0) _utf8Decoder = new TextDecoder("utf-8");
393
+ return _utf8Decoder;
394
+ }
395
+ //#endregion
396
+ //#region src/generateAssociationKeypair.ts
397
+ async function generateAssociationKeypair() {
398
+ return await crypto.subtle.generateKey({
399
+ name: "ECDSA",
400
+ namedCurve: "P-256"
401
+ }, false, ["sign"]);
402
+ }
403
+ //#endregion
404
+ //#region src/generateECDHKeypair.ts
405
+ async function generateECDHKeypair() {
406
+ return await crypto.subtle.generateKey({
407
+ name: "ECDH",
408
+ namedCurve: "P-256"
409
+ }, false, ["deriveKey", "deriveBits"]);
410
+ }
411
+ //#endregion
412
+ //#region src/arrayBufferToBase64String.ts
413
+ function arrayBufferToBase64String(buffer) {
414
+ let binary = "";
415
+ const bytes = new Uint8Array(buffer);
416
+ const len = bytes.byteLength;
417
+ for (let ii = 0; ii < len; ii++) binary += String.fromCharCode(bytes[ii]);
418
+ return window.btoa(binary);
419
+ }
420
+ //#endregion
421
+ //#region src/associationPort.ts
422
+ function getRandomAssociationPort() {
423
+ return assertAssociationPort(49152 + Math.floor(Math.random() * 16384));
424
+ }
425
+ function assertAssociationPort(port) {
426
+ if (port < 49152 || port > 65535) throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_ASSOCIATION_PORT_OUT_OF_RANGE, `Association port number must be between 49152 and 65535. ${port} given.`, { port });
427
+ return port;
428
+ }
429
+ //#endregion
430
+ //#region src/getStringWithURLUnsafeBase64CharactersReplaced.ts
431
+ function getStringWithURLUnsafeCharactersReplaced(unsafeBase64EncodedString) {
432
+ return unsafeBase64EncodedString.replace(/[/+=]/g, (m) => ({
433
+ "/": "_",
434
+ "+": "-",
435
+ "=": "."
436
+ })[m]);
437
+ }
438
+ //#endregion
439
+ //#region src/getAssociateAndroidIntentURL.ts
440
+ const INTENT_NAME = "solana-wallet";
441
+ function getPathParts(pathString) {
442
+ return pathString.replace(/(^\/+|\/+$)/g, "").split("/");
443
+ }
444
+ function getIntentURL(methodPathname, intentUrlBase) {
445
+ let baseUrl = null;
446
+ if (intentUrlBase) {
447
+ try {
448
+ baseUrl = new URL(intentUrlBase);
449
+ } catch {}
450
+ if (baseUrl?.protocol !== "https:") throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_FORBIDDEN_WALLET_BASE_URL, "Base URLs supplied by wallets must be valid `https` URLs");
451
+ }
452
+ baseUrl ||= new URL(`${INTENT_NAME}:/`);
453
+ const pathname = methodPathname.startsWith("/") ? methodPathname : [...getPathParts(baseUrl.pathname), ...getPathParts(methodPathname)].join("/");
454
+ return new URL(pathname, baseUrl);
455
+ }
456
+ async function getAssociateAndroidIntentURL(associationPublicKey, putativePort, associationURLBase, protocolVersions = ["v1"]) {
457
+ const associationPort = assertAssociationPort(putativePort);
458
+ const encodedKey = arrayBufferToBase64String(await crypto.subtle.exportKey("raw", associationPublicKey));
459
+ const url = getIntentURL("v1/associate/local", associationURLBase);
460
+ url.searchParams.set("association", getStringWithURLUnsafeCharactersReplaced(encodedKey));
461
+ url.searchParams.set("port", `${associationPort}`);
462
+ protocolVersions.forEach((version) => {
463
+ url.searchParams.set("v", version);
464
+ });
465
+ return url;
466
+ }
467
+ async function getRemoteAssociateAndroidIntentURL(associationPublicKey, hostAuthority, reflectorId, associationURLBase, protocolVersions = ["v1"]) {
468
+ const encodedKey = arrayBufferToBase64String(await crypto.subtle.exportKey("raw", associationPublicKey));
469
+ const url = getIntentURL("v1/associate/remote", associationURLBase);
470
+ url.searchParams.set("association", getStringWithURLUnsafeCharactersReplaced(encodedKey));
471
+ url.searchParams.set("reflector", `${hostAuthority}`);
472
+ url.searchParams.set("id", `${fromUint8Array$1(reflectorId, true)}`);
473
+ protocolVersions.forEach((version) => {
474
+ url.searchParams.set("v", version);
475
+ });
476
+ return url;
477
+ }
478
+ //#endregion
479
+ //#region src/jsonRpcMessage.ts
480
+ async function encryptJsonRpcMessage(jsonRpcMessage, sharedSecret) {
481
+ const plaintext = JSON.stringify(jsonRpcMessage);
482
+ const sequenceNumber = jsonRpcMessage.id;
483
+ return encryptMessage(plaintext, sequenceNumber, sharedSecret);
484
+ }
485
+ async function decryptJsonRpcMessage(message, sharedSecret) {
486
+ const plaintext = await decryptMessage(message, sharedSecret);
487
+ const jsonRpcMessage = JSON.parse(plaintext);
488
+ if (Object.hasOwnProperty.call(jsonRpcMessage, "error")) throw new SolanaMobileWalletAdapterProtocolError(jsonRpcMessage.id, jsonRpcMessage.error.code, jsonRpcMessage.error.message);
489
+ return jsonRpcMessage;
490
+ }
491
+ //#endregion
492
+ //#region src/parseHelloRsp.ts
493
+ async function parseHelloRsp(payloadBuffer, associationPublicKey, ecdhPrivateKey) {
494
+ const [associationPublicKeyBuffer, walletPublicKey] = await Promise.all([crypto.subtle.exportKey("raw", associationPublicKey), crypto.subtle.importKey("raw", payloadBuffer.slice(0, 65), {
495
+ name: "ECDH",
496
+ namedCurve: "P-256"
497
+ }, false, [])]);
498
+ const sharedSecret = await crypto.subtle.deriveBits({
499
+ name: "ECDH",
500
+ public: walletPublicKey
501
+ }, ecdhPrivateKey, 256);
502
+ const ecdhSecretKey = await crypto.subtle.importKey("raw", sharedSecret, "HKDF", false, ["deriveKey"]);
503
+ return await crypto.subtle.deriveKey({
504
+ name: "HKDF",
505
+ hash: "SHA-256",
506
+ salt: new Uint8Array(associationPublicKeyBuffer),
507
+ info: new Uint8Array()
508
+ }, ecdhSecretKey, {
509
+ name: "AES-GCM",
510
+ length: 128
511
+ }, false, ["encrypt", "decrypt"]);
512
+ }
513
+ //#endregion
514
+ //#region src/parseSessionProps.ts
515
+ async function parseSessionProps(message, sharedSecret) {
516
+ const plaintext = await decryptMessage(message, sharedSecret);
517
+ const jsonProperties = JSON.parse(plaintext);
518
+ let protocolVersion = "legacy";
519
+ if (Object.hasOwnProperty.call(jsonProperties, "v")) switch (jsonProperties.v) {
520
+ case 1:
521
+ case "1":
522
+ case "v1":
523
+ protocolVersion = "v1";
524
+ break;
525
+ case "legacy":
526
+ protocolVersion = "legacy";
527
+ break;
528
+ default: throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_INVALID_PROTOCOL_VERSION, `Unknown/unsupported protocol version: ${jsonProperties.v}`);
529
+ }
530
+ return { protocol_version: protocolVersion };
531
+ }
532
+ //#endregion
533
+ //#region src/startSession.ts
534
+ const Browser = {
535
+ Firefox: 0,
536
+ Other: 1
537
+ };
538
+ function assertUnreachable(x) {
539
+ return x;
540
+ }
541
+ function getBrowser() {
542
+ return navigator.userAgent.indexOf("Firefox/") !== -1 ? Browser.Firefox : Browser.Other;
543
+ }
544
+ function getDetectionPromise() {
545
+ return new Promise((resolve, reject) => {
546
+ function cleanup() {
547
+ clearTimeout(timeoutId);
548
+ window.removeEventListener("blur", handleBlur);
549
+ }
550
+ function handleBlur() {
551
+ cleanup();
552
+ resolve();
553
+ }
554
+ window.addEventListener("blur", handleBlur);
555
+ const timeoutId = setTimeout(() => {
556
+ cleanup();
557
+ reject();
558
+ }, 3e3);
559
+ });
560
+ }
561
+ let _frame = null;
562
+ function launchUrlThroughHiddenFrame(url) {
563
+ if (_frame == null) {
564
+ _frame = document.createElement("iframe");
565
+ _frame.style.display = "none";
566
+ document.body.appendChild(_frame);
567
+ }
568
+ _frame.contentWindow.location.href = url.toString();
569
+ }
570
+ async function launchAssociation(associationUrl) {
571
+ if (associationUrl.protocol === "https:") window.location.assign(associationUrl);
572
+ else try {
573
+ const browser = getBrowser();
574
+ switch (browser) {
575
+ case Browser.Firefox:
576
+ launchUrlThroughHiddenFrame(associationUrl);
577
+ break;
578
+ case Browser.Other: {
579
+ const detectionPromise = getDetectionPromise();
580
+ window.location.assign(associationUrl);
581
+ await detectionPromise;
582
+ break;
583
+ }
584
+ default: assertUnreachable(browser);
585
+ }
586
+ } catch {
587
+ throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_WALLET_NOT_FOUND, "Found no installed wallet that supports the mobile wallet protocol.");
588
+ }
589
+ }
590
+ async function startSession(associationPublicKey, associationURLBase) {
591
+ const randomAssociationPort = getRandomAssociationPort();
592
+ await launchAssociation(await getAssociateAndroidIntentURL(associationPublicKey, randomAssociationPort, associationURLBase));
593
+ return randomAssociationPort;
594
+ }
595
+ //#endregion
596
+ //#region src/transact.ts
597
+ const WEBSOCKET_CONNECTION_CONFIG = {
598
+ retryDelayScheduleMs: [
599
+ 150,
600
+ 150,
601
+ 200,
602
+ 500,
603
+ 500,
604
+ 750,
605
+ 750,
606
+ 1e3
607
+ ],
608
+ timeoutMs: 3e4
609
+ };
610
+ const WEBSOCKET_PROTOCOL_BINARY = "com.solana.mobilewalletadapter.v1";
611
+ const WEBSOCKET_PROTOCOL_BASE64 = "com.solana.mobilewalletadapter.v1.base64";
612
+ function assertSecureContext() {
613
+ if (typeof window === "undefined" || window.isSecureContext !== true) throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SECURE_CONTEXT_REQUIRED, "The mobile wallet adapter protocol must be used in a secure context (`https`).");
614
+ }
615
+ function assertSecureEndpointSpecificURI(walletUriBase) {
616
+ let url;
617
+ try {
618
+ url = new URL(walletUriBase);
619
+ } catch {
620
+ throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_FORBIDDEN_WALLET_BASE_URL, "Invalid base URL supplied by wallet");
621
+ }
622
+ if (url.protocol !== "https:") throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_FORBIDDEN_WALLET_BASE_URL, "Base URLs supplied by wallets must be valid `https` URLs");
623
+ }
624
+ function getSequenceNumberFromByteArray(byteArray) {
625
+ return new DataView(byteArray).getUint32(0, false);
626
+ }
627
+ function decodeVarLong(byteArray) {
628
+ const bytes = new Uint8Array(byteArray);
629
+ const l = byteArray.byteLength;
630
+ const limit = 10;
631
+ let value = 0, offset = 0, b;
632
+ do {
633
+ if (offset >= l || offset > limit) throw new RangeError("Failed to decode varint");
634
+ b = bytes[offset++];
635
+ value |= (b & 127) << 7 * offset;
636
+ } while (b >= 128);
637
+ return {
638
+ value,
639
+ offset
640
+ };
641
+ }
642
+ function getReflectorIdFromByteArray(byteArray) {
643
+ const { value: length, offset } = decodeVarLong(byteArray);
644
+ return new Uint8Array(byteArray.slice(offset, offset + length));
645
+ }
646
+ async function startScenario(config) {
647
+ assertSecureContext();
648
+ const associationKeypair = await generateAssociationKeypair();
649
+ const websocketURL = `ws://localhost:${await startSession(associationKeypair.publicKey, config?.baseUri)}/solana-wallet`;
650
+ let connectionStartTime;
651
+ const getNextRetryDelayMs = (() => {
652
+ const schedule = [...WEBSOCKET_CONNECTION_CONFIG.retryDelayScheduleMs];
653
+ return () => schedule.length > 1 ? schedule.shift() : schedule[0];
654
+ })();
655
+ let nextJsonRpcMessageId = 1;
656
+ let lastKnownInboundSequenceNumber = 0;
657
+ let state = { __type: "disconnected" };
658
+ let socket;
659
+ let sessionEstablished = false;
660
+ let handleForceClose;
661
+ return {
662
+ close: () => {
663
+ socket.close();
664
+ handleForceClose();
665
+ },
666
+ wallet: new Promise((resolve, reject) => {
667
+ const jsonRpcResponsePromises = {};
668
+ const handleOpen = async () => {
669
+ if (state.__type !== "connecting") {
670
+ console.warn(`Expected adapter state to be \`connecting\` at the moment the websocket opens. Got \`${state.__type}\`.`);
671
+ return;
672
+ }
673
+ socket.removeEventListener("open", handleOpen);
674
+ const { associationKeypair } = state;
675
+ const ecdhKeypair = await generateECDHKeypair();
676
+ socket.send(await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
677
+ state = {
678
+ __type: "hello_req_sent",
679
+ associationPublicKey: associationKeypair.publicKey,
680
+ ecdhPrivateKey: ecdhKeypair.privateKey
681
+ };
682
+ };
683
+ const handleClose = (evt) => {
684
+ if (evt.wasClean) state = { __type: "disconnected" };
685
+ else reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session dropped unexpectedly (${evt.code}: ${evt.reason}).`, { closeEvent: evt }));
686
+ disposeSocket();
687
+ };
688
+ const handleError = async (_evt) => {
689
+ disposeSocket();
690
+ if (Date.now() - connectionStartTime >= WEBSOCKET_CONNECTION_CONFIG.timeoutMs) reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT, `Failed to connect to the wallet websocket at ${websocketURL}.`));
691
+ else {
692
+ await new Promise((resolve) => {
693
+ const retryDelayMs = getNextRetryDelayMs();
694
+ retryWaitTimeoutId = window.setTimeout(resolve, retryDelayMs);
695
+ });
696
+ attemptSocketConnection();
697
+ }
698
+ };
699
+ const handleMessage = async (evt) => {
700
+ const responseBuffer = await evt.data.arrayBuffer();
701
+ switch (state.__type) {
702
+ case "connecting": {
703
+ if (responseBuffer.byteLength !== 0) throw new Error("Encountered unexpected message while connecting");
704
+ const ecdhKeypair = await generateECDHKeypair();
705
+ socket.send(await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
706
+ state = {
707
+ __type: "hello_req_sent",
708
+ associationPublicKey: associationKeypair.publicKey,
709
+ ecdhPrivateKey: ecdhKeypair.privateKey
710
+ };
711
+ break;
712
+ }
713
+ case "connected":
714
+ try {
715
+ const sequenceNumber = getSequenceNumberFromByteArray(responseBuffer.slice(0, 4));
716
+ if (sequenceNumber !== lastKnownInboundSequenceNumber + 1) throw new Error("Encrypted message has invalid sequence number");
717
+ lastKnownInboundSequenceNumber = sequenceNumber;
718
+ const jsonRpcMessage = await decryptJsonRpcMessage(responseBuffer, state.sharedSecret);
719
+ const responsePromise = jsonRpcResponsePromises[jsonRpcMessage.id];
720
+ delete jsonRpcResponsePromises[jsonRpcMessage.id];
721
+ responsePromise.resolve(jsonRpcMessage.result);
722
+ } catch (e) {
723
+ if (e instanceof SolanaMobileWalletAdapterProtocolError) {
724
+ const responsePromise = jsonRpcResponsePromises[e.jsonRpcMessageId];
725
+ delete jsonRpcResponsePromises[e.jsonRpcMessageId];
726
+ responsePromise.reject(e);
727
+ } else throw e;
728
+ }
729
+ break;
730
+ case "hello_req_sent": {
731
+ if (responseBuffer.byteLength === 0) {
732
+ const ecdhKeypair = await generateECDHKeypair();
733
+ socket.send(await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey));
734
+ state = {
735
+ __type: "hello_req_sent",
736
+ associationPublicKey: associationKeypair.publicKey,
737
+ ecdhPrivateKey: ecdhKeypair.privateKey
738
+ };
739
+ break;
740
+ }
741
+ const sharedSecret = await parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
742
+ const sessionPropertiesBuffer = responseBuffer.slice(65);
743
+ const sessionProperties = sessionPropertiesBuffer.byteLength !== 0 ? await (async () => {
744
+ const sequenceNumber = getSequenceNumberFromByteArray(sessionPropertiesBuffer.slice(0, 4));
745
+ if (sequenceNumber !== lastKnownInboundSequenceNumber + 1) throw new Error("Encrypted message has invalid sequence number");
746
+ lastKnownInboundSequenceNumber = sequenceNumber;
747
+ return parseSessionProps(sessionPropertiesBuffer, sharedSecret);
748
+ })() : { protocol_version: "legacy" };
749
+ state = {
750
+ __type: "connected",
751
+ sharedSecret,
752
+ sessionProperties
753
+ };
754
+ const wallet = createMobileWalletProxy(sessionProperties.protocol_version, async (method, params) => {
755
+ const id = nextJsonRpcMessageId++;
756
+ socket.send(await encryptJsonRpcMessage({
757
+ id,
758
+ jsonrpc: "2.0",
759
+ method,
760
+ params: params ?? {}
761
+ }, sharedSecret));
762
+ return new Promise((resolve, reject) => {
763
+ jsonRpcResponsePromises[id] = {
764
+ resolve(result) {
765
+ switch (method) {
766
+ case "authorize":
767
+ case "reauthorize": {
768
+ const { wallet_uri_base } = result;
769
+ if (wallet_uri_base != null) try {
770
+ assertSecureEndpointSpecificURI(wallet_uri_base);
771
+ } catch (e) {
772
+ reject(e);
773
+ return;
774
+ }
775
+ break;
776
+ }
777
+ }
778
+ resolve(result);
779
+ },
780
+ reject
781
+ };
782
+ });
783
+ });
784
+ sessionEstablished = true;
785
+ try {
786
+ resolve(wallet);
787
+ } catch (e) {
788
+ reject(e);
789
+ }
790
+ break;
791
+ }
792
+ }
793
+ };
794
+ handleForceClose = () => {
795
+ socket.removeEventListener("message", handleMessage);
796
+ disposeSocket();
797
+ if (!sessionEstablished) reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session was closed before connection.`, { closeEvent: new CloseEvent("socket was closed before connection") }));
798
+ };
799
+ let disposeSocket;
800
+ let retryWaitTimeoutId;
801
+ const attemptSocketConnection = () => {
802
+ if (disposeSocket) disposeSocket();
803
+ state = {
804
+ __type: "connecting",
805
+ associationKeypair
806
+ };
807
+ if (connectionStartTime === void 0) connectionStartTime = Date.now();
808
+ socket = new WebSocket(websocketURL, [WEBSOCKET_PROTOCOL_BINARY]);
809
+ socket.addEventListener("open", handleOpen);
810
+ socket.addEventListener("close", handleClose);
811
+ socket.addEventListener("error", handleError);
812
+ socket.addEventListener("message", handleMessage);
813
+ disposeSocket = () => {
814
+ window.clearTimeout(retryWaitTimeoutId);
815
+ socket.removeEventListener("open", handleOpen);
816
+ socket.removeEventListener("close", handleClose);
817
+ socket.removeEventListener("error", handleError);
818
+ socket.removeEventListener("message", handleMessage);
819
+ };
820
+ };
821
+ attemptSocketConnection();
822
+ })
823
+ };
824
+ }
825
+ async function startRemoteScenario(config) {
826
+ assertSecureContext();
827
+ const associationKeypair = await generateAssociationKeypair();
828
+ const websocketURL = `wss://${config?.remoteHostAuthority}/reflect`;
829
+ let connectionStartTime;
830
+ const getNextRetryDelayMs = (() => {
831
+ const schedule = [...WEBSOCKET_CONNECTION_CONFIG.retryDelayScheduleMs];
832
+ return () => schedule.length > 1 ? schedule.shift() : schedule[0];
833
+ })();
834
+ let nextJsonRpcMessageId = 1;
835
+ let lastKnownInboundSequenceNumber = 0;
836
+ let encoding;
837
+ let state = { __type: "disconnected" };
838
+ let socket;
839
+ let disposeSocket;
840
+ const decodeBytes = async (evt) => {
841
+ if (encoding == "base64") return toUint8Array$1(await evt.data).buffer;
842
+ else return await evt.data.arrayBuffer();
843
+ };
844
+ const associationUrl = await new Promise((resolve, reject) => {
845
+ const handleOpen = async () => {
846
+ if (state.__type !== "connecting") {
847
+ console.warn(`Expected adapter state to be \`connecting\` at the moment the websocket opens. Got \`${state.__type}\`.`);
848
+ return;
849
+ }
850
+ if (socket.protocol.includes(WEBSOCKET_PROTOCOL_BASE64)) encoding = "base64";
851
+ else encoding = "binary";
852
+ socket.removeEventListener("open", handleOpen);
853
+ };
854
+ const handleClose = (evt) => {
855
+ if (evt.wasClean) state = { __type: "disconnected" };
856
+ else reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session dropped unexpectedly (${evt.code}: ${evt.reason}).`, { closeEvent: evt }));
857
+ disposeSocket();
858
+ };
859
+ const handleError = async (_evt) => {
860
+ disposeSocket();
861
+ if (Date.now() - connectionStartTime >= WEBSOCKET_CONNECTION_CONFIG.timeoutMs) reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_TIMEOUT, `Failed to connect to the wallet websocket at ${websocketURL}.`));
862
+ else {
863
+ await new Promise((resolve) => {
864
+ const retryDelayMs = getNextRetryDelayMs();
865
+ retryWaitTimeoutId = window.setTimeout(resolve, retryDelayMs);
866
+ });
867
+ attemptSocketConnection();
868
+ }
869
+ };
870
+ const handleReflectorIdMessage = async (evt) => {
871
+ const responseBuffer = await decodeBytes(evt);
872
+ if (state.__type === "connecting") {
873
+ if (responseBuffer.byteLength == 0) throw new Error("Encountered unexpected message while connecting");
874
+ const reflectorId = getReflectorIdFromByteArray(responseBuffer);
875
+ state = {
876
+ __type: "reflector_id_received",
877
+ reflectorId
878
+ };
879
+ const associationUrl = await getRemoteAssociateAndroidIntentURL(associationKeypair.publicKey, config.remoteHostAuthority, reflectorId, config?.baseUri);
880
+ socket.removeEventListener("message", handleReflectorIdMessage);
881
+ resolve(associationUrl);
882
+ }
883
+ };
884
+ let retryWaitTimeoutId;
885
+ const attemptSocketConnection = () => {
886
+ if (disposeSocket) disposeSocket();
887
+ state = {
888
+ __type: "connecting",
889
+ associationKeypair
890
+ };
891
+ if (connectionStartTime === void 0) connectionStartTime = Date.now();
892
+ socket = new WebSocket(websocketURL, [WEBSOCKET_PROTOCOL_BINARY, WEBSOCKET_PROTOCOL_BASE64]);
893
+ socket.addEventListener("open", handleOpen);
894
+ socket.addEventListener("close", handleClose);
895
+ socket.addEventListener("error", handleError);
896
+ socket.addEventListener("message", handleReflectorIdMessage);
897
+ disposeSocket = () => {
898
+ window.clearTimeout(retryWaitTimeoutId);
899
+ socket.removeEventListener("open", handleOpen);
900
+ socket.removeEventListener("close", handleClose);
901
+ socket.removeEventListener("error", handleError);
902
+ socket.removeEventListener("message", handleReflectorIdMessage);
903
+ };
904
+ };
905
+ attemptSocketConnection();
906
+ });
907
+ let sessionEstablished = false;
908
+ let handleClose;
909
+ return {
910
+ associationUrl,
911
+ close: () => {
912
+ socket.close();
913
+ handleClose();
914
+ },
915
+ wallet: new Promise((resolve, reject) => {
916
+ const jsonRpcResponsePromises = {};
917
+ const handleMessage = async (evt) => {
918
+ const responseBuffer = await decodeBytes(evt);
919
+ switch (state.__type) {
920
+ case "reflector_id_received": {
921
+ if (responseBuffer.byteLength !== 0) throw new Error("Encountered unexpected message while awaiting reflection");
922
+ const ecdhKeypair = await generateECDHKeypair();
923
+ const binaryMsg = await createHelloReq(ecdhKeypair.publicKey, associationKeypair.privateKey);
924
+ if (encoding == "base64") socket.send(fromUint8Array$1(binaryMsg));
925
+ else socket.send(binaryMsg);
926
+ state = {
927
+ __type: "hello_req_sent",
928
+ associationPublicKey: associationKeypair.publicKey,
929
+ ecdhPrivateKey: ecdhKeypair.privateKey
930
+ };
931
+ break;
932
+ }
933
+ case "connected":
934
+ try {
935
+ const sequenceNumber = getSequenceNumberFromByteArray(responseBuffer.slice(0, 4));
936
+ if (sequenceNumber !== lastKnownInboundSequenceNumber + 1) throw new Error("Encrypted message has invalid sequence number");
937
+ lastKnownInboundSequenceNumber = sequenceNumber;
938
+ const jsonRpcMessage = await decryptJsonRpcMessage(responseBuffer, state.sharedSecret);
939
+ const responsePromise = jsonRpcResponsePromises[jsonRpcMessage.id];
940
+ delete jsonRpcResponsePromises[jsonRpcMessage.id];
941
+ responsePromise.resolve(jsonRpcMessage.result);
942
+ } catch (e) {
943
+ if (e instanceof SolanaMobileWalletAdapterProtocolError) {
944
+ const responsePromise = jsonRpcResponsePromises[e.jsonRpcMessageId];
945
+ delete jsonRpcResponsePromises[e.jsonRpcMessageId];
946
+ responsePromise.reject(e);
947
+ } else throw e;
948
+ }
949
+ break;
950
+ case "hello_req_sent": {
951
+ const sharedSecret = await parseHelloRsp(responseBuffer, state.associationPublicKey, state.ecdhPrivateKey);
952
+ const sessionPropertiesBuffer = responseBuffer.slice(65);
953
+ const sessionProperties = sessionPropertiesBuffer.byteLength !== 0 ? await (async () => {
954
+ const sequenceNumber = getSequenceNumberFromByteArray(sessionPropertiesBuffer.slice(0, 4));
955
+ if (sequenceNumber !== lastKnownInboundSequenceNumber + 1) throw new Error("Encrypted message has invalid sequence number");
956
+ lastKnownInboundSequenceNumber = sequenceNumber;
957
+ return parseSessionProps(sessionPropertiesBuffer, sharedSecret);
958
+ })() : { protocol_version: "legacy" };
959
+ state = {
960
+ __type: "connected",
961
+ sharedSecret,
962
+ sessionProperties
963
+ };
964
+ const wallet = createMobileWalletProxy(sessionProperties.protocol_version, async (method, params) => {
965
+ const id = nextJsonRpcMessageId++;
966
+ const binaryMsg = await encryptJsonRpcMessage({
967
+ id,
968
+ jsonrpc: "2.0",
969
+ method,
970
+ params: params ?? {}
971
+ }, sharedSecret);
972
+ if (encoding == "base64") socket.send(fromUint8Array$1(binaryMsg));
973
+ else socket.send(binaryMsg);
974
+ return new Promise((resolve, reject) => {
975
+ jsonRpcResponsePromises[id] = {
976
+ resolve(result) {
977
+ switch (method) {
978
+ case "authorize":
979
+ case "reauthorize": {
980
+ const { wallet_uri_base } = result;
981
+ if (wallet_uri_base != null) try {
982
+ assertSecureEndpointSpecificURI(wallet_uri_base);
983
+ } catch (e) {
984
+ reject(e);
985
+ return;
986
+ }
987
+ break;
988
+ }
989
+ }
990
+ resolve(result);
991
+ },
992
+ reject
993
+ };
994
+ });
995
+ });
996
+ sessionEstablished = true;
997
+ try {
998
+ resolve(wallet);
999
+ } catch (e) {
1000
+ reject(e);
1001
+ }
1002
+ break;
1003
+ }
1004
+ }
1005
+ };
1006
+ socket.addEventListener("message", handleMessage);
1007
+ handleClose = () => {
1008
+ socket.removeEventListener("message", handleMessage);
1009
+ disposeSocket();
1010
+ if (!sessionEstablished) reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_SESSION_CLOSED, `The wallet session was closed before connection.`, { closeEvent: new CloseEvent("socket was closed before connection") }));
1011
+ };
1012
+ })
1013
+ };
1014
+ }
1015
+
25
1016
  /** Name of the feature. */
26
1017
  const StandardConnect = 'standard:connect';
27
1018
 
@@ -4128,12 +5119,12 @@ async function checkLocalNetworkAccessPermission() {
4128
5119
  const modal = new LoopbackPermissionBlockedModal();
4129
5120
  modal.init();
4130
5121
  modal.open();
4131
- throw new index_browser.SolanaMobileWalletAdapterError(index_browser.SolanaMobileWalletAdapterErrorCode.ERROR_LOOPBACK_ACCESS_BLOCKED, "Local Network Access permission denied");
5122
+ throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_LOOPBACK_ACCESS_BLOCKED, "Local Network Access permission denied");
4132
5123
  } else if (lnaPermission.state === "prompt") {
4133
5124
  const modal = new LoopbackPermissionModal();
4134
5125
  if (await new Promise((resolve, reject) => {
4135
5126
  modal.addEventListener("close", (event) => {
4136
- if (event) reject(new index_browser.SolanaMobileWalletAdapterError(index_browser.SolanaMobileWalletAdapterErrorCode.ERROR_ASSOCIATION_CANCELLED, "Wallet connection cancelled by user", { event }));
5127
+ if (event) reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_ASSOCIATION_CANCELLED, "Wallet connection cancelled by user", { event }));
4137
5128
  });
4138
5129
  lnaPermission.onchange = () => {
4139
5130
  lnaPermission.onchange = null;
@@ -4145,7 +5136,7 @@ async function checkLocalNetworkAccessPermission() {
4145
5136
  const modal = new LocalConnectionModal();
4146
5137
  await new Promise((resolve, reject) => {
4147
5138
  modal.addEventListener("close", (event) => {
4148
- if (event) reject(new index_browser.SolanaMobileWalletAdapterError(index_browser.SolanaMobileWalletAdapterErrorCode.ERROR_ASSOCIATION_CANCELLED, "Wallet connection cancelled by user", { event }));
5139
+ if (event) reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_ASSOCIATION_CANCELLED, "Wallet connection cancelled by user", { event }));
4149
5140
  });
4150
5141
  modal.initWithCallback(async () => {
4151
5142
  resolve(true);
@@ -4155,11 +5146,11 @@ async function checkLocalNetworkAccessPermission() {
4155
5146
  return;
4156
5147
  } else return await checkLocalNetworkAccessPermission();
4157
5148
  }
4158
- throw new index_browser.SolanaMobileWalletAdapterError(index_browser.SolanaMobileWalletAdapterErrorCode.ERROR_LOOPBACK_ACCESS_BLOCKED, "Local Network Access permission unknown");
5149
+ throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_LOOPBACK_ACCESS_BLOCKED, "Local Network Access permission unknown");
4159
5150
  } catch (e) {
4160
5151
  if (e instanceof TypeError && (e.message.includes("loopback-network") || e.message.includes("local-network-access"))) return;
4161
- if (e instanceof index_browser.SolanaMobileWalletAdapterError) throw e;
4162
- throw new index_browser.SolanaMobileWalletAdapterError(index_browser.SolanaMobileWalletAdapterErrorCode.ERROR_LOOPBACK_ACCESS_BLOCKED, e instanceof Error ? e.message : "Local Network Access permission unknown");
5152
+ if (e instanceof SolanaMobileWalletAdapterError) throw e;
5153
+ throw new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_LOOPBACK_ACCESS_BLOCKED, e instanceof Error ? e.message : "Local Network Access permission unknown");
4163
5154
  }
4164
5155
  }
4165
5156
  //#endregion
@@ -4394,7 +5385,7 @@ var LocalSolanaMobileWalletAdapterWallet = class {
4394
5385
  let timeout = void 0;
4395
5386
  const result = await Promise.race([checkLocalNetworkAccessPermission().then(async () => {
4396
5387
  loadingSpinner.init();
4397
- const { wallet, close } = await index_browser.startScenario(config);
5388
+ const { wallet, close } = await startScenario(config);
4398
5389
  associating = false;
4399
5390
  loadingSpinner.addEventListener("close", (event) => {
4400
5391
  if (event) close();
@@ -4406,7 +5397,7 @@ var LocalSolanaMobileWalletAdapterWallet = class {
4406
5397
  return result;
4407
5398
  }), new Promise((_, reject) => {
4408
5399
  timeout = setTimeout(() => {
4409
- if (associating) reject(new index_browser.SolanaMobileWalletAdapterError(index_browser.SolanaMobileWalletAdapterErrorCode.ERROR_ASSOCIATION_CANCELLED, "Wallet connection timed out", { event: void 0 }));
5400
+ if (associating) reject(new SolanaMobileWalletAdapterError(SolanaMobileWalletAdapterErrorCode.ERROR_ASSOCIATION_CANCELLED, "Wallet connection timed out", { event: void 0 }));
4410
5401
  }, WALLET_ASSOCIATION_TIMEOUT);
4411
5402
  })]);
4412
5403
  clearTimeout(timeout);
@@ -4752,7 +5743,7 @@ var RemoteSolanaMobileWalletAdapterWallet = class {
4752
5743
  try {
4753
5744
  modal.init();
4754
5745
  modal.open();
4755
- const { associationUrl, close, wallet } = await index_browser.startRemoteScenario(remoteConfig);
5746
+ const { associationUrl, close, wallet } = await startRemoteScenario(remoteConfig);
4756
5747
  const removeCloseListener = modal.addEventListener("close", (event) => {
4757
5748
  if (event) close();
4758
5749
  });
@@ -5076,4 +6067,4 @@ exports.createDefaultChainSelector = createDefaultChainSelector;
5076
6067
  exports.createDefaultWalletNotFoundHandler = createDefaultWalletNotFoundHandler;
5077
6068
  exports.defaultErrorModalWalletNotFoundHandler = defaultErrorModalWalletNotFoundHandler;
5078
6069
  exports.registerMwa = registerMwa;
5079
- //# sourceMappingURL=index.browser-C1QL04xM.js.map
6070
+ //# sourceMappingURL=index.browser-BJmFjY2f.js.map