@lydianpay/lydianconnect 0.0.0-managed → 1.0.1
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/LICENSE +21 -0
- package/README.md +50 -0
- package/dist/index.cjs +307 -217
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -163
- package/dist/index.d.ts +32 -163
- package/dist/index.js +308 -213
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lydian
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @lydianpay/lydianconnect
|
|
2
|
+
|
|
3
|
+
One API for every wallet. LydianConnect abstracts the messy differences between
|
|
4
|
+
wallet connection methods into a single, uniform interface.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @lydianpay/lydianconnect
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { LydianConnect } from '@lydianpay/lydianconnect';
|
|
16
|
+
|
|
17
|
+
const lc = new LydianConnect({
|
|
18
|
+
appName: 'My App',
|
|
19
|
+
walletConnectProjectId: 'your-wc-project-id',
|
|
20
|
+
icon: 'https://my.app/icon.png', // optional
|
|
21
|
+
description: 'My App checkout', // optional
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const conn = await lc.connect({ walletId: 'metamask', chainId: 137 });
|
|
25
|
+
const txHash = await conn.request({ method: 'eth_sendTransaction', params: [tx] });
|
|
26
|
+
|
|
27
|
+
lc.on((event) => {
|
|
28
|
+
// 'connect' | 'disconnect' | 'chainChanged' | 'accountsChanged' | 'display_uri' | 'wallet_open_failed'
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Config
|
|
33
|
+
|
|
34
|
+
| Field | Required | Notes |
|
|
35
|
+
|-------|----------|-------|
|
|
36
|
+
| `appName` | yes | Display name shown in the wallet's connect prompt. |
|
|
37
|
+
| `walletConnectProjectId` | yes | WalletConnect Cloud project id. |
|
|
38
|
+
| `icon` | no | Icon shown in the connect prompt. |
|
|
39
|
+
| `description` | no | Defaults to `appName`. |
|
|
40
|
+
|
|
41
|
+
`connect({ walletId, chainId })` — `chainId` is the chain the user is paying on (a number like `137`, or a CAIP-2 id like `'eip155:137'`).
|
|
42
|
+
|
|
43
|
+
## Supported wallets
|
|
44
|
+
|
|
45
|
+
**Native SDK:** MetaMask, Coinbase Wallet.
|
|
46
|
+
|
|
47
|
+
**WalletConnect:** Rainbow, Trust Wallet, OKX Wallet, Crypto.com, Phantom, Zerion,
|
|
48
|
+
Argent, Ledger, 1inch, SafePal, imToken, TokenPocket, Blockchain.com, Exodus,
|
|
49
|
+
Ronin Wallet, Coin98, Bitget Wallet, Infinity Wallet, Atomic Wallet, AlphaWallet,
|
|
50
|
+
MathWallet, BitPay — each with native deep-linking.
|
package/dist/index.cjs
CHANGED
|
@@ -8,20 +8,26 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
8
8
|
var SignClient__default = /*#__PURE__*/_interopDefault(SignClient);
|
|
9
9
|
|
|
10
10
|
// src/core/manager.ts
|
|
11
|
-
var
|
|
12
|
-
constructor(
|
|
11
|
+
var ConnectManager = class {
|
|
12
|
+
constructor(connectors) {
|
|
13
13
|
this.byWallet = /* @__PURE__ */ new Map();
|
|
14
14
|
this.connections = /* @__PURE__ */ new Map();
|
|
15
15
|
this.handlers = /* @__PURE__ */ new Set();
|
|
16
16
|
this.unsubs = [];
|
|
17
17
|
this.started = false;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
const fallbacks = connectors.filter((c) => c.walletIds.length === 0);
|
|
19
|
+
if (fallbacks.length !== 1) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`LydianConnect requires exactly one fallback connector (empty walletIds); found ${fallbacks.length}`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
this.fallback = fallbacks[0];
|
|
25
|
+
this.all = connectors;
|
|
26
|
+
for (const connector of connectors) {
|
|
21
27
|
for (const id of connector.walletIds) this.byWallet.set(id, connector);
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
|
-
/** Wire connector event forwarding, once.
|
|
30
|
+
/** Wire connector event forwarding, once. */
|
|
25
31
|
async init() {
|
|
26
32
|
if (this.started) return;
|
|
27
33
|
this.started = true;
|
|
@@ -29,18 +35,17 @@ var LydianConnect = class {
|
|
|
29
35
|
this.unsubs.push(connector.on((event) => this.handle(event)));
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
|
-
/** SDK connector if one claims this walletId, else the
|
|
38
|
+
/** SDK connector if one claims this walletId, else the fallback. The host app is oblivious. */
|
|
33
39
|
resolve(walletId) {
|
|
34
40
|
return this.byWallet.get(walletId) ?? this.fallback;
|
|
35
41
|
}
|
|
36
|
-
async connect(
|
|
42
|
+
async connect(req) {
|
|
37
43
|
if (!this.started) await this.init();
|
|
38
|
-
const connection = await this.resolve(
|
|
39
|
-
this.connections.set(
|
|
40
|
-
this.emit({ type: "connect", walletId:
|
|
44
|
+
const connection = await this.resolve(req.walletId).connect(req);
|
|
45
|
+
this.connections.set(req.walletId, connection);
|
|
46
|
+
this.emit({ type: "connect", walletId: req.walletId, connection });
|
|
41
47
|
return connection;
|
|
42
48
|
}
|
|
43
|
-
/** Resume any live sessions across all connectors (e.g. after a page reload). */
|
|
44
49
|
async restore() {
|
|
45
50
|
if (!this.started) await this.init();
|
|
46
51
|
const restored = [];
|
|
@@ -66,7 +71,6 @@ var LydianConnect = class {
|
|
|
66
71
|
await Promise.allSettled([...this.connections.values()].map((c) => c.disconnect()));
|
|
67
72
|
this.connections.clear();
|
|
68
73
|
}
|
|
69
|
-
/** Disconnect everything and clear all connector-held state. */
|
|
70
74
|
async reset() {
|
|
71
75
|
await this.disconnect();
|
|
72
76
|
await Promise.allSettled(this.all.map((c) => c.reset()));
|
|
@@ -84,6 +88,28 @@ var LydianConnect = class {
|
|
|
84
88
|
}
|
|
85
89
|
};
|
|
86
90
|
|
|
91
|
+
// src/core/namespace.ts
|
|
92
|
+
var DEFAULT_EVM_METHODS = [
|
|
93
|
+
"eth_sendTransaction",
|
|
94
|
+
"personal_sign",
|
|
95
|
+
"eth_signTypedData_v4",
|
|
96
|
+
"wallet_switchEthereumChain"
|
|
97
|
+
];
|
|
98
|
+
var DEFAULT_EVM_EVENTS = ["chainChanged", "accountsChanged"];
|
|
99
|
+
function buildNamespace(chainId) {
|
|
100
|
+
const caip = typeof chainId === "number" ? `eip155:${chainId}` : chainId;
|
|
101
|
+
const [name, reference] = caip.split(":");
|
|
102
|
+
if (name !== "eip155" || !reference || !/^\d+$/.test(reference) || Number(reference) <= 0) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Unsupported chain "${caip}". lydianconnect is EVM-only for now \u2014 pass a positive number or an "eip155:<id>" string.`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
name,
|
|
109
|
+
value: { chains: [caip], methods: DEFAULT_EVM_METHODS, events: DEFAULT_EVM_EVENTS }
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
87
113
|
// src/core/connector.ts
|
|
88
114
|
var BaseConnector = class {
|
|
89
115
|
constructor() {
|
|
@@ -104,6 +130,227 @@ var BaseConnector = class {
|
|
|
104
130
|
}
|
|
105
131
|
};
|
|
106
132
|
|
|
133
|
+
// src/core/app.ts
|
|
134
|
+
function deriveUrl() {
|
|
135
|
+
return typeof window !== "undefined" ? window.location.origin : "";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/connectors/metamask/connector.ts
|
|
139
|
+
var WALLET_ID = "metamask";
|
|
140
|
+
var MetaMaskConnector = class extends BaseConnector {
|
|
141
|
+
constructor(app) {
|
|
142
|
+
super();
|
|
143
|
+
this.app = app;
|
|
144
|
+
this.type = "sdk";
|
|
145
|
+
this.walletIds = [WALLET_ID];
|
|
146
|
+
this.sdk = null;
|
|
147
|
+
this.provider = null;
|
|
148
|
+
this.listenersBound = false;
|
|
149
|
+
}
|
|
150
|
+
isAvailable() {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
async getProvider() {
|
|
154
|
+
if (this.provider) return this.provider;
|
|
155
|
+
const { MetaMaskSDK } = await import('@metamask/sdk');
|
|
156
|
+
const dappMetadata = {
|
|
157
|
+
name: this.app.appName,
|
|
158
|
+
url: deriveUrl(),
|
|
159
|
+
...this.app.icon ? { iconUrl: this.app.icon } : {}
|
|
160
|
+
};
|
|
161
|
+
const sdk = new MetaMaskSDK({ dappMetadata });
|
|
162
|
+
await sdk.init();
|
|
163
|
+
const provider = sdk.getProvider();
|
|
164
|
+
if (!provider) throw new Error("MetaMask provider unavailable");
|
|
165
|
+
this.sdk = sdk;
|
|
166
|
+
this.provider = provider;
|
|
167
|
+
this.bindEvents(provider);
|
|
168
|
+
return provider;
|
|
169
|
+
}
|
|
170
|
+
bindEvents(provider) {
|
|
171
|
+
if (this.listenersBound) return;
|
|
172
|
+
this.listenersBound = true;
|
|
173
|
+
provider.on("chainChanged", (hex) => {
|
|
174
|
+
this.emit({ type: "chainChanged", walletId: WALLET_ID, chainId: toCaip(String(hex)) });
|
|
175
|
+
});
|
|
176
|
+
provider.on("accountsChanged", (accounts) => {
|
|
177
|
+
const account = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
178
|
+
if (account) this.emit({ type: "accountsChanged", walletId: WALLET_ID, account });
|
|
179
|
+
else this.emit({ type: "disconnect", walletId: WALLET_ID });
|
|
180
|
+
});
|
|
181
|
+
provider.on("disconnect", () => this.emit({ type: "disconnect", walletId: WALLET_ID }));
|
|
182
|
+
}
|
|
183
|
+
async connect(req) {
|
|
184
|
+
const provider = await this.getProvider();
|
|
185
|
+
const accounts = await provider.request({ method: "eth_requestAccounts" });
|
|
186
|
+
const account = accounts?.[0];
|
|
187
|
+
if (!account) throw new Error("MetaMask returned no account");
|
|
188
|
+
await this.ensureChain(provider, req);
|
|
189
|
+
const chainId = toCaip(await provider.request({ method: "eth_chainId" }));
|
|
190
|
+
return this.toConnection(provider, account, chainId);
|
|
191
|
+
}
|
|
192
|
+
async restore() {
|
|
193
|
+
const provider = await this.getProvider().catch(() => null);
|
|
194
|
+
if (!provider) return [];
|
|
195
|
+
const accounts = await provider.request({ method: "eth_accounts" }).catch(() => []);
|
|
196
|
+
const account = accounts?.[0];
|
|
197
|
+
if (!account) return [];
|
|
198
|
+
const chainId = toCaip(
|
|
199
|
+
await provider.request({ method: "eth_chainId" }).catch(() => "0x1")
|
|
200
|
+
);
|
|
201
|
+
return [this.toConnection(provider, account, chainId)];
|
|
202
|
+
}
|
|
203
|
+
async reset() {
|
|
204
|
+
await this.sdk?.terminate();
|
|
205
|
+
this.provider = null;
|
|
206
|
+
this.listenersBound = false;
|
|
207
|
+
}
|
|
208
|
+
/** Best-effort switch to the requested chain; leaves the wallet as-is if it's unknown to it. */
|
|
209
|
+
async ensureChain(provider, req) {
|
|
210
|
+
const wanted = req.namespace.value.chains?.[0];
|
|
211
|
+
const wantedNum = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
212
|
+
if (!Number.isFinite(wantedNum) || wantedNum <= 0) return;
|
|
213
|
+
const current = parseInt(
|
|
214
|
+
await provider.request({ method: "eth_chainId" }).catch(() => "0x0") ?? "0x0",
|
|
215
|
+
16
|
|
216
|
+
);
|
|
217
|
+
if (current === wantedNum) return;
|
|
218
|
+
await provider.request({
|
|
219
|
+
method: "wallet_switchEthereumChain",
|
|
220
|
+
params: [{ chainId: `0x${wantedNum.toString(16)}` }]
|
|
221
|
+
}).catch(() => {
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
toConnection(provider, account, chainId) {
|
|
225
|
+
return {
|
|
226
|
+
walletId: WALLET_ID,
|
|
227
|
+
account,
|
|
228
|
+
chainId,
|
|
229
|
+
request: async (args) => await provider.request({ method: args.method, params: args.params }),
|
|
230
|
+
disconnect: async () => {
|
|
231
|
+
await this.sdk?.terminate();
|
|
232
|
+
this.provider = null;
|
|
233
|
+
this.listenersBound = false;
|
|
234
|
+
this.emit({ type: "disconnect", walletId: WALLET_ID });
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
function toCaip(hexChainId) {
|
|
240
|
+
if (!hexChainId) return "eip155:1";
|
|
241
|
+
const num = hexChainId.startsWith("0x") ? parseInt(hexChainId, 16) : Number(hexChainId);
|
|
242
|
+
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/connectors/coinbase/connector.ts
|
|
246
|
+
function rpc(provider, method, params) {
|
|
247
|
+
return provider.request({ method, params });
|
|
248
|
+
}
|
|
249
|
+
var WALLET_ID2 = "coinbase";
|
|
250
|
+
var CoinbaseConnector = class extends BaseConnector {
|
|
251
|
+
constructor(app) {
|
|
252
|
+
super();
|
|
253
|
+
this.app = app;
|
|
254
|
+
this.type = "sdk";
|
|
255
|
+
this.walletIds = [WALLET_ID2];
|
|
256
|
+
this.provider = null;
|
|
257
|
+
this.listenersBound = false;
|
|
258
|
+
}
|
|
259
|
+
isAvailable() {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
async getProvider(appChainIds) {
|
|
263
|
+
if (this.provider) return this.provider;
|
|
264
|
+
const { CoinbaseWalletSDK } = await import('@coinbase/wallet-sdk');
|
|
265
|
+
const sdk = new CoinbaseWalletSDK({
|
|
266
|
+
appName: this.app.appName,
|
|
267
|
+
appLogoUrl: this.app.icon,
|
|
268
|
+
appChainIds
|
|
269
|
+
// one-time SDK-init hint; ensureChain enforces the actual chain per connect
|
|
270
|
+
});
|
|
271
|
+
const provider = sdk.makeWeb3Provider();
|
|
272
|
+
this.provider = provider;
|
|
273
|
+
this.bindEvents(provider);
|
|
274
|
+
return provider;
|
|
275
|
+
}
|
|
276
|
+
bindEvents(provider) {
|
|
277
|
+
if (this.listenersBound) return;
|
|
278
|
+
this.listenersBound = true;
|
|
279
|
+
provider.on("chainChanged", (hex) => {
|
|
280
|
+
this.emit({ type: "chainChanged", walletId: WALLET_ID2, chainId: toCaip2(String(hex)) });
|
|
281
|
+
});
|
|
282
|
+
provider.on("accountsChanged", (accounts) => {
|
|
283
|
+
const account = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
284
|
+
if (account) this.emit({ type: "accountsChanged", walletId: WALLET_ID2, account });
|
|
285
|
+
else this.emit({ type: "disconnect", walletId: WALLET_ID2 });
|
|
286
|
+
});
|
|
287
|
+
provider.on("disconnect", () => this.emit({ type: "disconnect", walletId: WALLET_ID2 }));
|
|
288
|
+
}
|
|
289
|
+
async connect(req) {
|
|
290
|
+
const provider = await this.getProvider(evmChainIds(req));
|
|
291
|
+
const accounts = await rpc(provider, "eth_requestAccounts");
|
|
292
|
+
const account = accounts?.[0];
|
|
293
|
+
if (!account) throw new Error("Coinbase Wallet returned no account");
|
|
294
|
+
await this.ensureChain(provider, req);
|
|
295
|
+
const chainId = toCaip2(await rpc(provider, "eth_chainId"));
|
|
296
|
+
return this.toConnection(provider, account, chainId);
|
|
297
|
+
}
|
|
298
|
+
async restore() {
|
|
299
|
+
const provider = await this.getProvider().catch(() => null);
|
|
300
|
+
if (!provider) return [];
|
|
301
|
+
const accounts = await rpc(provider, "eth_accounts").catch(() => []);
|
|
302
|
+
const account = accounts?.[0];
|
|
303
|
+
if (!account) return [];
|
|
304
|
+
const chainId = toCaip2(await rpc(provider, "eth_chainId").catch(() => "0x1"));
|
|
305
|
+
return [this.toConnection(provider, account, chainId)];
|
|
306
|
+
}
|
|
307
|
+
async reset() {
|
|
308
|
+
await this.provider?.disconnect().catch(() => {
|
|
309
|
+
});
|
|
310
|
+
this.provider = null;
|
|
311
|
+
this.listenersBound = false;
|
|
312
|
+
}
|
|
313
|
+
async ensureChain(provider, req) {
|
|
314
|
+
const wanted = req.namespace.value.chains?.[0];
|
|
315
|
+
const wantedNum = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
316
|
+
if (!Number.isFinite(wantedNum) || wantedNum <= 0) return;
|
|
317
|
+
const current = parseInt(
|
|
318
|
+
await rpc(provider, "eth_chainId").catch(() => "0x0") ?? "0x0",
|
|
319
|
+
16
|
|
320
|
+
);
|
|
321
|
+
if (current === wantedNum) return;
|
|
322
|
+
await rpc(provider, "wallet_switchEthereumChain", [{ chainId: `0x${wantedNum.toString(16)}` }]).catch(
|
|
323
|
+
() => {
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
toConnection(provider, account, chainId) {
|
|
328
|
+
return {
|
|
329
|
+
walletId: WALLET_ID2,
|
|
330
|
+
account,
|
|
331
|
+
chainId,
|
|
332
|
+
request: (args) => rpc(provider, args.method, args.params),
|
|
333
|
+
disconnect: async () => {
|
|
334
|
+
await provider.disconnect().catch(() => {
|
|
335
|
+
});
|
|
336
|
+
this.provider = null;
|
|
337
|
+
this.listenersBound = false;
|
|
338
|
+
this.emit({ type: "disconnect", walletId: WALLET_ID2 });
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
function toCaip2(hexChainId) {
|
|
344
|
+
if (!hexChainId) return "eip155:1";
|
|
345
|
+
const num = hexChainId.startsWith("0x") ? parseInt(hexChainId, 16) : Number(hexChainId);
|
|
346
|
+
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
347
|
+
}
|
|
348
|
+
function evmChainIds(req) {
|
|
349
|
+
const wanted = req.namespace.value.chains?.[0];
|
|
350
|
+
const n = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
351
|
+
return Number.isFinite(n) && n > 0 ? [n] : void 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
107
354
|
// src/connectors/walletconnect/wallet-links.generated.ts
|
|
108
355
|
var GENERATED_WALLET_LINKS = {
|
|
109
356
|
metamask: { "scheme": "metamask://wc", "universal": "https://metamask.app.link/wc", "store": { "ios": "https://apps.apple.com/us/app/metamask/id1438144202", "android": "https://play.google.com/store/apps/details?id=io.metamask" } },
|
|
@@ -196,9 +443,10 @@ function detectAppOpen(timeoutMs) {
|
|
|
196
443
|
// src/connectors/walletconnect/connector.ts
|
|
197
444
|
var STORAGE_KEY = "lydianconnect.wc.topics";
|
|
198
445
|
var WalletConnectConnector = class extends BaseConnector {
|
|
199
|
-
constructor(
|
|
446
|
+
constructor(app, options) {
|
|
200
447
|
super();
|
|
201
|
-
this.
|
|
448
|
+
this.app = app;
|
|
449
|
+
this.options = options;
|
|
202
450
|
this.type = "walletconnect";
|
|
203
451
|
this.walletIds = [];
|
|
204
452
|
// claims any wallet not served by an SDK connector
|
|
@@ -206,7 +454,7 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
206
454
|
this.topics = /* @__PURE__ */ new Map();
|
|
207
455
|
this.warm = null;
|
|
208
456
|
this.warming = null;
|
|
209
|
-
this.links = { ...DEFAULT_WALLET_LINKS, ...
|
|
457
|
+
this.links = { ...DEFAULT_WALLET_LINKS, ...options.walletLinks ?? {} };
|
|
210
458
|
}
|
|
211
459
|
isAvailable() {
|
|
212
460
|
return true;
|
|
@@ -214,9 +462,14 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
214
462
|
async getClient() {
|
|
215
463
|
if (this.client) return this.client;
|
|
216
464
|
const client = await SignClient__default.default.init({
|
|
217
|
-
projectId: this.
|
|
218
|
-
metadata:
|
|
219
|
-
|
|
465
|
+
projectId: this.options.projectId,
|
|
466
|
+
metadata: {
|
|
467
|
+
name: this.app.appName,
|
|
468
|
+
description: this.app.description ?? this.app.appName,
|
|
469
|
+
url: deriveUrl(),
|
|
470
|
+
icons: this.app.icon ? [this.app.icon] : []
|
|
471
|
+
},
|
|
472
|
+
relayUrl: this.options.relayUrl
|
|
220
473
|
});
|
|
221
474
|
client.on("session_delete", ({ topic }) => {
|
|
222
475
|
const walletId = this.walletForTopic(topic);
|
|
@@ -266,7 +519,7 @@ var WalletConnectConnector = class extends BaseConnector {
|
|
|
266
519
|
const link = this.links[req.walletId];
|
|
267
520
|
if (link) {
|
|
268
521
|
openWallet(link, warm.uri);
|
|
269
|
-
void detectAppOpen(this.
|
|
522
|
+
void detectAppOpen(this.options.openTimeoutMs ?? 2e3).then((opened) => {
|
|
270
523
|
if (!opened) this.emit({ type: "wallet_open_failed", walletId: req.walletId, uri: warm.uri });
|
|
271
524
|
});
|
|
272
525
|
}
|
|
@@ -405,216 +658,53 @@ function withSignal(promise, signal, onAbort) {
|
|
|
405
658
|
});
|
|
406
659
|
}
|
|
407
660
|
|
|
408
|
-
// src/
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
isAvailable() {
|
|
421
|
-
return true;
|
|
422
|
-
}
|
|
423
|
-
async getProvider() {
|
|
424
|
-
if (this.provider) return this.provider;
|
|
425
|
-
const { MetaMaskSDK } = await import('@metamask/sdk');
|
|
426
|
-
const sdk = new MetaMaskSDK({
|
|
427
|
-
dappMetadata: this.config.dappMetadata,
|
|
428
|
-
...this.config.sdkOptions
|
|
429
|
-
});
|
|
430
|
-
await sdk.init();
|
|
431
|
-
const provider = sdk.getProvider();
|
|
432
|
-
if (!provider) throw new Error("MetaMask provider unavailable");
|
|
433
|
-
this.sdk = sdk;
|
|
434
|
-
this.provider = provider;
|
|
435
|
-
this.bindEvents(provider);
|
|
436
|
-
return provider;
|
|
437
|
-
}
|
|
438
|
-
bindEvents(provider) {
|
|
439
|
-
if (this.listenersBound) return;
|
|
440
|
-
this.listenersBound = true;
|
|
441
|
-
provider.on("chainChanged", (hex) => {
|
|
442
|
-
this.emit({ type: "chainChanged", walletId: WALLET_ID, chainId: toCaip(String(hex)) });
|
|
443
|
-
});
|
|
444
|
-
provider.on("accountsChanged", (accounts) => {
|
|
445
|
-
const account = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
446
|
-
if (account) this.emit({ type: "accountsChanged", walletId: WALLET_ID, account });
|
|
447
|
-
else this.emit({ type: "disconnect", walletId: WALLET_ID });
|
|
448
|
-
});
|
|
449
|
-
provider.on("disconnect", () => this.emit({ type: "disconnect", walletId: WALLET_ID }));
|
|
450
|
-
}
|
|
451
|
-
async connect(req) {
|
|
452
|
-
const provider = await this.getProvider();
|
|
453
|
-
const accounts = await provider.request({ method: "eth_requestAccounts" });
|
|
454
|
-
const account = accounts?.[0];
|
|
455
|
-
if (!account) throw new Error("MetaMask returned no account");
|
|
456
|
-
await this.ensureChain(provider, req);
|
|
457
|
-
const chainId = toCaip(await provider.request({ method: "eth_chainId" }));
|
|
458
|
-
return this.toConnection(provider, account, chainId);
|
|
459
|
-
}
|
|
460
|
-
async restore() {
|
|
461
|
-
const provider = await this.getProvider().catch(() => null);
|
|
462
|
-
if (!provider) return [];
|
|
463
|
-
const accounts = await provider.request({ method: "eth_accounts" }).catch(() => []);
|
|
464
|
-
const account = accounts?.[0];
|
|
465
|
-
if (!account) return [];
|
|
466
|
-
const chainId = toCaip(
|
|
467
|
-
await provider.request({ method: "eth_chainId" }).catch(() => "0x1")
|
|
468
|
-
);
|
|
469
|
-
return [this.toConnection(provider, account, chainId)];
|
|
470
|
-
}
|
|
471
|
-
async reset() {
|
|
472
|
-
await this.sdk?.terminate();
|
|
473
|
-
this.provider = null;
|
|
474
|
-
this.listenersBound = false;
|
|
475
|
-
}
|
|
476
|
-
/** Best-effort switch to the requested chain; leaves the wallet as-is if it's unknown to it. */
|
|
477
|
-
async ensureChain(provider, req) {
|
|
478
|
-
const wanted = req.namespace.value.chains?.[0];
|
|
479
|
-
const wantedNum = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
480
|
-
if (!Number.isFinite(wantedNum) || wantedNum <= 0) return;
|
|
481
|
-
const current = parseInt(
|
|
482
|
-
await provider.request({ method: "eth_chainId" }).catch(() => "0x0") ?? "0x0",
|
|
483
|
-
16
|
|
484
|
-
);
|
|
485
|
-
if (current === wantedNum) return;
|
|
486
|
-
await provider.request({
|
|
487
|
-
method: "wallet_switchEthereumChain",
|
|
488
|
-
params: [{ chainId: `0x${wantedNum.toString(16)}` }]
|
|
489
|
-
}).catch(() => {
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
toConnection(provider, account, chainId) {
|
|
493
|
-
return {
|
|
494
|
-
walletId: WALLET_ID,
|
|
495
|
-
account,
|
|
496
|
-
chainId,
|
|
497
|
-
request: async (args) => await provider.request({ method: args.method, params: args.params }),
|
|
498
|
-
disconnect: async () => {
|
|
499
|
-
await this.sdk?.terminate();
|
|
500
|
-
this.provider = null;
|
|
501
|
-
this.listenersBound = false;
|
|
502
|
-
this.emit({ type: "disconnect", walletId: WALLET_ID });
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
};
|
|
507
|
-
function toCaip(hexChainId) {
|
|
508
|
-
if (!hexChainId) return "eip155:1";
|
|
509
|
-
const num = hexChainId.startsWith("0x") ? parseInt(hexChainId, 16) : Number(hexChainId);
|
|
510
|
-
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
661
|
+
// src/core/lydian-connect.ts
|
|
662
|
+
function createConnectors(config) {
|
|
663
|
+
const app = {
|
|
664
|
+
appName: config.appName,
|
|
665
|
+
icon: config.icon,
|
|
666
|
+
description: config.description
|
|
667
|
+
};
|
|
668
|
+
return [
|
|
669
|
+
new MetaMaskConnector(app),
|
|
670
|
+
new CoinbaseConnector(app),
|
|
671
|
+
new WalletConnectConnector(app, { projectId: config.walletConnectProjectId })
|
|
672
|
+
];
|
|
511
673
|
}
|
|
512
|
-
|
|
513
|
-
// src/connectors/coinbase/connector.ts
|
|
514
|
-
function rpc(provider, method, params) {
|
|
515
|
-
return provider.request({ method, params });
|
|
516
|
-
}
|
|
517
|
-
var WALLET_ID2 = "coinbase";
|
|
518
|
-
var CoinbaseConnector = class extends BaseConnector {
|
|
674
|
+
var LydianConnect = class {
|
|
519
675
|
constructor(config) {
|
|
520
|
-
|
|
521
|
-
this.config = config;
|
|
522
|
-
this.type = "sdk";
|
|
523
|
-
this.walletIds = [WALLET_ID2];
|
|
524
|
-
this.provider = null;
|
|
525
|
-
this.listenersBound = false;
|
|
676
|
+
this.manager = new ConnectManager(createConnectors(config));
|
|
526
677
|
}
|
|
527
|
-
|
|
528
|
-
return
|
|
678
|
+
init() {
|
|
679
|
+
return this.manager.init();
|
|
529
680
|
}
|
|
530
|
-
async
|
|
531
|
-
if (
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
681
|
+
async connect(input) {
|
|
682
|
+
if (input.chainId === void 0 || input.chainId === null) {
|
|
683
|
+
throw new Error('connect() requires a chainId (a number like 137 or an "eip155:<id>" string)');
|
|
684
|
+
}
|
|
685
|
+
return this.manager.connect({
|
|
686
|
+
walletId: input.walletId,
|
|
687
|
+
namespace: buildNamespace(input.chainId),
|
|
688
|
+
signal: input.signal
|
|
537
689
|
});
|
|
538
|
-
const provider = sdk.makeWeb3Provider();
|
|
539
|
-
this.provider = provider;
|
|
540
|
-
this.bindEvents(provider);
|
|
541
|
-
return provider;
|
|
542
690
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
this.listenersBound = true;
|
|
546
|
-
provider.on("chainChanged", (hex) => {
|
|
547
|
-
this.emit({ type: "chainChanged", walletId: WALLET_ID2, chainId: toCaip2(String(hex)) });
|
|
548
|
-
});
|
|
549
|
-
provider.on("accountsChanged", (accounts) => {
|
|
550
|
-
const account = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
551
|
-
if (account) this.emit({ type: "accountsChanged", walletId: WALLET_ID2, account });
|
|
552
|
-
else this.emit({ type: "disconnect", walletId: WALLET_ID2 });
|
|
553
|
-
});
|
|
554
|
-
provider.on("disconnect", () => this.emit({ type: "disconnect", walletId: WALLET_ID2 }));
|
|
691
|
+
restore() {
|
|
692
|
+
return this.manager.restore();
|
|
555
693
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
const accounts = await rpc(provider, "eth_requestAccounts");
|
|
559
|
-
const account = accounts?.[0];
|
|
560
|
-
if (!account) throw new Error("Coinbase Wallet returned no account");
|
|
561
|
-
await this.ensureChain(provider, req);
|
|
562
|
-
const chainId = toCaip2(await rpc(provider, "eth_chainId"));
|
|
563
|
-
return this.toConnection(provider, account, chainId);
|
|
694
|
+
disconnect(walletId) {
|
|
695
|
+
return this.manager.disconnect(walletId);
|
|
564
696
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (!provider) return [];
|
|
568
|
-
const accounts = await rpc(provider, "eth_accounts").catch(() => []);
|
|
569
|
-
const account = accounts?.[0];
|
|
570
|
-
if (!account) return [];
|
|
571
|
-
const chainId = toCaip2(await rpc(provider, "eth_chainId").catch(() => "0x1"));
|
|
572
|
-
return [this.toConnection(provider, account, chainId)];
|
|
697
|
+
reset() {
|
|
698
|
+
return this.manager.reset();
|
|
573
699
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
});
|
|
577
|
-
this.provider = null;
|
|
578
|
-
this.listenersBound = false;
|
|
579
|
-
}
|
|
580
|
-
async ensureChain(provider, req) {
|
|
581
|
-
const wanted = req.namespace.value.chains?.[0];
|
|
582
|
-
const wantedNum = wanted ? Number(wanted.split(":")[1]) : NaN;
|
|
583
|
-
if (!Number.isFinite(wantedNum) || wantedNum <= 0) return;
|
|
584
|
-
const current = parseInt(await rpc(provider, "eth_chainId").catch(() => "0x0"), 16);
|
|
585
|
-
if (current === wantedNum) return;
|
|
586
|
-
await rpc(provider, "wallet_switchEthereumChain", [{ chainId: `0x${wantedNum.toString(16)}` }]).catch(
|
|
587
|
-
() => {
|
|
588
|
-
}
|
|
589
|
-
);
|
|
700
|
+
get(walletId) {
|
|
701
|
+
return this.manager.get(walletId);
|
|
590
702
|
}
|
|
591
|
-
|
|
592
|
-
return
|
|
593
|
-
walletId: WALLET_ID2,
|
|
594
|
-
account,
|
|
595
|
-
chainId,
|
|
596
|
-
request: (args) => rpc(provider, args.method, args.params),
|
|
597
|
-
disconnect: async () => {
|
|
598
|
-
await provider.disconnect().catch(() => {
|
|
599
|
-
});
|
|
600
|
-
this.provider = null;
|
|
601
|
-
this.listenersBound = false;
|
|
602
|
-
this.emit({ type: "disconnect", walletId: WALLET_ID2 });
|
|
603
|
-
}
|
|
604
|
-
};
|
|
703
|
+
on(handler) {
|
|
704
|
+
return this.manager.on(handler);
|
|
605
705
|
}
|
|
606
706
|
};
|
|
607
|
-
function toCaip2(hexChainId) {
|
|
608
|
-
if (!hexChainId) return "eip155:1";
|
|
609
|
-
const num = hexChainId.startsWith("0x") ? parseInt(hexChainId, 16) : Number(hexChainId);
|
|
610
|
-
return `eip155:${Number.isFinite(num) ? num : 1}`;
|
|
611
|
-
}
|
|
612
707
|
|
|
613
|
-
exports.BaseConnector = BaseConnector;
|
|
614
|
-
exports.CoinbaseConnector = CoinbaseConnector;
|
|
615
|
-
exports.DEFAULT_WALLET_LINKS = DEFAULT_WALLET_LINKS;
|
|
616
708
|
exports.LydianConnect = LydianConnect;
|
|
617
|
-
exports.MetaMaskConnector = MetaMaskConnector;
|
|
618
|
-
exports.WalletConnectConnector = WalletConnectConnector;
|
|
619
709
|
//# sourceMappingURL=index.cjs.map
|
|
620
710
|
//# sourceMappingURL=index.cjs.map
|