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