@enclave-hq/wallet-sdk 1.2.3 → 1.2.5
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 +51 -1
- package/dist/index.d.mts +380 -195
- package/dist/index.js +3117 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3774 -111
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +91 -9
- package/dist/react/index.d.ts +91 -9
- package/dist/react/index.js +3651 -104
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +3625 -82
- package/dist/react/index.mjs.map +1 -1
- package/dist/tron.d.mts +36 -0
- package/dist/tron.js +852 -0
- package/dist/tron.js.map +1 -0
- package/dist/tron.mjs +846 -0
- package/dist/tron.mjs.map +1 -0
- package/dist/wallet-adapter-DRd0xm3N.d.mts +197 -0
- package/package.json +14 -4
- package/dist/index.d.ts +0 -477
package/dist/react/index.js
CHANGED
|
@@ -1,17 +1,589 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var React = require('react');
|
|
4
|
-
var EventEmitter = require('eventemitter3');
|
|
5
3
|
var chainUtils = require('@enclave-hq/chain-utils');
|
|
4
|
+
var React2 = require('react');
|
|
5
|
+
var EventEmitter = require('eventemitter3');
|
|
6
6
|
var viem = require('viem');
|
|
7
7
|
var accounts = require('viem/accounts');
|
|
8
|
+
var EthereumProvider = require('@walletconnect/ethereum-provider');
|
|
9
|
+
var walletconnectTron = require('@tronweb3/walletconnect-tron');
|
|
10
|
+
var QRCode = require('qrcode');
|
|
8
11
|
|
|
9
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
13
|
|
|
11
|
-
var
|
|
14
|
+
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
12
15
|
var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
|
|
16
|
+
var EthereumProvider__default = /*#__PURE__*/_interopDefault(EthereumProvider);
|
|
17
|
+
var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
var __defProp = Object.defineProperty;
|
|
20
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
21
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
22
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
23
|
+
var __esm = (fn, res) => function __init() {
|
|
24
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
25
|
+
};
|
|
26
|
+
var __export = (target, all) => {
|
|
27
|
+
for (var name in all)
|
|
28
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
29
|
+
};
|
|
30
|
+
var __copyProps = (to, from, except, desc) => {
|
|
31
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
32
|
+
for (let key of __getOwnPropNames(from))
|
|
33
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
34
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
35
|
+
}
|
|
36
|
+
return to;
|
|
37
|
+
};
|
|
38
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
39
|
+
var ChainType;
|
|
40
|
+
var init_types = __esm({
|
|
41
|
+
"src/core/types.ts"() {
|
|
42
|
+
ChainType = chainUtils.ChainType;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// src/adapters/deep-link/providers/tokenpocket.ts
|
|
47
|
+
var tokenpocket_exports = {};
|
|
48
|
+
__export(tokenpocket_exports, {
|
|
49
|
+
TokenPocketDeepLinkProvider: () => TokenPocketDeepLinkProvider
|
|
50
|
+
});
|
|
51
|
+
var TokenPocketDeepLinkProvider;
|
|
52
|
+
var init_tokenpocket = __esm({
|
|
53
|
+
"src/adapters/deep-link/providers/tokenpocket.ts"() {
|
|
54
|
+
init_types();
|
|
55
|
+
TokenPocketDeepLinkProvider = class {
|
|
56
|
+
constructor(options) {
|
|
57
|
+
this.name = "TokenPocket";
|
|
58
|
+
this.icon = "https://tokenpocket.pro/icon.png";
|
|
59
|
+
this.supportedChainTypes = [ChainType.EVM, ChainType.TRON];
|
|
60
|
+
this.callbackUrl = options?.callbackUrl;
|
|
61
|
+
this.callbackSchema = options?.callbackSchema;
|
|
62
|
+
}
|
|
63
|
+
async isAvailable() {
|
|
64
|
+
if (typeof window === "undefined") {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
68
|
+
if (isTelegramMiniApp) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
72
|
+
navigator.userAgent
|
|
73
|
+
);
|
|
74
|
+
return isMobile;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Generate unique actionId
|
|
78
|
+
*/
|
|
79
|
+
generateActionId() {
|
|
80
|
+
return `web-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get callback configuration
|
|
84
|
+
*/
|
|
85
|
+
getCallbackConfig() {
|
|
86
|
+
if (this.callbackSchema) {
|
|
87
|
+
return { callbackSchema: this.callbackSchema };
|
|
88
|
+
}
|
|
89
|
+
if (this.callbackUrl) {
|
|
90
|
+
return { callbackUrl: this.callbackUrl };
|
|
91
|
+
}
|
|
92
|
+
if (typeof window !== "undefined" && window.location) {
|
|
93
|
+
return {
|
|
94
|
+
callbackSchema: `${window.location.protocol}//${window.location.host}${window.location.pathname}`
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get blockchain configuration based on chain type
|
|
101
|
+
*/
|
|
102
|
+
getBlockchainConfig(chainId, chainType) {
|
|
103
|
+
if (chainType === ChainType.TRON) {
|
|
104
|
+
return {
|
|
105
|
+
chainId: String(chainId),
|
|
106
|
+
network: "tron"
|
|
107
|
+
};
|
|
108
|
+
} else if (chainType === ChainType.EVM) {
|
|
109
|
+
return {
|
|
110
|
+
chainId: String(chainId),
|
|
111
|
+
network: "ethereum"
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
115
|
+
}
|
|
116
|
+
buildSignMessageLink(params) {
|
|
117
|
+
const actionId = this.generateActionId();
|
|
118
|
+
const callback = this.getCallbackConfig();
|
|
119
|
+
const blockchain = this.getBlockchainConfig(params.chainId, params.chainType);
|
|
120
|
+
const param = {
|
|
121
|
+
action: "sign",
|
|
122
|
+
actionId,
|
|
123
|
+
message: params.message,
|
|
124
|
+
hash: false,
|
|
125
|
+
signType: params.chainType === ChainType.TRON ? "ethPersonalSign" : "ethPersonalSign",
|
|
126
|
+
memo: `${params.chainType} message signature`,
|
|
127
|
+
blockchains: [blockchain],
|
|
128
|
+
dappName: "Enclave Wallet SDK",
|
|
129
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
130
|
+
protocol: "TokenPocket",
|
|
131
|
+
version: "1.1.8",
|
|
132
|
+
expired: 0,
|
|
133
|
+
...callback
|
|
134
|
+
};
|
|
135
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
136
|
+
const url = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
137
|
+
return {
|
|
138
|
+
url,
|
|
139
|
+
actionId,
|
|
140
|
+
...callback
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
buildSignTransactionLink(params) {
|
|
144
|
+
const actionId = this.generateActionId();
|
|
145
|
+
const callback = this.getCallbackConfig();
|
|
146
|
+
const blockchain = this.getBlockchainConfig(params.chainId, params.chainType);
|
|
147
|
+
let transactionData;
|
|
148
|
+
if (typeof params.transaction === "string") {
|
|
149
|
+
transactionData = params.transaction;
|
|
150
|
+
} else {
|
|
151
|
+
transactionData = JSON.stringify(params.transaction);
|
|
152
|
+
}
|
|
153
|
+
const param = {
|
|
154
|
+
action: "pushTransaction",
|
|
155
|
+
actionId,
|
|
156
|
+
txData: transactionData,
|
|
157
|
+
blockchains: [blockchain],
|
|
158
|
+
dappName: "Enclave Wallet SDK",
|
|
159
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
160
|
+
protocol: "TokenPocket",
|
|
161
|
+
version: "1.1.8",
|
|
162
|
+
expired: 0,
|
|
163
|
+
...callback
|
|
164
|
+
};
|
|
165
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
166
|
+
const url = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
167
|
+
return {
|
|
168
|
+
url,
|
|
169
|
+
actionId,
|
|
170
|
+
...callback
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
buildConnectLink(params) {
|
|
174
|
+
const actionId = this.generateActionId();
|
|
175
|
+
const blockchain = this.getBlockchainConfig(params.chainId, params.chainType);
|
|
176
|
+
const param = {
|
|
177
|
+
action: "login",
|
|
178
|
+
actionId,
|
|
179
|
+
blockchains: [blockchain],
|
|
180
|
+
dappName: "Enclave Wallet SDK",
|
|
181
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
182
|
+
protocol: "TokenPocket",
|
|
183
|
+
version: "1.0",
|
|
184
|
+
expired: 1602
|
|
185
|
+
// 30 minutes
|
|
186
|
+
};
|
|
187
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
188
|
+
const url = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
189
|
+
return {
|
|
190
|
+
url,
|
|
191
|
+
actionId
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
parseCallbackResult(urlParams) {
|
|
195
|
+
const actionId = urlParams.get("actionId");
|
|
196
|
+
const resultParam = urlParams.get("result");
|
|
197
|
+
const error = urlParams.get("error");
|
|
198
|
+
let result = null;
|
|
199
|
+
if (resultParam) {
|
|
200
|
+
try {
|
|
201
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
202
|
+
} catch (e) {
|
|
203
|
+
result = resultParam;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
actionId,
|
|
208
|
+
result,
|
|
209
|
+
error
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
getDefaultCallbackSchema() {
|
|
213
|
+
if (typeof window !== "undefined" && window.location) {
|
|
214
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
215
|
+
}
|
|
216
|
+
return "";
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// src/adapters/deep-link/providers/tronlink.ts
|
|
223
|
+
var tronlink_exports = {};
|
|
224
|
+
__export(tronlink_exports, {
|
|
225
|
+
TronLinkDeepLinkProvider: () => TronLinkDeepLinkProvider
|
|
226
|
+
});
|
|
227
|
+
var TronLinkDeepLinkProvider;
|
|
228
|
+
var init_tronlink = __esm({
|
|
229
|
+
"src/adapters/deep-link/providers/tronlink.ts"() {
|
|
230
|
+
init_types();
|
|
231
|
+
TronLinkDeepLinkProvider = class {
|
|
232
|
+
constructor() {
|
|
233
|
+
this.name = "TronLink";
|
|
234
|
+
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
235
|
+
this.supportedChainTypes = [ChainType.TRON];
|
|
236
|
+
}
|
|
237
|
+
async isAvailable() {
|
|
238
|
+
if (typeof window === "undefined") {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
242
|
+
if (isTelegramMiniApp) {
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
246
|
+
navigator.userAgent
|
|
247
|
+
);
|
|
248
|
+
return isMobile;
|
|
249
|
+
}
|
|
250
|
+
buildSignMessageLink(params) {
|
|
251
|
+
if (params.chainType !== ChainType.TRON) {
|
|
252
|
+
throw new Error("TronLink only supports TRON chain");
|
|
253
|
+
}
|
|
254
|
+
const encodedMessage = encodeURIComponent(params.message);
|
|
255
|
+
const url = `tronlink://signMessage?message=${encodedMessage}`;
|
|
256
|
+
const actionId = `tronlink-${Date.now()}`;
|
|
257
|
+
return {
|
|
258
|
+
url,
|
|
259
|
+
actionId
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
buildSignTransactionLink(params) {
|
|
263
|
+
if (params.chainType !== ChainType.TRON) {
|
|
264
|
+
throw new Error("TronLink only supports TRON chain");
|
|
265
|
+
}
|
|
266
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
267
|
+
const encodedData = encodeURIComponent(transactionData);
|
|
268
|
+
const url = `tronlink://signTransaction?transaction=${encodedData}`;
|
|
269
|
+
const actionId = `tronlink-${Date.now()}`;
|
|
270
|
+
return {
|
|
271
|
+
url,
|
|
272
|
+
actionId
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
buildConnectLink(params) {
|
|
276
|
+
if (params.chainType !== ChainType.TRON) {
|
|
277
|
+
throw new Error("TronLink only supports TRON chain");
|
|
278
|
+
}
|
|
279
|
+
const url = `tronlink://open?action=connect&network=tron`;
|
|
280
|
+
return {
|
|
281
|
+
url
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
parseCallbackResult(_urlParams) {
|
|
285
|
+
return {
|
|
286
|
+
actionId: null,
|
|
287
|
+
result: null,
|
|
288
|
+
error: null
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// src/adapters/deep-link/providers/imtoken.ts
|
|
296
|
+
var imtoken_exports = {};
|
|
297
|
+
__export(imtoken_exports, {
|
|
298
|
+
ImTokenDeepLinkProvider: () => ImTokenDeepLinkProvider
|
|
299
|
+
});
|
|
300
|
+
var ImTokenDeepLinkProvider;
|
|
301
|
+
var init_imtoken = __esm({
|
|
302
|
+
"src/adapters/deep-link/providers/imtoken.ts"() {
|
|
303
|
+
init_types();
|
|
304
|
+
ImTokenDeepLinkProvider = class {
|
|
305
|
+
constructor(options) {
|
|
306
|
+
this.name = "ImToken";
|
|
307
|
+
this.icon = "https://token.im/static/img/logo.png";
|
|
308
|
+
this.supportedChainTypes = [ChainType.EVM, ChainType.TRON];
|
|
309
|
+
this.callbackUrl = options?.callbackUrl;
|
|
310
|
+
this.callbackSchema = options?.callbackSchema;
|
|
311
|
+
}
|
|
312
|
+
async isAvailable() {
|
|
313
|
+
if (typeof window === "undefined") {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
317
|
+
if (isTelegramMiniApp) {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
321
|
+
navigator.userAgent
|
|
322
|
+
);
|
|
323
|
+
return isMobile;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Generate unique actionId
|
|
327
|
+
*/
|
|
328
|
+
generateActionId() {
|
|
329
|
+
return `imtoken-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Get callback configuration
|
|
333
|
+
*/
|
|
334
|
+
getCallbackConfig() {
|
|
335
|
+
if (this.callbackSchema) {
|
|
336
|
+
return { callbackSchema: this.callbackSchema };
|
|
337
|
+
}
|
|
338
|
+
if (this.callbackUrl) {
|
|
339
|
+
return { callbackUrl: this.callbackUrl };
|
|
340
|
+
}
|
|
341
|
+
if (typeof window !== "undefined" && window.location) {
|
|
342
|
+
return {
|
|
343
|
+
callbackSchema: `${window.location.protocol}//${window.location.host}${window.location.pathname}`
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return {};
|
|
347
|
+
}
|
|
348
|
+
buildSignMessageLink(params) {
|
|
349
|
+
const actionId = this.generateActionId();
|
|
350
|
+
const callback = this.getCallbackConfig();
|
|
351
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signMessage&message=${encodeURIComponent(params.message)}&chainId=${params.chainId}`;
|
|
352
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
353
|
+
const url = `imtokenv2://navigate/DappView?url=${encodedDappUrl}`;
|
|
354
|
+
return {
|
|
355
|
+
url,
|
|
356
|
+
actionId,
|
|
357
|
+
...callback
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
buildSignTransactionLink(params) {
|
|
361
|
+
const actionId = this.generateActionId();
|
|
362
|
+
const callback = this.getCallbackConfig();
|
|
363
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
364
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signTransaction&transaction=${encodeURIComponent(transactionData)}&chainId=${params.chainId}`;
|
|
365
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
366
|
+
const url = `imtokenv2://navigate/DappView?url=${encodedDappUrl}`;
|
|
367
|
+
return {
|
|
368
|
+
url,
|
|
369
|
+
actionId,
|
|
370
|
+
...callback
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
buildConnectLink(params) {
|
|
374
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=connect&chainId=${params.chainId}`;
|
|
375
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
376
|
+
const url = `imtokenv2://navigate/DappView?url=${encodedDappUrl}`;
|
|
377
|
+
return {
|
|
378
|
+
url
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
parseCallbackResult(urlParams) {
|
|
382
|
+
const actionId = urlParams.get("actionId");
|
|
383
|
+
const resultParam = urlParams.get("result");
|
|
384
|
+
const error = urlParams.get("error");
|
|
385
|
+
let result = null;
|
|
386
|
+
if (resultParam) {
|
|
387
|
+
try {
|
|
388
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
389
|
+
} catch (e) {
|
|
390
|
+
result = resultParam;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
actionId,
|
|
395
|
+
result,
|
|
396
|
+
error
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
getDefaultCallbackSchema() {
|
|
400
|
+
if (typeof window !== "undefined" && window.location) {
|
|
401
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
402
|
+
}
|
|
403
|
+
return "";
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// src/adapters/deep-link/providers/metamask.ts
|
|
410
|
+
var metamask_exports = {};
|
|
411
|
+
__export(metamask_exports, {
|
|
412
|
+
MetaMaskDeepLinkProvider: () => MetaMaskDeepLinkProvider
|
|
413
|
+
});
|
|
414
|
+
var MetaMaskDeepLinkProvider;
|
|
415
|
+
var init_metamask = __esm({
|
|
416
|
+
"src/adapters/deep-link/providers/metamask.ts"() {
|
|
417
|
+
init_types();
|
|
418
|
+
MetaMaskDeepLinkProvider = class {
|
|
419
|
+
constructor() {
|
|
420
|
+
this.name = "MetaMask";
|
|
421
|
+
this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
|
|
422
|
+
this.supportedChainTypes = [ChainType.EVM];
|
|
423
|
+
}
|
|
424
|
+
async isAvailable() {
|
|
425
|
+
if (typeof window === "undefined") {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
429
|
+
if (isTelegramMiniApp) {
|
|
430
|
+
return true;
|
|
431
|
+
}
|
|
432
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
433
|
+
navigator.userAgent
|
|
434
|
+
);
|
|
435
|
+
return isMobile;
|
|
436
|
+
}
|
|
437
|
+
buildSignMessageLink(params) {
|
|
438
|
+
if (params.chainType !== ChainType.EVM) {
|
|
439
|
+
throw new Error("MetaMask only supports EVM chains");
|
|
440
|
+
}
|
|
441
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signMessage&message=${encodeURIComponent(params.message)}&chainId=${params.chainId}`;
|
|
442
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
443
|
+
const url = `https://link.metamask.io/dapp/${encodedDappUrl}`;
|
|
444
|
+
const actionId = `metamask-${Date.now()}`;
|
|
445
|
+
return {
|
|
446
|
+
url,
|
|
447
|
+
actionId
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
buildSignTransactionLink(params) {
|
|
451
|
+
if (params.chainType !== ChainType.EVM) {
|
|
452
|
+
throw new Error("MetaMask only supports EVM chains");
|
|
453
|
+
}
|
|
454
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
455
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signTransaction&transaction=${encodeURIComponent(transactionData)}&chainId=${params.chainId}`;
|
|
456
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
457
|
+
const url = `https://link.metamask.io/dapp/${encodedDappUrl}`;
|
|
458
|
+
const actionId = `metamask-${Date.now()}`;
|
|
459
|
+
return {
|
|
460
|
+
url,
|
|
461
|
+
actionId
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
buildConnectLink(params) {
|
|
465
|
+
if (params.chainType !== ChainType.EVM) {
|
|
466
|
+
throw new Error("MetaMask only supports EVM chains");
|
|
467
|
+
}
|
|
468
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=connect&chainId=${params.chainId}`;
|
|
469
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
470
|
+
const url = `https://link.metamask.io/dapp/${encodedDappUrl}`;
|
|
471
|
+
return {
|
|
472
|
+
url
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
parseCallbackResult(urlParams) {
|
|
476
|
+
const actionId = urlParams.get("actionId");
|
|
477
|
+
const resultParam = urlParams.get("result");
|
|
478
|
+
const error = urlParams.get("error");
|
|
479
|
+
let result = null;
|
|
480
|
+
if (resultParam) {
|
|
481
|
+
try {
|
|
482
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
483
|
+
} catch (e) {
|
|
484
|
+
result = resultParam;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return {
|
|
488
|
+
actionId,
|
|
489
|
+
result,
|
|
490
|
+
error
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
getDefaultCallbackSchema() {
|
|
494
|
+
if (typeof window !== "undefined" && window.location) {
|
|
495
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
496
|
+
}
|
|
497
|
+
return "";
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// src/adapters/deep-link/providers/okx.ts
|
|
504
|
+
var okx_exports = {};
|
|
505
|
+
__export(okx_exports, {
|
|
506
|
+
OKXDeepLinkProvider: () => OKXDeepLinkProvider
|
|
507
|
+
});
|
|
508
|
+
var OKXDeepLinkProvider;
|
|
509
|
+
var init_okx = __esm({
|
|
510
|
+
"src/adapters/deep-link/providers/okx.ts"() {
|
|
511
|
+
init_types();
|
|
512
|
+
OKXDeepLinkProvider = class {
|
|
513
|
+
constructor() {
|
|
514
|
+
this.name = "OKX";
|
|
515
|
+
this.icon = "https://www.okx.com/favicon.ico";
|
|
516
|
+
this.supportedChainTypes = [ChainType.EVM, ChainType.TRON];
|
|
517
|
+
}
|
|
518
|
+
async isAvailable() {
|
|
519
|
+
if (typeof window === "undefined") {
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
523
|
+
if (isTelegramMiniApp) {
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
527
|
+
navigator.userAgent
|
|
528
|
+
);
|
|
529
|
+
return isMobile;
|
|
530
|
+
}
|
|
531
|
+
buildSignMessageLink(params) {
|
|
532
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signMessage&message=${encodeURIComponent(params.message)}&chainId=${params.chainId}`;
|
|
533
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
534
|
+
const url = `okx://wallet/dapp/url?dappUrl=${encodedDappUrl}`;
|
|
535
|
+
const actionId = `okx-${Date.now()}`;
|
|
536
|
+
return {
|
|
537
|
+
url,
|
|
538
|
+
actionId
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
buildSignTransactionLink(params) {
|
|
542
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
543
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signTransaction&transaction=${encodeURIComponent(transactionData)}&chainId=${params.chainId}`;
|
|
544
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
545
|
+
const url = `okx://wallet/dapp/url?dappUrl=${encodedDappUrl}`;
|
|
546
|
+
const actionId = `okx-${Date.now()}`;
|
|
547
|
+
return {
|
|
548
|
+
url,
|
|
549
|
+
actionId
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
buildConnectLink(params) {
|
|
553
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=connect&chainId=${params.chainId}`;
|
|
554
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
555
|
+
const url = `okx://wallet/dapp/url?dappUrl=${encodedDappUrl}`;
|
|
556
|
+
return {
|
|
557
|
+
url
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
parseCallbackResult(urlParams) {
|
|
561
|
+
const actionId = urlParams.get("actionId");
|
|
562
|
+
const resultParam = urlParams.get("result");
|
|
563
|
+
const error = urlParams.get("error");
|
|
564
|
+
let result = null;
|
|
565
|
+
if (resultParam) {
|
|
566
|
+
try {
|
|
567
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
568
|
+
} catch (e) {
|
|
569
|
+
result = resultParam;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
actionId,
|
|
574
|
+
result,
|
|
575
|
+
error
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
getDefaultCallbackSchema() {
|
|
579
|
+
if (typeof window !== "undefined" && window.location) {
|
|
580
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
581
|
+
}
|
|
582
|
+
return "";
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
});
|
|
15
587
|
var TypedEventEmitter = class {
|
|
16
588
|
constructor() {
|
|
17
589
|
this.emitter = new EventEmitter__default.default();
|
|
@@ -40,7 +612,12 @@ var TypedEventEmitter = class {
|
|
|
40
612
|
return this;
|
|
41
613
|
}
|
|
42
614
|
};
|
|
43
|
-
|
|
615
|
+
|
|
616
|
+
// src/core/adapter-registry.ts
|
|
617
|
+
init_types();
|
|
618
|
+
|
|
619
|
+
// src/adapters/base/wallet-adapter.ts
|
|
620
|
+
init_types();
|
|
44
621
|
|
|
45
622
|
// src/core/errors.ts
|
|
46
623
|
var WalletSDKError = class _WalletSDKError extends Error {
|
|
@@ -111,6 +688,18 @@ var MethodNotSupportedError = class extends WalletSDKError {
|
|
|
111
688
|
this.name = "MethodNotSupportedError";
|
|
112
689
|
}
|
|
113
690
|
};
|
|
691
|
+
var ConfigurationError = class extends WalletSDKError {
|
|
692
|
+
constructor(message, details) {
|
|
693
|
+
super(message, "CONFIGURATION_ERROR", details);
|
|
694
|
+
this.name = "ConfigurationError";
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
var NetworkError = class extends WalletSDKError {
|
|
698
|
+
constructor(message, details) {
|
|
699
|
+
super(message, "NETWORK_ERROR", details);
|
|
700
|
+
this.name = "NetworkError";
|
|
701
|
+
}
|
|
702
|
+
};
|
|
114
703
|
|
|
115
704
|
// src/adapters/base/wallet-adapter.ts
|
|
116
705
|
var WalletAdapter = class extends EventEmitter__default.default {
|
|
@@ -120,6 +709,13 @@ var WalletAdapter = class extends EventEmitter__default.default {
|
|
|
120
709
|
this.state = "disconnected" /* DISCONNECTED */;
|
|
121
710
|
this.currentAccount = null;
|
|
122
711
|
}
|
|
712
|
+
/**
|
|
713
|
+
* Check if the wallet is currently connected
|
|
714
|
+
* @returns true if the wallet is connected (state is CONNECTED and has an account)
|
|
715
|
+
*/
|
|
716
|
+
isConnected() {
|
|
717
|
+
return this.state === "connected" /* CONNECTED */ && this.currentAccount !== null;
|
|
718
|
+
}
|
|
123
719
|
/**
|
|
124
720
|
* Get the signer's address (implements ISigner interface)
|
|
125
721
|
* Returns the native address of the current account
|
|
@@ -189,6 +785,7 @@ var WalletAdapter = class extends EventEmitter__default.default {
|
|
|
189
785
|
};
|
|
190
786
|
|
|
191
787
|
// src/adapters/base/browser-wallet-adapter.ts
|
|
788
|
+
init_types();
|
|
192
789
|
var BrowserWalletAdapter = class extends WalletAdapter {
|
|
193
790
|
/**
|
|
194
791
|
* 检查钱包是否可用
|
|
@@ -222,6 +819,9 @@ var BrowserWalletAdapter = class extends WalletAdapter {
|
|
|
222
819
|
}
|
|
223
820
|
};
|
|
224
821
|
|
|
822
|
+
// src/adapters/evm/metamask.ts
|
|
823
|
+
init_types();
|
|
824
|
+
|
|
225
825
|
// src/utils/address/universal-address.ts
|
|
226
826
|
function createUniversalAddress(chainId, address) {
|
|
227
827
|
return `${chainId}:${address}`;
|
|
@@ -246,7 +846,12 @@ var CHAIN_INFO = {
|
|
|
246
846
|
symbol: "ETH",
|
|
247
847
|
decimals: 18
|
|
248
848
|
},
|
|
249
|
-
|
|
849
|
+
// 使用支持浏览器 CORS 的公共 RPC,避免 dapp 域名被跨域拦截(如 eth.llamarpc.com 无 CORS 头)
|
|
850
|
+
rpcUrls: [
|
|
851
|
+
"https://cloudflare-eth.com",
|
|
852
|
+
"https://rpc.ankr.com/eth",
|
|
853
|
+
"https://eth.llamarpc.com"
|
|
854
|
+
],
|
|
250
855
|
blockExplorerUrls: ["https://etherscan.io"]
|
|
251
856
|
},
|
|
252
857
|
// EVM Testnets
|
|
@@ -466,6 +1071,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
466
1071
|
*/
|
|
467
1072
|
async connect(chainId) {
|
|
468
1073
|
await this.ensureAvailable();
|
|
1074
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId;
|
|
469
1075
|
try {
|
|
470
1076
|
this.setState("connecting" /* CONNECTING */);
|
|
471
1077
|
const provider = this.getBrowserProvider();
|
|
@@ -479,10 +1085,10 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
479
1085
|
method: "eth_chainId"
|
|
480
1086
|
});
|
|
481
1087
|
const parsedChainId = parseInt(currentChainId, 16);
|
|
482
|
-
if (
|
|
483
|
-
await this.switchChain(
|
|
1088
|
+
if (targetChainId && targetChainId !== parsedChainId) {
|
|
1089
|
+
await this.switchChain(targetChainId);
|
|
484
1090
|
}
|
|
485
|
-
const finalChainId =
|
|
1091
|
+
const finalChainId = targetChainId || parsedChainId;
|
|
486
1092
|
const viemChain = this.getViemChain(finalChainId);
|
|
487
1093
|
this.walletClient = viem.createWalletClient({
|
|
488
1094
|
account: accounts[0],
|
|
@@ -644,6 +1250,56 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
644
1250
|
}]
|
|
645
1251
|
});
|
|
646
1252
|
}
|
|
1253
|
+
/**
|
|
1254
|
+
* 请求切换账户
|
|
1255
|
+
* 弹出 MetaMask 账户选择界面,让用户选择或切换到目标地址
|
|
1256
|
+
* @param targetAddress 目标地址(可选),如果提供,会在切换后验证是否匹配
|
|
1257
|
+
* @returns 切换后的账户信息
|
|
1258
|
+
*/
|
|
1259
|
+
async requestSwitchAccount(targetAddress) {
|
|
1260
|
+
const provider = this.getBrowserProvider();
|
|
1261
|
+
if (!provider) {
|
|
1262
|
+
throw new Error("MetaMask provider not available");
|
|
1263
|
+
}
|
|
1264
|
+
try {
|
|
1265
|
+
await provider.request({
|
|
1266
|
+
method: "wallet_requestPermissions",
|
|
1267
|
+
params: [{ eth_accounts: {} }]
|
|
1268
|
+
});
|
|
1269
|
+
const accounts = await provider.request({
|
|
1270
|
+
method: "eth_accounts"
|
|
1271
|
+
});
|
|
1272
|
+
if (!accounts || accounts.length === 0) {
|
|
1273
|
+
throw new ConnectionRejectedError(this.type);
|
|
1274
|
+
}
|
|
1275
|
+
const address = formatEVMAddress(accounts[0]);
|
|
1276
|
+
if (targetAddress && address.toLowerCase() !== targetAddress.toLowerCase()) {
|
|
1277
|
+
throw new Error(`\u8BF7\u5728 MetaMask \u4E2D\u9009\u62E9\u5730\u5740 ${targetAddress.slice(0, 6)}...${targetAddress.slice(-4)}\uFF0C\u5F53\u524D\u9009\u62E9\u7684\u662F ${address.slice(0, 6)}...${address.slice(-4)}`);
|
|
1278
|
+
}
|
|
1279
|
+
const chainId = this.currentAccount?.chainId || 1;
|
|
1280
|
+
const account = {
|
|
1281
|
+
universalAddress: createUniversalAddress(chainId, address),
|
|
1282
|
+
nativeAddress: address,
|
|
1283
|
+
chainId,
|
|
1284
|
+
chainType: ChainType.EVM,
|
|
1285
|
+
isActive: true
|
|
1286
|
+
};
|
|
1287
|
+
this.setAccount(account);
|
|
1288
|
+
this.emitAccountChanged(account);
|
|
1289
|
+
const viemChain = this.getViemChain(chainId);
|
|
1290
|
+
this.walletClient = viem.createWalletClient({
|
|
1291
|
+
account: address,
|
|
1292
|
+
chain: viemChain,
|
|
1293
|
+
transport: viem.custom(provider)
|
|
1294
|
+
});
|
|
1295
|
+
return account;
|
|
1296
|
+
} catch (error) {
|
|
1297
|
+
if (error.code === 4001) {
|
|
1298
|
+
throw new ConnectionRejectedError(this.type);
|
|
1299
|
+
}
|
|
1300
|
+
throw error;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
647
1303
|
/**
|
|
648
1304
|
* 读取合约
|
|
649
1305
|
*/
|
|
@@ -868,6 +1524,47 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
868
1524
|
};
|
|
869
1525
|
|
|
870
1526
|
// src/adapters/tron/tronlink.ts
|
|
1527
|
+
init_types();
|
|
1528
|
+
var TronApiRateLimiter = class {
|
|
1529
|
+
constructor(minIntervalMs = 600) {
|
|
1530
|
+
this.lastCallTime = 0;
|
|
1531
|
+
this.minInterval = minIntervalMs;
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* 等待直到可以进行下一次 API 调用
|
|
1535
|
+
*/
|
|
1536
|
+
async waitForNextCall() {
|
|
1537
|
+
const now = Date.now();
|
|
1538
|
+
const timeSinceLastCall = now - this.lastCallTime;
|
|
1539
|
+
if (timeSinceLastCall < this.minInterval) {
|
|
1540
|
+
const waitTime = this.minInterval - timeSinceLastCall;
|
|
1541
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
1542
|
+
}
|
|
1543
|
+
this.lastCallTime = Date.now();
|
|
1544
|
+
}
|
|
1545
|
+
};
|
|
1546
|
+
var tronApiRateLimiter = new TronApiRateLimiter(600);
|
|
1547
|
+
async function retryWithBackoff(fn, maxRetries = 3, initialDelay = 500) {
|
|
1548
|
+
let lastError;
|
|
1549
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1550
|
+
try {
|
|
1551
|
+
return await fn();
|
|
1552
|
+
} catch (error) {
|
|
1553
|
+
lastError = error;
|
|
1554
|
+
const errorMsg = error?.message || String(error);
|
|
1555
|
+
const errorLower = errorMsg.toLowerCase();
|
|
1556
|
+
const isRateLimitError = error?.response?.status === 429 || error?.status === 429 || errorLower.includes("429") || errorLower.includes("rate limit") || errorLower.includes("too many requests") || error?.code === "ERR_BAD_REQUEST" && error?.response?.status === 429;
|
|
1557
|
+
if (isRateLimitError && attempt < maxRetries - 1) {
|
|
1558
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
1559
|
+
console.warn(`[TronLink] \u9047\u5230\u901F\u7387\u9650\u5236 (429)\uFF0C\u7B49\u5F85 ${delay}ms \u540E\u91CD\u8BD5 (${attempt + 1}/${maxRetries})...`);
|
|
1560
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1563
|
+
throw error;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
throw lastError;
|
|
1567
|
+
}
|
|
871
1568
|
var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
872
1569
|
constructor() {
|
|
873
1570
|
super(...arguments);
|
|
@@ -915,6 +1612,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
915
1612
|
*/
|
|
916
1613
|
async connect(chainId) {
|
|
917
1614
|
await this.ensureAvailable();
|
|
1615
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId;
|
|
918
1616
|
try {
|
|
919
1617
|
this.setState("connecting" /* CONNECTING */);
|
|
920
1618
|
const w = window;
|
|
@@ -969,7 +1667,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
969
1667
|
if (!address) {
|
|
970
1668
|
throw new Error("Failed to get Tron address. Please make sure your wallet is unlocked and try again.");
|
|
971
1669
|
}
|
|
972
|
-
const tronChainId =
|
|
1670
|
+
const tronChainId = targetChainId || _TronLinkAdapter.TRON_MAINNET_CHAIN_ID;
|
|
973
1671
|
const account = {
|
|
974
1672
|
universalAddress: createUniversalAddress(tronChainId, address),
|
|
975
1673
|
nativeAddress: address,
|
|
@@ -1044,10 +1742,12 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1044
1742
|
/**
|
|
1045
1743
|
* 读取合约
|
|
1046
1744
|
* 参考 webserver 的实现,使用 TronWeb 合约实例的标准 call() 方法
|
|
1745
|
+
* 带 TronGrid 限流 + 429 重试
|
|
1047
1746
|
*/
|
|
1048
1747
|
async readContract(params) {
|
|
1049
1748
|
this.ensureConnected();
|
|
1050
|
-
|
|
1749
|
+
await tronApiRateLimiter.waitForNextCall();
|
|
1750
|
+
const doRead = async () => {
|
|
1051
1751
|
const tronWeb = this.getTronWeb();
|
|
1052
1752
|
if (!this.currentAccount) {
|
|
1053
1753
|
throw new Error("No account connected");
|
|
@@ -1062,19 +1762,17 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1062
1762
|
return result;
|
|
1063
1763
|
} catch (method1Error) {
|
|
1064
1764
|
console.warn("\u26A0\uFE0F [\u65B9\u6CD51] TronWeb\u6807\u51C6\u65B9\u6CD5\u5931\u8D25\uFF0C\u5C1D\u8BD5\u65B9\u6CD52:", method1Error.message);
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
throw new Error(`Function ${params.functionName} not found in contract`);
|
|
1070
|
-
}
|
|
1071
|
-
const result = await method2(...params.args || []).call();
|
|
1072
|
-
return result;
|
|
1073
|
-
} catch (method2Error) {
|
|
1074
|
-
console.error("\u26A0\uFE0F [\u65B9\u6CD52] \u4E5F\u5931\u8D25:", method2Error.message);
|
|
1075
|
-
throw method1Error;
|
|
1765
|
+
const contract2 = await tronWeb.contract().at(params.address);
|
|
1766
|
+
const method2 = contract2[params.functionName];
|
|
1767
|
+
if (!method2 || typeof method2 !== "function") {
|
|
1768
|
+
throw new Error(`Function ${params.functionName} not found in contract`);
|
|
1076
1769
|
}
|
|
1770
|
+
const result = await method2(...params.args || []).call();
|
|
1771
|
+
return result;
|
|
1077
1772
|
}
|
|
1773
|
+
};
|
|
1774
|
+
try {
|
|
1775
|
+
return await retryWithBackoff(doRead, 3, 800);
|
|
1078
1776
|
} catch (error) {
|
|
1079
1777
|
console.error("Read contract error:", error);
|
|
1080
1778
|
throw new Error(`Failed to read contract: ${error.message || "Unknown error"}`);
|
|
@@ -1085,6 +1783,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1085
1783
|
*/
|
|
1086
1784
|
async writeContract(params) {
|
|
1087
1785
|
this.ensureConnected();
|
|
1786
|
+
await tronApiRateLimiter.waitForNextCall();
|
|
1088
1787
|
try {
|
|
1089
1788
|
const tronWeb = this.getTronWeb();
|
|
1090
1789
|
console.log("[TronLink] writeContract params:", {
|
|
@@ -1110,29 +1809,171 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1110
1809
|
}
|
|
1111
1810
|
console.log("[TronLink] Function ABI:", functionAbi);
|
|
1112
1811
|
console.log("[TronLink] Calling with args:", params.args);
|
|
1812
|
+
const TRON_FEE_LIMIT = 1e8;
|
|
1113
1813
|
const options = {
|
|
1114
|
-
feeLimit:
|
|
1115
|
-
//
|
|
1814
|
+
feeLimit: TRON_FEE_LIMIT,
|
|
1815
|
+
// 固定为 100 TRX 的能量限制
|
|
1116
1816
|
callValue: params.value || 0
|
|
1117
1817
|
// 发送的 TRX 数量(单位:SUN)
|
|
1118
1818
|
};
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1819
|
+
const hasTupleArray = functionAbi.inputs.some((input) => input.type === "tuple[]");
|
|
1820
|
+
console.log("[TronLink] \u68C0\u67E5 tuple[] \u7C7B\u578B:", {
|
|
1821
|
+
hasTupleArray,
|
|
1822
|
+
inputs: functionAbi.inputs.map((i) => ({ name: i.name, type: i.type }))
|
|
1823
|
+
});
|
|
1824
|
+
let tx;
|
|
1825
|
+
if (hasTupleArray) {
|
|
1826
|
+
console.log("[TronLink] \u68C0\u6D4B\u5230 tuple[] \u53C2\u6570\uFF0C\u4F7F\u7528\u624B\u52A8\u7F16\u7801\u65B9\u5F0F");
|
|
1827
|
+
const processedArgs = params.args.map((argValue, index) => {
|
|
1828
|
+
const input = functionAbi.inputs[index];
|
|
1829
|
+
if (input.type === "address" && typeof argValue === "string") {
|
|
1830
|
+
if (argValue.startsWith("T") && argValue.length === 34) {
|
|
1831
|
+
const hexAddress = tronWeb.address.toHex(argValue);
|
|
1832
|
+
return hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
|
|
1833
|
+
}
|
|
1834
|
+
return argValue.startsWith("0x") ? argValue : `0x${argValue}`;
|
|
1835
|
+
}
|
|
1836
|
+
if (input.type === "tuple[]" && Array.isArray(argValue)) {
|
|
1837
|
+
return argValue.map((tupleItem) => {
|
|
1838
|
+
if (input.components && Array.isArray(input.components)) {
|
|
1839
|
+
const processedTuple = {};
|
|
1840
|
+
input.components.forEach((component) => {
|
|
1841
|
+
let value = tupleItem[component.name];
|
|
1842
|
+
if (component.type === "address" && typeof value === "string") {
|
|
1843
|
+
if (value.startsWith("T") && value.length === 34) {
|
|
1844
|
+
const hexAddress = tronWeb.address.toHex(value);
|
|
1845
|
+
value = hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
|
|
1846
|
+
} else if (!value.startsWith("0x")) {
|
|
1847
|
+
value = `0x${value}`;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
processedTuple[component.name] = value;
|
|
1851
|
+
});
|
|
1852
|
+
return processedTuple;
|
|
1853
|
+
}
|
|
1854
|
+
return tupleItem;
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
if (input.type === "tuple" && typeof argValue === "object" && !Array.isArray(argValue)) {
|
|
1858
|
+
if (input.components && Array.isArray(input.components)) {
|
|
1859
|
+
const processedTuple = {};
|
|
1860
|
+
input.components.forEach((component) => {
|
|
1861
|
+
let value = argValue[component.name];
|
|
1862
|
+
if (component.type === "address" && typeof value === "string") {
|
|
1863
|
+
if (value.startsWith("T") && value.length === 34) {
|
|
1864
|
+
const hexAddress = tronWeb.address.toHex(value);
|
|
1865
|
+
value = hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
|
|
1866
|
+
} else if (!value.startsWith("0x")) {
|
|
1867
|
+
value = `0x${value}`;
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
processedTuple[component.name] = value;
|
|
1871
|
+
});
|
|
1872
|
+
return processedTuple;
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
return argValue;
|
|
1876
|
+
});
|
|
1877
|
+
console.log("[TronLink] \u5904\u7406\u540E\u7684\u53C2\u6570\uFF08\u7528\u4E8E viem \u7F16\u7801\uFF09:", processedArgs);
|
|
1878
|
+
const encodedData = viem.encodeFunctionData({
|
|
1879
|
+
abi: [functionAbi],
|
|
1880
|
+
functionName: params.functionName,
|
|
1881
|
+
args: processedArgs
|
|
1882
|
+
});
|
|
1883
|
+
console.log("[TronLink] \u7F16\u7801\u540E\u7684\u6570\u636E:", encodedData);
|
|
1884
|
+
const functionSelector = encodedData.slice(0, 10);
|
|
1885
|
+
const parameterData = encodedData.slice(10);
|
|
1886
|
+
console.log("[TronLink] \u51FD\u6570\u9009\u62E9\u5668:", functionSelector);
|
|
1887
|
+
console.log("[TronLink] \u53C2\u6570\u6570\u636E:", parameterData);
|
|
1888
|
+
const functionSignature = params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")";
|
|
1889
|
+
const parameterHexClean = parameterData.startsWith("0x") ? parameterData.slice(2) : parameterData;
|
|
1890
|
+
console.log("[TronLink] \u4F7F\u7528 TronWeb triggerSmartContract (rawParameter)...", {
|
|
1891
|
+
contractAddress: params.address,
|
|
1892
|
+
functionSelector: functionSignature,
|
|
1893
|
+
encodedDataLength: parameterHexClean.length
|
|
1894
|
+
});
|
|
1895
|
+
tx = await retryWithBackoff(
|
|
1896
|
+
() => tronWeb.transactionBuilder.triggerSmartContract(
|
|
1897
|
+
params.address,
|
|
1898
|
+
// Base58 格式的合约地址
|
|
1899
|
+
functionSignature,
|
|
1900
|
+
// 函数签名(用于识别函数)
|
|
1901
|
+
{
|
|
1902
|
+
feeLimit: options.feeLimit,
|
|
1903
|
+
callValue: options.callValue,
|
|
1904
|
+
rawParameter: parameterHexClean
|
|
1905
|
+
// 使用 rawParameter 直接提供编码后的数据
|
|
1906
|
+
},
|
|
1907
|
+
[],
|
|
1908
|
+
// parameter 留空(因为使用 rawParameter)
|
|
1909
|
+
this.currentAccount.nativeAddress
|
|
1910
|
+
// Base58 格式的发送地址
|
|
1911
|
+
),
|
|
1912
|
+
3,
|
|
1913
|
+
// 最多重试 3 次
|
|
1914
|
+
500
|
|
1915
|
+
// 初始延迟 500ms
|
|
1916
|
+
);
|
|
1917
|
+
console.log("[TronLink] \u4F7F\u7528 TronWeb API \u6784\u5EFA\u7684\u4EA4\u6613:", tx);
|
|
1918
|
+
} else {
|
|
1919
|
+
const parameter = functionAbi.inputs.map((input, index) => {
|
|
1920
|
+
const argValue = params.args[index];
|
|
1921
|
+
if (input.type === "tuple" && typeof argValue === "object" && !Array.isArray(argValue)) {
|
|
1922
|
+
if (input.components && Array.isArray(input.components)) {
|
|
1923
|
+
return {
|
|
1924
|
+
type: input.type,
|
|
1925
|
+
value: input.components.map((component) => ({
|
|
1926
|
+
type: component.type,
|
|
1927
|
+
value: argValue[component.name]
|
|
1928
|
+
}))
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
if (input.type === "address" && typeof argValue === "string") {
|
|
1933
|
+
if (argValue.startsWith("T") && argValue.length === 34) {
|
|
1934
|
+
return {
|
|
1935
|
+
type: input.type,
|
|
1936
|
+
value: argValue
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
try {
|
|
1940
|
+
const base58Address = tronWeb.address.fromHex(argValue.startsWith("0x") ? argValue : `0x${argValue}`);
|
|
1941
|
+
return {
|
|
1942
|
+
type: input.type,
|
|
1943
|
+
value: base58Address
|
|
1944
|
+
};
|
|
1945
|
+
} catch (e) {
|
|
1946
|
+
return {
|
|
1947
|
+
type: input.type,
|
|
1948
|
+
value: argValue
|
|
1949
|
+
};
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
return {
|
|
1953
|
+
type: input.type,
|
|
1954
|
+
value: argValue
|
|
1955
|
+
};
|
|
1956
|
+
});
|
|
1957
|
+
console.log("[TronLink] Transaction options:", options);
|
|
1958
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
1959
|
+
const functionSelector = params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")";
|
|
1960
|
+
console.log("[TronLink] Function selector:", functionSelector);
|
|
1961
|
+
console.log("[TronLink] Transaction options:", options);
|
|
1962
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
1963
|
+
tx = await retryWithBackoff(
|
|
1964
|
+
() => tronWeb.transactionBuilder.triggerSmartContract(
|
|
1965
|
+
params.address,
|
|
1966
|
+
functionSelector,
|
|
1967
|
+
options,
|
|
1968
|
+
parameter,
|
|
1969
|
+
this.currentAccount.nativeAddress
|
|
1970
|
+
),
|
|
1971
|
+
3,
|
|
1972
|
+
// 最多重试 3 次
|
|
1973
|
+
500
|
|
1974
|
+
// 初始延迟 500ms
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1136
1977
|
console.log("[TronLink] Transaction built:", tx);
|
|
1137
1978
|
if (!tx || !tx.transaction) {
|
|
1138
1979
|
throw new Error("Failed to build transaction");
|
|
@@ -1172,6 +2013,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1172
2013
|
const maxAttempts = 60;
|
|
1173
2014
|
while (attempts < maxAttempts) {
|
|
1174
2015
|
try {
|
|
2016
|
+
await tronApiRateLimiter.waitForNextCall();
|
|
1175
2017
|
const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
|
|
1176
2018
|
if (txInfo && txInfo.id) {
|
|
1177
2019
|
const receipt = {
|
|
@@ -1299,6 +2141,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1299
2141
|
// Tron 主网链 ID
|
|
1300
2142
|
_TronLinkAdapter.TRON_MAINNET_CHAIN_ID = 195;
|
|
1301
2143
|
var TronLinkAdapter = _TronLinkAdapter;
|
|
2144
|
+
init_types();
|
|
1302
2145
|
var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
1303
2146
|
constructor() {
|
|
1304
2147
|
super(...arguments);
|
|
@@ -1312,27 +2155,28 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1312
2155
|
/**
|
|
1313
2156
|
* 连接(导入私钥)
|
|
1314
2157
|
*/
|
|
1315
|
-
async connect(chainId
|
|
2158
|
+
async connect(chainId) {
|
|
1316
2159
|
if (!this.privateKey) {
|
|
1317
2160
|
throw new Error("Private key not set. Call setPrivateKey() first.");
|
|
1318
2161
|
}
|
|
1319
2162
|
try {
|
|
1320
2163
|
this.setState("connecting" /* CONNECTING */);
|
|
1321
2164
|
const account = accounts.privateKeyToAccount(this.privateKey);
|
|
2165
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId || 1;
|
|
1322
2166
|
this.walletClient = viem.createWalletClient({
|
|
1323
2167
|
account,
|
|
1324
|
-
chain: this.getViemChain(
|
|
2168
|
+
chain: this.getViemChain(targetChainId),
|
|
1325
2169
|
transport: viem.http()
|
|
1326
2170
|
});
|
|
1327
2171
|
this.publicClient = viem.createPublicClient({
|
|
1328
|
-
chain: this.getViemChain(
|
|
2172
|
+
chain: this.getViemChain(targetChainId),
|
|
1329
2173
|
transport: viem.http()
|
|
1330
2174
|
});
|
|
1331
2175
|
const address = formatEVMAddress(account.address);
|
|
1332
2176
|
const accountInfo = {
|
|
1333
|
-
universalAddress: createUniversalAddress(
|
|
2177
|
+
universalAddress: createUniversalAddress(targetChainId, address),
|
|
1334
2178
|
nativeAddress: address,
|
|
1335
|
-
chainId,
|
|
2179
|
+
chainId: targetChainId,
|
|
1336
2180
|
chainType: ChainType.EVM,
|
|
1337
2181
|
isActive: true
|
|
1338
2182
|
};
|
|
@@ -1544,38 +2388,2094 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1544
2388
|
};
|
|
1545
2389
|
}
|
|
1546
2390
|
};
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
this.
|
|
1552
|
-
this.
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
this.
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
2391
|
+
init_types();
|
|
2392
|
+
var _WalletConnectAdapter = class _WalletConnectAdapter extends WalletAdapter {
|
|
2393
|
+
constructor(projectId) {
|
|
2394
|
+
super();
|
|
2395
|
+
this.type = "walletconnect" /* WALLETCONNECT */;
|
|
2396
|
+
this.chainType = ChainType.EVM;
|
|
2397
|
+
this.name = "WalletConnect";
|
|
2398
|
+
this.icon = "https://avatars.githubusercontent.com/u/37784886";
|
|
2399
|
+
this.provider = null;
|
|
2400
|
+
this.walletClient = null;
|
|
2401
|
+
this.publicClient = null;
|
|
2402
|
+
this.supportedChains = [];
|
|
2403
|
+
/**
|
|
2404
|
+
* Handle accounts changed
|
|
2405
|
+
*/
|
|
2406
|
+
this.handleAccountsChanged = (accounts) => {
|
|
2407
|
+
if (accounts.length === 0) {
|
|
2408
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
2409
|
+
this.setAccount(null);
|
|
2410
|
+
this.emitAccountChanged(null);
|
|
2411
|
+
} else {
|
|
2412
|
+
const address = formatEVMAddress(accounts[0]);
|
|
2413
|
+
const account = {
|
|
2414
|
+
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
2415
|
+
nativeAddress: address,
|
|
2416
|
+
chainId: this.currentAccount.chainId,
|
|
2417
|
+
chainType: ChainType.EVM,
|
|
2418
|
+
isActive: true
|
|
2419
|
+
};
|
|
2420
|
+
this.setAccount(account);
|
|
2421
|
+
this.emitAccountChanged(account);
|
|
2422
|
+
}
|
|
2423
|
+
};
|
|
2424
|
+
/**
|
|
2425
|
+
* Handle chain changed
|
|
2426
|
+
*/
|
|
2427
|
+
this.handleChainChanged = (chainIdHex) => {
|
|
2428
|
+
const chainId = parseInt(chainIdHex, 16);
|
|
2429
|
+
if (this.currentAccount) {
|
|
2430
|
+
const account = {
|
|
2431
|
+
...this.currentAccount,
|
|
2432
|
+
chainId,
|
|
2433
|
+
universalAddress: createUniversalAddress(chainId, this.currentAccount.nativeAddress)
|
|
2434
|
+
};
|
|
2435
|
+
this.setAccount(account);
|
|
2436
|
+
this.emitChainChanged(chainId);
|
|
2437
|
+
const viemChain = this.getViemChain(chainId);
|
|
2438
|
+
const chainInfo = getChainInfo(chainId);
|
|
2439
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
2440
|
+
if (this.provider) {
|
|
2441
|
+
this.walletClient = viem.createWalletClient({
|
|
2442
|
+
account: this.currentAccount.nativeAddress,
|
|
2443
|
+
chain: viemChain,
|
|
2444
|
+
transport: viem.custom(this.provider)
|
|
2445
|
+
});
|
|
2446
|
+
this.publicClient = viem.createPublicClient({
|
|
2447
|
+
chain: viemChain,
|
|
2448
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(this.provider)
|
|
2449
|
+
});
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
};
|
|
2453
|
+
/**
|
|
2454
|
+
* Handle disconnect
|
|
2455
|
+
*/
|
|
2456
|
+
this.handleDisconnect = () => {
|
|
2457
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
2458
|
+
this.setAccount(null);
|
|
2459
|
+
if (_WalletConnectAdapter.providerInstance === this.provider) {
|
|
2460
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
2461
|
+
_WalletConnectAdapter.providerProjectId = null;
|
|
2462
|
+
}
|
|
2463
|
+
this.provider = null;
|
|
2464
|
+
this.walletClient = null;
|
|
2465
|
+
this.publicClient = null;
|
|
2466
|
+
this.emitDisconnected();
|
|
2467
|
+
};
|
|
2468
|
+
if (!projectId) {
|
|
2469
|
+
throw new ConfigurationError("WalletConnect projectId is required");
|
|
2470
|
+
}
|
|
2471
|
+
this.projectId = projectId;
|
|
2472
|
+
}
|
|
2473
|
+
/**
|
|
2474
|
+
* Check if WalletConnect is available
|
|
2475
|
+
* WalletConnect is always available (it's a web-based connection)
|
|
2476
|
+
* Also works in Telegram Mini Apps
|
|
2477
|
+
*/
|
|
2478
|
+
async isAvailable() {
|
|
2479
|
+
return typeof window !== "undefined";
|
|
2480
|
+
}
|
|
2481
|
+
/**
|
|
2482
|
+
* Check if running in Telegram environment (Mini App or Web)
|
|
2483
|
+
* Both Telegram Mini App (in client) and Telegram Web (web.telegram.org)
|
|
2484
|
+
* provide window.Telegram.WebApp API, so they are treated the same way.
|
|
2485
|
+
*
|
|
2486
|
+
* Reference: https://docs.reown.com/appkit/integrations/telegram-mini-apps
|
|
2487
|
+
*/
|
|
2488
|
+
isTelegramMiniApp() {
|
|
2489
|
+
if (typeof window === "undefined") return false;
|
|
2490
|
+
const tg = window.Telegram?.WebApp;
|
|
2491
|
+
if (!tg) return false;
|
|
2492
|
+
const platform = tg.platform || "unknown";
|
|
2493
|
+
console.log("[WalletConnect] Telegram environment detected:", {
|
|
2494
|
+
platform,
|
|
2495
|
+
version: tg.version,
|
|
2496
|
+
isMiniApp: platform !== "web",
|
|
2497
|
+
// Mini App if not web platform
|
|
2498
|
+
isWeb: platform === "web"
|
|
2499
|
+
// Telegram Web if web platform
|
|
2500
|
+
});
|
|
2501
|
+
return true;
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* Get Telegram WebApp instance if available
|
|
2505
|
+
*/
|
|
2506
|
+
getTelegramWebApp() {
|
|
2507
|
+
if (typeof window === "undefined") return null;
|
|
2508
|
+
return window.Telegram?.WebApp || null;
|
|
2509
|
+
}
|
|
2510
|
+
/**
|
|
2511
|
+
* Close Telegram deep link popup (wc:// links)
|
|
2512
|
+
* In Telegram Mini Apps, WalletConnect may open a wc:// deep link popup
|
|
2513
|
+
* that doesn't automatically close after the operation completes.
|
|
2514
|
+
* This method attempts to close it by:
|
|
2515
|
+
* 1. Trying to close any open windows/popups
|
|
2516
|
+
* 2. Using Telegram WebApp API if available
|
|
2517
|
+
* 3. Navigating back or closing the popup
|
|
2518
|
+
*/
|
|
2519
|
+
closeTelegramDeepLinkPopup() {
|
|
2520
|
+
if (!this.isTelegramMiniApp()) {
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
try {
|
|
2524
|
+
const tg = this.getTelegramWebApp();
|
|
2525
|
+
if (!tg) {
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
if (typeof window !== "undefined") {
|
|
2529
|
+
window.focus();
|
|
2530
|
+
if (tg.BackButton && tg.BackButton.isVisible) {
|
|
2531
|
+
console.log("[WalletConnect] Closing Telegram deep link popup via BackButton");
|
|
2532
|
+
}
|
|
2533
|
+
setTimeout(() => {
|
|
2534
|
+
if (document.hasFocus()) {
|
|
2535
|
+
console.log("[WalletConnect] Main window has focus, popup likely closed");
|
|
2536
|
+
} else {
|
|
2537
|
+
window.focus();
|
|
2538
|
+
console.log("[WalletConnect] Attempted to focus main window to close popup");
|
|
2539
|
+
}
|
|
2540
|
+
}, 500);
|
|
2541
|
+
const handleVisibilityChange = () => {
|
|
2542
|
+
if (document.visibilityState === "visible") {
|
|
2543
|
+
console.log("[WalletConnect] Page became visible, popup may have closed");
|
|
2544
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
2545
|
+
}
|
|
2546
|
+
};
|
|
2547
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
2548
|
+
setTimeout(() => {
|
|
2549
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
2550
|
+
}, 2e3);
|
|
2551
|
+
}
|
|
2552
|
+
} catch (error) {
|
|
2553
|
+
console.warn("[WalletConnect] Error closing Telegram deep link popup:", error);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
/**
|
|
2557
|
+
* Connect wallet
|
|
2558
|
+
*
|
|
2559
|
+
* @param chainId - Single chain ID or array of chain IDs to request
|
|
2560
|
+
* If array is provided, wallet will be requested to connect to multiple chains
|
|
2561
|
+
* When multiple chains are requested, the wallet can switch between them
|
|
2562
|
+
* Default: 1 (Ethereum Mainnet)
|
|
2563
|
+
*
|
|
2564
|
+
* @example
|
|
2565
|
+
* // Single chain
|
|
2566
|
+
* await adapter.connect(1) // Ethereum only
|
|
2567
|
+
*
|
|
2568
|
+
* @example
|
|
2569
|
+
* // Multiple chains
|
|
2570
|
+
* await adapter.connect([1, 56, 137]) // Ethereum, BSC, Polygon
|
|
2571
|
+
*/
|
|
2572
|
+
async connect(chainId) {
|
|
2573
|
+
if (typeof window === "undefined") {
|
|
2574
|
+
throw new Error("WalletConnect requires a browser environment");
|
|
2575
|
+
}
|
|
2576
|
+
if (_WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId) {
|
|
2577
|
+
const existingProvider = _WalletConnectAdapter.providerInstance;
|
|
2578
|
+
if (existingProvider.accounts && existingProvider.accounts.length > 0) {
|
|
2579
|
+
this.provider = existingProvider;
|
|
2580
|
+
let targetChains;
|
|
2581
|
+
if (Array.isArray(chainId)) {
|
|
2582
|
+
targetChains = chainId.length > 0 ? chainId : [1];
|
|
2583
|
+
} else if (chainId) {
|
|
2584
|
+
targetChains = [chainId];
|
|
2585
|
+
} else {
|
|
2586
|
+
targetChains = [1];
|
|
2587
|
+
}
|
|
2588
|
+
const existingChains = this.supportedChains || [];
|
|
2589
|
+
const mergedChains = [.../* @__PURE__ */ new Set([...existingChains, ...targetChains])];
|
|
2590
|
+
this.supportedChains = mergedChains;
|
|
2591
|
+
const currentChainId = existingProvider.chainId || targetChains[0];
|
|
2592
|
+
const address = formatEVMAddress(existingProvider.accounts[0]);
|
|
2593
|
+
const account = {
|
|
2594
|
+
universalAddress: createUniversalAddress(currentChainId, address),
|
|
2595
|
+
nativeAddress: address,
|
|
2596
|
+
chainId: currentChainId,
|
|
2597
|
+
chainType: ChainType.EVM,
|
|
2598
|
+
isActive: true
|
|
2599
|
+
};
|
|
2600
|
+
this.setState("connected" /* CONNECTED */);
|
|
2601
|
+
this.setAccount(account);
|
|
2602
|
+
if (!this.walletClient) {
|
|
2603
|
+
const viemChain = this.getViemChain(currentChainId);
|
|
2604
|
+
this.walletClient = viem.createWalletClient({
|
|
2605
|
+
account: existingProvider.accounts[0],
|
|
2606
|
+
chain: viemChain,
|
|
2607
|
+
transport: viem.custom(existingProvider)
|
|
2608
|
+
});
|
|
2609
|
+
const chainInfo = getChainInfo(currentChainId);
|
|
2610
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
2611
|
+
this.publicClient = viem.createPublicClient({
|
|
2612
|
+
chain: viemChain,
|
|
2613
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(existingProvider)
|
|
2614
|
+
});
|
|
2615
|
+
this.setupEventListeners();
|
|
2616
|
+
}
|
|
2617
|
+
console.log("[WalletConnect] Reusing existing provider session");
|
|
2618
|
+
return account;
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
if (this.state === "connected" /* CONNECTED */ && this.currentAccount && this.provider) {
|
|
2622
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2623
|
+
let targetChains;
|
|
2624
|
+
if (Array.isArray(chainId)) {
|
|
2625
|
+
targetChains = chainId.length > 0 ? chainId : [1];
|
|
2626
|
+
} else if (chainId) {
|
|
2627
|
+
targetChains = [chainId];
|
|
2628
|
+
} else {
|
|
2629
|
+
targetChains = [1];
|
|
2630
|
+
}
|
|
2631
|
+
const existingChains = this.supportedChains || [];
|
|
2632
|
+
const mergedChains = [.../* @__PURE__ */ new Set([...existingChains, ...targetChains])];
|
|
2633
|
+
this.supportedChains = mergedChains;
|
|
2634
|
+
console.log("[WalletConnect] Already connected, reusing existing connection");
|
|
2635
|
+
return this.currentAccount;
|
|
2636
|
+
} else {
|
|
2637
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
2638
|
+
this.setAccount(null);
|
|
2639
|
+
this.provider = null;
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
try {
|
|
2643
|
+
this.setState("connecting" /* CONNECTING */);
|
|
2644
|
+
let targetChains;
|
|
2645
|
+
if (Array.isArray(chainId)) {
|
|
2646
|
+
targetChains = chainId.length > 0 ? chainId : [1];
|
|
2647
|
+
} else if (chainId) {
|
|
2648
|
+
targetChains = [chainId];
|
|
2649
|
+
} else {
|
|
2650
|
+
targetChains = [1];
|
|
2651
|
+
}
|
|
2652
|
+
this.supportedChains = targetChains;
|
|
2653
|
+
const primaryChain = targetChains[0];
|
|
2654
|
+
const optionalChains = targetChains.slice(1);
|
|
2655
|
+
const isTelegram = this.isTelegramMiniApp();
|
|
2656
|
+
const telegramWebApp = this.getTelegramWebApp();
|
|
2657
|
+
let appUrl = "";
|
|
2658
|
+
if (typeof window !== "undefined") {
|
|
2659
|
+
try {
|
|
2660
|
+
if (window.location && window.location.origin) {
|
|
2661
|
+
appUrl = window.location.origin;
|
|
2662
|
+
} else if (window.location && window.location.href) {
|
|
2663
|
+
const url = new URL(window.location.href);
|
|
2664
|
+
appUrl = url.origin;
|
|
2665
|
+
}
|
|
2666
|
+
} catch (error) {
|
|
2667
|
+
console.warn("[WalletConnect] Failed to get origin from window.location:", error);
|
|
2668
|
+
}
|
|
2669
|
+
if (!appUrl) {
|
|
2670
|
+
appUrl = "https://enclave.network";
|
|
2671
|
+
}
|
|
2672
|
+
} else {
|
|
2673
|
+
appUrl = "https://enclave.network";
|
|
2674
|
+
}
|
|
2675
|
+
if (!appUrl || !appUrl.startsWith("http://") && !appUrl.startsWith("https://")) {
|
|
2676
|
+
appUrl = "https://enclave.network";
|
|
2677
|
+
}
|
|
2678
|
+
const icons = [
|
|
2679
|
+
"https://walletconnect.com/walletconnect-logo.svg",
|
|
2680
|
+
"https://avatars.githubusercontent.com/u/37784886"
|
|
2681
|
+
// WalletConnect GitHub avatar
|
|
2682
|
+
];
|
|
2683
|
+
const initOptions = {
|
|
2684
|
+
projectId: this.projectId,
|
|
2685
|
+
chains: [primaryChain],
|
|
2686
|
+
// Primary chain (required)
|
|
2687
|
+
showQrModal: true,
|
|
2688
|
+
// QR modal works in Telegram Mini Apps
|
|
2689
|
+
metadata: {
|
|
2690
|
+
name: "Enclave Wallet SDK",
|
|
2691
|
+
description: "Multi-chain wallet adapter for Enclave",
|
|
2692
|
+
url: appUrl,
|
|
2693
|
+
icons
|
|
2694
|
+
}
|
|
2695
|
+
};
|
|
2696
|
+
if (isTelegram && telegramWebApp) {
|
|
2697
|
+
const platform = telegramWebApp.platform || "unknown";
|
|
2698
|
+
const isMiniApp = platform !== "web";
|
|
2699
|
+
console.log("[WalletConnect] Detected Telegram environment:", {
|
|
2700
|
+
platform,
|
|
2701
|
+
isMiniApp,
|
|
2702
|
+
isWeb: platform === "web"
|
|
2703
|
+
});
|
|
2704
|
+
if (telegramWebApp.isExpanded === false) {
|
|
2705
|
+
telegramWebApp.expand();
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
if (optionalChains.length > 0) {
|
|
2709
|
+
initOptions.optionalChains = optionalChains;
|
|
2710
|
+
} else {
|
|
2711
|
+
initOptions.optionalChains = [primaryChain];
|
|
2712
|
+
}
|
|
2713
|
+
const hasExistingProvider = _WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId;
|
|
2714
|
+
const needsReinit = hasExistingProvider && _WalletConnectAdapter.providerChains !== null && JSON.stringify(_WalletConnectAdapter.providerChains.sort()) !== JSON.stringify(targetChains.sort());
|
|
2715
|
+
if (needsReinit) {
|
|
2716
|
+
console.log("[WalletConnect] Provider initialized with different chains, reinitializing...", {
|
|
2717
|
+
existing: _WalletConnectAdapter.providerChains,
|
|
2718
|
+
requested: targetChains
|
|
2719
|
+
});
|
|
2720
|
+
const existingProvider = _WalletConnectAdapter.providerInstance;
|
|
2721
|
+
if (existingProvider) {
|
|
2722
|
+
try {
|
|
2723
|
+
if (existingProvider.accounts && existingProvider.accounts.length > 0) {
|
|
2724
|
+
await existingProvider.disconnect();
|
|
2725
|
+
}
|
|
2726
|
+
} catch (error) {
|
|
2727
|
+
console.warn("[WalletConnect] Error disconnecting existing provider:", error);
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
2731
|
+
_WalletConnectAdapter.providerChains = null;
|
|
2732
|
+
}
|
|
2733
|
+
if (_WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId) {
|
|
2734
|
+
this.provider = _WalletConnectAdapter.providerInstance;
|
|
2735
|
+
console.log("[WalletConnect] Reusing existing provider instance");
|
|
2736
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2737
|
+
console.log("[WalletConnect] Provider already has accounts, skipping enable()");
|
|
2738
|
+
} else {
|
|
2739
|
+
const hasSession = this.provider.session !== void 0 && this.provider.session !== null;
|
|
2740
|
+
console.log("[WalletConnect] Provider has no accounts, calling enable() to show QR modal");
|
|
2741
|
+
console.log("[WalletConnect] Provider state:", {
|
|
2742
|
+
accounts: this.provider.accounts,
|
|
2743
|
+
chainId: this.provider.chainId,
|
|
2744
|
+
hasSession,
|
|
2745
|
+
sessionTopic: this.provider.session?.topic
|
|
2746
|
+
});
|
|
2747
|
+
if (hasSession && (!this.provider.accounts || this.provider.accounts.length === 0)) {
|
|
2748
|
+
console.log("[WalletConnect] Found stale session, disconnecting before reconnecting...");
|
|
2749
|
+
try {
|
|
2750
|
+
await this.provider.disconnect();
|
|
2751
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2752
|
+
} catch (disconnectError) {
|
|
2753
|
+
console.warn("[WalletConnect] Error disconnecting stale session:", disconnectError);
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
try {
|
|
2757
|
+
console.log("[WalletConnect] Calling enable()...");
|
|
2758
|
+
const enableResult = await this.provider.enable();
|
|
2759
|
+
console.log("[WalletConnect] enable() completed, result:", enableResult);
|
|
2760
|
+
console.log("[WalletConnect] Provider state after enable():", {
|
|
2761
|
+
accounts: this.provider.accounts,
|
|
2762
|
+
chainId: this.provider.chainId,
|
|
2763
|
+
session: this.provider.session ? {
|
|
2764
|
+
topic: this.provider.session.topic,
|
|
2765
|
+
namespaces: this.provider.session.namespaces ? Object.keys(this.provider.session.namespaces) : "none"
|
|
2766
|
+
} : "none"
|
|
2767
|
+
});
|
|
2768
|
+
} catch (error) {
|
|
2769
|
+
console.error("[WalletConnect] enable() error:", error);
|
|
2770
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2771
|
+
throw new ConnectionRejectedError(this.type);
|
|
2772
|
+
}
|
|
2773
|
+
throw error;
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
} else if (_WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId) {
|
|
2777
|
+
this.provider = _WalletConnectAdapter.providerInstance;
|
|
2778
|
+
console.log("[WalletConnect] Reusing existing provider instance (not connected)");
|
|
2779
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2780
|
+
console.log("[WalletConnect] Provider already has accounts after init, skipping enable()");
|
|
2781
|
+
} else {
|
|
2782
|
+
const hasSession = this.provider.session !== void 0 && this.provider.session !== null;
|
|
2783
|
+
console.log("[WalletConnect] Provider has no accounts, calling enable() to show QR modal");
|
|
2784
|
+
console.log("[WalletConnect] Provider state:", {
|
|
2785
|
+
accounts: this.provider.accounts,
|
|
2786
|
+
chainId: this.provider.chainId,
|
|
2787
|
+
hasSession,
|
|
2788
|
+
sessionTopic: this.provider.session?.topic
|
|
2789
|
+
});
|
|
2790
|
+
if (hasSession && (!this.provider.accounts || this.provider.accounts.length === 0)) {
|
|
2791
|
+
console.log("[WalletConnect] Found stale session after init, disconnecting before reconnecting...");
|
|
2792
|
+
try {
|
|
2793
|
+
await this.provider.disconnect();
|
|
2794
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2795
|
+
} catch (disconnectError) {
|
|
2796
|
+
console.warn("[WalletConnect] Error disconnecting stale session:", disconnectError);
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
try {
|
|
2800
|
+
await this.provider.enable();
|
|
2801
|
+
} catch (error) {
|
|
2802
|
+
console.error("[WalletConnect] enable() error:", error);
|
|
2803
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2804
|
+
throw new ConnectionRejectedError(this.type);
|
|
2805
|
+
}
|
|
2806
|
+
throw error;
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
} else if (_WalletConnectAdapter.isInitializing && _WalletConnectAdapter.initPromise) {
|
|
2810
|
+
console.log("[WalletConnect] Waiting for ongoing initialization...");
|
|
2811
|
+
this.provider = await _WalletConnectAdapter.initPromise;
|
|
2812
|
+
_WalletConnectAdapter.providerInstance = this.provider;
|
|
2813
|
+
_WalletConnectAdapter.providerProjectId = this.projectId;
|
|
2814
|
+
_WalletConnectAdapter.providerChains = targetChains;
|
|
2815
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2816
|
+
console.log("[WalletConnect] Provider already has accounts after init, skipping enable()");
|
|
2817
|
+
} else {
|
|
2818
|
+
try {
|
|
2819
|
+
await this.provider.enable();
|
|
2820
|
+
} catch (error) {
|
|
2821
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2822
|
+
throw new ConnectionRejectedError(this.type);
|
|
2823
|
+
}
|
|
2824
|
+
throw error;
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
} else {
|
|
2828
|
+
console.log("[WalletConnect] Initializing new provider with chains:", {
|
|
2829
|
+
primary: primaryChain,
|
|
2830
|
+
optional: optionalChains,
|
|
2831
|
+
all: targetChains
|
|
2832
|
+
});
|
|
2833
|
+
_WalletConnectAdapter.isInitializing = true;
|
|
2834
|
+
_WalletConnectAdapter.initPromise = EthereumProvider__default.default.init(initOptions);
|
|
2835
|
+
try {
|
|
2836
|
+
this.provider = await _WalletConnectAdapter.initPromise;
|
|
2837
|
+
_WalletConnectAdapter.providerInstance = this.provider;
|
|
2838
|
+
_WalletConnectAdapter.providerProjectId = this.projectId;
|
|
2839
|
+
_WalletConnectAdapter.providerChains = targetChains;
|
|
2840
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2841
|
+
console.log("[WalletConnect] Provider has restored session, skipping enable()");
|
|
2842
|
+
} else {
|
|
2843
|
+
const hasSession = this.provider.session !== void 0 && this.provider.session !== null;
|
|
2844
|
+
console.log("[WalletConnect] New provider initialized, calling enable() to show QR modal");
|
|
2845
|
+
console.log("[WalletConnect] Provider state:", {
|
|
2846
|
+
accounts: this.provider.accounts,
|
|
2847
|
+
chainId: this.provider.chainId,
|
|
2848
|
+
hasSession,
|
|
2849
|
+
sessionTopic: this.provider.session?.topic
|
|
2850
|
+
});
|
|
2851
|
+
if (hasSession && (!this.provider.accounts || this.provider.accounts.length === 0)) {
|
|
2852
|
+
console.log("[WalletConnect] Found stale session after init, disconnecting before reconnecting...");
|
|
2853
|
+
try {
|
|
2854
|
+
await this.provider.disconnect();
|
|
2855
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2856
|
+
} catch (disconnectError) {
|
|
2857
|
+
console.warn("[WalletConnect] Error disconnecting stale session:", disconnectError);
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
try {
|
|
2861
|
+
await this.provider.enable();
|
|
2862
|
+
} catch (error) {
|
|
2863
|
+
console.error("[WalletConnect] enable() error:", error);
|
|
2864
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2865
|
+
throw new ConnectionRejectedError(this.type);
|
|
2866
|
+
}
|
|
2867
|
+
throw error;
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
} finally {
|
|
2871
|
+
_WalletConnectAdapter.isInitializing = false;
|
|
2872
|
+
_WalletConnectAdapter.initPromise = null;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
let accounts = this.provider.accounts;
|
|
2876
|
+
if (!accounts || accounts.length === 0) {
|
|
2877
|
+
console.log("[WalletConnect] provider.accounts is empty, checking session.namespaces.eip155.accounts...");
|
|
2878
|
+
const session = this.provider.session;
|
|
2879
|
+
if (session && session.namespaces?.eip155?.accounts) {
|
|
2880
|
+
const sessionAccounts = session.namespaces.eip155.accounts.map((acc) => {
|
|
2881
|
+
const parts = acc.split(":");
|
|
2882
|
+
if (parts.length >= 3 && parts[0] === "eip155") {
|
|
2883
|
+
return parts[2];
|
|
2884
|
+
}
|
|
2885
|
+
return null;
|
|
2886
|
+
}).filter((addr) => addr !== null && addr.startsWith("0x"));
|
|
2887
|
+
if (sessionAccounts.length > 0) {
|
|
2888
|
+
const uniqueAccounts = [...new Set(sessionAccounts)];
|
|
2889
|
+
console.log("[WalletConnect] Found accounts in session.namespaces.eip155.accounts:", {
|
|
2890
|
+
raw: session.namespaces.eip155.accounts,
|
|
2891
|
+
extracted: uniqueAccounts,
|
|
2892
|
+
chains: session.namespaces.eip155.chains
|
|
2893
|
+
});
|
|
2894
|
+
accounts = uniqueAccounts;
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
if (!accounts || accounts.length === 0) {
|
|
2899
|
+
console.log("[WalletConnect] Accounts not available, waiting for provider.accounts to populate...");
|
|
2900
|
+
const maxWaitTime = 3e3;
|
|
2901
|
+
const checkInterval = 100;
|
|
2902
|
+
const maxChecks = maxWaitTime / checkInterval;
|
|
2903
|
+
for (let i = 0; i < maxChecks; i++) {
|
|
2904
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
2905
|
+
accounts = this.provider.accounts;
|
|
2906
|
+
if (accounts && accounts.length > 0) {
|
|
2907
|
+
console.log(`[WalletConnect] Accounts available after ${(i + 1) * checkInterval}ms`);
|
|
2908
|
+
break;
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
if (!accounts || accounts.length === 0) {
|
|
2913
|
+
const session = this.provider.session;
|
|
2914
|
+
const providerState = {
|
|
2915
|
+
providerAccounts: this.provider.accounts,
|
|
2916
|
+
providerChainId: this.provider.chainId,
|
|
2917
|
+
session: session ? {
|
|
2918
|
+
exists: true,
|
|
2919
|
+
topic: session.topic,
|
|
2920
|
+
namespaces: session.namespaces ? Object.keys(session.namespaces) : "none",
|
|
2921
|
+
eip155Namespace: session.namespaces?.eip155 ? {
|
|
2922
|
+
accounts: session.namespaces.eip155.accounts,
|
|
2923
|
+
// CAIP-10 format
|
|
2924
|
+
chains: session.namespaces.eip155.chains,
|
|
2925
|
+
// CAIP-2 format
|
|
2926
|
+
methods: session.namespaces.eip155.methods,
|
|
2927
|
+
events: session.namespaces.eip155.events
|
|
2928
|
+
} : "none",
|
|
2929
|
+
// Log full session structure for debugging
|
|
2930
|
+
fullSession: JSON.stringify(session, null, 2)
|
|
2931
|
+
} : "none",
|
|
2932
|
+
// Check if provider has any other properties that might contain accounts
|
|
2933
|
+
providerKeys: Object.keys(this.provider)
|
|
2934
|
+
};
|
|
2935
|
+
console.error("[WalletConnect] No accounts available after enable() and wait", providerState);
|
|
2936
|
+
console.error("[WalletConnect] Full provider object:", this.provider);
|
|
2937
|
+
console.error("[WalletConnect] Full session object:", session);
|
|
2938
|
+
console.error("[WalletConnect] Session namespaces structure:", session?.namespaces);
|
|
2939
|
+
throw new Error("WalletConnect connection established but no accounts available. Please check session.namespaces.eip155.accounts in the console logs above.");
|
|
2940
|
+
}
|
|
2941
|
+
const currentChainId = this.provider.chainId || targetChains[0];
|
|
2942
|
+
const viemChain = this.getViemChain(currentChainId);
|
|
2943
|
+
this.walletClient = viem.createWalletClient({
|
|
2944
|
+
account: accounts[0],
|
|
2945
|
+
chain: viemChain,
|
|
2946
|
+
transport: viem.custom(this.provider)
|
|
2947
|
+
});
|
|
2948
|
+
const chainInfo = getChainInfo(currentChainId);
|
|
2949
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
2950
|
+
this.publicClient = viem.createPublicClient({
|
|
2951
|
+
chain: viemChain,
|
|
2952
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(this.provider)
|
|
2953
|
+
});
|
|
2954
|
+
const address = formatEVMAddress(accounts[0]);
|
|
2955
|
+
const account = {
|
|
2956
|
+
universalAddress: createUniversalAddress(currentChainId, address),
|
|
2957
|
+
nativeAddress: address,
|
|
2958
|
+
chainId: currentChainId,
|
|
2959
|
+
chainType: ChainType.EVM,
|
|
2960
|
+
isActive: true
|
|
2961
|
+
};
|
|
2962
|
+
this.setState("connected" /* CONNECTED */);
|
|
2963
|
+
this.setAccount(account);
|
|
2964
|
+
this.setupEventListeners();
|
|
2965
|
+
return account;
|
|
2966
|
+
} catch (error) {
|
|
2967
|
+
this.setState("error" /* ERROR */);
|
|
2968
|
+
this.setAccount(null);
|
|
2969
|
+
const origin = typeof window !== "undefined" && window.location ? window.location.origin : "";
|
|
2970
|
+
const errorCode = error?.code;
|
|
2971
|
+
const errorMessage = error?.message || String(error);
|
|
2972
|
+
const isOriginNotAllowed = errorCode === 3e3 || /origin not allowed/i.test(errorMessage) || /Unauthorized:\s*origin not allowed/i.test(errorMessage);
|
|
2973
|
+
const session = this.provider?.session;
|
|
2974
|
+
const providerState = this.provider ? {
|
|
2975
|
+
accounts: this.provider.accounts,
|
|
2976
|
+
chainId: this.provider.chainId,
|
|
2977
|
+
session: session ? {
|
|
2978
|
+
exists: true,
|
|
2979
|
+
topic: session.topic,
|
|
2980
|
+
namespaces: session.namespaces ? Object.keys(session.namespaces) : "none",
|
|
2981
|
+
eip155Namespace: session.namespaces?.eip155 ? {
|
|
2982
|
+
accounts: session.namespaces.eip155.accounts,
|
|
2983
|
+
chains: session.namespaces.eip155.chains,
|
|
2984
|
+
methods: session.namespaces.eip155.methods,
|
|
2985
|
+
events: session.namespaces.eip155.events
|
|
2986
|
+
} : "none"
|
|
2987
|
+
} : "none",
|
|
2988
|
+
providerKeys: Object.keys(this.provider)
|
|
2989
|
+
} : "no provider";
|
|
2990
|
+
console.error("[WalletConnect] Connection error:", {
|
|
2991
|
+
error,
|
|
2992
|
+
code: error.code,
|
|
2993
|
+
message: error.message,
|
|
2994
|
+
stack: error.stack,
|
|
2995
|
+
providerState
|
|
2996
|
+
});
|
|
2997
|
+
if (this.provider) {
|
|
2998
|
+
console.error("[WalletConnect] Full provider object:", this.provider);
|
|
2999
|
+
console.error("[WalletConnect] Full session object:", session);
|
|
3000
|
+
}
|
|
3001
|
+
if (error.code === 4001 || error.message && (error.message.includes("User rejected") || error.message.includes("rejected by user") || error.message.includes("User cancelled"))) {
|
|
3002
|
+
throw new ConnectionRejectedError(this.type);
|
|
3003
|
+
}
|
|
3004
|
+
if (isOriginNotAllowed) {
|
|
3005
|
+
throw new ConfigurationError(
|
|
3006
|
+
`WalletConnect relayer rejected this origin (code 3000: Unauthorized: origin not allowed).
|
|
3007
|
+
|
|
3008
|
+
Fix:
|
|
3009
|
+
1) Open WalletConnect Cloud \u2192 your project (${this.projectId})
|
|
3010
|
+
2) Add this site origin to the allowlist:
|
|
3011
|
+
- ${origin || "(unknown origin)"}
|
|
3012
|
+
|
|
3013
|
+
Common dev origins to allow:
|
|
3014
|
+
- http://localhost:5173
|
|
3015
|
+
- http://192.168.0.221:5173 (your LAN dev URL)
|
|
3016
|
+
- https://wallet-test.enclave-hq.com (your Cloudflare Tunnel/custom domain)
|
|
3017
|
+
|
|
3018
|
+
Original error: ${errorMessage}`
|
|
3019
|
+
);
|
|
3020
|
+
}
|
|
3021
|
+
throw error;
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
/**
|
|
3025
|
+
* Disconnect wallet
|
|
3026
|
+
*/
|
|
3027
|
+
async disconnect() {
|
|
3028
|
+
if (this.provider) {
|
|
3029
|
+
try {
|
|
3030
|
+
await this.provider.disconnect();
|
|
3031
|
+
} catch (error) {
|
|
3032
|
+
console.warn("[WalletConnect] Error during disconnect:", error);
|
|
3033
|
+
}
|
|
3034
|
+
if (_WalletConnectAdapter.providerInstance === this.provider) {
|
|
3035
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
3036
|
+
_WalletConnectAdapter.providerProjectId = null;
|
|
3037
|
+
_WalletConnectAdapter.providerChains = null;
|
|
3038
|
+
}
|
|
3039
|
+
this.provider = null;
|
|
3040
|
+
}
|
|
3041
|
+
this.removeEventListeners();
|
|
3042
|
+
this.walletClient = null;
|
|
3043
|
+
this.publicClient = null;
|
|
3044
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
3045
|
+
this.setAccount(null);
|
|
3046
|
+
this.emitDisconnected();
|
|
3047
|
+
}
|
|
3048
|
+
/**
|
|
3049
|
+
* Sign message
|
|
3050
|
+
*/
|
|
3051
|
+
async signMessage(message) {
|
|
3052
|
+
this.ensureConnected();
|
|
3053
|
+
try {
|
|
3054
|
+
if (!this.provider) {
|
|
3055
|
+
throw new Error("Provider not initialized");
|
|
3056
|
+
}
|
|
3057
|
+
const signature = await this.provider.request({
|
|
3058
|
+
method: "personal_sign",
|
|
3059
|
+
params: [message, this.currentAccount.nativeAddress]
|
|
3060
|
+
});
|
|
3061
|
+
this.closeTelegramDeepLinkPopup();
|
|
3062
|
+
return signature;
|
|
3063
|
+
} catch (error) {
|
|
3064
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3065
|
+
throw new SignatureRejectedError();
|
|
3066
|
+
}
|
|
3067
|
+
throw error;
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
/**
|
|
3071
|
+
* Sign TypedData (EIP-712)
|
|
3072
|
+
*/
|
|
3073
|
+
async signTypedData(typedData) {
|
|
3074
|
+
this.ensureConnected();
|
|
3075
|
+
try {
|
|
3076
|
+
if (!this.provider) {
|
|
3077
|
+
throw new Error("Provider not initialized");
|
|
3078
|
+
}
|
|
3079
|
+
const signature = await this.provider.request({
|
|
3080
|
+
method: "eth_signTypedData_v4",
|
|
3081
|
+
params: [this.currentAccount.nativeAddress, JSON.stringify(typedData)]
|
|
3082
|
+
});
|
|
3083
|
+
this.closeTelegramDeepLinkPopup();
|
|
3084
|
+
return signature;
|
|
3085
|
+
} catch (error) {
|
|
3086
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3087
|
+
throw new SignatureRejectedError();
|
|
3088
|
+
}
|
|
3089
|
+
throw error;
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
/**
|
|
3093
|
+
* Sign transaction
|
|
3094
|
+
*/
|
|
3095
|
+
async signTransaction(transaction) {
|
|
3096
|
+
this.ensureConnected();
|
|
3097
|
+
try {
|
|
3098
|
+
if (!this.provider) {
|
|
3099
|
+
throw new Error("Provider not initialized");
|
|
3100
|
+
}
|
|
3101
|
+
const tx = {
|
|
3102
|
+
from: this.currentAccount.nativeAddress,
|
|
3103
|
+
to: transaction.to,
|
|
3104
|
+
value: transaction.value ? `0x${BigInt(transaction.value).toString(16)}` : void 0,
|
|
3105
|
+
data: transaction.data || "0x",
|
|
3106
|
+
gas: transaction.gas ? `0x${BigInt(transaction.gas).toString(16)}` : void 0,
|
|
3107
|
+
gasPrice: transaction.gasPrice && transaction.gasPrice !== "auto" ? `0x${BigInt(transaction.gasPrice).toString(16)}` : void 0,
|
|
3108
|
+
maxFeePerGas: transaction.maxFeePerGas ? `0x${BigInt(transaction.maxFeePerGas).toString(16)}` : void 0,
|
|
3109
|
+
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? `0x${BigInt(transaction.maxPriorityFeePerGas).toString(16)}` : void 0,
|
|
3110
|
+
nonce: transaction.nonce !== void 0 ? `0x${transaction.nonce.toString(16)}` : void 0,
|
|
3111
|
+
chainId: transaction.chainId || this.currentAccount.chainId
|
|
3112
|
+
};
|
|
3113
|
+
const signature = await this.provider.request({
|
|
3114
|
+
method: "eth_signTransaction",
|
|
3115
|
+
params: [tx]
|
|
3116
|
+
});
|
|
3117
|
+
this.closeTelegramDeepLinkPopup();
|
|
3118
|
+
return signature;
|
|
3119
|
+
} catch (error) {
|
|
3120
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3121
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
3122
|
+
}
|
|
3123
|
+
throw error;
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
/**
|
|
3127
|
+
* Get supported chains from current connection
|
|
3128
|
+
* Returns the chains that were requested during connection
|
|
3129
|
+
*/
|
|
3130
|
+
getSupportedChains() {
|
|
3131
|
+
return [...this.supportedChains];
|
|
3132
|
+
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Switch chain
|
|
3135
|
+
*
|
|
3136
|
+
* Note: WalletConnect v2 with mobile wallets may not support chain switching reliably.
|
|
3137
|
+
* Some wallets may ignore the switch request or fail silently.
|
|
3138
|
+
* It's recommended to include all needed chains in the initial connection.
|
|
3139
|
+
*
|
|
3140
|
+
* Reference: https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces
|
|
3141
|
+
*/
|
|
3142
|
+
async switchChain(chainId) {
|
|
3143
|
+
if (!this.provider) {
|
|
3144
|
+
throw new Error("Provider not initialized");
|
|
3145
|
+
}
|
|
3146
|
+
const session = this.provider.session;
|
|
3147
|
+
const supportedChains = session?.namespaces?.eip155?.chains || [];
|
|
3148
|
+
const targetChainCAIP = `eip155:${chainId}`;
|
|
3149
|
+
const isChainApproved = supportedChains.includes(targetChainCAIP);
|
|
3150
|
+
if (!isChainApproved) {
|
|
3151
|
+
console.warn(`[WalletConnect] Chain ${chainId} (${targetChainCAIP}) not in session approved chains:`, supportedChains);
|
|
3152
|
+
console.warn("[WalletConnect] Chain switching may fail. Consider including all chains in initial connection.");
|
|
3153
|
+
}
|
|
3154
|
+
try {
|
|
3155
|
+
console.log(`[WalletConnect] Attempting to switch to chain ${chainId} (${targetChainCAIP})`);
|
|
3156
|
+
const result = await this.provider.request({
|
|
3157
|
+
method: "wallet_switchEthereumChain",
|
|
3158
|
+
params: [{ chainId: `0x${chainId.toString(16)}` }]
|
|
3159
|
+
});
|
|
3160
|
+
if (result !== null && result !== void 0) {
|
|
3161
|
+
console.warn("[WalletConnect] wallet_switchEthereumChain returned non-null result:", result);
|
|
3162
|
+
}
|
|
3163
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3164
|
+
const currentChainId = this.provider.chainId;
|
|
3165
|
+
if (currentChainId !== chainId) {
|
|
3166
|
+
console.warn(`[WalletConnect] Chain switch may have failed. Expected ${chainId}, got ${currentChainId}`);
|
|
3167
|
+
console.warn("[WalletConnect] Some mobile wallets may not support chain switching via WalletConnect.");
|
|
3168
|
+
console.warn("[WalletConnect] User may need to manually switch chains in the wallet app.");
|
|
3169
|
+
}
|
|
3170
|
+
if (this.currentAccount) {
|
|
3171
|
+
const updatedAccount = {
|
|
3172
|
+
...this.currentAccount,
|
|
3173
|
+
chainId,
|
|
3174
|
+
universalAddress: createUniversalAddress(chainId, this.currentAccount.nativeAddress)
|
|
3175
|
+
};
|
|
3176
|
+
this.setAccount(updatedAccount);
|
|
3177
|
+
this.emitChainChanged(chainId);
|
|
3178
|
+
const viemChain = this.getViemChain(chainId);
|
|
3179
|
+
const chainInfo = getChainInfo(chainId);
|
|
3180
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
3181
|
+
this.walletClient = viem.createWalletClient({
|
|
3182
|
+
account: this.currentAccount.nativeAddress,
|
|
3183
|
+
chain: viemChain,
|
|
3184
|
+
transport: viem.custom(this.provider)
|
|
3185
|
+
});
|
|
3186
|
+
this.publicClient = viem.createPublicClient({
|
|
3187
|
+
chain: viemChain,
|
|
3188
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(this.provider)
|
|
3189
|
+
});
|
|
3190
|
+
}
|
|
3191
|
+
} catch (error) {
|
|
3192
|
+
console.error("[WalletConnect] Chain switch error:", {
|
|
3193
|
+
chainId,
|
|
3194
|
+
errorCode: error.code,
|
|
3195
|
+
errorMessage: error.message,
|
|
3196
|
+
supportedChains
|
|
3197
|
+
});
|
|
3198
|
+
if (error.code === 4902) {
|
|
3199
|
+
console.log(`[WalletConnect] Chain ${chainId} not found in wallet, attempting to add...`);
|
|
3200
|
+
const chainInfo = getChainInfo(chainId);
|
|
3201
|
+
if (chainInfo) {
|
|
3202
|
+
try {
|
|
3203
|
+
await this.addChain({
|
|
3204
|
+
chainId: chainInfo.id,
|
|
3205
|
+
chainName: chainInfo.name,
|
|
3206
|
+
nativeCurrency: chainInfo.nativeCurrency,
|
|
3207
|
+
rpcUrls: chainInfo.rpcUrls,
|
|
3208
|
+
blockExplorerUrls: chainInfo.blockExplorerUrls
|
|
3209
|
+
});
|
|
3210
|
+
console.log(`[WalletConnect] Chain added, attempting to switch again...`);
|
|
3211
|
+
await this.switchChain(chainId);
|
|
3212
|
+
} catch (addError) {
|
|
3213
|
+
console.error("[WalletConnect] Failed to add chain:", addError);
|
|
3214
|
+
throw new Error(`Failed to add chain ${chainId}: ${addError.message}`);
|
|
3215
|
+
}
|
|
3216
|
+
} else {
|
|
3217
|
+
throw new Error(`Chain ${chainId} not supported`);
|
|
3218
|
+
}
|
|
3219
|
+
} else if (error.code === 4001) {
|
|
3220
|
+
throw new Error("User rejected chain switch");
|
|
3221
|
+
} else if (error.code === 4100) {
|
|
3222
|
+
throw new Error("Wallet does not support wallet_switchEthereumChain. Please switch chains manually in your wallet app.");
|
|
3223
|
+
} else {
|
|
3224
|
+
console.warn("[WalletConnect] Chain switch may not be supported by this wallet. User may need to switch manually.");
|
|
3225
|
+
throw error;
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
/**
|
|
3230
|
+
* Add chain
|
|
3231
|
+
*/
|
|
3232
|
+
async addChain(chainConfig) {
|
|
3233
|
+
if (!this.provider) {
|
|
3234
|
+
throw new Error("Provider not initialized");
|
|
3235
|
+
}
|
|
3236
|
+
await this.provider.request({
|
|
3237
|
+
method: "wallet_addEthereumChain",
|
|
3238
|
+
params: [{
|
|
3239
|
+
chainId: `0x${chainConfig.chainId.toString(16)}`,
|
|
3240
|
+
chainName: chainConfig.chainName,
|
|
3241
|
+
nativeCurrency: chainConfig.nativeCurrency,
|
|
3242
|
+
rpcUrls: chainConfig.rpcUrls,
|
|
3243
|
+
blockExplorerUrls: chainConfig.blockExplorerUrls
|
|
3244
|
+
}]
|
|
3245
|
+
});
|
|
3246
|
+
}
|
|
3247
|
+
/**
|
|
3248
|
+
* Read contract
|
|
3249
|
+
*/
|
|
3250
|
+
async readContract(params) {
|
|
3251
|
+
if (!this.publicClient) {
|
|
3252
|
+
throw new Error("Public client not initialized");
|
|
3253
|
+
}
|
|
3254
|
+
const result = await this.publicClient.readContract({
|
|
3255
|
+
address: params.address,
|
|
3256
|
+
abi: params.abi,
|
|
3257
|
+
functionName: params.functionName,
|
|
3258
|
+
...params.args ? { args: params.args } : {}
|
|
3259
|
+
});
|
|
3260
|
+
return result;
|
|
3261
|
+
}
|
|
3262
|
+
/**
|
|
3263
|
+
* Write contract
|
|
3264
|
+
*/
|
|
3265
|
+
async writeContract(params) {
|
|
3266
|
+
this.ensureConnected();
|
|
3267
|
+
if (!this.walletClient) {
|
|
3268
|
+
throw new Error("Wallet client not initialized");
|
|
3269
|
+
}
|
|
3270
|
+
try {
|
|
3271
|
+
const txOptions = {
|
|
3272
|
+
address: params.address,
|
|
3273
|
+
abi: params.abi,
|
|
3274
|
+
functionName: params.functionName,
|
|
3275
|
+
...params.args ? { args: params.args } : {},
|
|
3276
|
+
value: params.value ? BigInt(params.value) : void 0,
|
|
3277
|
+
gas: params.gas ? BigInt(params.gas) : void 0
|
|
3278
|
+
};
|
|
3279
|
+
if (params.maxFeePerGas || params.maxPriorityFeePerGas) {
|
|
3280
|
+
if (params.maxFeePerGas) {
|
|
3281
|
+
txOptions.maxFeePerGas = BigInt(params.maxFeePerGas);
|
|
3282
|
+
}
|
|
3283
|
+
if (params.maxPriorityFeePerGas) {
|
|
3284
|
+
txOptions.maxPriorityFeePerGas = BigInt(params.maxPriorityFeePerGas);
|
|
3285
|
+
}
|
|
3286
|
+
} else if (params.gasPrice && params.gasPrice !== "auto") {
|
|
3287
|
+
txOptions.gasPrice = BigInt(params.gasPrice);
|
|
3288
|
+
} else {
|
|
3289
|
+
if (this.publicClient) {
|
|
3290
|
+
try {
|
|
3291
|
+
const feesPerGas = await this.publicClient.estimateFeesPerGas().catch(() => null);
|
|
3292
|
+
if (feesPerGas) {
|
|
3293
|
+
const minPriorityFeeWei = BigInt(1e8);
|
|
3294
|
+
const maxPriorityFeePerGas = feesPerGas.maxPriorityFeePerGas > minPriorityFeeWei ? feesPerGas.maxPriorityFeePerGas : minPriorityFeeWei;
|
|
3295
|
+
const adjustedMaxFeePerGas = feesPerGas.maxFeePerGas > maxPriorityFeePerGas ? feesPerGas.maxFeePerGas : maxPriorityFeePerGas + BigInt(1e9);
|
|
3296
|
+
txOptions.maxFeePerGas = adjustedMaxFeePerGas;
|
|
3297
|
+
txOptions.maxPriorityFeePerGas = maxPriorityFeePerGas;
|
|
3298
|
+
} else {
|
|
3299
|
+
const gasPrice = await this.publicClient.getGasPrice();
|
|
3300
|
+
txOptions.gasPrice = gasPrice;
|
|
3301
|
+
}
|
|
3302
|
+
} catch (err) {
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
const txHash = await this.walletClient.writeContract(txOptions);
|
|
3307
|
+
this.closeTelegramDeepLinkPopup();
|
|
3308
|
+
return txHash;
|
|
3309
|
+
} catch (error) {
|
|
3310
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3311
|
+
throw new SignatureRejectedError("Transaction was rejected by user");
|
|
3312
|
+
}
|
|
3313
|
+
throw error;
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
/**
|
|
3317
|
+
* Estimate gas
|
|
3318
|
+
*/
|
|
3319
|
+
async estimateGas(params) {
|
|
3320
|
+
if (!this.publicClient) {
|
|
3321
|
+
throw new Error("Public client not initialized");
|
|
3322
|
+
}
|
|
3323
|
+
const gas = await this.publicClient.estimateContractGas({
|
|
3324
|
+
address: params.address,
|
|
3325
|
+
abi: params.abi,
|
|
3326
|
+
functionName: params.functionName,
|
|
3327
|
+
...params.args ? { args: params.args } : {},
|
|
3328
|
+
value: params.value ? BigInt(params.value) : void 0,
|
|
3329
|
+
account: this.currentAccount.nativeAddress
|
|
3330
|
+
});
|
|
3331
|
+
return gas;
|
|
3332
|
+
}
|
|
3333
|
+
/**
|
|
3334
|
+
* Wait for transaction
|
|
3335
|
+
*/
|
|
3336
|
+
async waitForTransaction(txHash, confirmations = 1) {
|
|
3337
|
+
if (!this.publicClient) {
|
|
3338
|
+
throw new Error("Public client not initialized");
|
|
3339
|
+
}
|
|
3340
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({
|
|
3341
|
+
hash: txHash,
|
|
3342
|
+
confirmations
|
|
3343
|
+
});
|
|
3344
|
+
if (receipt.status === "reverted") {
|
|
3345
|
+
throw new TransactionFailedError(txHash, "Transaction reverted");
|
|
3346
|
+
}
|
|
3347
|
+
return {
|
|
3348
|
+
transactionHash: receipt.transactionHash,
|
|
3349
|
+
blockNumber: Number(receipt.blockNumber),
|
|
3350
|
+
blockHash: receipt.blockHash,
|
|
3351
|
+
from: receipt.from,
|
|
3352
|
+
to: receipt.to || void 0,
|
|
3353
|
+
status: receipt.status === "success" ? "success" : "failed",
|
|
3354
|
+
gasUsed: receipt.gasUsed.toString(),
|
|
3355
|
+
effectiveGasPrice: receipt.effectiveGasPrice?.toString(),
|
|
3356
|
+
logs: receipt.logs
|
|
3357
|
+
};
|
|
3358
|
+
}
|
|
3359
|
+
/**
|
|
3360
|
+
* Get provider
|
|
3361
|
+
*/
|
|
3362
|
+
getProvider() {
|
|
3363
|
+
return this.provider;
|
|
3364
|
+
}
|
|
3365
|
+
/**
|
|
3366
|
+
* Get signer
|
|
3367
|
+
*/
|
|
3368
|
+
getSigner() {
|
|
3369
|
+
return this.walletClient;
|
|
3370
|
+
}
|
|
3371
|
+
/**
|
|
3372
|
+
* Setup event listeners
|
|
3373
|
+
*/
|
|
3374
|
+
setupEventListeners() {
|
|
3375
|
+
if (!this.provider) return;
|
|
3376
|
+
this.provider.on("accountsChanged", this.handleAccountsChanged);
|
|
3377
|
+
this.provider.on("chainChanged", this.handleChainChanged);
|
|
3378
|
+
this.provider.on("disconnect", this.handleDisconnect);
|
|
3379
|
+
}
|
|
3380
|
+
/**
|
|
3381
|
+
* Remove event listeners
|
|
3382
|
+
*/
|
|
3383
|
+
removeEventListeners() {
|
|
3384
|
+
if (!this.provider) return;
|
|
3385
|
+
this.provider.removeListener("accountsChanged", this.handleAccountsChanged);
|
|
3386
|
+
this.provider.removeListener("chainChanged", this.handleChainChanged);
|
|
3387
|
+
this.provider.removeListener("disconnect", this.handleDisconnect);
|
|
3388
|
+
}
|
|
3389
|
+
/**
|
|
3390
|
+
* Get viem chain config
|
|
3391
|
+
*/
|
|
3392
|
+
getViemChain(chainId) {
|
|
3393
|
+
const chainInfo = getChainInfo(chainId);
|
|
3394
|
+
if (chainInfo) {
|
|
3395
|
+
return {
|
|
3396
|
+
id: chainId,
|
|
3397
|
+
name: chainInfo.name,
|
|
3398
|
+
network: chainInfo.name.toLowerCase().replace(/\s+/g, "-"),
|
|
3399
|
+
nativeCurrency: chainInfo.nativeCurrency,
|
|
3400
|
+
rpcUrls: {
|
|
3401
|
+
default: { http: chainInfo.rpcUrls },
|
|
3402
|
+
public: { http: chainInfo.rpcUrls }
|
|
3403
|
+
},
|
|
3404
|
+
blockExplorers: chainInfo.blockExplorerUrls ? {
|
|
3405
|
+
default: { name: "Explorer", url: chainInfo.blockExplorerUrls[0] }
|
|
3406
|
+
} : void 0
|
|
3407
|
+
};
|
|
3408
|
+
}
|
|
3409
|
+
return {
|
|
3410
|
+
id: chainId,
|
|
3411
|
+
name: `Chain ${chainId}`,
|
|
3412
|
+
network: `chain-${chainId}`,
|
|
3413
|
+
nativeCurrency: {
|
|
3414
|
+
name: "ETH",
|
|
3415
|
+
symbol: "ETH",
|
|
3416
|
+
decimals: 18
|
|
3417
|
+
},
|
|
3418
|
+
rpcUrls: {
|
|
3419
|
+
default: { http: [] },
|
|
3420
|
+
public: { http: [] }
|
|
3421
|
+
}
|
|
3422
|
+
};
|
|
3423
|
+
}
|
|
3424
|
+
};
|
|
3425
|
+
// Store supported chains from connection
|
|
3426
|
+
// Static provider instance to avoid multiple initializations
|
|
3427
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
3428
|
+
_WalletConnectAdapter.providerProjectId = null;
|
|
3429
|
+
_WalletConnectAdapter.providerChains = null;
|
|
3430
|
+
// Store the chains used during initialization
|
|
3431
|
+
_WalletConnectAdapter.isInitializing = false;
|
|
3432
|
+
_WalletConnectAdapter.initPromise = null;
|
|
3433
|
+
var WalletConnectAdapter = _WalletConnectAdapter;
|
|
3434
|
+
|
|
3435
|
+
// src/adapters/tron/wallet-connect.ts
|
|
3436
|
+
var wallet_connect_exports = {};
|
|
3437
|
+
__export(wallet_connect_exports, {
|
|
3438
|
+
WalletConnectTronAdapter: () => WalletConnectTronAdapter
|
|
3439
|
+
});
|
|
3440
|
+
init_types();
|
|
3441
|
+
var _WalletConnectTronAdapter = class _WalletConnectTronAdapter extends WalletAdapter {
|
|
3442
|
+
constructor(projectId) {
|
|
3443
|
+
super();
|
|
3444
|
+
this.type = "walletconnect-tron" /* WALLETCONNECT_TRON */;
|
|
3445
|
+
this.chainType = ChainType.TRON;
|
|
3446
|
+
this.name = "WalletConnect (Tron)";
|
|
3447
|
+
this.icon = "https://avatars.githubusercontent.com/u/37784886";
|
|
3448
|
+
this.wallet = null;
|
|
3449
|
+
this.currentAddress = null;
|
|
3450
|
+
if (!projectId) {
|
|
3451
|
+
throw new ConfigurationError("WalletConnect projectId is required");
|
|
3452
|
+
}
|
|
3453
|
+
this.projectId = projectId;
|
|
3454
|
+
}
|
|
3455
|
+
/**
|
|
3456
|
+
* Check if WalletConnect is available
|
|
3457
|
+
*/
|
|
3458
|
+
async isAvailable() {
|
|
3459
|
+
return typeof window !== "undefined";
|
|
3460
|
+
}
|
|
3461
|
+
/**
|
|
3462
|
+
* Check if running in Telegram environment (Mini App or Web)
|
|
3463
|
+
* Both Telegram Mini App (in client) and Telegram Web (web.telegram.org)
|
|
3464
|
+
* provide window.Telegram.WebApp API, so they are treated the same way.
|
|
3465
|
+
*/
|
|
3466
|
+
isTelegramMiniApp() {
|
|
3467
|
+
if (typeof window === "undefined") return false;
|
|
3468
|
+
const tg = window.Telegram?.WebApp;
|
|
3469
|
+
if (!tg) return false;
|
|
3470
|
+
const platform = tg.platform || "unknown";
|
|
3471
|
+
console.log("[WalletConnect Tron] Telegram environment detected:", {
|
|
3472
|
+
platform,
|
|
3473
|
+
version: tg.version,
|
|
3474
|
+
isMiniApp: platform !== "web",
|
|
3475
|
+
// Mini App if not web platform
|
|
3476
|
+
isWeb: platform === "web"
|
|
3477
|
+
// Telegram Web if web platform
|
|
3478
|
+
});
|
|
3479
|
+
return true;
|
|
3480
|
+
}
|
|
3481
|
+
/**
|
|
3482
|
+
* Restore session from existing wallet (for storage restoration)
|
|
3483
|
+
*/
|
|
3484
|
+
async restoreSession(chainId) {
|
|
3485
|
+
if (typeof window === "undefined") {
|
|
3486
|
+
return null;
|
|
3487
|
+
}
|
|
3488
|
+
try {
|
|
3489
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] || _WalletConnectTronAdapter.TRON_MAINNET_CHAIN_ID : chainId || _WalletConnectTronAdapter.TRON_MAINNET_CHAIN_ID;
|
|
3490
|
+
if (!_WalletConnectTronAdapter.walletInstance || _WalletConnectTronAdapter.walletProjectId !== this.projectId) {
|
|
3491
|
+
this.initializeWallet(targetChainId);
|
|
3492
|
+
}
|
|
3493
|
+
this.wallet = _WalletConnectTronAdapter.walletInstance;
|
|
3494
|
+
if (!this.wallet) {
|
|
3495
|
+
return null;
|
|
3496
|
+
}
|
|
3497
|
+
const status = await this.wallet.checkConnectStatus();
|
|
3498
|
+
if (status && status.address) {
|
|
3499
|
+
this.currentAddress = status.address;
|
|
3500
|
+
const account = {
|
|
3501
|
+
universalAddress: createUniversalAddress(targetChainId, status.address),
|
|
3502
|
+
nativeAddress: status.address,
|
|
3503
|
+
chainId: targetChainId,
|
|
3504
|
+
chainType: ChainType.TRON,
|
|
3505
|
+
isActive: true
|
|
3506
|
+
};
|
|
3507
|
+
this.setState("connected" /* CONNECTED */);
|
|
3508
|
+
this.setAccount(account);
|
|
3509
|
+
this.setupEventListeners();
|
|
3510
|
+
return account;
|
|
3511
|
+
}
|
|
3512
|
+
return null;
|
|
3513
|
+
} catch (error) {
|
|
3514
|
+
console.debug("[WalletConnect Tron] Restore session failed:", error);
|
|
3515
|
+
return null;
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
/**
|
|
3519
|
+
* Initialize WalletConnect wallet instance
|
|
3520
|
+
* @param chainId - Optional chain ID to determine network (default: Mainnet)
|
|
3521
|
+
*/
|
|
3522
|
+
initializeWallet(chainId) {
|
|
3523
|
+
if (_WalletConnectTronAdapter.walletInstance && _WalletConnectTronAdapter.walletProjectId === this.projectId) {
|
|
3524
|
+
return;
|
|
3525
|
+
}
|
|
3526
|
+
let appUrl = "";
|
|
3527
|
+
if (typeof window !== "undefined") {
|
|
3528
|
+
try {
|
|
3529
|
+
if (window.location && window.location.origin) {
|
|
3530
|
+
appUrl = window.location.origin;
|
|
3531
|
+
} else if (window.location && window.location.href) {
|
|
3532
|
+
const url = new URL(window.location.href);
|
|
3533
|
+
appUrl = url.origin;
|
|
3534
|
+
}
|
|
3535
|
+
} catch (error) {
|
|
3536
|
+
console.warn("[WalletConnect Tron] Failed to get origin from window.location:", error);
|
|
3537
|
+
}
|
|
3538
|
+
if (appUrl && (appUrl.includes("serveo.net") || appUrl.includes("loca.lt") || appUrl.includes("ngrok.io") || appUrl.includes("ngrok-free.app") || appUrl.includes("cloudflared.io"))) {
|
|
3539
|
+
console.log("[WalletConnect Tron] Detected tunnel service URL:", appUrl);
|
|
3540
|
+
console.log("[WalletConnect Tron] \u26A0\uFE0F Make sure this URL is added to WalletConnect Cloud project allowlist");
|
|
3541
|
+
}
|
|
3542
|
+
if (!appUrl) {
|
|
3543
|
+
const tg = window.Telegram?.WebApp;
|
|
3544
|
+
if (tg && tg.initDataUnsafe?.start_param) {
|
|
3545
|
+
appUrl = "https://enclave.network";
|
|
3546
|
+
} else {
|
|
3547
|
+
appUrl = "https://enclave.network";
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
} else {
|
|
3551
|
+
appUrl = "https://enclave.network";
|
|
3552
|
+
}
|
|
3553
|
+
if (!appUrl || !appUrl.startsWith("http://") && !appUrl.startsWith("https://")) {
|
|
3554
|
+
appUrl = "https://enclave.network";
|
|
3555
|
+
}
|
|
3556
|
+
const icons = [
|
|
3557
|
+
"https://walletconnect.com/walletconnect-logo.svg",
|
|
3558
|
+
"https://avatars.githubusercontent.com/u/37784886"
|
|
3559
|
+
// WalletConnect GitHub avatar
|
|
3560
|
+
];
|
|
3561
|
+
let network = walletconnectTron.WalletConnectChainID.Mainnet;
|
|
3562
|
+
if (chainId !== void 0) {
|
|
3563
|
+
if (chainId === 195 || chainId === _WalletConnectTronAdapter.TRON_MAINNET_CHAIN_ID) {
|
|
3564
|
+
network = walletconnectTron.WalletConnectChainID.Mainnet;
|
|
3565
|
+
} else if (chainId === 201910292) {
|
|
3566
|
+
network = walletconnectTron.WalletConnectChainID.Shasta;
|
|
3567
|
+
} else if (chainId === 2494104990) {
|
|
3568
|
+
network = walletconnectTron.WalletConnectChainID.Nile;
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
const metadataInfo = {
|
|
3572
|
+
name: "Enclave Wallet SDK",
|
|
3573
|
+
description: "Multi-chain wallet adapter for Enclave",
|
|
3574
|
+
url: appUrl,
|
|
3575
|
+
icons,
|
|
3576
|
+
network,
|
|
3577
|
+
chainId,
|
|
3578
|
+
isTelegram: this.isTelegramMiniApp(),
|
|
3579
|
+
projectId: this.projectId,
|
|
3580
|
+
urlValid: appUrl && (appUrl.startsWith("http://") || appUrl.startsWith("https://")),
|
|
3581
|
+
iconsValid: icons && icons.length > 0 && icons.every((icon) => icon && icon.startsWith("http")),
|
|
3582
|
+
currentLocation: typeof window !== "undefined" ? window.location.href : "N/A",
|
|
3583
|
+
telegramPlatform: typeof window !== "undefined" && window.Telegram?.WebApp?.platform || "N/A"
|
|
3584
|
+
};
|
|
3585
|
+
console.log("[WalletConnect Tron] Initializing with metadata:", metadataInfo);
|
|
3586
|
+
if (!metadataInfo.urlValid) {
|
|
3587
|
+
console.warn("[WalletConnect Tron] \u26A0\uFE0F Invalid URL in metadata:", appUrl);
|
|
3588
|
+
}
|
|
3589
|
+
if (!metadataInfo.iconsValid) {
|
|
3590
|
+
console.warn("[WalletConnect Tron] \u26A0\uFE0F Invalid icons in metadata:", icons);
|
|
3591
|
+
}
|
|
3592
|
+
console.log("[WalletConnect Tron] Initializing wallet...", {
|
|
3593
|
+
network,
|
|
3594
|
+
chainId,
|
|
3595
|
+
note: "If no wallets are in WalletConnect Explorer for TRON, QR code will be displayed for scanning"
|
|
3596
|
+
});
|
|
3597
|
+
_WalletConnectTronAdapter.walletInstance = new walletconnectTron.WalletConnectWallet({
|
|
3598
|
+
network,
|
|
3599
|
+
options: {
|
|
3600
|
+
projectId: this.projectId,
|
|
3601
|
+
metadata: {
|
|
3602
|
+
name: "Enclave Wallet SDK",
|
|
3603
|
+
description: "Multi-chain wallet adapter for Enclave",
|
|
3604
|
+
url: appUrl,
|
|
3605
|
+
icons
|
|
3606
|
+
}
|
|
3607
|
+
},
|
|
3608
|
+
// Theme configuration
|
|
3609
|
+
themeMode: "light",
|
|
3610
|
+
themeVariables: {
|
|
3611
|
+
"--w3m-z-index": 1e4
|
|
3612
|
+
// Ensure modal appears above Telegram UI
|
|
3613
|
+
},
|
|
3614
|
+
// Web3Modal configuration for recommended wallets
|
|
3615
|
+
// According to official docs: https://developers.tron.network/docs/walletconnect-tron
|
|
3616
|
+
// Note: If no wallets are registered in WalletConnect Explorer for TRON,
|
|
3617
|
+
// explorerRecommendedWalletIds will have no effect, and QR code will be shown instead.
|
|
3618
|
+
// @ts-ignore - web3ModalConfig is supported but may not be in TypeScript types
|
|
3619
|
+
web3ModalConfig: {
|
|
3620
|
+
themeMode: "light",
|
|
3621
|
+
themeVariables: {
|
|
3622
|
+
"--w3m-z-index": 1e4
|
|
3623
|
+
},
|
|
3624
|
+
/**
|
|
3625
|
+
* Recommended Wallets are fetched from WalletConnect explore api:
|
|
3626
|
+
* https://walletconnect.com/explorer?type=wallet&version=2
|
|
3627
|
+
*
|
|
3628
|
+
* IMPORTANT: If wallets are not registered in Explorer for TRON, this list will be ignored.
|
|
3629
|
+
* The AppKit will show a QR code instead, which users can scan with any WalletConnect-compatible wallet.
|
|
3630
|
+
*
|
|
3631
|
+
* Wallet IDs (for reference, may not work if not in Explorer):
|
|
3632
|
+
* - TokenPocket: 20459438007b75f4f4acb98bf29aa3b800550309646d375da5fd4aac6c2a2c66
|
|
3633
|
+
* - TronLink: 1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369
|
|
3634
|
+
*/
|
|
3635
|
+
explorerRecommendedWalletIds: [
|
|
3636
|
+
// These IDs are kept for when wallets register in WalletConnect Explorer
|
|
3637
|
+
// Currently, if no TRON wallets are in Explorer, QR code will be shown
|
|
3638
|
+
"20459438007b75f4f4acb98bf29aa3b800550309646d375da5fd4aac6c2a2c66",
|
|
3639
|
+
// TokenPocket
|
|
3640
|
+
"1ae92b26df02f0abca6304df07debccd18262fdf5fe82daa81593582dac9a369",
|
|
3641
|
+
// TronLink
|
|
3642
|
+
"4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0"
|
|
3643
|
+
// TokenPocket (backup)
|
|
3644
|
+
]
|
|
3645
|
+
}
|
|
3646
|
+
});
|
|
3647
|
+
_WalletConnectTronAdapter.walletProjectId = this.projectId;
|
|
3648
|
+
}
|
|
3649
|
+
/**
|
|
3650
|
+
* Connect wallet
|
|
3651
|
+
*/
|
|
3652
|
+
async connect(chainId) {
|
|
3653
|
+
if (typeof window === "undefined") {
|
|
3654
|
+
throw new Error("WalletConnect requires a browser environment");
|
|
3655
|
+
}
|
|
3656
|
+
const currentState = this.state;
|
|
3657
|
+
if (currentState === "connecting" /* CONNECTING */) {
|
|
3658
|
+
console.warn("[WalletConnect Tron] Connection already in progress, waiting...");
|
|
3659
|
+
let attempts = 0;
|
|
3660
|
+
while (this.state === "connecting" /* CONNECTING */ && attempts < 50) {
|
|
3661
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3662
|
+
attempts++;
|
|
3663
|
+
}
|
|
3664
|
+
if (this.state === "connected" /* CONNECTED */ && this.currentAccount) {
|
|
3665
|
+
return this.currentAccount;
|
|
3666
|
+
}
|
|
3667
|
+
if (this.state === "connecting" /* CONNECTING */) {
|
|
3668
|
+
throw new Error("Connection timeout - previous connection attempt is still pending");
|
|
3669
|
+
}
|
|
3670
|
+
}
|
|
3671
|
+
if (this.state === "connected" /* CONNECTED */ && this.currentAccount) {
|
|
3672
|
+
return this.currentAccount;
|
|
3673
|
+
}
|
|
3674
|
+
try {
|
|
3675
|
+
this.setState("connecting" /* CONNECTING */);
|
|
3676
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] || _WalletConnectTronAdapter.TRON_MAINNET_CHAIN_ID : chainId || _WalletConnectTronAdapter.TRON_MAINNET_CHAIN_ID;
|
|
3677
|
+
if (!_WalletConnectTronAdapter.walletInstance || _WalletConnectTronAdapter.walletProjectId !== this.projectId) {
|
|
3678
|
+
this.initializeWallet(targetChainId);
|
|
3679
|
+
}
|
|
3680
|
+
this.wallet = _WalletConnectTronAdapter.walletInstance;
|
|
3681
|
+
if (!this.wallet) {
|
|
3682
|
+
throw new Error("Failed to initialize WalletConnect wallet");
|
|
3683
|
+
}
|
|
3684
|
+
let network = walletconnectTron.WalletConnectChainID.Mainnet;
|
|
3685
|
+
if (targetChainId === 195) {
|
|
3686
|
+
network = walletconnectTron.WalletConnectChainID.Mainnet;
|
|
3687
|
+
} else if (targetChainId === 201910292) {
|
|
3688
|
+
network = walletconnectTron.WalletConnectChainID.Shasta;
|
|
3689
|
+
} else if (targetChainId === 2494104990) {
|
|
3690
|
+
network = walletconnectTron.WalletConnectChainID.Nile;
|
|
3691
|
+
}
|
|
3692
|
+
let address;
|
|
3693
|
+
try {
|
|
3694
|
+
console.log("[WalletConnect Tron] Attempting to connect...", {
|
|
3695
|
+
network,
|
|
3696
|
+
chainId: targetChainId,
|
|
3697
|
+
isTelegram: this.isTelegramMiniApp(),
|
|
3698
|
+
projectId: this.projectId
|
|
3699
|
+
});
|
|
3700
|
+
const result = await this.wallet.connect();
|
|
3701
|
+
address = result.address;
|
|
3702
|
+
if (!address) {
|
|
3703
|
+
throw new ConnectionRejectedError(this.type);
|
|
3704
|
+
}
|
|
3705
|
+
console.log("[WalletConnect Tron] Connection successful:", {
|
|
3706
|
+
address,
|
|
3707
|
+
network,
|
|
3708
|
+
chainId: targetChainId,
|
|
3709
|
+
isTelegram: this.isTelegramMiniApp()
|
|
3710
|
+
});
|
|
3711
|
+
} catch (error) {
|
|
3712
|
+
const errorMessage = error.message || String(error);
|
|
3713
|
+
const errorCode = error.code || error.error?.code;
|
|
3714
|
+
const origin = typeof window !== "undefined" && window.location ? window.location.origin : "";
|
|
3715
|
+
let detailedError = errorMessage;
|
|
3716
|
+
if (error.error) {
|
|
3717
|
+
if (typeof error.error === "string") {
|
|
3718
|
+
detailedError = error.error;
|
|
3719
|
+
} else if (error.error.message) {
|
|
3720
|
+
detailedError = error.error.message;
|
|
3721
|
+
} else if (error.error.data) {
|
|
3722
|
+
detailedError = JSON.stringify(error.error.data);
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
const isNoWalletFound = errorMessage.includes("\u6CA1\u6709\u627E\u5230\u652F\u6301\u7684\u94B1\u5305") || errorMessage.includes("No matching wallet") || errorMessage.includes("No wallet found") || errorMessage.includes("\u627E\u4E0D\u5230\u94B1\u5305") || errorMessage.includes("not found") || errorMessage.includes("no matching");
|
|
3726
|
+
const isTimeout = errorMessage.includes("timeout") || errorMessage.includes("\u8D85\u65F6") || errorCode === "TIMEOUT";
|
|
3727
|
+
const isRejected = errorMessage.includes("rejected") || errorMessage.includes("\u62D2\u7EDD") || errorCode === 4001;
|
|
3728
|
+
const isOriginNotAllowed = errorCode === 3e3 || /origin not allowed/i.test(errorMessage) || /Unauthorized:\s*origin not allowed/i.test(errorMessage);
|
|
3729
|
+
const currentMetadata = this.wallet ? {
|
|
3730
|
+
// Try to get metadata from wallet instance if available
|
|
3731
|
+
projectId: this.projectId,
|
|
3732
|
+
network
|
|
3733
|
+
} : null;
|
|
3734
|
+
const errorDetails = {
|
|
3735
|
+
error: errorMessage,
|
|
3736
|
+
detailedError,
|
|
3737
|
+
code: errorCode,
|
|
3738
|
+
isTelegram: this.isTelegramMiniApp(),
|
|
3739
|
+
network,
|
|
3740
|
+
chainId: targetChainId,
|
|
3741
|
+
projectId: this.projectId,
|
|
3742
|
+
metadata: currentMetadata,
|
|
3743
|
+
// Get URL from window.location if available
|
|
3744
|
+
currentUrl: typeof window !== "undefined" ? window.location.href : "N/A",
|
|
3745
|
+
telegramPlatform: typeof window !== "undefined" && window.Telegram?.WebApp?.platform || "N/A",
|
|
3746
|
+
errorType: isNoWalletFound ? "NO_WALLET_FOUND" : isTimeout ? "TIMEOUT" : isRejected ? "REJECTED" : "UNKNOWN"
|
|
3747
|
+
};
|
|
3748
|
+
console.error("[WalletConnect Tron] Connection error - Full details:", errorDetails);
|
|
3749
|
+
console.error("[WalletConnect Tron] Error object:", error);
|
|
3750
|
+
console.error("[WalletConnect Tron] Error stack:", error.stack);
|
|
3751
|
+
if (isNoWalletFound) {
|
|
3752
|
+
const noWalletErrorDetails = [
|
|
3753
|
+
`
|
|
3754
|
+
=== WalletConnect Tron: No Matching Wallet Found ===`,
|
|
3755
|
+
`Error: ${errorMessage}`,
|
|
3756
|
+
`Detailed: ${detailedError}`,
|
|
3757
|
+
`Code: ${errorCode || "N/A"}`,
|
|
3758
|
+
``,
|
|
3759
|
+
`Environment:`,
|
|
3760
|
+
` - Telegram Mini App: ${this.isTelegramMiniApp() ? "Yes" : "No"}`,
|
|
3761
|
+
` - Platform: ${errorDetails.telegramPlatform}`,
|
|
3762
|
+
` - Current URL: ${errorDetails.currentUrl}`,
|
|
3763
|
+
``,
|
|
3764
|
+
`Configuration:`,
|
|
3765
|
+
` - Project ID: ${this.projectId ? "Set" : "Missing"}`,
|
|
3766
|
+
` - Network: ${network}`,
|
|
3767
|
+
` - Chain ID: ${targetChainId}`,
|
|
3768
|
+
` - Metadata URL: ${typeof window !== "undefined" ? window.location.origin : "N/A"}`,
|
|
3769
|
+
``,
|
|
3770
|
+
`Possible Causes:`,
|
|
3771
|
+
` 1. No WalletConnect-compatible wallet (TokenPocket, etc.) installed on device`,
|
|
3772
|
+
` 2. Wallet app not opened or not responding to deep link (wc://)`,
|
|
3773
|
+
` 3. Deep link handling issue in Telegram Mini App environment`,
|
|
3774
|
+
` 4. WalletConnect session timeout (user took too long to approve)`,
|
|
3775
|
+
` 5. Network connectivity issue preventing WalletConnect relay connection`,
|
|
3776
|
+
``,
|
|
3777
|
+
`Solutions:`,
|
|
3778
|
+
` 1. Ensure TokenPocket or other WalletConnect-compatible wallet is installed`,
|
|
3779
|
+
` 2. Try opening the wallet app manually before connecting`,
|
|
3780
|
+
` 3. In Telegram Mini App, ensure the deep link popup is not blocked`,
|
|
3781
|
+
` 4. Try connecting again (may need to wait a few seconds)`,
|
|
3782
|
+
` 5. Check network connection and WalletConnect relay server accessibility`,
|
|
3783
|
+
``,
|
|
3784
|
+
`For more details, see the error object logged above.`,
|
|
3785
|
+
`===========================================
|
|
3786
|
+
`
|
|
3787
|
+
].join("\n");
|
|
3788
|
+
console.error(noWalletErrorDetails);
|
|
3789
|
+
throw new ConnectionRejectedError(
|
|
3790
|
+
`WalletConnect Tron: \u6CA1\u6709\u627E\u5230\u652F\u6301\u7684\u94B1\u5305 (No matching wallet found)
|
|
3791
|
+
|
|
3792
|
+
\u53EF\u80FD\u7684\u539F\u56E0\uFF1A
|
|
3793
|
+
1. \u8BBE\u5907\u4E0A\u672A\u5B89\u88C5\u652F\u6301 WalletConnect \u7684\u94B1\u5305\uFF08\u5982 TokenPocket\uFF09
|
|
3794
|
+
2. \u94B1\u5305\u5E94\u7528\u672A\u6253\u5F00\u6216\u672A\u54CD\u5E94 deep link (wc://)
|
|
3795
|
+
3. \u5728 Telegram Mini App \u4E2D\uFF0Cdeep link \u5904\u7406\u53EF\u80FD\u6709\u95EE\u9898
|
|
3796
|
+
4. \u8FDE\u63A5\u8D85\u65F6\uFF08\u7528\u6237\u672A\u53CA\u65F6\u6279\u51C6\uFF09
|
|
3797
|
+
5. \u7F51\u7EDC\u8FDE\u63A5\u95EE\u9898
|
|
3798
|
+
|
|
3799
|
+
\u89E3\u51B3\u65B9\u6848\uFF1A
|
|
3800
|
+
1. \u786E\u4FDD\u5DF2\u5B89\u88C5 TokenPocket \u6216\u5176\u4ED6\u652F\u6301 WalletConnect \u7684\u94B1\u5305
|
|
3801
|
+
2. \u5C1D\u8BD5\u624B\u52A8\u6253\u5F00\u94B1\u5305\u5E94\u7528\u540E\u518D\u8FDE\u63A5
|
|
3802
|
+
3. \u5728 Telegram Mini App \u4E2D\uFF0C\u786E\u4FDD deep link \u5F39\u7A97\u672A\u88AB\u963B\u6B62
|
|
3803
|
+
4. \u7A0D\u7B49\u51E0\u79D2\u540E\u91CD\u8BD5\u8FDE\u63A5
|
|
3804
|
+
5. \u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5\u548C WalletConnect \u4E2D\u7EE7\u670D\u52A1\u5668\u53EF\u8BBF\u95EE\u6027
|
|
3805
|
+
|
|
3806
|
+
\u8BE6\u7EC6\u9519\u8BEF\u4FE1\u606F\u8BF7\u67E5\u770B\u63A7\u5236\u53F0\u65E5\u5FD7\u3002`
|
|
3807
|
+
);
|
|
3808
|
+
}
|
|
3809
|
+
if (errorMessage.includes("Invalid") || errorMessage.includes("Configuration") || errorMessage.includes("App Config") || errorMessage.includes("Invalid App")) {
|
|
3810
|
+
const configErrorDetails = [
|
|
3811
|
+
`
|
|
3812
|
+
=== WalletConnect Tron Configuration Error ===`,
|
|
3813
|
+
`Error: ${errorMessage}`,
|
|
3814
|
+
`Detailed: ${detailedError}`,
|
|
3815
|
+
`Code: ${errorCode || "N/A"}`,
|
|
3816
|
+
`
|
|
3817
|
+
Environment:`,
|
|
3818
|
+
` - Telegram Mini App: ${this.isTelegramMiniApp() ? "Yes" : "No"}`,
|
|
3819
|
+
` - Platform: ${errorDetails.telegramPlatform}`,
|
|
3820
|
+
` - Current URL: ${errorDetails.currentUrl}`,
|
|
3821
|
+
`
|
|
3822
|
+
Configuration:`,
|
|
3823
|
+
` - Project ID: ${this.projectId ? "Set" : "Missing"}`,
|
|
3824
|
+
` - Network: ${network}`,
|
|
3825
|
+
` - Chain ID: ${targetChainId}`,
|
|
3826
|
+
`
|
|
3827
|
+
Possible Causes:`,
|
|
3828
|
+
` 1. Deep link (wc://) handling issue in Telegram Mini App`,
|
|
3829
|
+
` 2. Invalid metadata configuration (URL or icons not accessible)`,
|
|
3830
|
+
` 3. Network/chainId mismatch`,
|
|
3831
|
+
` 4. WalletConnect project ID not configured correctly`,
|
|
3832
|
+
` 5. Domain not added to WalletConnect Cloud allowlist`,
|
|
3833
|
+
`
|
|
3834
|
+
Please check:`,
|
|
3835
|
+
` - WalletConnect Project ID is valid and active`,
|
|
3836
|
+
` - Domain is added to WalletConnect Cloud allowlist (for serveo.net, etc.)`,
|
|
3837
|
+
` - Metadata URL is accessible: Check console for metadata logs`,
|
|
3838
|
+
` - Icons are accessible: Check console for icon URLs`,
|
|
3839
|
+
` - Network matches chainId: Expected ${network} for chainId ${targetChainId}`,
|
|
3840
|
+
`
|
|
3841
|
+
For more details, see the error object logged above.`,
|
|
3842
|
+
`===========================================
|
|
3843
|
+
`
|
|
3844
|
+
].join("\n");
|
|
3845
|
+
console.error(configErrorDetails);
|
|
3846
|
+
throw new ConfigurationError(
|
|
3847
|
+
`WalletConnect Tron connection failed: ${errorMessage}
|
|
3848
|
+
|
|
3849
|
+
Configuration Details:
|
|
3850
|
+
- Telegram Mini App: ${this.isTelegramMiniApp() ? "Yes" : "No"}
|
|
3851
|
+
- Platform: ${errorDetails.telegramPlatform}
|
|
3852
|
+
- Origin: ${origin || "(unknown)"}
|
|
3853
|
+
- Project ID: ${this.projectId ? "Set" : "Missing"}
|
|
3854
|
+
- Network: ${network}
|
|
3855
|
+
- Chain ID: ${targetChainId}
|
|
3856
|
+
|
|
3857
|
+
This "Invalid App Configuration" error may be caused by:
|
|
3858
|
+
1. Deep link (wc://) handling issue in Telegram Mini App
|
|
3859
|
+
2. Invalid metadata configuration (URL or icons)
|
|
3860
|
+
3. Network/chainId mismatch
|
|
3861
|
+
4. Domain not added to WalletConnect Cloud allowlist
|
|
3862
|
+
|
|
3863
|
+
Please check the console for detailed error information.`
|
|
3864
|
+
);
|
|
3865
|
+
}
|
|
3866
|
+
if (isOriginNotAllowed) {
|
|
3867
|
+
throw new ConfigurationError(
|
|
3868
|
+
`WalletConnect Tron relayer rejected this origin (code 3000: Unauthorized: origin not allowed).
|
|
3869
|
+
|
|
3870
|
+
Fix:
|
|
3871
|
+
1) Open WalletConnect Cloud \u2192 your project (${this.projectId})
|
|
3872
|
+
2) Add this site origin to the allowlist:
|
|
3873
|
+
- ${origin || "(unknown origin)"}
|
|
3874
|
+
|
|
3875
|
+
Common dev origins to allow:
|
|
3876
|
+
- http://localhost:5173
|
|
3877
|
+
- http://192.168.0.221:5173 (your LAN dev URL)
|
|
3878
|
+
- https://wallet-test.enclave-hq.com (your Cloudflare Tunnel/custom domain)
|
|
3879
|
+
|
|
3880
|
+
Original error: ${errorMessage}`
|
|
3881
|
+
);
|
|
3882
|
+
}
|
|
3883
|
+
if (isTimeout) {
|
|
3884
|
+
throw new ConnectionRejectedError(
|
|
3885
|
+
`WalletConnect Tron connection timeout. Please try again and ensure your wallet app is open and ready.`
|
|
3886
|
+
);
|
|
3887
|
+
}
|
|
3888
|
+
if (isRejected) {
|
|
3889
|
+
throw new ConnectionRejectedError(this.type);
|
|
3890
|
+
}
|
|
3891
|
+
throw error;
|
|
3892
|
+
}
|
|
3893
|
+
this.currentAddress = address;
|
|
3894
|
+
const account = {
|
|
3895
|
+
universalAddress: createUniversalAddress(targetChainId, address),
|
|
3896
|
+
nativeAddress: address,
|
|
3897
|
+
chainId: targetChainId,
|
|
3898
|
+
chainType: ChainType.TRON,
|
|
3899
|
+
isActive: true
|
|
3900
|
+
};
|
|
3901
|
+
this.setState("connected" /* CONNECTED */);
|
|
3902
|
+
this.setAccount(account);
|
|
3903
|
+
this.setupEventListeners();
|
|
3904
|
+
return account;
|
|
3905
|
+
} catch (error) {
|
|
3906
|
+
this.setState("error" /* ERROR */);
|
|
3907
|
+
this.setAccount(null);
|
|
3908
|
+
this.currentAddress = null;
|
|
3909
|
+
if (error.message?.includes("rejected") || error.code === 4001) {
|
|
3910
|
+
throw new ConnectionRejectedError(this.type);
|
|
3911
|
+
}
|
|
3912
|
+
throw error;
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
/**
|
|
3916
|
+
* Disconnect wallet
|
|
3917
|
+
*/
|
|
3918
|
+
async disconnect() {
|
|
3919
|
+
this.removeEventListeners();
|
|
3920
|
+
if (this.wallet) {
|
|
3921
|
+
try {
|
|
3922
|
+
await this.wallet.disconnect();
|
|
3923
|
+
} catch (error) {
|
|
3924
|
+
console.warn("[WalletConnect Tron] Error during disconnect:", error);
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
this.wallet = null;
|
|
3928
|
+
this.currentAddress = null;
|
|
3929
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
3930
|
+
this.setAccount(null);
|
|
3931
|
+
this.emitDisconnected();
|
|
3932
|
+
}
|
|
3933
|
+
/**
|
|
3934
|
+
* Sign message
|
|
3935
|
+
*/
|
|
3936
|
+
async signMessage(message) {
|
|
3937
|
+
this.ensureConnected();
|
|
3938
|
+
try {
|
|
3939
|
+
if (!this.wallet) {
|
|
3940
|
+
throw new Error("Wallet not initialized");
|
|
3941
|
+
}
|
|
3942
|
+
const signature = await this.wallet.signMessage(message);
|
|
3943
|
+
if (typeof signature === "string") {
|
|
3944
|
+
return signature;
|
|
3945
|
+
} else if (signature && typeof signature === "object") {
|
|
3946
|
+
if ("signature" in signature) {
|
|
3947
|
+
return signature.signature;
|
|
3948
|
+
} else if ("result" in signature) {
|
|
3949
|
+
return signature.result;
|
|
3950
|
+
} else {
|
|
3951
|
+
return JSON.stringify(signature);
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
throw new Error("Invalid signature format returned from wallet");
|
|
3955
|
+
} catch (error) {
|
|
3956
|
+
console.error("[WalletConnect Tron] Sign message error:", error);
|
|
3957
|
+
let errorMessage = "Unknown error";
|
|
3958
|
+
if (typeof error === "string") {
|
|
3959
|
+
errorMessage = error;
|
|
3960
|
+
} else if (error?.message) {
|
|
3961
|
+
errorMessage = error.message;
|
|
3962
|
+
} else if (error?.error?.message) {
|
|
3963
|
+
errorMessage = error.error.message;
|
|
3964
|
+
} else {
|
|
3965
|
+
try {
|
|
3966
|
+
errorMessage = JSON.stringify(error);
|
|
3967
|
+
} catch {
|
|
3968
|
+
errorMessage = String(error);
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
if (errorMessage?.includes("rejected") || errorMessage?.includes("declined") || errorMessage?.includes("User rejected") || error?.code === 4001 || error?.code === "USER_REJECTED" || error?.error?.code === 4001) {
|
|
3972
|
+
throw new SignatureRejectedError();
|
|
3973
|
+
}
|
|
3974
|
+
if (errorMessage?.includes("not supported") || errorMessage?.includes("method not found") || errorMessage?.includes("Method not found") || error?.code === -32601 || error?.error?.code === -32601) {
|
|
3975
|
+
throw new Error("tron_signMessage is not supported by the connected wallet. Please use a wallet that supports WalletConnect Tron signing, or use TronLink extension for browser-based signing.");
|
|
3976
|
+
}
|
|
3977
|
+
throw new Error(`WalletConnect Tron sign message failed: ${errorMessage}`);
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
/**
|
|
3981
|
+
* Sign transaction
|
|
3982
|
+
*
|
|
3983
|
+
* @param transaction - Tron transaction object
|
|
3984
|
+
* Can be created using TronWeb (if available) or any TRON transaction builder
|
|
3985
|
+
* Format: { raw_data: {...}, raw_data_hex: "...", txID: "..." }
|
|
3986
|
+
* @returns Signed transaction object or signature
|
|
3987
|
+
*/
|
|
3988
|
+
async signTransaction(transaction) {
|
|
3989
|
+
this.ensureConnected();
|
|
3990
|
+
try {
|
|
3991
|
+
if (!this.wallet) {
|
|
3992
|
+
throw new Error("Wallet not initialized");
|
|
3993
|
+
}
|
|
3994
|
+
if (!transaction) {
|
|
3995
|
+
throw new Error("Transaction object is required");
|
|
3996
|
+
}
|
|
3997
|
+
console.log("[WalletConnect Tron] Signing transaction:", {
|
|
3998
|
+
hasRawData: !!transaction.raw_data,
|
|
3999
|
+
hasRawDataHex: !!transaction.raw_data_hex,
|
|
4000
|
+
hasTxID: !!transaction.txID
|
|
4001
|
+
});
|
|
4002
|
+
const result = await this.wallet.signTransaction(transaction);
|
|
4003
|
+
if (typeof result === "string") {
|
|
4004
|
+
return result;
|
|
4005
|
+
} else if (result && typeof result === "object") {
|
|
4006
|
+
if ("txID" in result && typeof result.txID === "string") {
|
|
4007
|
+
return result.txID;
|
|
4008
|
+
} else if ("txid" in result && typeof result.txid === "string") {
|
|
4009
|
+
return result.txid;
|
|
4010
|
+
} else if ("signature" in result) {
|
|
4011
|
+
return JSON.stringify(result);
|
|
4012
|
+
} else {
|
|
4013
|
+
return JSON.stringify(result);
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
throw new Error("Invalid signature format returned from wallet");
|
|
4017
|
+
} catch (error) {
|
|
4018
|
+
console.error("[WalletConnect Tron] Sign transaction error:", error);
|
|
4019
|
+
let errorMessage = "Unknown error";
|
|
4020
|
+
if (typeof error === "string") {
|
|
4021
|
+
errorMessage = error;
|
|
4022
|
+
} else if (error?.message) {
|
|
4023
|
+
errorMessage = error.message;
|
|
4024
|
+
} else if (error?.error?.message) {
|
|
4025
|
+
errorMessage = error.error.message;
|
|
4026
|
+
} else if (error?.data?.message) {
|
|
4027
|
+
errorMessage = error.data.message;
|
|
4028
|
+
} else {
|
|
4029
|
+
try {
|
|
4030
|
+
errorMessage = JSON.stringify(error);
|
|
4031
|
+
} catch {
|
|
4032
|
+
errorMessage = String(error);
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
if (errorMessage?.includes("rejected") || errorMessage?.includes("declined") || errorMessage?.includes("User rejected") || error?.code === 4001 || error?.code === "USER_REJECTED" || error?.error?.code === 4001) {
|
|
4036
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
4037
|
+
}
|
|
4038
|
+
if (errorMessage?.includes("not supported") || errorMessage?.includes("method not found") || errorMessage?.includes("Method not found") || errorMessage?.includes("Not support") || error?.code === -32601 || error?.error?.code === -32601) {
|
|
4039
|
+
throw new Error("tron_signTransaction is not supported by the connected wallet. Please use a wallet that supports WalletConnect Tron signing, or use TronLink extension for browser-based signing.");
|
|
4040
|
+
}
|
|
4041
|
+
throw new Error(`WalletConnect Tron sign transaction failed: ${errorMessage}`);
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
/**
|
|
4045
|
+
* Read contract (not supported by WalletConnect)
|
|
4046
|
+
*/
|
|
4047
|
+
async readContract(_params) {
|
|
4048
|
+
this.ensureConnected();
|
|
4049
|
+
throw new Error("WalletConnect Tron does not support direct contract reading. Please use direct Tron RPC calls or a wallet extension (like TronLink) for read operations.");
|
|
4050
|
+
}
|
|
4051
|
+
/**
|
|
4052
|
+
* Write contract (not yet implemented)
|
|
4053
|
+
*/
|
|
4054
|
+
async writeContract(_params) {
|
|
4055
|
+
throw new Error("Contract write not yet implemented for WalletConnect Tron");
|
|
4056
|
+
}
|
|
4057
|
+
/**
|
|
4058
|
+
* Estimate gas (not yet implemented)
|
|
4059
|
+
*/
|
|
4060
|
+
async estimateGas(_params) {
|
|
4061
|
+
throw new Error("Gas estimation not yet implemented for WalletConnect Tron");
|
|
4062
|
+
}
|
|
4063
|
+
/**
|
|
4064
|
+
* Wait for transaction (not yet implemented)
|
|
4065
|
+
*/
|
|
4066
|
+
async waitForTransaction(_txHash, _confirmations) {
|
|
4067
|
+
throw new Error("Transaction waiting not yet implemented for WalletConnect Tron");
|
|
4068
|
+
}
|
|
4069
|
+
/**
|
|
4070
|
+
* Setup event listeners
|
|
4071
|
+
*/
|
|
4072
|
+
setupEventListeners() {
|
|
4073
|
+
if (!this.wallet) {
|
|
4074
|
+
return;
|
|
4075
|
+
}
|
|
4076
|
+
this.wallet.on("accountsChanged", (accounts) => {
|
|
4077
|
+
if (accounts && accounts.length > 0 && accounts[0] !== this.currentAddress) {
|
|
4078
|
+
const newAddress = accounts[0];
|
|
4079
|
+
this.currentAddress = newAddress;
|
|
4080
|
+
if (this.currentAccount) {
|
|
4081
|
+
const newAccount = {
|
|
4082
|
+
...this.currentAccount,
|
|
4083
|
+
nativeAddress: newAddress,
|
|
4084
|
+
universalAddress: createUniversalAddress(this.currentAccount.chainId, newAddress)
|
|
4085
|
+
};
|
|
4086
|
+
this.setAccount(newAccount);
|
|
4087
|
+
this.emit("accountChanged", newAccount);
|
|
4088
|
+
}
|
|
4089
|
+
} else if (!accounts || accounts.length === 0) {
|
|
4090
|
+
this.disconnect();
|
|
4091
|
+
}
|
|
4092
|
+
});
|
|
4093
|
+
this.wallet.on("disconnect", () => {
|
|
4094
|
+
this.disconnect();
|
|
4095
|
+
});
|
|
4096
|
+
}
|
|
4097
|
+
/**
|
|
4098
|
+
* Remove event listeners
|
|
4099
|
+
*/
|
|
4100
|
+
removeEventListeners() {
|
|
4101
|
+
if (!this.wallet) {
|
|
4102
|
+
return;
|
|
4103
|
+
}
|
|
4104
|
+
this.wallet.removeAllListeners("accountsChanged");
|
|
4105
|
+
this.wallet.removeAllListeners("disconnect");
|
|
4106
|
+
}
|
|
4107
|
+
/**
|
|
4108
|
+
* Get provider (returns wallet instance)
|
|
4109
|
+
*/
|
|
4110
|
+
getProvider() {
|
|
4111
|
+
return this.wallet;
|
|
4112
|
+
}
|
|
4113
|
+
/**
|
|
4114
|
+
* Clear static wallet instance (for complete cleanup)
|
|
4115
|
+
*/
|
|
4116
|
+
static clearWalletInstance() {
|
|
4117
|
+
if (_WalletConnectTronAdapter.walletInstance) {
|
|
4118
|
+
_WalletConnectTronAdapter.walletInstance.disconnect().catch(() => {
|
|
4119
|
+
});
|
|
4120
|
+
_WalletConnectTronAdapter.walletInstance = null;
|
|
4121
|
+
_WalletConnectTronAdapter.walletProjectId = null;
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
};
|
|
4125
|
+
// Tron 主网链 ID
|
|
4126
|
+
_WalletConnectTronAdapter.TRON_MAINNET_CHAIN_ID = 195;
|
|
4127
|
+
// Static wallet instance to avoid multiple initializations
|
|
4128
|
+
_WalletConnectTronAdapter.walletInstance = null;
|
|
4129
|
+
_WalletConnectTronAdapter.walletProjectId = null;
|
|
4130
|
+
var WalletConnectTronAdapter = _WalletConnectTronAdapter;
|
|
4131
|
+
|
|
4132
|
+
// src/internal/walletconnect-tron-loader.esm.ts
|
|
4133
|
+
function loadWalletConnectTronModule() {
|
|
4134
|
+
return wallet_connect_exports;
|
|
4135
|
+
}
|
|
4136
|
+
|
|
4137
|
+
// src/adapters/deep-link/adapter.ts
|
|
4138
|
+
init_types();
|
|
4139
|
+
var _DeepLinkAdapter = class _DeepLinkAdapter extends WalletAdapter {
|
|
4140
|
+
constructor(config) {
|
|
4141
|
+
super();
|
|
4142
|
+
this.currentChainId = null;
|
|
4143
|
+
this.currentChainType = null;
|
|
4144
|
+
this.provider = this.createProvider(config);
|
|
4145
|
+
this.name = `${this.provider.name} (Deep Link)`;
|
|
4146
|
+
this.icon = this.provider.icon;
|
|
4147
|
+
if (this.provider.supportedChainTypes.includes(ChainType.EVM)) {
|
|
4148
|
+
this.chainType = ChainType.EVM;
|
|
4149
|
+
this.type = "deep-link-evm" /* DEEP_LINK_EVM */;
|
|
4150
|
+
} else if (this.provider.supportedChainTypes.includes(ChainType.TRON)) {
|
|
4151
|
+
this.chainType = ChainType.TRON;
|
|
4152
|
+
this.type = "deep-link-tron" /* DEEP_LINK_TRON */;
|
|
4153
|
+
} else {
|
|
4154
|
+
this.chainType = ChainType.EVM;
|
|
4155
|
+
this.type = "deep-link-evm" /* DEEP_LINK_EVM */;
|
|
4156
|
+
}
|
|
4157
|
+
if (typeof window !== "undefined") {
|
|
4158
|
+
this.setupCallbackHandler();
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4161
|
+
/**
|
|
4162
|
+
* Create provider instance based on type
|
|
4163
|
+
*/
|
|
4164
|
+
createProvider(config) {
|
|
4165
|
+
switch (config.providerType) {
|
|
4166
|
+
case "tokenpocket" /* TOKENPOCKET */: {
|
|
4167
|
+
const { TokenPocketDeepLinkProvider: TokenPocketDeepLinkProvider2 } = (init_tokenpocket(), __toCommonJS(tokenpocket_exports));
|
|
4168
|
+
return new TokenPocketDeepLinkProvider2({
|
|
4169
|
+
callbackUrl: config.callbackUrl,
|
|
4170
|
+
callbackSchema: config.callbackSchema
|
|
4171
|
+
});
|
|
4172
|
+
}
|
|
4173
|
+
case "tronlink" /* TRONLINK */: {
|
|
4174
|
+
const { TronLinkDeepLinkProvider: TronLinkDeepLinkProvider2 } = (init_tronlink(), __toCommonJS(tronlink_exports));
|
|
4175
|
+
return new TronLinkDeepLinkProvider2();
|
|
4176
|
+
}
|
|
4177
|
+
case "imtoken" /* IMTOKEN */: {
|
|
4178
|
+
const { ImTokenDeepLinkProvider: ImTokenDeepLinkProvider2 } = (init_imtoken(), __toCommonJS(imtoken_exports));
|
|
4179
|
+
return new ImTokenDeepLinkProvider2({
|
|
4180
|
+
callbackUrl: config.callbackUrl,
|
|
4181
|
+
callbackSchema: config.callbackSchema
|
|
4182
|
+
});
|
|
4183
|
+
}
|
|
4184
|
+
case "metamask" /* METAMASK */: {
|
|
4185
|
+
const { MetaMaskDeepLinkProvider: MetaMaskDeepLinkProvider2 } = (init_metamask(), __toCommonJS(metamask_exports));
|
|
4186
|
+
return new MetaMaskDeepLinkProvider2();
|
|
4187
|
+
}
|
|
4188
|
+
case "okx" /* OKX */: {
|
|
4189
|
+
const { OKXDeepLinkProvider: OKXDeepLinkProvider2 } = (init_okx(), __toCommonJS(okx_exports));
|
|
4190
|
+
return new OKXDeepLinkProvider2();
|
|
4191
|
+
}
|
|
4192
|
+
default:
|
|
4193
|
+
throw new Error(`Unsupported deep link provider type: ${config.providerType}`);
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
/**
|
|
4197
|
+
* Setup callback handler for deep link results
|
|
4198
|
+
*/
|
|
4199
|
+
setupCallbackHandler() {
|
|
4200
|
+
if (typeof window === "undefined") {
|
|
4201
|
+
return;
|
|
4202
|
+
}
|
|
4203
|
+
const handleUrlChange = () => {
|
|
4204
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
4205
|
+
const result = this.provider.parseCallbackResult(urlParams);
|
|
4206
|
+
if (result.actionId && _DeepLinkAdapter.pendingActions.has(result.actionId)) {
|
|
4207
|
+
const callback = _DeepLinkAdapter.pendingActions.get(result.actionId);
|
|
4208
|
+
if (result.error) {
|
|
4209
|
+
callback.reject(new Error(result.error));
|
|
4210
|
+
} else if (result.result) {
|
|
4211
|
+
callback.resolve(result.result);
|
|
4212
|
+
}
|
|
4213
|
+
_DeepLinkAdapter.pendingActions.delete(result.actionId);
|
|
4214
|
+
}
|
|
4215
|
+
};
|
|
4216
|
+
window.addEventListener("popstate", handleUrlChange);
|
|
4217
|
+
window.addEventListener("hashchange", handleUrlChange);
|
|
4218
|
+
handleUrlChange();
|
|
4219
|
+
}
|
|
4220
|
+
/**
|
|
4221
|
+
* Check if deep link is available
|
|
4222
|
+
*/
|
|
4223
|
+
async isAvailable() {
|
|
4224
|
+
return this.provider.isAvailable();
|
|
4225
|
+
}
|
|
4226
|
+
/**
|
|
4227
|
+
* Connect to wallet via deep link
|
|
4228
|
+
*
|
|
4229
|
+
* Note: Deep links typically don't support persistent connections
|
|
4230
|
+
* This method may throw ConnectionRejectedError as deep links are
|
|
4231
|
+
* primarily used for signing operations, not connection
|
|
4232
|
+
*/
|
|
4233
|
+
async connect(chainId) {
|
|
4234
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId || 1;
|
|
4235
|
+
let chainType;
|
|
4236
|
+
if (targetChainId === 195) {
|
|
4237
|
+
chainType = ChainType.TRON;
|
|
4238
|
+
} else {
|
|
4239
|
+
chainType = ChainType.EVM;
|
|
4240
|
+
}
|
|
4241
|
+
if (!this.provider.supportedChainTypes.includes(chainType)) {
|
|
4242
|
+
throw new Error(
|
|
4243
|
+
`Provider ${this.provider.name} does not support chain type ${chainType}`
|
|
4244
|
+
);
|
|
4245
|
+
}
|
|
4246
|
+
if (this.provider.buildConnectLink) {
|
|
4247
|
+
const linkInfo = this.provider.buildConnectLink({
|
|
4248
|
+
chainId: targetChainId,
|
|
4249
|
+
chainType
|
|
4250
|
+
});
|
|
4251
|
+
if (linkInfo.actionId) {
|
|
4252
|
+
return new Promise((resolve, reject) => {
|
|
4253
|
+
_DeepLinkAdapter.pendingActions.set(linkInfo.actionId, {
|
|
4254
|
+
resolve: (result) => {
|
|
4255
|
+
const address = result?.address || result?.account || result;
|
|
4256
|
+
if (!address || typeof address !== "string") {
|
|
4257
|
+
reject(new ConnectionRejectedError("Invalid connection result: no address found"));
|
|
4258
|
+
return;
|
|
4259
|
+
}
|
|
4260
|
+
const account = {
|
|
4261
|
+
universalAddress: createUniversalAddress(targetChainId, address),
|
|
4262
|
+
nativeAddress: address,
|
|
4263
|
+
chainId: targetChainId,
|
|
4264
|
+
chainType,
|
|
4265
|
+
isActive: true
|
|
4266
|
+
};
|
|
4267
|
+
this.setState("connected" /* CONNECTED */);
|
|
4268
|
+
this.setAccount(account);
|
|
4269
|
+
this.emit("connected", account);
|
|
4270
|
+
resolve(account);
|
|
4271
|
+
},
|
|
4272
|
+
reject: (error) => {
|
|
4273
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
4274
|
+
reject(error);
|
|
4275
|
+
}
|
|
4276
|
+
});
|
|
4277
|
+
window.location.href = linkInfo.url;
|
|
4278
|
+
setTimeout(() => {
|
|
4279
|
+
if (_DeepLinkAdapter.pendingActions.has(linkInfo.actionId)) {
|
|
4280
|
+
_DeepLinkAdapter.pendingActions.delete(linkInfo.actionId);
|
|
4281
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
4282
|
+
reject(new ConnectionRejectedError("Deep link connection timeout"));
|
|
4283
|
+
}
|
|
4284
|
+
}, 3e4);
|
|
4285
|
+
});
|
|
4286
|
+
} else {
|
|
4287
|
+
window.location.href = linkInfo.url;
|
|
4288
|
+
throw new ConnectionRejectedError(
|
|
4289
|
+
"Deep link connection initiated. Please complete the connection in your wallet app."
|
|
4290
|
+
);
|
|
4291
|
+
}
|
|
4292
|
+
} else {
|
|
4293
|
+
throw new ConnectionRejectedError(
|
|
4294
|
+
`Deep link connection is not supported by ${this.provider.name}. Deep links are primarily used for signing operations.`
|
|
4295
|
+
);
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
/**
|
|
4299
|
+
* Disconnect from wallet
|
|
4300
|
+
*/
|
|
4301
|
+
async disconnect() {
|
|
4302
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
4303
|
+
this.setAccount(null);
|
|
4304
|
+
this.currentChainId = null;
|
|
4305
|
+
this.currentChainType = null;
|
|
4306
|
+
this.emitDisconnected();
|
|
4307
|
+
}
|
|
4308
|
+
/**
|
|
4309
|
+
* Sign a message
|
|
4310
|
+
*/
|
|
4311
|
+
async signMessage(message) {
|
|
4312
|
+
this.ensureConnected();
|
|
4313
|
+
if (!this.currentChainId || !this.currentChainType) {
|
|
4314
|
+
throw new WalletNotConnectedError(this.type);
|
|
4315
|
+
}
|
|
4316
|
+
const linkInfo = this.provider.buildSignMessageLink({
|
|
4317
|
+
message,
|
|
4318
|
+
chainId: this.currentChainId,
|
|
4319
|
+
chainType: this.currentChainType
|
|
4320
|
+
});
|
|
4321
|
+
if (linkInfo.callbackSchema || linkInfo.callbackUrl) {
|
|
4322
|
+
return new Promise((resolve, reject) => {
|
|
4323
|
+
_DeepLinkAdapter.pendingActions.set(linkInfo.actionId, { resolve, reject });
|
|
4324
|
+
window.location.href = linkInfo.url;
|
|
4325
|
+
setTimeout(() => {
|
|
4326
|
+
if (_DeepLinkAdapter.pendingActions.has(linkInfo.actionId)) {
|
|
4327
|
+
_DeepLinkAdapter.pendingActions.delete(linkInfo.actionId);
|
|
4328
|
+
reject(new SignatureRejectedError("Message signature timeout"));
|
|
4329
|
+
}
|
|
4330
|
+
}, 3e4);
|
|
4331
|
+
});
|
|
4332
|
+
} else {
|
|
4333
|
+
window.location.href = linkInfo.url;
|
|
4334
|
+
throw new SignatureRejectedError(
|
|
4335
|
+
"Deep link signature initiated. Please complete the signature in your wallet app."
|
|
4336
|
+
);
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
/**
|
|
4340
|
+
* Sign a transaction
|
|
4341
|
+
*/
|
|
4342
|
+
async signTransaction(transaction) {
|
|
4343
|
+
this.ensureConnected();
|
|
4344
|
+
if (!this.currentChainId || !this.currentChainType) {
|
|
4345
|
+
throw new WalletNotConnectedError(this.type);
|
|
4346
|
+
}
|
|
4347
|
+
const linkInfo = this.provider.buildSignTransactionLink({
|
|
4348
|
+
transaction,
|
|
4349
|
+
chainId: this.currentChainId,
|
|
4350
|
+
chainType: this.currentChainType
|
|
4351
|
+
});
|
|
4352
|
+
if (linkInfo.callbackSchema || linkInfo.callbackUrl) {
|
|
4353
|
+
return new Promise((resolve, reject) => {
|
|
4354
|
+
_DeepLinkAdapter.pendingActions.set(linkInfo.actionId, { resolve, reject });
|
|
4355
|
+
window.location.href = linkInfo.url;
|
|
4356
|
+
setTimeout(() => {
|
|
4357
|
+
if (_DeepLinkAdapter.pendingActions.has(linkInfo.actionId)) {
|
|
4358
|
+
_DeepLinkAdapter.pendingActions.delete(linkInfo.actionId);
|
|
4359
|
+
reject(new SignatureRejectedError("Transaction signature timeout"));
|
|
4360
|
+
}
|
|
4361
|
+
}, 3e4);
|
|
4362
|
+
});
|
|
4363
|
+
} else {
|
|
4364
|
+
window.location.href = linkInfo.url;
|
|
4365
|
+
throw new SignatureRejectedError(
|
|
4366
|
+
"Deep link transaction signature initiated. Please complete the signature in your wallet app."
|
|
4367
|
+
);
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
/**
|
|
4371
|
+
* Get provider (not applicable for deep links)
|
|
4372
|
+
*/
|
|
4373
|
+
getProvider() {
|
|
4374
|
+
return null;
|
|
4375
|
+
}
|
|
4376
|
+
/**
|
|
4377
|
+
* Static method to handle callback from wallet apps
|
|
4378
|
+
* This can be called from anywhere in the application
|
|
4379
|
+
*/
|
|
4380
|
+
static handleCallback() {
|
|
4381
|
+
if (typeof window === "undefined") {
|
|
4382
|
+
return;
|
|
4383
|
+
}
|
|
4384
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
4385
|
+
const actionId = urlParams.get("actionId");
|
|
4386
|
+
if (actionId && _DeepLinkAdapter.pendingActions.has(actionId)) {
|
|
4387
|
+
const callback = _DeepLinkAdapter.pendingActions.get(actionId);
|
|
4388
|
+
const result = urlParams.get("result");
|
|
4389
|
+
const error = urlParams.get("error");
|
|
4390
|
+
if (error) {
|
|
4391
|
+
callback.reject(new Error(error));
|
|
4392
|
+
} else if (result) {
|
|
4393
|
+
try {
|
|
4394
|
+
const parsedResult = JSON.parse(decodeURIComponent(result));
|
|
4395
|
+
callback.resolve(parsedResult);
|
|
4396
|
+
} catch (e) {
|
|
4397
|
+
callback.resolve(result);
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
_DeepLinkAdapter.pendingActions.delete(actionId);
|
|
4401
|
+
}
|
|
4402
|
+
}
|
|
4403
|
+
/**
|
|
4404
|
+
* Set current account (called after successful connection)
|
|
4405
|
+
*/
|
|
4406
|
+
setAccount(account) {
|
|
4407
|
+
this.currentAccount = account;
|
|
4408
|
+
if (account) {
|
|
4409
|
+
this.currentChainId = account.chainId;
|
|
4410
|
+
this.currentChainType = account.chainType;
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
/**
|
|
4414
|
+
* Emit disconnected event
|
|
4415
|
+
*/
|
|
4416
|
+
emitDisconnected() {
|
|
4417
|
+
this.emit("disconnected");
|
|
4418
|
+
}
|
|
4419
|
+
};
|
|
4420
|
+
// Static map to store pending actions across all instances
|
|
4421
|
+
// Key: actionId, Value: { resolve, reject }
|
|
4422
|
+
_DeepLinkAdapter.pendingActions = /* @__PURE__ */ new Map();
|
|
4423
|
+
var DeepLinkAdapter = _DeepLinkAdapter;
|
|
4424
|
+
|
|
4425
|
+
// src/core/adapter-registry.ts
|
|
4426
|
+
var AdapterRegistry = class {
|
|
4427
|
+
constructor(config = {}) {
|
|
4428
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
4429
|
+
this.config = config;
|
|
4430
|
+
this.registerDefaultAdapters();
|
|
4431
|
+
}
|
|
4432
|
+
/**
|
|
4433
|
+
* Register default adapters
|
|
4434
|
+
*/
|
|
4435
|
+
registerDefaultAdapters() {
|
|
4436
|
+
this.register("metamask" /* METAMASK */, () => new MetaMaskAdapter());
|
|
4437
|
+
this.register("private-key" /* PRIVATE_KEY */, () => new EVMPrivateKeyAdapter());
|
|
4438
|
+
if (this.config.walletConnectProjectId) {
|
|
4439
|
+
this.register(
|
|
4440
|
+
"walletconnect" /* WALLETCONNECT */,
|
|
4441
|
+
() => new WalletConnectAdapter(this.config.walletConnectProjectId)
|
|
4442
|
+
);
|
|
4443
|
+
this.register("walletconnect-tron" /* WALLETCONNECT_TRON */, () => {
|
|
4444
|
+
const { WalletConnectTronAdapter: WalletConnectTronAdapter2 } = loadWalletConnectTronModule();
|
|
4445
|
+
return new WalletConnectTronAdapter2(this.config.walletConnectProjectId);
|
|
4446
|
+
});
|
|
4447
|
+
}
|
|
4448
|
+
this.register("tronlink" /* TRONLINK */, () => new TronLinkAdapter());
|
|
4449
|
+
this.register(
|
|
4450
|
+
"deep-link-evm" /* DEEP_LINK_EVM */,
|
|
4451
|
+
() => new DeepLinkAdapter({
|
|
4452
|
+
providerType: "tokenpocket" /* TOKENPOCKET */
|
|
4453
|
+
})
|
|
4454
|
+
);
|
|
4455
|
+
this.register(
|
|
4456
|
+
"deep-link-tron" /* DEEP_LINK_TRON */,
|
|
4457
|
+
() => new DeepLinkAdapter({
|
|
4458
|
+
providerType: "tokenpocket" /* TOKENPOCKET */
|
|
4459
|
+
})
|
|
4460
|
+
);
|
|
4461
|
+
}
|
|
4462
|
+
/**
|
|
4463
|
+
* Register adapter
|
|
4464
|
+
*/
|
|
4465
|
+
register(type, factory) {
|
|
4466
|
+
this.adapters.set(type, factory);
|
|
4467
|
+
}
|
|
4468
|
+
/**
|
|
4469
|
+
* Get adapter
|
|
4470
|
+
*/
|
|
4471
|
+
getAdapter(type) {
|
|
4472
|
+
const factory = this.adapters.get(type);
|
|
4473
|
+
if (!factory) {
|
|
4474
|
+
return null;
|
|
4475
|
+
}
|
|
4476
|
+
return factory();
|
|
4477
|
+
}
|
|
4478
|
+
/**
|
|
1579
4479
|
* Check if adapter is registered
|
|
1580
4480
|
*/
|
|
1581
4481
|
has(type) {
|
|
@@ -1602,6 +4502,190 @@ var AdapterRegistry = class {
|
|
|
1602
4502
|
}
|
|
1603
4503
|
};
|
|
1604
4504
|
|
|
4505
|
+
// src/core/wallet-manager.ts
|
|
4506
|
+
init_types();
|
|
4507
|
+
var QRCodeSigner = class {
|
|
4508
|
+
constructor(config) {
|
|
4509
|
+
this.pollTimer = null;
|
|
4510
|
+
this.timeoutTimer = null;
|
|
4511
|
+
this.status = "waiting" /* WAITING */;
|
|
4512
|
+
this.qrCodeDataUrl = null;
|
|
4513
|
+
this.result = null;
|
|
4514
|
+
this.config = {
|
|
4515
|
+
requestId: config.requestId,
|
|
4516
|
+
requestUrl: config.requestUrl,
|
|
4517
|
+
pollUrl: config.pollUrl || "",
|
|
4518
|
+
pollInterval: config.pollInterval || 2e3,
|
|
4519
|
+
timeout: config.timeout || 3e5,
|
|
4520
|
+
// 5 minutes
|
|
4521
|
+
pollFn: config.pollFn
|
|
4522
|
+
};
|
|
4523
|
+
}
|
|
4524
|
+
/**
|
|
4525
|
+
* 生成二维码图片(Data URL)
|
|
4526
|
+
*/
|
|
4527
|
+
async generateQRCode(options) {
|
|
4528
|
+
if (this.qrCodeDataUrl) {
|
|
4529
|
+
return this.qrCodeDataUrl;
|
|
4530
|
+
}
|
|
4531
|
+
try {
|
|
4532
|
+
const qrCodeOptions = {
|
|
4533
|
+
width: options?.width || 300,
|
|
4534
|
+
margin: options?.margin || 2,
|
|
4535
|
+
color: {
|
|
4536
|
+
dark: options?.color?.dark || "#000000",
|
|
4537
|
+
light: options?.color?.light || "#FFFFFF"
|
|
4538
|
+
}
|
|
4539
|
+
};
|
|
4540
|
+
this.qrCodeDataUrl = await QRCode__default.default.toDataURL(this.config.requestUrl, qrCodeOptions);
|
|
4541
|
+
return this.qrCodeDataUrl;
|
|
4542
|
+
} catch (error) {
|
|
4543
|
+
throw new Error(`Failed to generate QR code: ${error instanceof Error ? error.message : String(error)}`);
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4546
|
+
/**
|
|
4547
|
+
* 开始轮询签名结果
|
|
4548
|
+
*/
|
|
4549
|
+
async startPolling(onStatusChange, onResult) {
|
|
4550
|
+
if (this.status === "success" /* SUCCESS */ && this.result?.signature) {
|
|
4551
|
+
return this.result.signature;
|
|
4552
|
+
}
|
|
4553
|
+
if (this.status === "cancelled" /* CANCELLED */ || this.status === "timeout" /* TIMEOUT */) {
|
|
4554
|
+
throw new SignatureRejectedError("Signature request was cancelled or timed out");
|
|
4555
|
+
}
|
|
4556
|
+
this.timeoutTimer = setTimeout(() => {
|
|
4557
|
+
this.stopPolling();
|
|
4558
|
+
this.status = "timeout" /* TIMEOUT */;
|
|
4559
|
+
onStatusChange?.(this.status);
|
|
4560
|
+
throw new SignatureRejectedError("Signature request timed out");
|
|
4561
|
+
}, this.config.timeout);
|
|
4562
|
+
return new Promise((resolve, reject) => {
|
|
4563
|
+
const poll = async () => {
|
|
4564
|
+
try {
|
|
4565
|
+
let result = null;
|
|
4566
|
+
if (this.config.pollFn) {
|
|
4567
|
+
result = await this.config.pollFn(this.config.requestId);
|
|
4568
|
+
} else if (this.config.pollUrl) {
|
|
4569
|
+
result = await this.defaultPoll(this.config.requestId);
|
|
4570
|
+
} else {
|
|
4571
|
+
return;
|
|
4572
|
+
}
|
|
4573
|
+
if (result?.completed) {
|
|
4574
|
+
this.stopPolling();
|
|
4575
|
+
this.result = result;
|
|
4576
|
+
if (result.signature) {
|
|
4577
|
+
this.status = "success" /* SUCCESS */;
|
|
4578
|
+
onStatusChange?.(this.status);
|
|
4579
|
+
onResult?.(result);
|
|
4580
|
+
resolve(result.signature);
|
|
4581
|
+
} else if (result.error) {
|
|
4582
|
+
this.status = "failed" /* FAILED */;
|
|
4583
|
+
onStatusChange?.(this.status);
|
|
4584
|
+
reject(new SignatureRejectedError(result.error));
|
|
4585
|
+
}
|
|
4586
|
+
} else if (result) {
|
|
4587
|
+
if (this.status === "waiting" /* WAITING */) {
|
|
4588
|
+
this.status = "pending" /* PENDING */;
|
|
4589
|
+
onStatusChange?.(this.status);
|
|
4590
|
+
}
|
|
4591
|
+
this.pollTimer = setTimeout(poll, this.config.pollInterval);
|
|
4592
|
+
} else {
|
|
4593
|
+
this.pollTimer = setTimeout(poll, this.config.pollInterval);
|
|
4594
|
+
}
|
|
4595
|
+
} catch (error) {
|
|
4596
|
+
this.stopPolling();
|
|
4597
|
+
this.status = "failed" /* FAILED */;
|
|
4598
|
+
onStatusChange?.(this.status);
|
|
4599
|
+
reject(error);
|
|
4600
|
+
}
|
|
4601
|
+
};
|
|
4602
|
+
poll();
|
|
4603
|
+
});
|
|
4604
|
+
}
|
|
4605
|
+
/**
|
|
4606
|
+
* 默认 HTTP 轮询函数
|
|
4607
|
+
*/
|
|
4608
|
+
async defaultPoll(requestId) {
|
|
4609
|
+
if (!this.config.pollUrl) {
|
|
4610
|
+
return null;
|
|
4611
|
+
}
|
|
4612
|
+
try {
|
|
4613
|
+
const url = `${this.config.pollUrl}?requestId=${encodeURIComponent(requestId)}`;
|
|
4614
|
+
const response = await fetch(url, {
|
|
4615
|
+
method: "GET",
|
|
4616
|
+
headers: {
|
|
4617
|
+
"Content-Type": "application/json"
|
|
4618
|
+
}
|
|
4619
|
+
});
|
|
4620
|
+
if (!response.ok) {
|
|
4621
|
+
if (response.status === 404) {
|
|
4622
|
+
return null;
|
|
4623
|
+
}
|
|
4624
|
+
throw new NetworkError(`Poll request failed: ${response.statusText}`);
|
|
4625
|
+
}
|
|
4626
|
+
const data = await response.json();
|
|
4627
|
+
return {
|
|
4628
|
+
completed: data.completed === true,
|
|
4629
|
+
signature: data.signature,
|
|
4630
|
+
error: data.error,
|
|
4631
|
+
signer: data.signer
|
|
4632
|
+
};
|
|
4633
|
+
} catch (error) {
|
|
4634
|
+
if (error instanceof NetworkError) {
|
|
4635
|
+
throw error;
|
|
4636
|
+
}
|
|
4637
|
+
return null;
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
/**
|
|
4641
|
+
* 停止轮询
|
|
4642
|
+
*/
|
|
4643
|
+
stopPolling() {
|
|
4644
|
+
if (this.pollTimer) {
|
|
4645
|
+
clearTimeout(this.pollTimer);
|
|
4646
|
+
this.pollTimer = null;
|
|
4647
|
+
}
|
|
4648
|
+
if (this.timeoutTimer) {
|
|
4649
|
+
clearTimeout(this.timeoutTimer);
|
|
4650
|
+
this.timeoutTimer = null;
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
/**
|
|
4654
|
+
* 取消签名请求
|
|
4655
|
+
*/
|
|
4656
|
+
cancel() {
|
|
4657
|
+
this.stopPolling();
|
|
4658
|
+
this.status = "cancelled" /* CANCELLED */;
|
|
4659
|
+
}
|
|
4660
|
+
/**
|
|
4661
|
+
* 获取当前状态
|
|
4662
|
+
*/
|
|
4663
|
+
getStatus() {
|
|
4664
|
+
return this.status;
|
|
4665
|
+
}
|
|
4666
|
+
/**
|
|
4667
|
+
* 获取二维码 URL
|
|
4668
|
+
*/
|
|
4669
|
+
getQRCodeUrl() {
|
|
4670
|
+
return this.config.requestUrl;
|
|
4671
|
+
}
|
|
4672
|
+
/**
|
|
4673
|
+
* 获取结果
|
|
4674
|
+
*/
|
|
4675
|
+
getResult() {
|
|
4676
|
+
return this.result;
|
|
4677
|
+
}
|
|
4678
|
+
/**
|
|
4679
|
+
* 清理资源
|
|
4680
|
+
*/
|
|
4681
|
+
cleanup() {
|
|
4682
|
+
this.stopPolling();
|
|
4683
|
+
this.qrCodeDataUrl = null;
|
|
4684
|
+
this.result = null;
|
|
4685
|
+
this.status = "waiting" /* WAITING */;
|
|
4686
|
+
}
|
|
4687
|
+
};
|
|
4688
|
+
|
|
1605
4689
|
// src/core/wallet-manager.ts
|
|
1606
4690
|
var WalletManager = class extends TypedEventEmitter {
|
|
1607
4691
|
constructor(config = {}) {
|
|
@@ -1617,9 +4701,15 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1617
4701
|
defaultTronChainId: config.defaultTronChainId ?? 195,
|
|
1618
4702
|
walletConnectProjectId: config.walletConnectProjectId ?? ""
|
|
1619
4703
|
};
|
|
1620
|
-
this.registry = new AdapterRegistry();
|
|
4704
|
+
this.registry = new AdapterRegistry(this.config);
|
|
1621
4705
|
}
|
|
1622
4706
|
// ===== Connection Management =====
|
|
4707
|
+
/**
|
|
4708
|
+
* Check if adapter is registered for a wallet type
|
|
4709
|
+
*/
|
|
4710
|
+
hasAdapter(type) {
|
|
4711
|
+
return this.registry.has(type);
|
|
4712
|
+
}
|
|
1623
4713
|
/**
|
|
1624
4714
|
* Connect primary wallet
|
|
1625
4715
|
*/
|
|
@@ -1686,7 +4776,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1686
4776
|
this.connectedWallets.delete(chainType);
|
|
1687
4777
|
this.primaryWallet = null;
|
|
1688
4778
|
if (this.config.enableStorage) {
|
|
1689
|
-
this.
|
|
4779
|
+
this.clearStorage();
|
|
1690
4780
|
}
|
|
1691
4781
|
this.emit("disconnected");
|
|
1692
4782
|
}
|
|
@@ -1775,6 +4865,35 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1775
4865
|
}
|
|
1776
4866
|
return adapter.signMessage(message);
|
|
1777
4867
|
}
|
|
4868
|
+
/**
|
|
4869
|
+
* Create QR code signer for message signing
|
|
4870
|
+
*
|
|
4871
|
+
* This method creates a QR code signer that can be used to display a QR code
|
|
4872
|
+
* for users to scan with their wallet app to sign a message.
|
|
4873
|
+
*
|
|
4874
|
+
* @param message - Message to sign
|
|
4875
|
+
* @param config - QR code signer configuration
|
|
4876
|
+
* @returns QRCodeSigner instance
|
|
4877
|
+
*
|
|
4878
|
+
* @example
|
|
4879
|
+
* ```typescript
|
|
4880
|
+
* const signer = walletManager.createQRCodeSigner('Hello World', {
|
|
4881
|
+
* requestId: 'sign-123',
|
|
4882
|
+
* requestUrl: 'https://example.com/sign?requestId=sign-123&message=Hello%20World',
|
|
4883
|
+
* pollUrl: 'https://api.example.com/sign/status',
|
|
4884
|
+
* })
|
|
4885
|
+
*
|
|
4886
|
+
* const qrCodeUrl = await signer.generateQRCode()
|
|
4887
|
+
* const signature = await signer.startPolling()
|
|
4888
|
+
* ```
|
|
4889
|
+
*/
|
|
4890
|
+
createQRCodeSigner(message, config) {
|
|
4891
|
+
return new QRCodeSigner({
|
|
4892
|
+
...config,
|
|
4893
|
+
// Encode message in request URL if not already encoded
|
|
4894
|
+
requestUrl: config.requestUrl.includes(encodeURIComponent(message)) ? config.requestUrl : `${config.requestUrl}${config.requestUrl.includes("?") ? "&" : "?"}message=${encodeURIComponent(message)}`
|
|
4895
|
+
});
|
|
4896
|
+
}
|
|
1778
4897
|
/**
|
|
1779
4898
|
* Sign TypedData (EVM only)
|
|
1780
4899
|
*/
|
|
@@ -1839,6 +4958,41 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1839
4958
|
throw error;
|
|
1840
4959
|
}
|
|
1841
4960
|
}
|
|
4961
|
+
/**
|
|
4962
|
+
* Request account switch (opens wallet account selector)
|
|
4963
|
+
* @param targetAddress Optional target address to verify after switching
|
|
4964
|
+
* @returns The new account after switching
|
|
4965
|
+
*/
|
|
4966
|
+
async requestSwitchAccount(targetAddress) {
|
|
4967
|
+
if (!this.primaryWallet) {
|
|
4968
|
+
throw new WalletNotConnectedError();
|
|
4969
|
+
}
|
|
4970
|
+
if (!this.primaryWallet.requestSwitchAccount) {
|
|
4971
|
+
throw new Error(`Account switching not supported by ${this.primaryWallet.type}`);
|
|
4972
|
+
}
|
|
4973
|
+
const account = await this.primaryWallet.requestSwitchAccount(targetAddress);
|
|
4974
|
+
if (this.config.enableStorage) {
|
|
4975
|
+
this.saveToStorage();
|
|
4976
|
+
}
|
|
4977
|
+
return account;
|
|
4978
|
+
}
|
|
4979
|
+
/**
|
|
4980
|
+
* Ensure the current account matches the target address
|
|
4981
|
+
* If not matching, request account switch
|
|
4982
|
+
* @param targetAddress The address that should be active
|
|
4983
|
+
* @returns The account (either existing or after switch)
|
|
4984
|
+
*/
|
|
4985
|
+
async ensureAccount(targetAddress) {
|
|
4986
|
+
const currentAccount = this.getPrimaryAccount();
|
|
4987
|
+
if (!currentAccount) {
|
|
4988
|
+
throw new WalletNotConnectedError();
|
|
4989
|
+
}
|
|
4990
|
+
if (currentAccount.nativeAddress.toLowerCase() === targetAddress.toLowerCase()) {
|
|
4991
|
+
return currentAccount;
|
|
4992
|
+
}
|
|
4993
|
+
console.log(`[WalletManager] Current account ${currentAccount.nativeAddress} doesn't match target ${targetAddress}, requesting switch...`);
|
|
4994
|
+
return this.requestSwitchAccount(targetAddress);
|
|
4995
|
+
}
|
|
1842
4996
|
// ===== Contract Calls =====
|
|
1843
4997
|
/**
|
|
1844
4998
|
* Read contract
|
|
@@ -2085,6 +5239,29 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
2085
5239
|
console.debug("Silent TronLink connection failed:", silentError);
|
|
2086
5240
|
}
|
|
2087
5241
|
}
|
|
5242
|
+
if (data.primaryWalletType === "walletconnect-tron" /* WALLETCONNECT_TRON */) {
|
|
5243
|
+
try {
|
|
5244
|
+
const wcAdapter = adapter;
|
|
5245
|
+
if (typeof wcAdapter.restoreSession === "function") {
|
|
5246
|
+
console.debug("[WalletManager] Attempting to restore WalletConnect Tron session...");
|
|
5247
|
+
const account2 = await wcAdapter.restoreSession(data.primaryChainId);
|
|
5248
|
+
if (account2) {
|
|
5249
|
+
console.debug("[WalletManager] WalletConnect Tron session restored successfully");
|
|
5250
|
+
this.setPrimaryWallet(adapter);
|
|
5251
|
+
this.connectedWallets.set(adapter.chainType, adapter);
|
|
5252
|
+
this.setupAdapterListeners(adapter, true);
|
|
5253
|
+
this.emit("accountChanged", account2);
|
|
5254
|
+
return account2;
|
|
5255
|
+
} else {
|
|
5256
|
+
console.debug("[WalletManager] No valid WalletConnect Tron session found");
|
|
5257
|
+
return null;
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
5260
|
+
} catch (restoreError) {
|
|
5261
|
+
console.debug("[WalletManager] WalletConnect Tron restore failed:", restoreError);
|
|
5262
|
+
return null;
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
2088
5265
|
const account = await adapter.connect(data.primaryChainId);
|
|
2089
5266
|
this.setPrimaryWallet(adapter);
|
|
2090
5267
|
this.connectedWallets.set(adapter.chainType, adapter);
|
|
@@ -2132,44 +5309,44 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
2132
5309
|
};
|
|
2133
5310
|
|
|
2134
5311
|
// src/react/WalletContext.tsx
|
|
2135
|
-
var WalletContext =
|
|
5312
|
+
var WalletContext = React2.createContext(null);
|
|
2136
5313
|
function WalletProvider({ children, walletManager: externalWalletManager }) {
|
|
2137
|
-
const [walletManager] =
|
|
2138
|
-
const [account, setAccount] =
|
|
2139
|
-
const [connectedWallets, setConnectedWallets] =
|
|
2140
|
-
const [isRestoring, setIsRestoring] =
|
|
2141
|
-
const updateConnectedWallets =
|
|
5314
|
+
const [walletManager] = React2.useState(() => externalWalletManager || new WalletManager());
|
|
5315
|
+
const [account, setAccount] = React2.useState(null);
|
|
5316
|
+
const [connectedWallets, setConnectedWallets] = React2.useState([]);
|
|
5317
|
+
const [isRestoring, setIsRestoring] = React2.useState(true);
|
|
5318
|
+
const updateConnectedWallets = React2.useCallback(() => {
|
|
2142
5319
|
setConnectedWallets(walletManager.getConnectedWallets());
|
|
2143
5320
|
}, [walletManager]);
|
|
2144
|
-
const connect =
|
|
5321
|
+
const connect = React2.useCallback(async (type, chainId) => {
|
|
2145
5322
|
const account2 = await walletManager.connect(type, chainId);
|
|
2146
5323
|
setAccount(account2);
|
|
2147
5324
|
updateConnectedWallets();
|
|
2148
5325
|
return account2;
|
|
2149
5326
|
}, [walletManager, updateConnectedWallets]);
|
|
2150
|
-
const connectAdditional =
|
|
5327
|
+
const connectAdditional = React2.useCallback(async (type, chainId) => {
|
|
2151
5328
|
const account2 = await walletManager.connectAdditional(type, chainId);
|
|
2152
5329
|
updateConnectedWallets();
|
|
2153
5330
|
return account2;
|
|
2154
5331
|
}, [walletManager, updateConnectedWallets]);
|
|
2155
|
-
const disconnect =
|
|
5332
|
+
const disconnect = React2.useCallback(async () => {
|
|
2156
5333
|
await walletManager.disconnect();
|
|
2157
5334
|
setAccount(null);
|
|
2158
5335
|
updateConnectedWallets();
|
|
2159
5336
|
}, [walletManager, updateConnectedWallets]);
|
|
2160
|
-
const switchPrimaryWallet =
|
|
5337
|
+
const switchPrimaryWallet = React2.useCallback(async (chainType) => {
|
|
2161
5338
|
const account2 = await walletManager.switchPrimaryWallet(chainType);
|
|
2162
5339
|
setAccount(account2);
|
|
2163
5340
|
updateConnectedWallets();
|
|
2164
5341
|
return account2;
|
|
2165
5342
|
}, [walletManager, updateConnectedWallets]);
|
|
2166
|
-
const signMessage =
|
|
5343
|
+
const signMessage = React2.useCallback(async (message) => {
|
|
2167
5344
|
return walletManager.signMessage(message);
|
|
2168
5345
|
}, [walletManager]);
|
|
2169
|
-
const signTransaction =
|
|
5346
|
+
const signTransaction = React2.useCallback(async (transaction) => {
|
|
2170
5347
|
return walletManager.signTransaction(transaction);
|
|
2171
5348
|
}, [walletManager]);
|
|
2172
|
-
|
|
5349
|
+
React2.useEffect(() => {
|
|
2173
5350
|
const restoreConnection = async () => {
|
|
2174
5351
|
try {
|
|
2175
5352
|
const restoredAccount = await walletManager.restoreFromStorage();
|
|
@@ -2185,7 +5362,7 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
|
|
|
2185
5362
|
};
|
|
2186
5363
|
restoreConnection();
|
|
2187
5364
|
}, [walletManager, updateConnectedWallets]);
|
|
2188
|
-
|
|
5365
|
+
React2.useEffect(() => {
|
|
2189
5366
|
const handleAccountChanged = (newAccount) => {
|
|
2190
5367
|
setAccount(newAccount);
|
|
2191
5368
|
updateConnectedWallets();
|
|
@@ -2233,10 +5410,10 @@ function WalletProvider({ children, walletManager: externalWalletManager }) {
|
|
|
2233
5410
|
signMessage,
|
|
2234
5411
|
signTransaction
|
|
2235
5412
|
};
|
|
2236
|
-
return /* @__PURE__ */
|
|
5413
|
+
return /* @__PURE__ */ React2__default.default.createElement(WalletContext.Provider, { value }, children);
|
|
2237
5414
|
}
|
|
2238
5415
|
function useWallet() {
|
|
2239
|
-
const context =
|
|
5416
|
+
const context = React2.useContext(WalletContext);
|
|
2240
5417
|
if (!context) {
|
|
2241
5418
|
throw new Error("useWallet must be used within a WalletProvider");
|
|
2242
5419
|
}
|
|
@@ -2256,8 +5433,8 @@ function useAccount() {
|
|
|
2256
5433
|
}
|
|
2257
5434
|
function useConnect() {
|
|
2258
5435
|
const { connect: contextConnect, connectAdditional: contextConnectAdditional } = useWallet();
|
|
2259
|
-
const [isConnecting, setIsConnecting] =
|
|
2260
|
-
const [error, setError] =
|
|
5436
|
+
const [isConnecting, setIsConnecting] = React2.useState(false);
|
|
5437
|
+
const [error, setError] = React2.useState(null);
|
|
2261
5438
|
const connect = async (type, chainId) => {
|
|
2262
5439
|
setIsConnecting(true);
|
|
2263
5440
|
setError(null);
|
|
@@ -2295,8 +5472,8 @@ function useConnect() {
|
|
|
2295
5472
|
}
|
|
2296
5473
|
function useDisconnect() {
|
|
2297
5474
|
const { disconnect: contextDisconnect } = useWallet();
|
|
2298
|
-
const [isDisconnecting, setIsDisconnecting] =
|
|
2299
|
-
const [error, setError] =
|
|
5475
|
+
const [isDisconnecting, setIsDisconnecting] = React2.useState(false);
|
|
5476
|
+
const [error, setError] = React2.useState(null);
|
|
2300
5477
|
const disconnect = async () => {
|
|
2301
5478
|
setIsDisconnecting(true);
|
|
2302
5479
|
setError(null);
|
|
@@ -2318,8 +5495,8 @@ function useDisconnect() {
|
|
|
2318
5495
|
}
|
|
2319
5496
|
function useSignMessage() {
|
|
2320
5497
|
const { signMessage: contextSignMessage } = useWallet();
|
|
2321
|
-
const [isSigning, setIsSigning] =
|
|
2322
|
-
const [error, setError] =
|
|
5498
|
+
const [isSigning, setIsSigning] = React2.useState(false);
|
|
5499
|
+
const [error, setError] = React2.useState(null);
|
|
2323
5500
|
const signMessage = async (message) => {
|
|
2324
5501
|
setIsSigning(true);
|
|
2325
5502
|
setError(null);
|
|
@@ -2342,8 +5519,8 @@ function useSignMessage() {
|
|
|
2342
5519
|
}
|
|
2343
5520
|
function useSignTransaction() {
|
|
2344
5521
|
const { signTransaction: contextSignTransaction } = useWallet();
|
|
2345
|
-
const [isSigning, setIsSigning] =
|
|
2346
|
-
const [error, setError] =
|
|
5522
|
+
const [isSigning, setIsSigning] = React2.useState(false);
|
|
5523
|
+
const [error, setError] = React2.useState(null);
|
|
2347
5524
|
const signTransaction = async (transaction) => {
|
|
2348
5525
|
setIsSigning(true);
|
|
2349
5526
|
setError(null);
|
|
@@ -2364,11 +5541,381 @@ function useSignTransaction() {
|
|
|
2364
5541
|
error
|
|
2365
5542
|
};
|
|
2366
5543
|
}
|
|
5544
|
+
function useQRCodeSigner(config) {
|
|
5545
|
+
const [qrCodeDataUrl, setQrCodeDataUrl] = React2.useState(null);
|
|
5546
|
+
const [status, setStatus] = React2.useState("waiting" /* WAITING */);
|
|
5547
|
+
const [result, setResult] = React2.useState(null);
|
|
5548
|
+
const [isPolling, setIsPolling] = React2.useState(false);
|
|
5549
|
+
const [error, setError] = React2.useState(null);
|
|
5550
|
+
const signerRef = React2.useRef(null);
|
|
5551
|
+
React2.useEffect(() => {
|
|
5552
|
+
signerRef.current = new QRCodeSigner(config);
|
|
5553
|
+
return () => {
|
|
5554
|
+
signerRef.current?.cleanup();
|
|
5555
|
+
};
|
|
5556
|
+
}, [config.requestId, config.requestUrl, config.pollUrl]);
|
|
5557
|
+
const generateQRCode = React2.useCallback(async () => {
|
|
5558
|
+
if (!signerRef.current) return;
|
|
5559
|
+
try {
|
|
5560
|
+
const dataUrl = await signerRef.current.generateQRCode();
|
|
5561
|
+
setQrCodeDataUrl(dataUrl);
|
|
5562
|
+
} catch (err) {
|
|
5563
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
5564
|
+
setError(error2);
|
|
5565
|
+
}
|
|
5566
|
+
}, []);
|
|
5567
|
+
const startSign = React2.useCallback(async () => {
|
|
5568
|
+
if (!signerRef.current) {
|
|
5569
|
+
throw new Error("QRCodeSigner not initialized");
|
|
5570
|
+
}
|
|
5571
|
+
setError(null);
|
|
5572
|
+
setStatus("waiting" /* WAITING */);
|
|
5573
|
+
setIsPolling(true);
|
|
5574
|
+
try {
|
|
5575
|
+
await generateQRCode();
|
|
5576
|
+
const signature = await signerRef.current.startPolling(
|
|
5577
|
+
(newStatus) => {
|
|
5578
|
+
setStatus(newStatus);
|
|
5579
|
+
},
|
|
5580
|
+
(signResult) => {
|
|
5581
|
+
setResult(signResult);
|
|
5582
|
+
}
|
|
5583
|
+
);
|
|
5584
|
+
setIsPolling(false);
|
|
5585
|
+
return signature;
|
|
5586
|
+
} catch (err) {
|
|
5587
|
+
setIsPolling(false);
|
|
5588
|
+
const error2 = err instanceof Error ? err : new SignatureRejectedError(err instanceof Error ? err.message : String(err));
|
|
5589
|
+
setError(error2);
|
|
5590
|
+
throw error2;
|
|
5591
|
+
}
|
|
5592
|
+
}, [generateQRCode]);
|
|
5593
|
+
const stopPolling = React2.useCallback(() => {
|
|
5594
|
+
signerRef.current?.stopPolling();
|
|
5595
|
+
setIsPolling(false);
|
|
5596
|
+
}, []);
|
|
5597
|
+
const cancel = React2.useCallback(() => {
|
|
5598
|
+
signerRef.current?.cancel();
|
|
5599
|
+
setStatus("cancelled" /* CANCELLED */);
|
|
5600
|
+
setIsPolling(false);
|
|
5601
|
+
}, []);
|
|
5602
|
+
return {
|
|
5603
|
+
qrCodeDataUrl,
|
|
5604
|
+
status,
|
|
5605
|
+
result,
|
|
5606
|
+
isPolling,
|
|
5607
|
+
startSign,
|
|
5608
|
+
stopPolling,
|
|
5609
|
+
cancel,
|
|
5610
|
+
error
|
|
5611
|
+
};
|
|
5612
|
+
}
|
|
5613
|
+
function QRCodeModal({
|
|
5614
|
+
isOpen,
|
|
5615
|
+
onClose,
|
|
5616
|
+
qrCodeDataUrl,
|
|
5617
|
+
status,
|
|
5618
|
+
error,
|
|
5619
|
+
title = "\u626B\u7801\u7B7E\u540D",
|
|
5620
|
+
description
|
|
5621
|
+
}) {
|
|
5622
|
+
React2.useEffect(() => {
|
|
5623
|
+
if (isOpen) {
|
|
5624
|
+
document.body.style.overflow = "hidden";
|
|
5625
|
+
} else {
|
|
5626
|
+
document.body.style.overflow = "";
|
|
5627
|
+
}
|
|
5628
|
+
return () => {
|
|
5629
|
+
document.body.style.overflow = "";
|
|
5630
|
+
};
|
|
5631
|
+
}, [isOpen]);
|
|
5632
|
+
if (!isOpen) {
|
|
5633
|
+
return null;
|
|
5634
|
+
}
|
|
5635
|
+
const getStatusText = () => {
|
|
5636
|
+
switch (status) {
|
|
5637
|
+
case "waiting" /* WAITING */:
|
|
5638
|
+
return "\u8BF7\u4F7F\u7528\u94B1\u5305\u626B\u63CF\u4E8C\u7EF4\u7801";
|
|
5639
|
+
case "pending" /* PENDING */:
|
|
5640
|
+
return "\u5DF2\u626B\u63CF\uFF0C\u8BF7\u5728\u94B1\u5305\u4E2D\u786E\u8BA4\u7B7E\u540D";
|
|
5641
|
+
case "success" /* SUCCESS */:
|
|
5642
|
+
return "\u7B7E\u540D\u6210\u529F";
|
|
5643
|
+
case "failed" /* FAILED */:
|
|
5644
|
+
return "\u7B7E\u540D\u5931\u8D25";
|
|
5645
|
+
case "timeout" /* TIMEOUT */:
|
|
5646
|
+
return "\u7B7E\u540D\u8D85\u65F6";
|
|
5647
|
+
case "cancelled" /* CANCELLED */:
|
|
5648
|
+
return "\u5DF2\u53D6\u6D88";
|
|
5649
|
+
default:
|
|
5650
|
+
return "\u7B49\u5F85\u626B\u63CF";
|
|
5651
|
+
}
|
|
5652
|
+
};
|
|
5653
|
+
const getStatusColor = () => {
|
|
5654
|
+
switch (status) {
|
|
5655
|
+
case "waiting" /* WAITING */:
|
|
5656
|
+
case "pending" /* PENDING */:
|
|
5657
|
+
return "#3b82f6";
|
|
5658
|
+
// blue
|
|
5659
|
+
case "success" /* SUCCESS */:
|
|
5660
|
+
return "#10b981";
|
|
5661
|
+
// green
|
|
5662
|
+
case "failed" /* FAILED */:
|
|
5663
|
+
case "timeout" /* TIMEOUT */:
|
|
5664
|
+
case "cancelled" /* CANCELLED */:
|
|
5665
|
+
return "#ef4444";
|
|
5666
|
+
// red
|
|
5667
|
+
default:
|
|
5668
|
+
return "#6b7280";
|
|
5669
|
+
}
|
|
5670
|
+
};
|
|
5671
|
+
return /* @__PURE__ */ React2__default.default.createElement(
|
|
5672
|
+
"div",
|
|
5673
|
+
{
|
|
5674
|
+
style: {
|
|
5675
|
+
position: "fixed",
|
|
5676
|
+
top: 0,
|
|
5677
|
+
left: 0,
|
|
5678
|
+
right: 0,
|
|
5679
|
+
bottom: 0,
|
|
5680
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
5681
|
+
display: "flex",
|
|
5682
|
+
alignItems: "center",
|
|
5683
|
+
justifyContent: "center",
|
|
5684
|
+
zIndex: 1e4,
|
|
5685
|
+
padding: "20px"
|
|
5686
|
+
},
|
|
5687
|
+
onClick: (e) => {
|
|
5688
|
+
if (e.target === e.currentTarget) {
|
|
5689
|
+
onClose();
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
},
|
|
5693
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5694
|
+
"div",
|
|
5695
|
+
{
|
|
5696
|
+
style: {
|
|
5697
|
+
backgroundColor: "#ffffff",
|
|
5698
|
+
borderRadius: "12px",
|
|
5699
|
+
padding: "24px",
|
|
5700
|
+
maxWidth: "400px",
|
|
5701
|
+
width: "100%",
|
|
5702
|
+
boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
|
|
5703
|
+
}
|
|
5704
|
+
},
|
|
5705
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5706
|
+
"div",
|
|
5707
|
+
{
|
|
5708
|
+
style: {
|
|
5709
|
+
display: "flex",
|
|
5710
|
+
justifyContent: "space-between",
|
|
5711
|
+
alignItems: "center",
|
|
5712
|
+
marginBottom: "20px"
|
|
5713
|
+
}
|
|
5714
|
+
},
|
|
5715
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5716
|
+
"h2",
|
|
5717
|
+
{
|
|
5718
|
+
style: {
|
|
5719
|
+
margin: 0,
|
|
5720
|
+
fontSize: "20px",
|
|
5721
|
+
fontWeight: 600,
|
|
5722
|
+
color: "#111827"
|
|
5723
|
+
}
|
|
5724
|
+
},
|
|
5725
|
+
title
|
|
5726
|
+
),
|
|
5727
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5728
|
+
"button",
|
|
5729
|
+
{
|
|
5730
|
+
onClick: onClose,
|
|
5731
|
+
style: {
|
|
5732
|
+
background: "none",
|
|
5733
|
+
border: "none",
|
|
5734
|
+
fontSize: "24px",
|
|
5735
|
+
cursor: "pointer",
|
|
5736
|
+
color: "#6b7280",
|
|
5737
|
+
padding: 0,
|
|
5738
|
+
width: "24px",
|
|
5739
|
+
height: "24px",
|
|
5740
|
+
display: "flex",
|
|
5741
|
+
alignItems: "center",
|
|
5742
|
+
justifyContent: "center"
|
|
5743
|
+
}
|
|
5744
|
+
},
|
|
5745
|
+
"\xD7"
|
|
5746
|
+
)
|
|
5747
|
+
),
|
|
5748
|
+
description && /* @__PURE__ */ React2__default.default.createElement(
|
|
5749
|
+
"p",
|
|
5750
|
+
{
|
|
5751
|
+
style: {
|
|
5752
|
+
margin: "0 0 20px 0",
|
|
5753
|
+
fontSize: "14px",
|
|
5754
|
+
color: "#6b7280"
|
|
5755
|
+
}
|
|
5756
|
+
},
|
|
5757
|
+
description
|
|
5758
|
+
),
|
|
5759
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5760
|
+
"div",
|
|
5761
|
+
{
|
|
5762
|
+
style: {
|
|
5763
|
+
display: "flex",
|
|
5764
|
+
justifyContent: "center",
|
|
5765
|
+
marginBottom: "20px"
|
|
5766
|
+
}
|
|
5767
|
+
},
|
|
5768
|
+
qrCodeDataUrl ? /* @__PURE__ */ React2__default.default.createElement(
|
|
5769
|
+
"img",
|
|
5770
|
+
{
|
|
5771
|
+
src: qrCodeDataUrl,
|
|
5772
|
+
alt: "QR Code",
|
|
5773
|
+
style: {
|
|
5774
|
+
width: "100%",
|
|
5775
|
+
maxWidth: "300px",
|
|
5776
|
+
height: "auto",
|
|
5777
|
+
border: "1px solid #e5e7eb",
|
|
5778
|
+
borderRadius: "8px"
|
|
5779
|
+
}
|
|
5780
|
+
}
|
|
5781
|
+
) : /* @__PURE__ */ React2__default.default.createElement(
|
|
5782
|
+
"div",
|
|
5783
|
+
{
|
|
5784
|
+
style: {
|
|
5785
|
+
width: "300px",
|
|
5786
|
+
height: "300px",
|
|
5787
|
+
backgroundColor: "#f3f4f6",
|
|
5788
|
+
display: "flex",
|
|
5789
|
+
alignItems: "center",
|
|
5790
|
+
justifyContent: "center",
|
|
5791
|
+
borderRadius: "8px",
|
|
5792
|
+
color: "#6b7280"
|
|
5793
|
+
}
|
|
5794
|
+
},
|
|
5795
|
+
"\u751F\u6210\u4E8C\u7EF4\u7801\u4E2D..."
|
|
5796
|
+
)
|
|
5797
|
+
),
|
|
5798
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5799
|
+
"div",
|
|
5800
|
+
{
|
|
5801
|
+
style: {
|
|
5802
|
+
textAlign: "center",
|
|
5803
|
+
marginBottom: "20px"
|
|
5804
|
+
}
|
|
5805
|
+
},
|
|
5806
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5807
|
+
"div",
|
|
5808
|
+
{
|
|
5809
|
+
style: {
|
|
5810
|
+
display: "inline-flex",
|
|
5811
|
+
alignItems: "center",
|
|
5812
|
+
gap: "8px",
|
|
5813
|
+
padding: "8px 16px",
|
|
5814
|
+
borderRadius: "6px",
|
|
5815
|
+
backgroundColor: `${getStatusColor()}15`,
|
|
5816
|
+
color: getStatusColor(),
|
|
5817
|
+
fontSize: "14px",
|
|
5818
|
+
fontWeight: 500
|
|
5819
|
+
}
|
|
5820
|
+
},
|
|
5821
|
+
status === "waiting" /* WAITING */ && /* @__PURE__ */ React2__default.default.createElement(
|
|
5822
|
+
"div",
|
|
5823
|
+
{
|
|
5824
|
+
style: {
|
|
5825
|
+
width: "8px",
|
|
5826
|
+
height: "8px",
|
|
5827
|
+
borderRadius: "50%",
|
|
5828
|
+
backgroundColor: getStatusColor(),
|
|
5829
|
+
animation: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5832
|
+
),
|
|
5833
|
+
status === "pending" /* PENDING */ && /* @__PURE__ */ React2__default.default.createElement(
|
|
5834
|
+
"div",
|
|
5835
|
+
{
|
|
5836
|
+
style: {
|
|
5837
|
+
width: "8px",
|
|
5838
|
+
height: "8px",
|
|
5839
|
+
borderRadius: "50%",
|
|
5840
|
+
backgroundColor: getStatusColor()
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
),
|
|
5844
|
+
status === "success" /* SUCCESS */ && "\u2713",
|
|
5845
|
+
status === "failed" /* FAILED */ && "\u2715",
|
|
5846
|
+
getStatusText()
|
|
5847
|
+
)
|
|
5848
|
+
),
|
|
5849
|
+
error && /* @__PURE__ */ React2__default.default.createElement(
|
|
5850
|
+
"div",
|
|
5851
|
+
{
|
|
5852
|
+
style: {
|
|
5853
|
+
padding: "12px",
|
|
5854
|
+
backgroundColor: "#fef2f2",
|
|
5855
|
+
border: "1px solid #fecaca",
|
|
5856
|
+
borderRadius: "6px",
|
|
5857
|
+
marginBottom: "20px"
|
|
5858
|
+
}
|
|
5859
|
+
},
|
|
5860
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5861
|
+
"p",
|
|
5862
|
+
{
|
|
5863
|
+
style: {
|
|
5864
|
+
margin: 0,
|
|
5865
|
+
fontSize: "14px",
|
|
5866
|
+
color: "#dc2626"
|
|
5867
|
+
}
|
|
5868
|
+
},
|
|
5869
|
+
error.message
|
|
5870
|
+
)
|
|
5871
|
+
),
|
|
5872
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5873
|
+
"div",
|
|
5874
|
+
{
|
|
5875
|
+
style: {
|
|
5876
|
+
display: "flex",
|
|
5877
|
+
gap: "12px"
|
|
5878
|
+
}
|
|
5879
|
+
},
|
|
5880
|
+
/* @__PURE__ */ React2__default.default.createElement(
|
|
5881
|
+
"button",
|
|
5882
|
+
{
|
|
5883
|
+
onClick: onClose,
|
|
5884
|
+
style: {
|
|
5885
|
+
flex: 1,
|
|
5886
|
+
padding: "10px 20px",
|
|
5887
|
+
border: "1px solid #d1d5db",
|
|
5888
|
+
borderRadius: "6px",
|
|
5889
|
+
backgroundColor: "#ffffff",
|
|
5890
|
+
color: "#374151",
|
|
5891
|
+
fontSize: "14px",
|
|
5892
|
+
fontWeight: 500,
|
|
5893
|
+
cursor: "pointer"
|
|
5894
|
+
}
|
|
5895
|
+
},
|
|
5896
|
+
status === "success" /* SUCCESS */ ? "\u5173\u95ED" : "\u53D6\u6D88"
|
|
5897
|
+
)
|
|
5898
|
+
)
|
|
5899
|
+
),
|
|
5900
|
+
/* @__PURE__ */ React2__default.default.createElement("style", null, `
|
|
5901
|
+
@keyframes pulse {
|
|
5902
|
+
0%, 100% {
|
|
5903
|
+
opacity: 1;
|
|
5904
|
+
}
|
|
5905
|
+
50% {
|
|
5906
|
+
opacity: 0.5;
|
|
5907
|
+
}
|
|
5908
|
+
}
|
|
5909
|
+
`)
|
|
5910
|
+
);
|
|
5911
|
+
}
|
|
2367
5912
|
|
|
5913
|
+
exports.QRCodeModal = QRCodeModal;
|
|
2368
5914
|
exports.WalletProvider = WalletProvider;
|
|
2369
5915
|
exports.useAccount = useAccount;
|
|
2370
5916
|
exports.useConnect = useConnect;
|
|
2371
5917
|
exports.useDisconnect = useDisconnect;
|
|
5918
|
+
exports.useQRCodeSigner = useQRCodeSigner;
|
|
2372
5919
|
exports.useSignMessage = useSignMessage;
|
|
2373
5920
|
exports.useSignTransaction = useSignTransaction;
|
|
2374
5921
|
exports.useWallet = useWallet;
|