@lydianpay/lydianconnect 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -13
- package/dist/index.cjs +766 -230
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -8
- package/dist/index.d.ts +46 -8
- package/dist/index.js +766 -230
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -66,6 +66,14 @@ var ConnectManager = class {
|
|
|
66
66
|
get(walletId) {
|
|
67
67
|
return this.connections.get(walletId);
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Fire a wallet's deep link. Goes straight to the fallback: it is the only
|
|
71
|
+
* connector that owns a link table, and the only one that emits the
|
|
72
|
+
* `display_uri` a host is responding to when it calls this.
|
|
73
|
+
*/
|
|
74
|
+
openWallet(input) {
|
|
75
|
+
return this.fallback.openWallet?.(input) ?? false;
|
|
76
|
+
}
|
|
69
77
|
async disconnect(walletId) {
|
|
70
78
|
if (walletId) {
|
|
71
79
|
await this.connections.get(walletId)?.disconnect().catch(() => {
|
|
@@ -73,7 +81,9 @@ var ConnectManager = class {
|
|
|
73
81
|
this.connections.delete(walletId);
|
|
74
82
|
return;
|
|
75
83
|
}
|
|
76
|
-
await Promise.allSettled(
|
|
84
|
+
await Promise.allSettled(
|
|
85
|
+
[...this.connections.values()].map((c) => c.disconnect())
|
|
86
|
+
);
|
|
77
87
|
this.connections.clear();
|
|
78
88
|
}
|
|
79
89
|
async reset() {
|
|
@@ -105,7 +115,11 @@ var NAMESPACE_DEFAULTS = {
|
|
|
105
115
|
events: ["chainChanged", "accountsChanged"]
|
|
106
116
|
},
|
|
107
117
|
solana: {
|
|
108
|
-
methods: [
|
|
118
|
+
methods: [
|
|
119
|
+
"solana_signTransaction",
|
|
120
|
+
"solana_signMessage",
|
|
121
|
+
"solana_signAndSendTransaction"
|
|
122
|
+
],
|
|
109
123
|
events: []
|
|
110
124
|
},
|
|
111
125
|
bip122: {
|
|
@@ -123,11 +137,17 @@ function buildNamespace(chainId) {
|
|
|
123
137
|
);
|
|
124
138
|
}
|
|
125
139
|
if (name === "eip155" && !(/^\d+$/.test(reference) && Number(reference) > 0)) {
|
|
126
|
-
throw new Error(
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Invalid eip155 chain "${caip}" \u2014 the reference must be a positive integer.`
|
|
142
|
+
);
|
|
127
143
|
}
|
|
128
144
|
return {
|
|
129
145
|
name,
|
|
130
|
-
value: {
|
|
146
|
+
value: {
|
|
147
|
+
chains: [caip],
|
|
148
|
+
methods: defaults.methods,
|
|
149
|
+
events: defaults.events
|
|
150
|
+
}
|
|
131
151
|
};
|
|
132
152
|
}
|
|
133
153
|
|
|
@@ -226,10 +246,15 @@ var WALLET_CATALOG = WALLETS.map((w) => ({
|
|
|
226
246
|
}));
|
|
227
247
|
|
|
228
248
|
// src/core/connector.ts
|
|
249
|
+
function requestedChain(req) {
|
|
250
|
+
return req.namespace.value.chains?.[0];
|
|
251
|
+
}
|
|
229
252
|
var BaseConnector = class {
|
|
230
253
|
constructor() {
|
|
231
254
|
this.walletIds = [];
|
|
232
255
|
this.handlers = /* @__PURE__ */ new Set();
|
|
256
|
+
/** Depth of in-flight connects; see {@link duringConnect}. */
|
|
257
|
+
this.connecting = 0;
|
|
233
258
|
}
|
|
234
259
|
servesNamespace(_namespaceName) {
|
|
235
260
|
return true;
|
|
@@ -243,7 +268,28 @@ var BaseConnector = class {
|
|
|
243
268
|
this.handlers.add(handler);
|
|
244
269
|
return () => this.handlers.delete(handler);
|
|
245
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* Run a connect with its handshake events suppressed.
|
|
273
|
+
*
|
|
274
|
+
* A connector that binds provider listeners before requesting accounts sees the
|
|
275
|
+
* wallet's own setup traffic — an initial `chainChanged`, and another when
|
|
276
|
+
* `ensureChain` switches. Forwarding those makes the host believe the user moved
|
|
277
|
+
* networks mid-connect. Nothing is lost by dropping them: connect() reads the
|
|
278
|
+
* authoritative account and chain when it settles, and only changes made after
|
|
279
|
+
* that are the user's.
|
|
280
|
+
*/
|
|
281
|
+
async duringConnect(run) {
|
|
282
|
+
this.connecting++;
|
|
283
|
+
try {
|
|
284
|
+
return await run();
|
|
285
|
+
} finally {
|
|
286
|
+
this.connecting--;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
246
289
|
emit(event) {
|
|
290
|
+
if (this.connecting > 0 && (event.type === "chainChanged" || event.type === "accountsChanged")) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
247
293
|
for (const handler of this.handlers) handler(event);
|
|
248
294
|
}
|
|
249
295
|
};
|
|
@@ -253,6 +299,80 @@ function deriveUrl() {
|
|
|
253
299
|
return typeof window !== "undefined" ? window.location.origin : "";
|
|
254
300
|
}
|
|
255
301
|
|
|
302
|
+
// src/connectors/eip155/chain.ts
|
|
303
|
+
var CHAIN_SETTLE = { timeoutMs: 4e3, intervalMs: 100 };
|
|
304
|
+
function toCaip(chainId) {
|
|
305
|
+
if (!chainId) return "eip155:1";
|
|
306
|
+
const num = chainId.startsWith("0x") ? parseInt(chainId, 16) : Number(chainId);
|
|
307
|
+
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
308
|
+
}
|
|
309
|
+
async function currentChain(rpc2) {
|
|
310
|
+
const raw = await rpc2({ method: "eth_chainId" }).catch(() => null);
|
|
311
|
+
return toCaip(typeof raw === "string" ? raw : null);
|
|
312
|
+
}
|
|
313
|
+
async function settleChain({
|
|
314
|
+
rpc: rpc2,
|
|
315
|
+
chainId,
|
|
316
|
+
timeoutMs,
|
|
317
|
+
intervalMs
|
|
318
|
+
}) {
|
|
319
|
+
const deadline = Date.now() + timeoutMs;
|
|
320
|
+
for (; ; ) {
|
|
321
|
+
const actual = await currentChain(rpc2);
|
|
322
|
+
if (actual === chainId || Date.now() >= deadline) return;
|
|
323
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
async function ensureChain({
|
|
327
|
+
rpc: rpc2,
|
|
328
|
+
chainId,
|
|
329
|
+
timeoutMs = CHAIN_SETTLE.timeoutMs,
|
|
330
|
+
intervalMs = CHAIN_SETTLE.intervalMs
|
|
331
|
+
}) {
|
|
332
|
+
const chainNumber = chainId ? Number(chainId.split(":")[1]) : NaN;
|
|
333
|
+
if (!Number.isFinite(chainNumber) || chainNumber <= 0) return;
|
|
334
|
+
const requested = `eip155:${chainNumber}`;
|
|
335
|
+
if (await currentChain(rpc2) === requested) return;
|
|
336
|
+
const switched = await rpc2({
|
|
337
|
+
method: "wallet_switchEthereumChain",
|
|
338
|
+
params: [{ chainId: `0x${chainNumber.toString(16)}` }]
|
|
339
|
+
}).then(
|
|
340
|
+
() => true,
|
|
341
|
+
// Chain not added to the wallet, or the user declined — the caller's
|
|
342
|
+
// chainChanged will reflect reality. No settle: the chain isn't moving.
|
|
343
|
+
() => false
|
|
344
|
+
);
|
|
345
|
+
if (switched) {
|
|
346
|
+
await settleChain({ rpc: rpc2, chainId: requested, timeoutMs, intervalMs });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/core/abort.ts
|
|
351
|
+
function withSignal(promise, signal, onAbort) {
|
|
352
|
+
if (!signal) return promise;
|
|
353
|
+
if (signal.aborted) {
|
|
354
|
+
onAbort?.();
|
|
355
|
+
return Promise.reject(new DOMException("Aborted", "AbortError"));
|
|
356
|
+
}
|
|
357
|
+
return new Promise((resolve, reject) => {
|
|
358
|
+
const abortHandler = () => {
|
|
359
|
+
onAbort?.();
|
|
360
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
361
|
+
};
|
|
362
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
363
|
+
promise.then(
|
|
364
|
+
(value) => {
|
|
365
|
+
signal.removeEventListener("abort", abortHandler);
|
|
366
|
+
resolve(value);
|
|
367
|
+
},
|
|
368
|
+
(error) => {
|
|
369
|
+
signal.removeEventListener("abort", abortHandler);
|
|
370
|
+
reject(error);
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
256
376
|
// src/connectors/metamask/connector.ts
|
|
257
377
|
var WALLET_ID = "metamask";
|
|
258
378
|
var MetaMaskConnector = class extends BaseConnector {
|
|
@@ -292,23 +412,41 @@ var MetaMaskConnector = class extends BaseConnector {
|
|
|
292
412
|
if (this.listenersBound) return;
|
|
293
413
|
this.listenersBound = true;
|
|
294
414
|
provider.on("chainChanged", (hex) => {
|
|
295
|
-
this.emit({
|
|
415
|
+
this.emit({
|
|
416
|
+
type: "chainChanged",
|
|
417
|
+
walletId: WALLET_ID,
|
|
418
|
+
chainId: toCaip(String(hex))
|
|
419
|
+
});
|
|
296
420
|
});
|
|
297
421
|
provider.on("accountsChanged", (accounts) => {
|
|
298
422
|
const account = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
299
|
-
if (account)
|
|
423
|
+
if (account)
|
|
424
|
+
this.emit({ type: "accountsChanged", walletId: WALLET_ID, account });
|
|
300
425
|
else this.emit({ type: "disconnect", walletId: WALLET_ID });
|
|
301
426
|
});
|
|
302
|
-
provider.on(
|
|
427
|
+
provider.on(
|
|
428
|
+
"disconnect",
|
|
429
|
+
() => this.emit({ type: "disconnect", walletId: WALLET_ID })
|
|
430
|
+
);
|
|
303
431
|
}
|
|
304
432
|
async connect(req) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
433
|
+
return this.duringConnect(async () => {
|
|
434
|
+
const provider = await this.getProvider();
|
|
435
|
+
const accounts = await withSignal(
|
|
436
|
+
provider.request({ method: "eth_requestAccounts" }),
|
|
437
|
+
req.signal
|
|
438
|
+
);
|
|
439
|
+
const account = accounts?.[0];
|
|
440
|
+
if (!account) throw new Error("MetaMask returned no account");
|
|
441
|
+
await ensureChain({
|
|
442
|
+
rpc: rpcFor(provider),
|
|
443
|
+
chainId: requestedChain(req)
|
|
444
|
+
});
|
|
445
|
+
const chainId = toCaip(
|
|
446
|
+
await provider.request({ method: "eth_chainId" })
|
|
447
|
+
);
|
|
448
|
+
return this.toConnection(provider, account, chainId);
|
|
449
|
+
});
|
|
312
450
|
}
|
|
313
451
|
async restore() {
|
|
314
452
|
const provider = await this.getProvider().catch(() => null);
|
|
@@ -326,28 +464,15 @@ var MetaMaskConnector = class extends BaseConnector {
|
|
|
326
464
|
this.provider = null;
|
|
327
465
|
this.listenersBound = false;
|
|
328
466
|
}
|
|
329
|
-
/** Best-effort switch to the requested chain; leaves the wallet as-is if it's unknown to it. */
|
|
330
|
-
async ensureChain(provider, req) {
|
|
331
|
-
const wanted = req.namespace.value.chains?.[0];
|
|
332
|
-
const wantedNum = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
333
|
-
if (!Number.isFinite(wantedNum) || wantedNum <= 0) return;
|
|
334
|
-
const current = parseInt(
|
|
335
|
-
await provider.request({ method: "eth_chainId" }).catch(() => "0x0") ?? "0x0",
|
|
336
|
-
16
|
|
337
|
-
);
|
|
338
|
-
if (current === wantedNum) return;
|
|
339
|
-
await provider.request({
|
|
340
|
-
method: "wallet_switchEthereumChain",
|
|
341
|
-
params: [{ chainId: `0x${wantedNum.toString(16)}` }]
|
|
342
|
-
}).catch(() => {
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
467
|
toConnection(provider, account, chainId) {
|
|
346
468
|
return {
|
|
347
469
|
walletId: WALLET_ID,
|
|
348
470
|
account,
|
|
349
471
|
chainId,
|
|
350
|
-
request: async (args) => await provider.request({
|
|
472
|
+
request: async (args) => await provider.request({
|
|
473
|
+
method: args.method,
|
|
474
|
+
params: args.params
|
|
475
|
+
}),
|
|
351
476
|
openWallet: () => {
|
|
352
477
|
},
|
|
353
478
|
// MetaMask SDK foregrounds the wallet on request
|
|
@@ -360,17 +485,18 @@ var MetaMaskConnector = class extends BaseConnector {
|
|
|
360
485
|
};
|
|
361
486
|
}
|
|
362
487
|
};
|
|
363
|
-
function
|
|
364
|
-
|
|
365
|
-
const num = hexChainId.startsWith("0x") ? parseInt(hexChainId, 16) : Number(hexChainId);
|
|
366
|
-
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
488
|
+
function rpcFor(provider) {
|
|
489
|
+
return (args) => provider.request(args);
|
|
367
490
|
}
|
|
368
491
|
|
|
369
492
|
// src/connectors/coinbase/connector.ts
|
|
493
|
+
var WALLET_ID2 = "coinbase";
|
|
370
494
|
function rpc(provider, method, params) {
|
|
371
|
-
return provider.request({
|
|
495
|
+
return provider.request({
|
|
496
|
+
method,
|
|
497
|
+
params
|
|
498
|
+
});
|
|
372
499
|
}
|
|
373
|
-
var WALLET_ID2 = "coinbase";
|
|
374
500
|
var CoinbaseConnector = class extends BaseConnector {
|
|
375
501
|
constructor(app) {
|
|
376
502
|
super();
|
|
@@ -404,31 +530,48 @@ var CoinbaseConnector = class extends BaseConnector {
|
|
|
404
530
|
if (this.listenersBound) return;
|
|
405
531
|
this.listenersBound = true;
|
|
406
532
|
provider.on("chainChanged", (hex) => {
|
|
407
|
-
this.emit({
|
|
533
|
+
this.emit({
|
|
534
|
+
type: "chainChanged",
|
|
535
|
+
walletId: WALLET_ID2,
|
|
536
|
+
chainId: toCaip(String(hex))
|
|
537
|
+
});
|
|
408
538
|
});
|
|
409
539
|
provider.on("accountsChanged", (accounts) => {
|
|
410
540
|
const account = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
411
|
-
if (account)
|
|
541
|
+
if (account)
|
|
542
|
+
this.emit({ type: "accountsChanged", walletId: WALLET_ID2, account });
|
|
412
543
|
else this.emit({ type: "disconnect", walletId: WALLET_ID2 });
|
|
413
544
|
});
|
|
414
|
-
provider.on(
|
|
545
|
+
provider.on(
|
|
546
|
+
"disconnect",
|
|
547
|
+
() => this.emit({ type: "disconnect", walletId: WALLET_ID2 })
|
|
548
|
+
);
|
|
415
549
|
}
|
|
416
550
|
async connect(req) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
551
|
+
return this.duringConnect(async () => {
|
|
552
|
+
const provider = await this.getProvider(evmChainIds(req));
|
|
553
|
+
const accounts = await rpc(provider, "eth_requestAccounts");
|
|
554
|
+
const account = accounts?.[0];
|
|
555
|
+
if (!account) throw new Error("Coinbase Wallet returned no account");
|
|
556
|
+
await ensureChain({
|
|
557
|
+
rpc: rpcFor2(provider),
|
|
558
|
+
chainId: requestedChain(req)
|
|
559
|
+
});
|
|
560
|
+
const chainId = toCaip(await rpc(provider, "eth_chainId"));
|
|
561
|
+
return this.toConnection(provider, account, chainId);
|
|
562
|
+
});
|
|
424
563
|
}
|
|
425
564
|
async restore() {
|
|
426
565
|
const provider = await this.getProvider().catch(() => null);
|
|
427
566
|
if (!provider) return [];
|
|
428
|
-
const accounts = await rpc(provider, "eth_accounts").catch(
|
|
567
|
+
const accounts = await rpc(provider, "eth_accounts").catch(
|
|
568
|
+
() => []
|
|
569
|
+
);
|
|
429
570
|
const account = accounts?.[0];
|
|
430
571
|
if (!account) return [];
|
|
431
|
-
const chainId =
|
|
572
|
+
const chainId = toCaip(
|
|
573
|
+
await rpc(provider, "eth_chainId").catch(() => "0x1")
|
|
574
|
+
);
|
|
432
575
|
return [this.toConnection(provider, account, chainId)];
|
|
433
576
|
}
|
|
434
577
|
async reset() {
|
|
@@ -437,20 +580,6 @@ var CoinbaseConnector = class extends BaseConnector {
|
|
|
437
580
|
this.provider = null;
|
|
438
581
|
this.listenersBound = false;
|
|
439
582
|
}
|
|
440
|
-
async ensureChain(provider, req) {
|
|
441
|
-
const wanted = req.namespace.value.chains?.[0];
|
|
442
|
-
const wantedNum = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
443
|
-
if (!Number.isFinite(wantedNum) || wantedNum <= 0) return;
|
|
444
|
-
const current = parseInt(
|
|
445
|
-
await rpc(provider, "eth_chainId").catch(() => "0x0") ?? "0x0",
|
|
446
|
-
16
|
|
447
|
-
);
|
|
448
|
-
if (current === wantedNum) return;
|
|
449
|
-
await rpc(provider, "wallet_switchEthereumChain", [{ chainId: `0x${wantedNum.toString(16)}` }]).catch(
|
|
450
|
-
() => {
|
|
451
|
-
}
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
583
|
toConnection(provider, account, chainId) {
|
|
455
584
|
return {
|
|
456
585
|
walletId: WALLET_ID2,
|
|
@@ -470,10 +599,8 @@ var CoinbaseConnector = class extends BaseConnector {
|
|
|
470
599
|
};
|
|
471
600
|
}
|
|
472
601
|
};
|
|
473
|
-
function
|
|
474
|
-
|
|
475
|
-
const num = hexChainId.startsWith("0x") ? parseInt(hexChainId, 16) : Number(hexChainId);
|
|
476
|
-
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
602
|
+
function rpcFor2(provider) {
|
|
603
|
+
return ({ method, params }) => rpc(provider, method, params);
|
|
477
604
|
}
|
|
478
605
|
function evmChainIds(req) {
|
|
479
606
|
const wanted = req.namespace.value.chains?.[0];
|
|
@@ -507,7 +634,8 @@ var InjectedConnector = class extends BaseConnector {
|
|
|
507
634
|
this.listening = true;
|
|
508
635
|
window.addEventListener("eip6963:announceProvider", (event) => {
|
|
509
636
|
const detail = event.detail;
|
|
510
|
-
if (detail?.info?.rdns && detail.provider)
|
|
637
|
+
if (detail?.info?.rdns && detail.provider)
|
|
638
|
+
this.discovered.set(detail.info.rdns, detail);
|
|
511
639
|
});
|
|
512
640
|
window.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
513
641
|
}
|
|
@@ -526,16 +654,20 @@ var InjectedConnector = class extends BaseConnector {
|
|
|
526
654
|
}
|
|
527
655
|
async connect(req) {
|
|
528
656
|
const provider = this.providerFor(req.walletId);
|
|
529
|
-
if (!provider)
|
|
657
|
+
if (!provider)
|
|
658
|
+
throw new Error(`No injected provider announced for "${req.walletId}"`);
|
|
530
659
|
const accounts = await withSignal(
|
|
531
660
|
provider.request({ method: "eth_requestAccounts" }),
|
|
532
661
|
// triggers the extension popup
|
|
533
662
|
req.signal
|
|
534
663
|
);
|
|
535
664
|
const account = accounts?.[0];
|
|
536
|
-
if (!account)
|
|
537
|
-
|
|
538
|
-
|
|
665
|
+
if (!account)
|
|
666
|
+
throw new Error(`${req.walletId} extension returned no account`);
|
|
667
|
+
await ensureChain({ rpc: rpcFor3(provider), chainId: requestedChain(req) });
|
|
668
|
+
const chainId = toCaip(
|
|
669
|
+
await provider.request({ method: "eth_chainId" })
|
|
670
|
+
);
|
|
539
671
|
this.bindEvents(provider, req.walletId);
|
|
540
672
|
return this.toConnection(provider, req.walletId, account, chainId);
|
|
541
673
|
}
|
|
@@ -552,7 +684,7 @@ var InjectedConnector = class extends BaseConnector {
|
|
|
552
684
|
const accounts = await provider.request({ method: "eth_accounts" }).catch(() => []);
|
|
553
685
|
const account = accounts?.[0];
|
|
554
686
|
if (!account) continue;
|
|
555
|
-
const chainId =
|
|
687
|
+
const chainId = toCaip(
|
|
556
688
|
await provider.request({ method: "eth_chainId" }).catch(() => "0x1")
|
|
557
689
|
);
|
|
558
690
|
this.bindEvents(provider, walletId);
|
|
@@ -568,133 +700,480 @@ var InjectedConnector = class extends BaseConnector {
|
|
|
568
700
|
if (this.bound.has(provider)) return;
|
|
569
701
|
this.bound.add(provider);
|
|
570
702
|
provider.on("chainChanged", (hex) => {
|
|
571
|
-
this.emit({
|
|
703
|
+
this.emit({
|
|
704
|
+
type: "chainChanged",
|
|
705
|
+
walletId,
|
|
706
|
+
chainId: toCaip(String(hex))
|
|
707
|
+
});
|
|
572
708
|
});
|
|
573
709
|
provider.on("accountsChanged", (accounts) => {
|
|
574
710
|
const account = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
575
711
|
if (account) this.emit({ type: "accountsChanged", walletId, account });
|
|
576
712
|
else this.emit({ type: "disconnect", walletId });
|
|
577
713
|
});
|
|
578
|
-
provider.on(
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
async ensureChain(provider, req) {
|
|
582
|
-
const wanted = req.namespace.value.chains?.[0];
|
|
583
|
-
const wantedNum = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
584
|
-
if (!Number.isFinite(wantedNum) || wantedNum <= 0) return;
|
|
585
|
-
const current = parseInt(
|
|
586
|
-
await provider.request({ method: "eth_chainId" }).catch(() => "0x0") ?? "0x0",
|
|
587
|
-
16
|
|
714
|
+
provider.on(
|
|
715
|
+
"disconnect",
|
|
716
|
+
() => this.emit({ type: "disconnect", walletId })
|
|
588
717
|
);
|
|
589
|
-
if (current === wantedNum) return;
|
|
590
|
-
await provider.request({
|
|
591
|
-
method: "wallet_switchEthereumChain",
|
|
592
|
-
params: [{ chainId: `0x${wantedNum.toString(16)}` }]
|
|
593
|
-
}).catch(() => {
|
|
594
|
-
});
|
|
595
718
|
}
|
|
596
719
|
toConnection(provider, walletId, account, chainId) {
|
|
597
720
|
return {
|
|
598
721
|
walletId,
|
|
599
722
|
account,
|
|
600
723
|
chainId,
|
|
601
|
-
request: async (args) => await provider.request({
|
|
724
|
+
request: async (args) => await provider.request({
|
|
725
|
+
method: args.method,
|
|
726
|
+
params: args.params
|
|
727
|
+
}),
|
|
602
728
|
openWallet: () => {
|
|
603
729
|
},
|
|
604
730
|
// the extension foregrounds its own popup on request
|
|
605
731
|
disconnect: async () => {
|
|
606
|
-
await provider.request({
|
|
732
|
+
await provider.request({
|
|
733
|
+
method: "wallet_revokePermissions",
|
|
734
|
+
params: [{ eth_accounts: {} }]
|
|
735
|
+
}).catch(() => {
|
|
607
736
|
});
|
|
608
737
|
this.emit({ type: "disconnect", walletId });
|
|
609
738
|
}
|
|
610
739
|
};
|
|
611
740
|
}
|
|
612
741
|
};
|
|
613
|
-
function
|
|
614
|
-
|
|
615
|
-
const num = hexChainId.startsWith("0x") ? parseInt(hexChainId, 16) : Number(hexChainId);
|
|
616
|
-
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
617
|
-
}
|
|
618
|
-
function withSignal(promise, signal) {
|
|
619
|
-
if (!signal) return promise;
|
|
620
|
-
if (signal.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
|
|
621
|
-
return new Promise((resolve, reject) => {
|
|
622
|
-
const onAbort = () => reject(new DOMException("Aborted", "AbortError"));
|
|
623
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
624
|
-
promise.then(
|
|
625
|
-
(value) => {
|
|
626
|
-
signal.removeEventListener("abort", onAbort);
|
|
627
|
-
resolve(value);
|
|
628
|
-
},
|
|
629
|
-
(error) => {
|
|
630
|
-
signal.removeEventListener("abort", onAbort);
|
|
631
|
-
reject(error);
|
|
632
|
-
}
|
|
633
|
-
);
|
|
634
|
-
});
|
|
742
|
+
function rpcFor3(provider) {
|
|
743
|
+
return (args) => provider.request(args);
|
|
635
744
|
}
|
|
636
745
|
|
|
637
746
|
// src/connectors/walletconnect/wallet-links.ts
|
|
638
747
|
var WALLET_LINKS = {
|
|
639
|
-
metamask: {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
748
|
+
metamask: {
|
|
749
|
+
native: "metamask://",
|
|
750
|
+
scheme: "metamask://wc",
|
|
751
|
+
universal: "https://metamask.app.link/wc",
|
|
752
|
+
store: {
|
|
753
|
+
ios: "https://apps.apple.com/us/app/metamask/id1438144202",
|
|
754
|
+
android: "https://play.google.com/store/apps/details?id=io.metamask"
|
|
755
|
+
}
|
|
756
|
+
},
|
|
757
|
+
trust: {
|
|
758
|
+
native: "trust://",
|
|
759
|
+
scheme: "trust://wc",
|
|
760
|
+
universal: "https://link.trustwallet.com/wc",
|
|
761
|
+
store: {
|
|
762
|
+
ios: "https://apps.apple.com/app/apple-store/id1288339409",
|
|
763
|
+
android: "https://play.google.com/store/apps/details?id=com.wallet.crypto.trustapp"
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
rainbow: {
|
|
767
|
+
native: "rainbow://",
|
|
768
|
+
scheme: "rainbow://wc",
|
|
769
|
+
universal: "https://rnbwapp.com/wc",
|
|
770
|
+
store: {
|
|
771
|
+
ios: "https://apps.apple.com/app/apple-store/id1457119021?pt=119997837&ct=wc&mt=8",
|
|
772
|
+
android: "https://play.google.com/store/apps/details?id=me.rainbow&referrer=utm_source%3Dwc%26utm_medium%3Dconnector%26utm_campaign%3Dwc"
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
coinbase: {
|
|
776
|
+
store: {
|
|
777
|
+
ios: "https://apps.apple.com/us/app/base-formerly-coinbase-wallet/id1278383455"
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
zerion: {
|
|
781
|
+
native: "zerion://",
|
|
782
|
+
scheme: "zerion://wc",
|
|
783
|
+
universal: "https://wallet.zerion.io/wc/wc",
|
|
784
|
+
store: {
|
|
785
|
+
ios: "https://apps.apple.com/app/id1456732565",
|
|
786
|
+
android: "https://play.google.com/store/apps/details?id=io.zerion.android&hl=en&gl=US"
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
tokenpocket: {
|
|
790
|
+
native: "tpoutside://",
|
|
791
|
+
scheme: "tpoutside://wc",
|
|
792
|
+
store: {
|
|
793
|
+
ios: "https://apps.apple.com/us/app/tp-wallet/id6444625622?l=en",
|
|
794
|
+
android: "https://play.google.com/store/apps/details?id=vip.mytokenpocket"
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
blockchaincom: {
|
|
798
|
+
native: "blockchain-wallet://",
|
|
799
|
+
scheme: "blockchain-wallet://wc",
|
|
800
|
+
universal: "https://login.blockchain.com/app/wc",
|
|
801
|
+
store: {
|
|
802
|
+
ios: "https://apps.apple.com/us/app/blockchain-bitcoin-wallet/id493253309",
|
|
803
|
+
android: "https://play.google.com/store/apps/details?id=piuk.blockchain.android"
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
exodus: {
|
|
807
|
+
native: "exodus://",
|
|
808
|
+
scheme: "exodus://wc",
|
|
809
|
+
universal: "https://exodus.com/m/wc",
|
|
810
|
+
store: {
|
|
811
|
+
ios: "https://apps.apple.com/us/app/exodus-crypto-bitcoin-wallet/id1414384820",
|
|
812
|
+
android: "https://play.google.com/store/apps/details?id=exodusmovement.exodus&hl=en&gl=US"
|
|
813
|
+
}
|
|
814
|
+
},
|
|
815
|
+
phantom: {
|
|
816
|
+
store: {
|
|
817
|
+
ios: "https://apps.apple.com/us/app/phantom-crypto-wallet/id1598432977",
|
|
818
|
+
android: "https://play.google.com/store/apps/details?id=app.phantom&hl=en"
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
okx: {
|
|
822
|
+
native: "okxwallet://main",
|
|
823
|
+
scheme: "okxwallet://main/wc",
|
|
824
|
+
store: {
|
|
825
|
+
ios: "https://apps.apple.com/us/app/okx-buy-bitcoin-eth-crypto/id1327268470",
|
|
826
|
+
android: "https://play.google.com/store/apps/details?id=com.okinc.okex.gp"
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
cryptocom: {
|
|
830
|
+
native: "cryptowallet://",
|
|
831
|
+
scheme: "cryptowallet://wc",
|
|
832
|
+
store: {
|
|
833
|
+
ios: "https://apps.apple.com/US/app/id1512048310?mt=8",
|
|
834
|
+
android: "https://play.google.com/store/apps/details?id=com.defi.wallet"
|
|
835
|
+
}
|
|
836
|
+
},
|
|
837
|
+
argent: {
|
|
838
|
+
native: "argent://app/",
|
|
839
|
+
scheme: "argent://app/wc",
|
|
840
|
+
universal: "https://www.argent.xyz/app/wc",
|
|
841
|
+
store: {
|
|
842
|
+
ios: "https://apps.apple.com/us/app/argent-defi-in-a-tap/id1358741926",
|
|
843
|
+
android: "https://play.google.com/store/apps/details?id=im.argent.contractwalletclient&hl=en&gl=US&pli=1"
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
safepal: {
|
|
847
|
+
native: "safepalwallet://",
|
|
848
|
+
scheme: "safepalwallet://wc",
|
|
849
|
+
universal: "https://link.safepal.io/wc",
|
|
850
|
+
store: {
|
|
851
|
+
ios: "https://apps.apple.com/app/safepal-wallet/id1548297139",
|
|
852
|
+
android: "https://play.google.com/store/apps/details?id=io.safepal.wallet"
|
|
853
|
+
}
|
|
854
|
+
},
|
|
855
|
+
imtoken: {
|
|
856
|
+
native: "imtokenv2://",
|
|
857
|
+
scheme: "imtokenv2://wc",
|
|
858
|
+
store: {
|
|
859
|
+
ios: "https://apps.apple.com/us/app/imtoken2/id1384798940",
|
|
860
|
+
android: "https://play.google.com/store/apps/details?id=im.token.app"
|
|
861
|
+
}
|
|
862
|
+
},
|
|
863
|
+
ronin: {
|
|
864
|
+
native: "roninwallet://",
|
|
865
|
+
scheme: "roninwallet://wc",
|
|
866
|
+
universal: "https://wallet.roninchain.com/wc",
|
|
867
|
+
store: {
|
|
868
|
+
ios: "https://apps.apple.com/us/app/ronin-wallet/id1592675001",
|
|
869
|
+
android: "https://play.google.com/store/apps/details?id=com.skymavis.genesis"
|
|
870
|
+
}
|
|
871
|
+
},
|
|
872
|
+
coin98: {
|
|
873
|
+
native: "coin98://",
|
|
874
|
+
scheme: "coin98://wc",
|
|
875
|
+
universal: "https://coin98.com/wc",
|
|
876
|
+
store: {
|
|
877
|
+
ios: "https://apps.apple.com/vn/app/coin98-wallet/id1561969966",
|
|
878
|
+
android: "https://play.google.com/store/apps/details?id=coin98.crypto.finance.media&hl=vi&gl=US"
|
|
879
|
+
}
|
|
880
|
+
},
|
|
881
|
+
bitkeep: {
|
|
882
|
+
native: "bitkeep://",
|
|
883
|
+
scheme: "bitkeep://wc",
|
|
884
|
+
universal: "https://bkapp.vip/wc",
|
|
885
|
+
store: {
|
|
886
|
+
ios: "https://web3.bitget.com/en/wallet-download?type=0",
|
|
887
|
+
android: "https://web3.bitget.com/en/wallet-download?type=0"
|
|
888
|
+
}
|
|
889
|
+
},
|
|
890
|
+
"1inch": {
|
|
891
|
+
native: "oneinch://open/nobodywilleveruseit",
|
|
892
|
+
scheme: "oneinch://open/nobodywilleveruseit/wc",
|
|
893
|
+
universal: "https://wallet.1inch.io/app/nobodywilleveruseit/wc",
|
|
894
|
+
store: {
|
|
895
|
+
ios: "https://apps.apple.com/us/app/1inch-defi-wallet/id1546049391",
|
|
896
|
+
android: "https://play.google.com/store/apps/details?id=io.oneinch.android"
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
ledgerlive: {
|
|
900
|
+
native: "ledgerlive://",
|
|
901
|
+
scheme: "ledgerlive://wc",
|
|
902
|
+
store: {
|
|
903
|
+
ios: "https://itunes.apple.com/app/id1361671700",
|
|
904
|
+
android: "https://play.google.com/store/apps/details?id=com.ledger.live"
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
atomic: {
|
|
908
|
+
native: "atomicwallet://",
|
|
909
|
+
scheme: "atomicwallet://wc",
|
|
910
|
+
store: {
|
|
911
|
+
ios: "https://apps.apple.com/us/app/atomic-wallet/id1478257827",
|
|
912
|
+
android: "https://play.google.com/store/apps/details?id=io.atomicwallet"
|
|
913
|
+
}
|
|
914
|
+
},
|
|
915
|
+
alpha: {
|
|
916
|
+
native: "awallet://",
|
|
917
|
+
scheme: "awallet://wc",
|
|
918
|
+
universal: "https://aw.app/wc",
|
|
919
|
+
store: {
|
|
920
|
+
ios: "https://apps.apple.com/us/app/alphawallet-eth-wallet/id1358230430",
|
|
921
|
+
android: "https://play.google.com/store/apps/details?id=io.stormbird.wallet"
|
|
922
|
+
}
|
|
923
|
+
},
|
|
924
|
+
math: {
|
|
925
|
+
native: "mathwallet://",
|
|
926
|
+
scheme: "mathwallet://wc",
|
|
927
|
+
universal: "https://www.mathwallet.org/wc",
|
|
928
|
+
store: {
|
|
929
|
+
ios: "https://apps.apple.com/us/app/mathwallet5/id1582612388",
|
|
930
|
+
android: "https://play.google.com/store/apps/details?id=com.mathwallet.android"
|
|
931
|
+
}
|
|
932
|
+
},
|
|
933
|
+
bitpay: {
|
|
934
|
+
native: "bitpay://",
|
|
935
|
+
scheme: "bitpay://wc",
|
|
936
|
+
universal: "https://link.bitpay.com/wc",
|
|
937
|
+
store: {
|
|
938
|
+
ios: "https://bitpay.onelink.me/Cenw/ejjaw7bs",
|
|
939
|
+
android: "https://bitpay.onelink.me/Cenw/ejjaw7bs"
|
|
940
|
+
}
|
|
941
|
+
},
|
|
942
|
+
rabby: {
|
|
943
|
+
native: "rabby://",
|
|
944
|
+
scheme: "rabby://wc",
|
|
945
|
+
store: {
|
|
946
|
+
ios: "https://apps.apple.com/us/app/rabby-wallet-crypto-evm/id6474381673",
|
|
947
|
+
android: "https://play.google.com/store/apps/details?id=com.debank.rabbymobile"
|
|
948
|
+
}
|
|
949
|
+
},
|
|
663
950
|
// Bybit's WC deep link nests the uri inside a targetUrl wrapper (bybitapp://open/route?targetUrl=by://web3/walletconnect/wc?uri=...), which the `${scheme}?uri=` builder can't express — QR/scan connect only.
|
|
664
|
-
bybit: {
|
|
665
|
-
|
|
666
|
-
|
|
951
|
+
bybit: {
|
|
952
|
+
store: {
|
|
953
|
+
ios: "https://apps.apple.com/us/app/bybit-buy-trade-crypto/id1488296980",
|
|
954
|
+
android: "https://play.google.com/store/apps/details?id=com.bybit.app"
|
|
955
|
+
}
|
|
956
|
+
},
|
|
957
|
+
binance: {
|
|
958
|
+
native: "bnc://app.binance.com/cedefi/",
|
|
959
|
+
scheme: "bnc://app.binance.com/cedefi/wc",
|
|
960
|
+
store: {
|
|
961
|
+
ios: "https://apps.apple.com/us/app/id1436799971",
|
|
962
|
+
android: "https://play.google.com/store/apps/details?id=com.binance.dev"
|
|
963
|
+
}
|
|
964
|
+
},
|
|
965
|
+
gate: {
|
|
966
|
+
native: "gtweb3wallet://",
|
|
967
|
+
scheme: "gtweb3wallet://wc",
|
|
968
|
+
store: {
|
|
969
|
+
ios: "https://apps.apple.com/us/app/gate-io-buy-bitcoin-crypto/id1294998195",
|
|
970
|
+
android: "https://play.google.com/store/apps/details?id=com.gateio.gateio"
|
|
971
|
+
}
|
|
972
|
+
},
|
|
667
973
|
// Core: `core://` scheme not corroborated to 2 sources — QR/scan connect only.
|
|
668
|
-
core: {
|
|
974
|
+
core: {
|
|
975
|
+
store: {
|
|
976
|
+
ios: "https://apps.apple.com/us/app/core-wallet/id6443685999",
|
|
977
|
+
android: "https://play.google.com/store/apps/details?id=com.avaxwallet"
|
|
978
|
+
}
|
|
979
|
+
},
|
|
669
980
|
// Backpack: `backpack://` scheme not corroborated to 2 sources — QR/scan connect only.
|
|
670
|
-
backpack: {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
981
|
+
backpack: {
|
|
982
|
+
store: {
|
|
983
|
+
ios: "https://apps.apple.com/us/app/backpack-wallet-exchange/id6445964121",
|
|
984
|
+
android: "https://play.google.com/store/apps/details?id=app.backpack.mobile"
|
|
985
|
+
}
|
|
986
|
+
},
|
|
987
|
+
frontier: {
|
|
988
|
+
native: "frontier://",
|
|
989
|
+
scheme: "frontier://wc",
|
|
990
|
+
store: {
|
|
991
|
+
ios: "https://apps.apple.com/us/app/frontier-crypto-defi-wallet/id1482380988",
|
|
992
|
+
android: "https://play.google.com/store/apps/details?id=com.frontierwallet"
|
|
993
|
+
}
|
|
994
|
+
},
|
|
995
|
+
onekey: {
|
|
996
|
+
native: "onekey-wallet://",
|
|
997
|
+
scheme: "onekey-wallet://wc",
|
|
998
|
+
store: {
|
|
999
|
+
ios: "https://apps.apple.com/us/app/onekey-open-source-wallet/id1609559473",
|
|
1000
|
+
android: "https://play.google.com/store/apps/details?id=so.onekey.app.wallet"
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
kraken: {
|
|
1004
|
+
native: "krakenwallet://",
|
|
1005
|
+
scheme: "krakenwallet://wc",
|
|
1006
|
+
store: {
|
|
1007
|
+
ios: "https://apps.apple.com/us/app/kraken-wallet/id1626327149",
|
|
1008
|
+
android: "https://play.google.com/store/apps/details?id=com.kraken.superwallet"
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
1011
|
+
uniswap: {
|
|
1012
|
+
native: "uniswap://",
|
|
1013
|
+
scheme: "uniswap://wc",
|
|
1014
|
+
store: {
|
|
1015
|
+
ios: "https://apps.apple.com/us/app/uniswap-crypto-nft-wallet/id6443944476",
|
|
1016
|
+
android: "https://play.google.com/store/apps/details?id=com.uniswap.mobile"
|
|
1017
|
+
}
|
|
1018
|
+
},
|
|
1019
|
+
omni: {
|
|
1020
|
+
native: "omni://",
|
|
1021
|
+
scheme: "omni://wc",
|
|
1022
|
+
store: {
|
|
1023
|
+
ios: "https://apps.apple.com/us/app/omni-web3-wallet/id1569375204",
|
|
1024
|
+
android: "https://play.google.com/store/apps/details?id=fi.steakwallet.app"
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
mew: {
|
|
1028
|
+
universal: "https://mewwallet.com/wc",
|
|
1029
|
+
store: {
|
|
1030
|
+
ios: "https://apps.apple.com/app/id1464614025",
|
|
1031
|
+
android: "https://play.google.com/store/apps/details?id=com.myetherwallet.mewwallet"
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
foxwallet: {
|
|
1035
|
+
native: "foxwallet://",
|
|
1036
|
+
scheme: "foxwallet://wc",
|
|
1037
|
+
universal: "https://link.foxwallet.com/wc",
|
|
1038
|
+
store: {
|
|
1039
|
+
ios: "https://apps.apple.com/app/foxwallet-crypto-web3/id1590983231",
|
|
1040
|
+
android: "https://play.google.com/store/apps/details?id=com.foxwallet.play"
|
|
1041
|
+
}
|
|
1042
|
+
},
|
|
1043
|
+
nova: {
|
|
1044
|
+
native: "novawallet://",
|
|
1045
|
+
scheme: "novawallet://wc",
|
|
1046
|
+
store: {
|
|
1047
|
+
ios: "https://apps.apple.com/us/app/nova-polkadot-wallet/id1597119355",
|
|
1048
|
+
android: "https://play.google.com/store/apps/details?id=io.novafoundation.nova.market"
|
|
1049
|
+
}
|
|
1050
|
+
},
|
|
1051
|
+
subwallet: {
|
|
1052
|
+
native: "subwallet://",
|
|
1053
|
+
scheme: "subwallet://wc",
|
|
1054
|
+
store: {
|
|
1055
|
+
ios: "https://apps.apple.com/us/app/subwallet-polkadot-wallet/id1633050285",
|
|
1056
|
+
android: "https://play.google.com/store/apps/details?id=app.subwallet.mobile"
|
|
1057
|
+
}
|
|
1058
|
+
},
|
|
1059
|
+
safe: {
|
|
1060
|
+
native: "safe://",
|
|
1061
|
+
scheme: "safe://wc",
|
|
1062
|
+
store: {
|
|
1063
|
+
ios: "https://apps.apple.com/us/app/safe-mobile/id6748754793",
|
|
1064
|
+
android: "https://play.google.com/store/apps/details?id=global.safe.mobileapp"
|
|
1065
|
+
}
|
|
1066
|
+
},
|
|
1067
|
+
robinhood: {
|
|
1068
|
+
native: "robinhood-wallet://",
|
|
1069
|
+
scheme: "robinhood-wallet://wc",
|
|
1070
|
+
store: {
|
|
1071
|
+
ios: "https://apps.apple.com/us/app/robinhood-wallet-swap-crypto/id1634080733",
|
|
1072
|
+
android: "https://play.google.com/store/apps/details?id=com.robinhood.gateway"
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
tangem: {
|
|
1076
|
+
native: "tangem://",
|
|
1077
|
+
scheme: "tangem://wc",
|
|
1078
|
+
store: {
|
|
1079
|
+
ios: "https://apps.apple.com/app/tangem/id1354868448",
|
|
1080
|
+
android: "https://play.google.com/store/apps/details?id=com.tangem.wallet"
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
683
1083
|
// Trezor Suite: WalletConnect pairing is QR/paste-into-Suite (no corroborated custom scheme) — QR connect only.
|
|
684
|
-
trezor: {
|
|
685
|
-
|
|
1084
|
+
trezor: {
|
|
1085
|
+
store: {
|
|
1086
|
+
ios: "https://apps.apple.com/us/app/trezor-suite/id1631884497",
|
|
1087
|
+
android: "https://play.google.com/store/apps/details?id=io.trezor.suite"
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
kucoin: {
|
|
1091
|
+
native: "kucoin://",
|
|
1092
|
+
scheme: "kucoin:///wallet/walletConnect",
|
|
1093
|
+
store: {
|
|
1094
|
+
ios: "https://apps.apple.com/app/kucoin-buy-bitcoin-crypto/id1378956601",
|
|
1095
|
+
android: "https://play.google.com/store/apps/details?id=com.kubi.kucoin"
|
|
1096
|
+
}
|
|
1097
|
+
},
|
|
686
1098
|
// Jupiter (Solana): no corroborated WC deep-link scheme — QR connect only.
|
|
687
|
-
jupiter: {
|
|
688
|
-
|
|
1099
|
+
jupiter: {
|
|
1100
|
+
store: {
|
|
1101
|
+
ios: "https://apps.apple.com/us/app/jupiter-solana-swap-wallet/id6484069059",
|
|
1102
|
+
android: "https://play.google.com/store/apps/details?id=ag.jup.jupiter.android"
|
|
1103
|
+
}
|
|
1104
|
+
},
|
|
1105
|
+
zengo: {
|
|
1106
|
+
native: "zengo://get.zengo.com/",
|
|
1107
|
+
scheme: "zengo://get.zengo.com/wc",
|
|
1108
|
+
store: {
|
|
1109
|
+
ios: "https://apps.apple.com/us/app/zengo-crypto-bitcoin-wallet/id1440147115",
|
|
1110
|
+
android: "https://play.google.com/store/apps/details?id=com.zengo.wallet"
|
|
1111
|
+
}
|
|
1112
|
+
},
|
|
689
1113
|
// Bitcoin.com Wallet: no corroborated WC deep-link scheme — QR connect only.
|
|
690
|
-
bitcoincom: {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
1114
|
+
bitcoincom: {
|
|
1115
|
+
store: {
|
|
1116
|
+
ios: "https://apps.apple.com/us/app/bitcoin-wallet-by-bitcoin-com/id1252903728",
|
|
1117
|
+
android: "https://play.google.com/store/apps/details?id=com.bitcoin.mwallet"
|
|
1118
|
+
}
|
|
1119
|
+
},
|
|
1120
|
+
keplr: {
|
|
1121
|
+
native: "keplrwallet://",
|
|
1122
|
+
scheme: "keplrwallet://wcV2",
|
|
1123
|
+
store: {
|
|
1124
|
+
ios: "https://apps.apple.com/us/app/keplr-wallet/id1567851089",
|
|
1125
|
+
android: "https://play.google.com/store/apps/details?id=com.chainapsis.keplr"
|
|
1126
|
+
}
|
|
1127
|
+
},
|
|
1128
|
+
cake: {
|
|
1129
|
+
native: "cakewallet://",
|
|
1130
|
+
scheme: "cakewallet://wc",
|
|
1131
|
+
store: {
|
|
1132
|
+
ios: "https://apps.apple.com/us/app/cake-wallet/id1334702542",
|
|
1133
|
+
android: "https://play.google.com/store/apps/details?id=com.cakewallet.cake_wallet"
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
unstoppable: {
|
|
1137
|
+
native: "unstoppable.money://",
|
|
1138
|
+
scheme: "unstoppable.money://wc",
|
|
1139
|
+
store: {
|
|
1140
|
+
ios: "https://apps.apple.com/us/app/unstoppable-crypto-wallet/id1447619907",
|
|
1141
|
+
android: "https://play.google.com/store/apps/details?id=io.horizontalsystems.bankwallet"
|
|
1142
|
+
}
|
|
1143
|
+
},
|
|
1144
|
+
bifrost: {
|
|
1145
|
+
native: "bifrostwallet://",
|
|
1146
|
+
scheme: "bifrostwallet://wc",
|
|
1147
|
+
store: {
|
|
1148
|
+
ios: "https://apps.apple.com/us/app/bifrost-wallet/id1577198351",
|
|
1149
|
+
android: "https://play.google.com/store/apps/details?id=com.bifrostwallet.app"
|
|
1150
|
+
}
|
|
1151
|
+
},
|
|
1152
|
+
pintu: {
|
|
1153
|
+
native: "pintu://web3wallet",
|
|
1154
|
+
scheme: "pintu://web3wallet/wc",
|
|
1155
|
+
store: {
|
|
1156
|
+
ios: "https://apps.apple.com/id/app/pintu-buy-invest-crypto/id1494119678",
|
|
1157
|
+
android: "https://play.google.com/store/apps/details?id=com.valar.pintu"
|
|
1158
|
+
}
|
|
1159
|
+
},
|
|
1160
|
+
hot: {
|
|
1161
|
+
native: "hotwallet://",
|
|
1162
|
+
scheme: "hotwallet://wc",
|
|
1163
|
+
store: {
|
|
1164
|
+
ios: "https://apps.apple.com/us/app/hot-wallet/id6740916148",
|
|
1165
|
+
android: "https://play.google.com/store/apps/details?id=app.herewallet.hot"
|
|
1166
|
+
}
|
|
1167
|
+
},
|
|
1168
|
+
arculus: {
|
|
1169
|
+
native: "arculuswc://",
|
|
1170
|
+
scheme: "arculuswc://wc",
|
|
1171
|
+
universal: "https://gw.arculus.co/app/wc",
|
|
1172
|
+
store: {
|
|
1173
|
+
ios: "https://apps.apple.com/us/app/arculus-wallet/id1575425801",
|
|
1174
|
+
android: "https://play.google.com/store/apps/details?id=co.arculus.wallet.android"
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
698
1177
|
};
|
|
699
1178
|
|
|
700
1179
|
// src/connectors/walletconnect/registry.ts
|
|
@@ -711,13 +1190,15 @@ function buildLink(base, uri) {
|
|
|
711
1190
|
const sep = base.includes("?") ? "&" : "?";
|
|
712
1191
|
return `${base}${sep}uri=${encodeURIComponent(uri)}`;
|
|
713
1192
|
}
|
|
714
|
-
function
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
1193
|
+
function canOpen(link) {
|
|
1194
|
+
return !!(link?.scheme || link?.universal);
|
|
1195
|
+
}
|
|
1196
|
+
function openWallet(link, uri, via = "scheme") {
|
|
1197
|
+
if (typeof document === "undefined") return false;
|
|
1198
|
+
const base = via === "universal" ? link.universal : link.scheme ?? link.universal;
|
|
1199
|
+
if (!base) return false;
|
|
1200
|
+
openHref(buildLink(base, uri));
|
|
1201
|
+
return true;
|
|
721
1202
|
}
|
|
722
1203
|
function openWalletApp(link) {
|
|
723
1204
|
if (typeof document === "undefined") return;
|
|
@@ -756,6 +1237,7 @@ function detectAppOpen(timeoutMs) {
|
|
|
756
1237
|
|
|
757
1238
|
// src/connectors/walletconnect/connector.ts
|
|
758
1239
|
var STORAGE_KEY = "lydianconnect.wc.topics";
|
|
1240
|
+
var PING_TIMEOUT_MS = 3e3;
|
|
759
1241
|
var WalletConnectConnector = class extends BaseConnector {
|
|
760
1242
|
constructor(app, options) {
|
|
761
1243
|
super();
|
|
@@ -766,6 +1248,9 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
766
1248
|
// claims any wallet not served by an SDK connector
|
|
767
1249
|
this.client = null;
|
|
768
1250
|
this.topics = /* @__PURE__ */ new Map();
|
|
1251
|
+
/** walletId -> pairing URI of the connect currently awaiting approval, so a
|
|
1252
|
+
* host-driven open button can fire without the host tracking the URI itself. */
|
|
1253
|
+
this.pending = /* @__PURE__ */ new Map();
|
|
769
1254
|
this.links = { ...DEFAULT_WALLET_LINKS, ...options.walletLinks ?? {} };
|
|
770
1255
|
}
|
|
771
1256
|
isAvailable() {
|
|
@@ -809,43 +1294,71 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
809
1294
|
}
|
|
810
1295
|
async connect(req) {
|
|
811
1296
|
const client = await this.getClient();
|
|
812
|
-
const reused = this.tryReuse(client, req);
|
|
1297
|
+
const reused = await this.tryReuse(client, req);
|
|
813
1298
|
if (reused) return reused;
|
|
814
1299
|
const { uri, approval } = await client.connect({
|
|
815
1300
|
requiredNamespaces: { [req.namespace.name]: req.namespace.value }
|
|
816
1301
|
});
|
|
817
1302
|
if (!uri) throw new Error("WalletConnect did not return a pairing URI");
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1303
|
+
const link = isMobile() ? this.links[req.walletId] : void 0;
|
|
1304
|
+
this.emit({
|
|
1305
|
+
type: "display_uri",
|
|
1306
|
+
walletId: req.walletId,
|
|
1307
|
+
uri,
|
|
1308
|
+
deepLink: canOpen(link)
|
|
1309
|
+
});
|
|
1310
|
+
if (link && canOpen(link)) {
|
|
1311
|
+
this.pending.set(req.walletId, uri);
|
|
1312
|
+
openWallet(link, uri);
|
|
1313
|
+
void detectAppOpen(this.options.openTimeoutMs ?? 2e3).then((opened) => {
|
|
1314
|
+
if (!opened)
|
|
1315
|
+
this.emit({
|
|
1316
|
+
type: "wallet_open_failed",
|
|
1317
|
+
walletId: req.walletId,
|
|
1318
|
+
uri,
|
|
1319
|
+
store: link.store
|
|
1320
|
+
});
|
|
1321
|
+
});
|
|
833
1322
|
}
|
|
834
1323
|
const pairingTopic = parseUri(uri).topic;
|
|
835
|
-
const session = await
|
|
1324
|
+
const session = await withSignal(approval(), req.signal, () => {
|
|
836
1325
|
void client.core.pairing.disconnect({ topic: pairingTopic }).catch(() => {
|
|
837
1326
|
});
|
|
838
|
-
});
|
|
839
|
-
const connection = this.toConnection(
|
|
1327
|
+
}).finally(() => this.pending.delete(req.walletId));
|
|
1328
|
+
const connection = this.toConnection(
|
|
1329
|
+
client,
|
|
1330
|
+
req.walletId,
|
|
1331
|
+
session,
|
|
1332
|
+
req.namespace
|
|
1333
|
+
);
|
|
840
1334
|
this.topics.set(req.walletId, session.topic);
|
|
841
1335
|
this.persist();
|
|
842
1336
|
return connection;
|
|
843
1337
|
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Fire a wallet's deep link on demand. The host calls this from a real click,
|
|
1340
|
+
* which is the one context a mobile browser reliably allows a scheme
|
|
1341
|
+
* navigation from — see the note on {@link openWallet}.
|
|
1342
|
+
*/
|
|
1343
|
+
openWallet(input) {
|
|
1344
|
+
const link = this.links[input.walletId];
|
|
1345
|
+
if (!link) return false;
|
|
1346
|
+
const uri = input.uri ?? this.pending.get(input.walletId);
|
|
1347
|
+
if (!uri) {
|
|
1348
|
+
openWalletApp(link);
|
|
1349
|
+
return !!link.native;
|
|
1350
|
+
}
|
|
1351
|
+
return openWallet(link, uri, input.via ?? "scheme");
|
|
1352
|
+
}
|
|
844
1353
|
async restore() {
|
|
845
1354
|
const client = await this.getClient();
|
|
1355
|
+
const checked = await Promise.all(
|
|
1356
|
+
[...this.topics].map(
|
|
1357
|
+
async ([walletId, topic]) => [walletId, await this.liveSession(client, topic)]
|
|
1358
|
+
)
|
|
1359
|
+
);
|
|
846
1360
|
const out = [];
|
|
847
|
-
for (const [walletId,
|
|
848
|
-
const session = this.liveSession(client, topic);
|
|
1361
|
+
for (const [walletId, session] of checked) {
|
|
849
1362
|
if (!session) {
|
|
850
1363
|
this.topics.delete(walletId);
|
|
851
1364
|
continue;
|
|
@@ -860,19 +1373,26 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
860
1373
|
const client = this.client;
|
|
861
1374
|
if (client) {
|
|
862
1375
|
await Promise.allSettled(
|
|
863
|
-
client.session.getAll().map(
|
|
1376
|
+
client.session.getAll().map(
|
|
1377
|
+
(s) => client.disconnect({
|
|
1378
|
+
topic: s.topic,
|
|
1379
|
+
reason: getSdkError("USER_DISCONNECTED")
|
|
1380
|
+
})
|
|
1381
|
+
)
|
|
864
1382
|
);
|
|
865
1383
|
}
|
|
866
1384
|
this.topics.clear();
|
|
1385
|
+
this.pending.clear();
|
|
867
1386
|
this.persist();
|
|
868
1387
|
}
|
|
869
1388
|
// --- helpers ---
|
|
870
|
-
tryReuse(client, req) {
|
|
1389
|
+
async tryReuse(client, req) {
|
|
871
1390
|
const topic = this.topics.get(req.walletId);
|
|
872
1391
|
if (!topic) return null;
|
|
873
|
-
const session = this.liveSession(client, topic);
|
|
1392
|
+
const session = await this.liveSession(client, topic);
|
|
874
1393
|
if (!session) {
|
|
875
1394
|
this.topics.delete(req.walletId);
|
|
1395
|
+
this.persist();
|
|
876
1396
|
return null;
|
|
877
1397
|
}
|
|
878
1398
|
const ns = session.namespaces[req.namespace.name];
|
|
@@ -883,7 +1403,9 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
883
1403
|
toConnection(client, walletId, session, namespace) {
|
|
884
1404
|
const ns = session.namespaces[namespace.name];
|
|
885
1405
|
const account = (ns?.accounts ?? []).map((a) => a.split(":")[2]).find((a) => !!a) ?? "";
|
|
886
|
-
const
|
|
1406
|
+
const approved = ns?.chains?.length ? ns.chains : (ns?.accounts ?? []).map((a) => a.split(":").slice(0, 2).join(":"));
|
|
1407
|
+
const wanted = namespace.value.chains?.[0];
|
|
1408
|
+
const chainId = wanted && approved.includes(wanted) ? wanted : approved[0] ?? `${namespace.name}:1`;
|
|
887
1409
|
const topic = session.topic;
|
|
888
1410
|
return {
|
|
889
1411
|
walletId,
|
|
@@ -908,12 +1430,27 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
908
1430
|
}
|
|
909
1431
|
};
|
|
910
1432
|
}
|
|
911
|
-
|
|
1433
|
+
/**
|
|
1434
|
+
* A stored session the wallet is still on the other end of. The local record
|
|
1435
|
+
* is not evidence — it survives the user clearing the dApp inside their
|
|
1436
|
+
* wallet — and reusing a dead one returns a Connection that looks healthy
|
|
1437
|
+
* while every request hangs. So the peer has to answer for it.
|
|
1438
|
+
*/
|
|
1439
|
+
async liveSession(client, topic) {
|
|
1440
|
+
let session;
|
|
912
1441
|
try {
|
|
913
|
-
|
|
1442
|
+
session = client.session.get(topic);
|
|
914
1443
|
} catch {
|
|
915
1444
|
return void 0;
|
|
916
1445
|
}
|
|
1446
|
+
let timer;
|
|
1447
|
+
const alive = await Promise.race([
|
|
1448
|
+
client.ping({ topic }).then(() => true).catch(() => false),
|
|
1449
|
+
new Promise((resolve) => {
|
|
1450
|
+
timer = setTimeout(() => resolve(false), PING_TIMEOUT_MS);
|
|
1451
|
+
})
|
|
1452
|
+
]).finally(() => clearTimeout(timer));
|
|
1453
|
+
return alive ? session : void 0;
|
|
917
1454
|
}
|
|
918
1455
|
walletForTopic(topic) {
|
|
919
1456
|
for (const [walletId, t] of this.topics) if (t === topic) return walletId;
|
|
@@ -928,7 +1465,8 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
928
1465
|
load() {
|
|
929
1466
|
try {
|
|
930
1467
|
const raw = localStorage.getItem(STORAGE_KEY);
|
|
931
|
-
if (raw)
|
|
1468
|
+
if (raw)
|
|
1469
|
+
this.topics = new Map(JSON.parse(raw));
|
|
932
1470
|
} catch {
|
|
933
1471
|
}
|
|
934
1472
|
}
|
|
@@ -938,38 +1476,18 @@ function firstNamespace(session) {
|
|
|
938
1476
|
if (!name) return null;
|
|
939
1477
|
const v = session.namespaces[name];
|
|
940
1478
|
if (!v) return null;
|
|
941
|
-
return {
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
if (signal.aborted) {
|
|
946
|
-
onAbort();
|
|
947
|
-
return Promise.reject(new DOMException("Aborted", "AbortError"));
|
|
948
|
-
}
|
|
949
|
-
return new Promise((resolve, reject) => {
|
|
950
|
-
const abortHandler = () => {
|
|
951
|
-
onAbort();
|
|
952
|
-
reject(new DOMException("Aborted", "AbortError"));
|
|
953
|
-
};
|
|
954
|
-
signal.addEventListener("abort", abortHandler, { once: true });
|
|
955
|
-
promise.then(
|
|
956
|
-
(v) => {
|
|
957
|
-
signal.removeEventListener("abort", abortHandler);
|
|
958
|
-
resolve(v);
|
|
959
|
-
},
|
|
960
|
-
(e) => {
|
|
961
|
-
signal.removeEventListener("abort", abortHandler);
|
|
962
|
-
reject(e);
|
|
963
|
-
}
|
|
964
|
-
);
|
|
965
|
-
});
|
|
1479
|
+
return {
|
|
1480
|
+
name,
|
|
1481
|
+
value: { chains: v.chains, methods: v.methods, events: v.events }
|
|
1482
|
+
};
|
|
966
1483
|
}
|
|
967
1484
|
|
|
968
1485
|
// src/core/lydian-connect.ts
|
|
969
1486
|
function injectedRdnsMap(sdkServed) {
|
|
970
1487
|
const map = {};
|
|
971
1488
|
for (const w of WALLET_CATALOG) {
|
|
972
|
-
if (w.rdns && w.namespaces.includes("eip155") && !sdkServed.has(w.id))
|
|
1489
|
+
if (w.rdns && w.namespaces.includes("eip155") && !sdkServed.has(w.id))
|
|
1490
|
+
map[w.id] = w.rdns;
|
|
973
1491
|
}
|
|
974
1492
|
return map;
|
|
975
1493
|
}
|
|
@@ -984,7 +1502,9 @@ function createConnectors(config) {
|
|
|
984
1502
|
return [
|
|
985
1503
|
...sdk,
|
|
986
1504
|
new InjectedConnector(injectedRdnsMap(sdkServed)),
|
|
987
|
-
new WalletConnectConnector(app, {
|
|
1505
|
+
new WalletConnectConnector(app, {
|
|
1506
|
+
projectId: config.walletConnectProjectId
|
|
1507
|
+
})
|
|
988
1508
|
];
|
|
989
1509
|
}
|
|
990
1510
|
var LydianConnect = class {
|
|
@@ -996,7 +1516,9 @@ var LydianConnect = class {
|
|
|
996
1516
|
}
|
|
997
1517
|
async connect(input) {
|
|
998
1518
|
if (input.chainId === void 0 || input.chainId === null) {
|
|
999
|
-
throw new Error(
|
|
1519
|
+
throw new Error(
|
|
1520
|
+
'connect() requires a chainId (a number like 137 or an "eip155:<id>" string)'
|
|
1521
|
+
);
|
|
1000
1522
|
}
|
|
1001
1523
|
return this.manager.connect({
|
|
1002
1524
|
walletId: input.walletId,
|
|
@@ -1004,6 +1526,20 @@ var LydianConnect = class {
|
|
|
1004
1526
|
signal: input.signal
|
|
1005
1527
|
});
|
|
1006
1528
|
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Open a wallet app, optionally handing it the pairing URI from `display_uri`.
|
|
1531
|
+
*
|
|
1532
|
+
* Call this from a real click handler. A mobile browser will suppress the same
|
|
1533
|
+
* navigation issued automatically after an async step, which is why the
|
|
1534
|
+
* `display_uri` event reports `deepLink` — that is the library asking the host
|
|
1535
|
+
* for a button to put this behind.
|
|
1536
|
+
*
|
|
1537
|
+
* Returns whether a link was fired. `false` means nothing is known for this
|
|
1538
|
+
* wallet on this device; show the QR code instead.
|
|
1539
|
+
*/
|
|
1540
|
+
openWallet(input) {
|
|
1541
|
+
return this.manager.openWallet(input);
|
|
1542
|
+
}
|
|
1007
1543
|
restore() {
|
|
1008
1544
|
return this.manager.restore();
|
|
1009
1545
|
}
|