@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/index.js
CHANGED
|
@@ -2,16 +2,609 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var EventEmitter = require('eventemitter3');
|
|
6
5
|
var chainUtils = require('@enclave-hq/chain-utils');
|
|
6
|
+
var EventEmitter = require('eventemitter3');
|
|
7
7
|
var viem = require('viem');
|
|
8
8
|
var accounts = require('viem/accounts');
|
|
9
|
+
var EthereumProvider = require('@walletconnect/ethereum-provider');
|
|
10
|
+
var module$1 = require('module');
|
|
11
|
+
var path = require('path');
|
|
12
|
+
var url = require('url');
|
|
13
|
+
var QRCode = require('qrcode');
|
|
9
14
|
|
|
15
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
17
|
|
|
12
18
|
var EventEmitter__default = /*#__PURE__*/_interopDefault(EventEmitter);
|
|
19
|
+
var EthereumProvider__default = /*#__PURE__*/_interopDefault(EthereumProvider);
|
|
20
|
+
var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
|
|
21
|
+
|
|
22
|
+
var __defProp = Object.defineProperty;
|
|
23
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
24
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
25
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
26
|
+
var __esm = (fn, res) => function __init() {
|
|
27
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
28
|
+
};
|
|
29
|
+
var __export = (target, all) => {
|
|
30
|
+
for (var name in all)
|
|
31
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
32
|
+
};
|
|
33
|
+
var __copyProps = (to, from, except, desc) => {
|
|
34
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
35
|
+
for (let key of __getOwnPropNames(from))
|
|
36
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
37
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
38
|
+
}
|
|
39
|
+
return to;
|
|
40
|
+
};
|
|
41
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
42
|
+
exports.ChainType = void 0; exports.WalletType = void 0; exports.WalletState = void 0;
|
|
43
|
+
var init_types = __esm({
|
|
44
|
+
"src/core/types.ts"() {
|
|
45
|
+
exports.ChainType = chainUtils.ChainType;
|
|
46
|
+
exports.WalletType = /* @__PURE__ */ ((WalletType3) => {
|
|
47
|
+
WalletType3["METAMASK"] = "metamask";
|
|
48
|
+
WalletType3["WALLETCONNECT"] = "walletconnect";
|
|
49
|
+
WalletType3["COINBASE_WALLET"] = "coinbase-wallet";
|
|
50
|
+
WalletType3["TRONLINK"] = "tronlink";
|
|
51
|
+
WalletType3["WALLETCONNECT_TRON"] = "walletconnect-tron";
|
|
52
|
+
WalletType3["PRIVATE_KEY"] = "private-key";
|
|
53
|
+
WalletType3["DEEP_LINK_EVM"] = "deep-link-evm";
|
|
54
|
+
WalletType3["DEEP_LINK_TRON"] = "deep-link-tron";
|
|
55
|
+
return WalletType3;
|
|
56
|
+
})(exports.WalletType || {});
|
|
57
|
+
exports.WalletState = /* @__PURE__ */ ((WalletState2) => {
|
|
58
|
+
WalletState2["DISCONNECTED"] = "disconnected";
|
|
59
|
+
WalletState2["CONNECTING"] = "connecting";
|
|
60
|
+
WalletState2["CONNECTED"] = "connected";
|
|
61
|
+
WalletState2["ERROR"] = "error";
|
|
62
|
+
return WalletState2;
|
|
63
|
+
})(exports.WalletState || {});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// src/adapters/deep-link/providers/tokenpocket.ts
|
|
68
|
+
var tokenpocket_exports = {};
|
|
69
|
+
__export(tokenpocket_exports, {
|
|
70
|
+
TokenPocketDeepLinkProvider: () => exports.TokenPocketDeepLinkProvider
|
|
71
|
+
});
|
|
72
|
+
exports.TokenPocketDeepLinkProvider = void 0;
|
|
73
|
+
var init_tokenpocket = __esm({
|
|
74
|
+
"src/adapters/deep-link/providers/tokenpocket.ts"() {
|
|
75
|
+
init_types();
|
|
76
|
+
exports.TokenPocketDeepLinkProvider = class {
|
|
77
|
+
constructor(options) {
|
|
78
|
+
this.name = "TokenPocket";
|
|
79
|
+
this.icon = "https://tokenpocket.pro/icon.png";
|
|
80
|
+
this.supportedChainTypes = [exports.ChainType.EVM, exports.ChainType.TRON];
|
|
81
|
+
this.callbackUrl = options?.callbackUrl;
|
|
82
|
+
this.callbackSchema = options?.callbackSchema;
|
|
83
|
+
}
|
|
84
|
+
async isAvailable() {
|
|
85
|
+
if (typeof window === "undefined") {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
89
|
+
if (isTelegramMiniApp) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
93
|
+
navigator.userAgent
|
|
94
|
+
);
|
|
95
|
+
return isMobile;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Generate unique actionId
|
|
99
|
+
*/
|
|
100
|
+
generateActionId() {
|
|
101
|
+
return `web-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get callback configuration
|
|
105
|
+
*/
|
|
106
|
+
getCallbackConfig() {
|
|
107
|
+
if (this.callbackSchema) {
|
|
108
|
+
return { callbackSchema: this.callbackSchema };
|
|
109
|
+
}
|
|
110
|
+
if (this.callbackUrl) {
|
|
111
|
+
return { callbackUrl: this.callbackUrl };
|
|
112
|
+
}
|
|
113
|
+
if (typeof window !== "undefined" && window.location) {
|
|
114
|
+
return {
|
|
115
|
+
callbackSchema: `${window.location.protocol}//${window.location.host}${window.location.pathname}`
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return {};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get blockchain configuration based on chain type
|
|
122
|
+
*/
|
|
123
|
+
getBlockchainConfig(chainId, chainType) {
|
|
124
|
+
if (chainType === exports.ChainType.TRON) {
|
|
125
|
+
return {
|
|
126
|
+
chainId: String(chainId),
|
|
127
|
+
network: "tron"
|
|
128
|
+
};
|
|
129
|
+
} else if (chainType === exports.ChainType.EVM) {
|
|
130
|
+
return {
|
|
131
|
+
chainId: String(chainId),
|
|
132
|
+
network: "ethereum"
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
136
|
+
}
|
|
137
|
+
buildSignMessageLink(params) {
|
|
138
|
+
const actionId = this.generateActionId();
|
|
139
|
+
const callback = this.getCallbackConfig();
|
|
140
|
+
const blockchain = this.getBlockchainConfig(params.chainId, params.chainType);
|
|
141
|
+
const param = {
|
|
142
|
+
action: "sign",
|
|
143
|
+
actionId,
|
|
144
|
+
message: params.message,
|
|
145
|
+
hash: false,
|
|
146
|
+
signType: params.chainType === exports.ChainType.TRON ? "ethPersonalSign" : "ethPersonalSign",
|
|
147
|
+
memo: `${params.chainType} message signature`,
|
|
148
|
+
blockchains: [blockchain],
|
|
149
|
+
dappName: "Enclave Wallet SDK",
|
|
150
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
151
|
+
protocol: "TokenPocket",
|
|
152
|
+
version: "1.1.8",
|
|
153
|
+
expired: 0,
|
|
154
|
+
...callback
|
|
155
|
+
};
|
|
156
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
157
|
+
const url = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
158
|
+
return {
|
|
159
|
+
url,
|
|
160
|
+
actionId,
|
|
161
|
+
...callback
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
buildSignTransactionLink(params) {
|
|
165
|
+
const actionId = this.generateActionId();
|
|
166
|
+
const callback = this.getCallbackConfig();
|
|
167
|
+
const blockchain = this.getBlockchainConfig(params.chainId, params.chainType);
|
|
168
|
+
let transactionData;
|
|
169
|
+
if (typeof params.transaction === "string") {
|
|
170
|
+
transactionData = params.transaction;
|
|
171
|
+
} else {
|
|
172
|
+
transactionData = JSON.stringify(params.transaction);
|
|
173
|
+
}
|
|
174
|
+
const param = {
|
|
175
|
+
action: "pushTransaction",
|
|
176
|
+
actionId,
|
|
177
|
+
txData: transactionData,
|
|
178
|
+
blockchains: [blockchain],
|
|
179
|
+
dappName: "Enclave Wallet SDK",
|
|
180
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
181
|
+
protocol: "TokenPocket",
|
|
182
|
+
version: "1.1.8",
|
|
183
|
+
expired: 0,
|
|
184
|
+
...callback
|
|
185
|
+
};
|
|
186
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
187
|
+
const url = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
188
|
+
return {
|
|
189
|
+
url,
|
|
190
|
+
actionId,
|
|
191
|
+
...callback
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
buildConnectLink(params) {
|
|
195
|
+
const actionId = this.generateActionId();
|
|
196
|
+
const blockchain = this.getBlockchainConfig(params.chainId, params.chainType);
|
|
197
|
+
const param = {
|
|
198
|
+
action: "login",
|
|
199
|
+
actionId,
|
|
200
|
+
blockchains: [blockchain],
|
|
201
|
+
dappName: "Enclave Wallet SDK",
|
|
202
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
203
|
+
protocol: "TokenPocket",
|
|
204
|
+
version: "1.0",
|
|
205
|
+
expired: 1602
|
|
206
|
+
// 30 minutes
|
|
207
|
+
};
|
|
208
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
209
|
+
const url = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
210
|
+
return {
|
|
211
|
+
url,
|
|
212
|
+
actionId
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
parseCallbackResult(urlParams) {
|
|
216
|
+
const actionId = urlParams.get("actionId");
|
|
217
|
+
const resultParam = urlParams.get("result");
|
|
218
|
+
const error = urlParams.get("error");
|
|
219
|
+
let result = null;
|
|
220
|
+
if (resultParam) {
|
|
221
|
+
try {
|
|
222
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
223
|
+
} catch (e) {
|
|
224
|
+
result = resultParam;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
actionId,
|
|
229
|
+
result,
|
|
230
|
+
error
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
getDefaultCallbackSchema() {
|
|
234
|
+
if (typeof window !== "undefined" && window.location) {
|
|
235
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
236
|
+
}
|
|
237
|
+
return "";
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// src/adapters/deep-link/providers/tronlink.ts
|
|
244
|
+
var tronlink_exports = {};
|
|
245
|
+
__export(tronlink_exports, {
|
|
246
|
+
TronLinkDeepLinkProvider: () => exports.TronLinkDeepLinkProvider
|
|
247
|
+
});
|
|
248
|
+
exports.TronLinkDeepLinkProvider = void 0;
|
|
249
|
+
var init_tronlink = __esm({
|
|
250
|
+
"src/adapters/deep-link/providers/tronlink.ts"() {
|
|
251
|
+
init_types();
|
|
252
|
+
exports.TronLinkDeepLinkProvider = class {
|
|
253
|
+
constructor() {
|
|
254
|
+
this.name = "TronLink";
|
|
255
|
+
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
256
|
+
this.supportedChainTypes = [exports.ChainType.TRON];
|
|
257
|
+
}
|
|
258
|
+
async isAvailable() {
|
|
259
|
+
if (typeof window === "undefined") {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
263
|
+
if (isTelegramMiniApp) {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
267
|
+
navigator.userAgent
|
|
268
|
+
);
|
|
269
|
+
return isMobile;
|
|
270
|
+
}
|
|
271
|
+
buildSignMessageLink(params) {
|
|
272
|
+
if (params.chainType !== exports.ChainType.TRON) {
|
|
273
|
+
throw new Error("TronLink only supports TRON chain");
|
|
274
|
+
}
|
|
275
|
+
const encodedMessage = encodeURIComponent(params.message);
|
|
276
|
+
const url = `tronlink://signMessage?message=${encodedMessage}`;
|
|
277
|
+
const actionId = `tronlink-${Date.now()}`;
|
|
278
|
+
return {
|
|
279
|
+
url,
|
|
280
|
+
actionId
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
buildSignTransactionLink(params) {
|
|
284
|
+
if (params.chainType !== exports.ChainType.TRON) {
|
|
285
|
+
throw new Error("TronLink only supports TRON chain");
|
|
286
|
+
}
|
|
287
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
288
|
+
const encodedData = encodeURIComponent(transactionData);
|
|
289
|
+
const url = `tronlink://signTransaction?transaction=${encodedData}`;
|
|
290
|
+
const actionId = `tronlink-${Date.now()}`;
|
|
291
|
+
return {
|
|
292
|
+
url,
|
|
293
|
+
actionId
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
buildConnectLink(params) {
|
|
297
|
+
if (params.chainType !== exports.ChainType.TRON) {
|
|
298
|
+
throw new Error("TronLink only supports TRON chain");
|
|
299
|
+
}
|
|
300
|
+
const url = `tronlink://open?action=connect&network=tron`;
|
|
301
|
+
return {
|
|
302
|
+
url
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
parseCallbackResult(_urlParams) {
|
|
306
|
+
return {
|
|
307
|
+
actionId: null,
|
|
308
|
+
result: null,
|
|
309
|
+
error: null
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// src/adapters/deep-link/providers/imtoken.ts
|
|
317
|
+
var imtoken_exports = {};
|
|
318
|
+
__export(imtoken_exports, {
|
|
319
|
+
ImTokenDeepLinkProvider: () => exports.ImTokenDeepLinkProvider
|
|
320
|
+
});
|
|
321
|
+
exports.ImTokenDeepLinkProvider = void 0;
|
|
322
|
+
var init_imtoken = __esm({
|
|
323
|
+
"src/adapters/deep-link/providers/imtoken.ts"() {
|
|
324
|
+
init_types();
|
|
325
|
+
exports.ImTokenDeepLinkProvider = class {
|
|
326
|
+
constructor(options) {
|
|
327
|
+
this.name = "ImToken";
|
|
328
|
+
this.icon = "https://token.im/static/img/logo.png";
|
|
329
|
+
this.supportedChainTypes = [exports.ChainType.EVM, exports.ChainType.TRON];
|
|
330
|
+
this.callbackUrl = options?.callbackUrl;
|
|
331
|
+
this.callbackSchema = options?.callbackSchema;
|
|
332
|
+
}
|
|
333
|
+
async isAvailable() {
|
|
334
|
+
if (typeof window === "undefined") {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
338
|
+
if (isTelegramMiniApp) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
342
|
+
navigator.userAgent
|
|
343
|
+
);
|
|
344
|
+
return isMobile;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Generate unique actionId
|
|
348
|
+
*/
|
|
349
|
+
generateActionId() {
|
|
350
|
+
return `imtoken-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Get callback configuration
|
|
354
|
+
*/
|
|
355
|
+
getCallbackConfig() {
|
|
356
|
+
if (this.callbackSchema) {
|
|
357
|
+
return { callbackSchema: this.callbackSchema };
|
|
358
|
+
}
|
|
359
|
+
if (this.callbackUrl) {
|
|
360
|
+
return { callbackUrl: this.callbackUrl };
|
|
361
|
+
}
|
|
362
|
+
if (typeof window !== "undefined" && window.location) {
|
|
363
|
+
return {
|
|
364
|
+
callbackSchema: `${window.location.protocol}//${window.location.host}${window.location.pathname}`
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
return {};
|
|
368
|
+
}
|
|
369
|
+
buildSignMessageLink(params) {
|
|
370
|
+
const actionId = this.generateActionId();
|
|
371
|
+
const callback = this.getCallbackConfig();
|
|
372
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signMessage&message=${encodeURIComponent(params.message)}&chainId=${params.chainId}`;
|
|
373
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
374
|
+
const url = `imtokenv2://navigate/DappView?url=${encodedDappUrl}`;
|
|
375
|
+
return {
|
|
376
|
+
url,
|
|
377
|
+
actionId,
|
|
378
|
+
...callback
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
buildSignTransactionLink(params) {
|
|
382
|
+
const actionId = this.generateActionId();
|
|
383
|
+
const callback = this.getCallbackConfig();
|
|
384
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
385
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signTransaction&transaction=${encodeURIComponent(transactionData)}&chainId=${params.chainId}`;
|
|
386
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
387
|
+
const url = `imtokenv2://navigate/DappView?url=${encodedDappUrl}`;
|
|
388
|
+
return {
|
|
389
|
+
url,
|
|
390
|
+
actionId,
|
|
391
|
+
...callback
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
buildConnectLink(params) {
|
|
395
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=connect&chainId=${params.chainId}`;
|
|
396
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
397
|
+
const url = `imtokenv2://navigate/DappView?url=${encodedDappUrl}`;
|
|
398
|
+
return {
|
|
399
|
+
url
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
parseCallbackResult(urlParams) {
|
|
403
|
+
const actionId = urlParams.get("actionId");
|
|
404
|
+
const resultParam = urlParams.get("result");
|
|
405
|
+
const error = urlParams.get("error");
|
|
406
|
+
let result = null;
|
|
407
|
+
if (resultParam) {
|
|
408
|
+
try {
|
|
409
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
410
|
+
} catch (e) {
|
|
411
|
+
result = resultParam;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
actionId,
|
|
416
|
+
result,
|
|
417
|
+
error
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
getDefaultCallbackSchema() {
|
|
421
|
+
if (typeof window !== "undefined" && window.location) {
|
|
422
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
423
|
+
}
|
|
424
|
+
return "";
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// src/adapters/deep-link/providers/metamask.ts
|
|
431
|
+
var metamask_exports = {};
|
|
432
|
+
__export(metamask_exports, {
|
|
433
|
+
MetaMaskDeepLinkProvider: () => exports.MetaMaskDeepLinkProvider
|
|
434
|
+
});
|
|
435
|
+
exports.MetaMaskDeepLinkProvider = void 0;
|
|
436
|
+
var init_metamask = __esm({
|
|
437
|
+
"src/adapters/deep-link/providers/metamask.ts"() {
|
|
438
|
+
init_types();
|
|
439
|
+
exports.MetaMaskDeepLinkProvider = class {
|
|
440
|
+
constructor() {
|
|
441
|
+
this.name = "MetaMask";
|
|
442
|
+
this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
|
|
443
|
+
this.supportedChainTypes = [exports.ChainType.EVM];
|
|
444
|
+
}
|
|
445
|
+
async isAvailable() {
|
|
446
|
+
if (typeof window === "undefined") {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
450
|
+
if (isTelegramMiniApp) {
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
454
|
+
navigator.userAgent
|
|
455
|
+
);
|
|
456
|
+
return isMobile;
|
|
457
|
+
}
|
|
458
|
+
buildSignMessageLink(params) {
|
|
459
|
+
if (params.chainType !== exports.ChainType.EVM) {
|
|
460
|
+
throw new Error("MetaMask only supports EVM chains");
|
|
461
|
+
}
|
|
462
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signMessage&message=${encodeURIComponent(params.message)}&chainId=${params.chainId}`;
|
|
463
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
464
|
+
const url = `https://link.metamask.io/dapp/${encodedDappUrl}`;
|
|
465
|
+
const actionId = `metamask-${Date.now()}`;
|
|
466
|
+
return {
|
|
467
|
+
url,
|
|
468
|
+
actionId
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
buildSignTransactionLink(params) {
|
|
472
|
+
if (params.chainType !== exports.ChainType.EVM) {
|
|
473
|
+
throw new Error("MetaMask only supports EVM chains");
|
|
474
|
+
}
|
|
475
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
476
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signTransaction&transaction=${encodeURIComponent(transactionData)}&chainId=${params.chainId}`;
|
|
477
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
478
|
+
const url = `https://link.metamask.io/dapp/${encodedDappUrl}`;
|
|
479
|
+
const actionId = `metamask-${Date.now()}`;
|
|
480
|
+
return {
|
|
481
|
+
url,
|
|
482
|
+
actionId
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
buildConnectLink(params) {
|
|
486
|
+
if (params.chainType !== exports.ChainType.EVM) {
|
|
487
|
+
throw new Error("MetaMask only supports EVM chains");
|
|
488
|
+
}
|
|
489
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=connect&chainId=${params.chainId}`;
|
|
490
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
491
|
+
const url = `https://link.metamask.io/dapp/${encodedDappUrl}`;
|
|
492
|
+
return {
|
|
493
|
+
url
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
parseCallbackResult(urlParams) {
|
|
497
|
+
const actionId = urlParams.get("actionId");
|
|
498
|
+
const resultParam = urlParams.get("result");
|
|
499
|
+
const error = urlParams.get("error");
|
|
500
|
+
let result = null;
|
|
501
|
+
if (resultParam) {
|
|
502
|
+
try {
|
|
503
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
504
|
+
} catch (e) {
|
|
505
|
+
result = resultParam;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
actionId,
|
|
510
|
+
result,
|
|
511
|
+
error
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
getDefaultCallbackSchema() {
|
|
515
|
+
if (typeof window !== "undefined" && window.location) {
|
|
516
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
517
|
+
}
|
|
518
|
+
return "";
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
});
|
|
13
523
|
|
|
14
|
-
// src/
|
|
524
|
+
// src/adapters/deep-link/providers/okx.ts
|
|
525
|
+
var okx_exports = {};
|
|
526
|
+
__export(okx_exports, {
|
|
527
|
+
OKXDeepLinkProvider: () => exports.OKXDeepLinkProvider
|
|
528
|
+
});
|
|
529
|
+
exports.OKXDeepLinkProvider = void 0;
|
|
530
|
+
var init_okx = __esm({
|
|
531
|
+
"src/adapters/deep-link/providers/okx.ts"() {
|
|
532
|
+
init_types();
|
|
533
|
+
exports.OKXDeepLinkProvider = class {
|
|
534
|
+
constructor() {
|
|
535
|
+
this.name = "OKX";
|
|
536
|
+
this.icon = "https://www.okx.com/favicon.ico";
|
|
537
|
+
this.supportedChainTypes = [exports.ChainType.EVM, exports.ChainType.TRON];
|
|
538
|
+
}
|
|
539
|
+
async isAvailable() {
|
|
540
|
+
if (typeof window === "undefined") {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
544
|
+
if (isTelegramMiniApp) {
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
548
|
+
navigator.userAgent
|
|
549
|
+
);
|
|
550
|
+
return isMobile;
|
|
551
|
+
}
|
|
552
|
+
buildSignMessageLink(params) {
|
|
553
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signMessage&message=${encodeURIComponent(params.message)}&chainId=${params.chainId}`;
|
|
554
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
555
|
+
const url = `okx://wallet/dapp/url?dappUrl=${encodedDappUrl}`;
|
|
556
|
+
const actionId = `okx-${Date.now()}`;
|
|
557
|
+
return {
|
|
558
|
+
url,
|
|
559
|
+
actionId
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
buildSignTransactionLink(params) {
|
|
563
|
+
const transactionData = typeof params.transaction === "string" ? params.transaction : JSON.stringify(params.transaction);
|
|
564
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=signTransaction&transaction=${encodeURIComponent(transactionData)}&chainId=${params.chainId}`;
|
|
565
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
566
|
+
const url = `okx://wallet/dapp/url?dappUrl=${encodedDappUrl}`;
|
|
567
|
+
const actionId = `okx-${Date.now()}`;
|
|
568
|
+
return {
|
|
569
|
+
url,
|
|
570
|
+
actionId
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
buildConnectLink(params) {
|
|
574
|
+
const dappUrl = `${window.location.origin}${window.location.pathname}?action=connect&chainId=${params.chainId}`;
|
|
575
|
+
const encodedDappUrl = encodeURIComponent(dappUrl);
|
|
576
|
+
const url = `okx://wallet/dapp/url?dappUrl=${encodedDappUrl}`;
|
|
577
|
+
return {
|
|
578
|
+
url
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
parseCallbackResult(urlParams) {
|
|
582
|
+
const actionId = urlParams.get("actionId");
|
|
583
|
+
const resultParam = urlParams.get("result");
|
|
584
|
+
const error = urlParams.get("error");
|
|
585
|
+
let result = null;
|
|
586
|
+
if (resultParam) {
|
|
587
|
+
try {
|
|
588
|
+
result = JSON.parse(decodeURIComponent(resultParam));
|
|
589
|
+
} catch (e) {
|
|
590
|
+
result = resultParam;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
actionId,
|
|
595
|
+
result,
|
|
596
|
+
error
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
getDefaultCallbackSchema() {
|
|
600
|
+
if (typeof window !== "undefined" && window.location) {
|
|
601
|
+
return `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
602
|
+
}
|
|
603
|
+
return "";
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
});
|
|
15
608
|
var TypedEventEmitter = class {
|
|
16
609
|
constructor() {
|
|
17
610
|
this.emitter = new EventEmitter__default.default();
|
|
@@ -40,23 +633,12 @@ var TypedEventEmitter = class {
|
|
|
40
633
|
return this;
|
|
41
634
|
}
|
|
42
635
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
WalletType3["WALLETCONNECT_TRON"] = "walletconnect-tron";
|
|
50
|
-
WalletType3["PRIVATE_KEY"] = "private-key";
|
|
51
|
-
return WalletType3;
|
|
52
|
-
})(WalletType || {});
|
|
53
|
-
var WalletState = /* @__PURE__ */ ((WalletState2) => {
|
|
54
|
-
WalletState2["DISCONNECTED"] = "disconnected";
|
|
55
|
-
WalletState2["CONNECTING"] = "connecting";
|
|
56
|
-
WalletState2["CONNECTED"] = "connected";
|
|
57
|
-
WalletState2["ERROR"] = "error";
|
|
58
|
-
return WalletState2;
|
|
59
|
-
})(WalletState || {});
|
|
636
|
+
|
|
637
|
+
// src/core/adapter-registry.ts
|
|
638
|
+
init_types();
|
|
639
|
+
|
|
640
|
+
// src/adapters/base/wallet-adapter.ts
|
|
641
|
+
init_types();
|
|
60
642
|
|
|
61
643
|
// src/core/errors.ts
|
|
62
644
|
var WalletSDKError = class _WalletSDKError extends Error {
|
|
@@ -158,6 +740,13 @@ var WalletAdapter = class extends EventEmitter__default.default {
|
|
|
158
740
|
this.state = "disconnected" /* DISCONNECTED */;
|
|
159
741
|
this.currentAccount = null;
|
|
160
742
|
}
|
|
743
|
+
/**
|
|
744
|
+
* Check if the wallet is currently connected
|
|
745
|
+
* @returns true if the wallet is connected (state is CONNECTED and has an account)
|
|
746
|
+
*/
|
|
747
|
+
isConnected() {
|
|
748
|
+
return this.state === "connected" /* CONNECTED */ && this.currentAccount !== null;
|
|
749
|
+
}
|
|
161
750
|
/**
|
|
162
751
|
* Get the signer's address (implements ISigner interface)
|
|
163
752
|
* Returns the native address of the current account
|
|
@@ -227,6 +816,7 @@ var WalletAdapter = class extends EventEmitter__default.default {
|
|
|
227
816
|
};
|
|
228
817
|
|
|
229
818
|
// src/adapters/base/browser-wallet-adapter.ts
|
|
819
|
+
init_types();
|
|
230
820
|
var BrowserWalletAdapter = class extends WalletAdapter {
|
|
231
821
|
/**
|
|
232
822
|
* 检查钱包是否可用
|
|
@@ -260,6 +850,9 @@ var BrowserWalletAdapter = class extends WalletAdapter {
|
|
|
260
850
|
}
|
|
261
851
|
};
|
|
262
852
|
|
|
853
|
+
// src/adapters/evm/metamask.ts
|
|
854
|
+
init_types();
|
|
855
|
+
|
|
263
856
|
// src/utils/address/universal-address.ts
|
|
264
857
|
function createUniversalAddress(chainId, address) {
|
|
265
858
|
return `${chainId}:${address}`;
|
|
@@ -329,7 +922,12 @@ var CHAIN_INFO = {
|
|
|
329
922
|
symbol: "ETH",
|
|
330
923
|
decimals: 18
|
|
331
924
|
},
|
|
332
|
-
|
|
925
|
+
// 使用支持浏览器 CORS 的公共 RPC,避免 dapp 域名被跨域拦截(如 eth.llamarpc.com 无 CORS 头)
|
|
926
|
+
rpcUrls: [
|
|
927
|
+
"https://cloudflare-eth.com",
|
|
928
|
+
"https://rpc.ankr.com/eth",
|
|
929
|
+
"https://eth.llamarpc.com"
|
|
930
|
+
],
|
|
333
931
|
blockExplorerUrls: ["https://etherscan.io"]
|
|
334
932
|
},
|
|
335
933
|
// EVM Testnets
|
|
@@ -495,7 +1093,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
495
1093
|
constructor() {
|
|
496
1094
|
super(...arguments);
|
|
497
1095
|
this.type = "metamask" /* METAMASK */;
|
|
498
|
-
this.chainType = ChainType.EVM;
|
|
1096
|
+
this.chainType = exports.ChainType.EVM;
|
|
499
1097
|
this.name = "MetaMask";
|
|
500
1098
|
this.icon = "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg";
|
|
501
1099
|
this.walletClient = null;
|
|
@@ -522,7 +1120,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
522
1120
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
523
1121
|
nativeAddress: address,
|
|
524
1122
|
chainId: this.currentAccount.chainId,
|
|
525
|
-
chainType: ChainType.EVM,
|
|
1123
|
+
chainType: exports.ChainType.EVM,
|
|
526
1124
|
isActive: true
|
|
527
1125
|
};
|
|
528
1126
|
this.setAccount(account);
|
|
@@ -558,6 +1156,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
558
1156
|
*/
|
|
559
1157
|
async connect(chainId) {
|
|
560
1158
|
await this.ensureAvailable();
|
|
1159
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId;
|
|
561
1160
|
try {
|
|
562
1161
|
this.setState("connecting" /* CONNECTING */);
|
|
563
1162
|
const provider = this.getBrowserProvider();
|
|
@@ -571,10 +1170,10 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
571
1170
|
method: "eth_chainId"
|
|
572
1171
|
});
|
|
573
1172
|
const parsedChainId = parseInt(currentChainId, 16);
|
|
574
|
-
if (
|
|
575
|
-
await this.switchChain(
|
|
1173
|
+
if (targetChainId && targetChainId !== parsedChainId) {
|
|
1174
|
+
await this.switchChain(targetChainId);
|
|
576
1175
|
}
|
|
577
|
-
const finalChainId =
|
|
1176
|
+
const finalChainId = targetChainId || parsedChainId;
|
|
578
1177
|
const viemChain = this.getViemChain(finalChainId);
|
|
579
1178
|
this.walletClient = viem.createWalletClient({
|
|
580
1179
|
account: accounts[0],
|
|
@@ -593,7 +1192,7 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
593
1192
|
universalAddress: createUniversalAddress(finalChainId, address),
|
|
594
1193
|
nativeAddress: address,
|
|
595
1194
|
chainId: finalChainId,
|
|
596
|
-
chainType: ChainType.EVM,
|
|
1195
|
+
chainType: exports.ChainType.EVM,
|
|
597
1196
|
isActive: true
|
|
598
1197
|
};
|
|
599
1198
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -736,6 +1335,56 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
736
1335
|
}]
|
|
737
1336
|
});
|
|
738
1337
|
}
|
|
1338
|
+
/**
|
|
1339
|
+
* 请求切换账户
|
|
1340
|
+
* 弹出 MetaMask 账户选择界面,让用户选择或切换到目标地址
|
|
1341
|
+
* @param targetAddress 目标地址(可选),如果提供,会在切换后验证是否匹配
|
|
1342
|
+
* @returns 切换后的账户信息
|
|
1343
|
+
*/
|
|
1344
|
+
async requestSwitchAccount(targetAddress) {
|
|
1345
|
+
const provider = this.getBrowserProvider();
|
|
1346
|
+
if (!provider) {
|
|
1347
|
+
throw new Error("MetaMask provider not available");
|
|
1348
|
+
}
|
|
1349
|
+
try {
|
|
1350
|
+
await provider.request({
|
|
1351
|
+
method: "wallet_requestPermissions",
|
|
1352
|
+
params: [{ eth_accounts: {} }]
|
|
1353
|
+
});
|
|
1354
|
+
const accounts = await provider.request({
|
|
1355
|
+
method: "eth_accounts"
|
|
1356
|
+
});
|
|
1357
|
+
if (!accounts || accounts.length === 0) {
|
|
1358
|
+
throw new ConnectionRejectedError(this.type);
|
|
1359
|
+
}
|
|
1360
|
+
const address = formatEVMAddress(accounts[0]);
|
|
1361
|
+
if (targetAddress && address.toLowerCase() !== targetAddress.toLowerCase()) {
|
|
1362
|
+
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)}`);
|
|
1363
|
+
}
|
|
1364
|
+
const chainId = this.currentAccount?.chainId || 1;
|
|
1365
|
+
const account = {
|
|
1366
|
+
universalAddress: createUniversalAddress(chainId, address),
|
|
1367
|
+
nativeAddress: address,
|
|
1368
|
+
chainId,
|
|
1369
|
+
chainType: exports.ChainType.EVM,
|
|
1370
|
+
isActive: true
|
|
1371
|
+
};
|
|
1372
|
+
this.setAccount(account);
|
|
1373
|
+
this.emitAccountChanged(account);
|
|
1374
|
+
const viemChain = this.getViemChain(chainId);
|
|
1375
|
+
this.walletClient = viem.createWalletClient({
|
|
1376
|
+
account: address,
|
|
1377
|
+
chain: viemChain,
|
|
1378
|
+
transport: viem.custom(provider)
|
|
1379
|
+
});
|
|
1380
|
+
return account;
|
|
1381
|
+
} catch (error) {
|
|
1382
|
+
if (error.code === 4001) {
|
|
1383
|
+
throw new ConnectionRejectedError(this.type);
|
|
1384
|
+
}
|
|
1385
|
+
throw error;
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
739
1388
|
/**
|
|
740
1389
|
* 读取合约
|
|
741
1390
|
*/
|
|
@@ -960,11 +1609,52 @@ var MetaMaskAdapter = class extends BrowserWalletAdapter {
|
|
|
960
1609
|
};
|
|
961
1610
|
|
|
962
1611
|
// src/adapters/tron/tronlink.ts
|
|
1612
|
+
init_types();
|
|
1613
|
+
var TronApiRateLimiter = class {
|
|
1614
|
+
constructor(minIntervalMs = 600) {
|
|
1615
|
+
this.lastCallTime = 0;
|
|
1616
|
+
this.minInterval = minIntervalMs;
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* 等待直到可以进行下一次 API 调用
|
|
1620
|
+
*/
|
|
1621
|
+
async waitForNextCall() {
|
|
1622
|
+
const now = Date.now();
|
|
1623
|
+
const timeSinceLastCall = now - this.lastCallTime;
|
|
1624
|
+
if (timeSinceLastCall < this.minInterval) {
|
|
1625
|
+
const waitTime = this.minInterval - timeSinceLastCall;
|
|
1626
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
1627
|
+
}
|
|
1628
|
+
this.lastCallTime = Date.now();
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
var tronApiRateLimiter = new TronApiRateLimiter(600);
|
|
1632
|
+
async function retryWithBackoff(fn, maxRetries = 3, initialDelay = 500) {
|
|
1633
|
+
let lastError;
|
|
1634
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1635
|
+
try {
|
|
1636
|
+
return await fn();
|
|
1637
|
+
} catch (error) {
|
|
1638
|
+
lastError = error;
|
|
1639
|
+
const errorMsg = error?.message || String(error);
|
|
1640
|
+
const errorLower = errorMsg.toLowerCase();
|
|
1641
|
+
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;
|
|
1642
|
+
if (isRateLimitError && attempt < maxRetries - 1) {
|
|
1643
|
+
const delay = initialDelay * Math.pow(2, attempt);
|
|
1644
|
+
console.warn(`[TronLink] \u9047\u5230\u901F\u7387\u9650\u5236 (429)\uFF0C\u7B49\u5F85 ${delay}ms \u540E\u91CD\u8BD5 (${attempt + 1}/${maxRetries})...`);
|
|
1645
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1648
|
+
throw error;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
throw lastError;
|
|
1652
|
+
}
|
|
963
1653
|
var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
964
1654
|
constructor() {
|
|
965
1655
|
super(...arguments);
|
|
966
1656
|
this.type = "tronlink" /* TRONLINK */;
|
|
967
|
-
this.chainType = ChainType.TRON;
|
|
1657
|
+
this.chainType = exports.ChainType.TRON;
|
|
968
1658
|
this.name = "TronWeb";
|
|
969
1659
|
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
970
1660
|
/**
|
|
@@ -986,7 +1676,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
986
1676
|
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
987
1677
|
nativeAddress: address,
|
|
988
1678
|
chainId: this.currentAccount.chainId,
|
|
989
|
-
chainType: ChainType.TRON,
|
|
1679
|
+
chainType: exports.ChainType.TRON,
|
|
990
1680
|
isActive: true
|
|
991
1681
|
};
|
|
992
1682
|
this.setAccount(account);
|
|
@@ -1007,6 +1697,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1007
1697
|
*/
|
|
1008
1698
|
async connect(chainId) {
|
|
1009
1699
|
await this.ensureAvailable();
|
|
1700
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId;
|
|
1010
1701
|
try {
|
|
1011
1702
|
this.setState("connecting" /* CONNECTING */);
|
|
1012
1703
|
const w = window;
|
|
@@ -1061,12 +1752,12 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1061
1752
|
if (!address) {
|
|
1062
1753
|
throw new Error("Failed to get Tron address. Please make sure your wallet is unlocked and try again.");
|
|
1063
1754
|
}
|
|
1064
|
-
const tronChainId =
|
|
1755
|
+
const tronChainId = targetChainId || _TronLinkAdapter.TRON_MAINNET_CHAIN_ID;
|
|
1065
1756
|
const account = {
|
|
1066
1757
|
universalAddress: createUniversalAddress(tronChainId, address),
|
|
1067
1758
|
nativeAddress: address,
|
|
1068
1759
|
chainId: tronChainId,
|
|
1069
|
-
chainType: ChainType.TRON,
|
|
1760
|
+
chainType: exports.ChainType.TRON,
|
|
1070
1761
|
isActive: true
|
|
1071
1762
|
};
|
|
1072
1763
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -1136,10 +1827,12 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1136
1827
|
/**
|
|
1137
1828
|
* 读取合约
|
|
1138
1829
|
* 参考 webserver 的实现,使用 TronWeb 合约实例的标准 call() 方法
|
|
1830
|
+
* 带 TronGrid 限流 + 429 重试
|
|
1139
1831
|
*/
|
|
1140
1832
|
async readContract(params) {
|
|
1141
1833
|
this.ensureConnected();
|
|
1142
|
-
|
|
1834
|
+
await tronApiRateLimiter.waitForNextCall();
|
|
1835
|
+
const doRead = async () => {
|
|
1143
1836
|
const tronWeb = this.getTronWeb();
|
|
1144
1837
|
if (!this.currentAccount) {
|
|
1145
1838
|
throw new Error("No account connected");
|
|
@@ -1154,19 +1847,17 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1154
1847
|
return result;
|
|
1155
1848
|
} catch (method1Error) {
|
|
1156
1849
|
console.warn("\u26A0\uFE0F [\u65B9\u6CD51] TronWeb\u6807\u51C6\u65B9\u6CD5\u5931\u8D25\uFF0C\u5C1D\u8BD5\u65B9\u6CD52:", method1Error.message);
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
throw new Error(`Function ${params.functionName} not found in contract`);
|
|
1162
|
-
}
|
|
1163
|
-
const result = await method2(...params.args || []).call();
|
|
1164
|
-
return result;
|
|
1165
|
-
} catch (method2Error) {
|
|
1166
|
-
console.error("\u26A0\uFE0F [\u65B9\u6CD52] \u4E5F\u5931\u8D25:", method2Error.message);
|
|
1167
|
-
throw method1Error;
|
|
1850
|
+
const contract2 = await tronWeb.contract().at(params.address);
|
|
1851
|
+
const method2 = contract2[params.functionName];
|
|
1852
|
+
if (!method2 || typeof method2 !== "function") {
|
|
1853
|
+
throw new Error(`Function ${params.functionName} not found in contract`);
|
|
1168
1854
|
}
|
|
1855
|
+
const result = await method2(...params.args || []).call();
|
|
1856
|
+
return result;
|
|
1169
1857
|
}
|
|
1858
|
+
};
|
|
1859
|
+
try {
|
|
1860
|
+
return await retryWithBackoff(doRead, 3, 800);
|
|
1170
1861
|
} catch (error) {
|
|
1171
1862
|
console.error("Read contract error:", error);
|
|
1172
1863
|
throw new Error(`Failed to read contract: ${error.message || "Unknown error"}`);
|
|
@@ -1177,6 +1868,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1177
1868
|
*/
|
|
1178
1869
|
async writeContract(params) {
|
|
1179
1870
|
this.ensureConnected();
|
|
1871
|
+
await tronApiRateLimiter.waitForNextCall();
|
|
1180
1872
|
try {
|
|
1181
1873
|
const tronWeb = this.getTronWeb();
|
|
1182
1874
|
console.log("[TronLink] writeContract params:", {
|
|
@@ -1202,29 +1894,171 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1202
1894
|
}
|
|
1203
1895
|
console.log("[TronLink] Function ABI:", functionAbi);
|
|
1204
1896
|
console.log("[TronLink] Calling with args:", params.args);
|
|
1897
|
+
const TRON_FEE_LIMIT = 1e8;
|
|
1205
1898
|
const options = {
|
|
1206
|
-
feeLimit:
|
|
1207
|
-
//
|
|
1899
|
+
feeLimit: TRON_FEE_LIMIT,
|
|
1900
|
+
// 固定为 100 TRX 的能量限制
|
|
1208
1901
|
callValue: params.value || 0
|
|
1209
1902
|
// 发送的 TRX 数量(单位:SUN)
|
|
1210
1903
|
};
|
|
1211
|
-
const
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1904
|
+
const hasTupleArray = functionAbi.inputs.some((input) => input.type === "tuple[]");
|
|
1905
|
+
console.log("[TronLink] \u68C0\u67E5 tuple[] \u7C7B\u578B:", {
|
|
1906
|
+
hasTupleArray,
|
|
1907
|
+
inputs: functionAbi.inputs.map((i) => ({ name: i.name, type: i.type }))
|
|
1908
|
+
});
|
|
1909
|
+
let tx;
|
|
1910
|
+
if (hasTupleArray) {
|
|
1911
|
+
console.log("[TronLink] \u68C0\u6D4B\u5230 tuple[] \u53C2\u6570\uFF0C\u4F7F\u7528\u624B\u52A8\u7F16\u7801\u65B9\u5F0F");
|
|
1912
|
+
const processedArgs = params.args.map((argValue, index) => {
|
|
1913
|
+
const input = functionAbi.inputs[index];
|
|
1914
|
+
if (input.type === "address" && typeof argValue === "string") {
|
|
1915
|
+
if (argValue.startsWith("T") && argValue.length === 34) {
|
|
1916
|
+
const hexAddress = tronWeb.address.toHex(argValue);
|
|
1917
|
+
return hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
|
|
1918
|
+
}
|
|
1919
|
+
return argValue.startsWith("0x") ? argValue : `0x${argValue}`;
|
|
1920
|
+
}
|
|
1921
|
+
if (input.type === "tuple[]" && Array.isArray(argValue)) {
|
|
1922
|
+
return argValue.map((tupleItem) => {
|
|
1923
|
+
if (input.components && Array.isArray(input.components)) {
|
|
1924
|
+
const processedTuple = {};
|
|
1925
|
+
input.components.forEach((component) => {
|
|
1926
|
+
let value = tupleItem[component.name];
|
|
1927
|
+
if (component.type === "address" && typeof value === "string") {
|
|
1928
|
+
if (value.startsWith("T") && value.length === 34) {
|
|
1929
|
+
const hexAddress = tronWeb.address.toHex(value);
|
|
1930
|
+
value = hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
|
|
1931
|
+
} else if (!value.startsWith("0x")) {
|
|
1932
|
+
value = `0x${value}`;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
processedTuple[component.name] = value;
|
|
1936
|
+
});
|
|
1937
|
+
return processedTuple;
|
|
1938
|
+
}
|
|
1939
|
+
return tupleItem;
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
if (input.type === "tuple" && typeof argValue === "object" && !Array.isArray(argValue)) {
|
|
1943
|
+
if (input.components && Array.isArray(input.components)) {
|
|
1944
|
+
const processedTuple = {};
|
|
1945
|
+
input.components.forEach((component) => {
|
|
1946
|
+
let value = argValue[component.name];
|
|
1947
|
+
if (component.type === "address" && typeof value === "string") {
|
|
1948
|
+
if (value.startsWith("T") && value.length === 34) {
|
|
1949
|
+
const hexAddress = tronWeb.address.toHex(value);
|
|
1950
|
+
value = hexAddress.startsWith("0x") ? hexAddress : `0x${hexAddress}`;
|
|
1951
|
+
} else if (!value.startsWith("0x")) {
|
|
1952
|
+
value = `0x${value}`;
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
processedTuple[component.name] = value;
|
|
1956
|
+
});
|
|
1957
|
+
return processedTuple;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
return argValue;
|
|
1961
|
+
});
|
|
1962
|
+
console.log("[TronLink] \u5904\u7406\u540E\u7684\u53C2\u6570\uFF08\u7528\u4E8E viem \u7F16\u7801\uFF09:", processedArgs);
|
|
1963
|
+
const encodedData = viem.encodeFunctionData({
|
|
1964
|
+
abi: [functionAbi],
|
|
1965
|
+
functionName: params.functionName,
|
|
1966
|
+
args: processedArgs
|
|
1967
|
+
});
|
|
1968
|
+
console.log("[TronLink] \u7F16\u7801\u540E\u7684\u6570\u636E:", encodedData);
|
|
1969
|
+
const functionSelector = encodedData.slice(0, 10);
|
|
1970
|
+
const parameterData = encodedData.slice(10);
|
|
1971
|
+
console.log("[TronLink] \u51FD\u6570\u9009\u62E9\u5668:", functionSelector);
|
|
1972
|
+
console.log("[TronLink] \u53C2\u6570\u6570\u636E:", parameterData);
|
|
1973
|
+
const functionSignature = params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")";
|
|
1974
|
+
const parameterHexClean = parameterData.startsWith("0x") ? parameterData.slice(2) : parameterData;
|
|
1975
|
+
console.log("[TronLink] \u4F7F\u7528 TronWeb triggerSmartContract (rawParameter)...", {
|
|
1976
|
+
contractAddress: params.address,
|
|
1977
|
+
functionSelector: functionSignature,
|
|
1978
|
+
encodedDataLength: parameterHexClean.length
|
|
1979
|
+
});
|
|
1980
|
+
tx = await retryWithBackoff(
|
|
1981
|
+
() => tronWeb.transactionBuilder.triggerSmartContract(
|
|
1982
|
+
params.address,
|
|
1983
|
+
// Base58 格式的合约地址
|
|
1984
|
+
functionSignature,
|
|
1985
|
+
// 函数签名(用于识别函数)
|
|
1986
|
+
{
|
|
1987
|
+
feeLimit: options.feeLimit,
|
|
1988
|
+
callValue: options.callValue,
|
|
1989
|
+
rawParameter: parameterHexClean
|
|
1990
|
+
// 使用 rawParameter 直接提供编码后的数据
|
|
1991
|
+
},
|
|
1992
|
+
[],
|
|
1993
|
+
// parameter 留空(因为使用 rawParameter)
|
|
1994
|
+
this.currentAccount.nativeAddress
|
|
1995
|
+
// Base58 格式的发送地址
|
|
1996
|
+
),
|
|
1997
|
+
3,
|
|
1998
|
+
// 最多重试 3 次
|
|
1999
|
+
500
|
|
2000
|
+
// 初始延迟 500ms
|
|
2001
|
+
);
|
|
2002
|
+
console.log("[TronLink] \u4F7F\u7528 TronWeb API \u6784\u5EFA\u7684\u4EA4\u6613:", tx);
|
|
2003
|
+
} else {
|
|
2004
|
+
const parameter = functionAbi.inputs.map((input, index) => {
|
|
2005
|
+
const argValue = params.args[index];
|
|
2006
|
+
if (input.type === "tuple" && typeof argValue === "object" && !Array.isArray(argValue)) {
|
|
2007
|
+
if (input.components && Array.isArray(input.components)) {
|
|
2008
|
+
return {
|
|
2009
|
+
type: input.type,
|
|
2010
|
+
value: input.components.map((component) => ({
|
|
2011
|
+
type: component.type,
|
|
2012
|
+
value: argValue[component.name]
|
|
2013
|
+
}))
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
if (input.type === "address" && typeof argValue === "string") {
|
|
2018
|
+
if (argValue.startsWith("T") && argValue.length === 34) {
|
|
2019
|
+
return {
|
|
2020
|
+
type: input.type,
|
|
2021
|
+
value: argValue
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
try {
|
|
2025
|
+
const base58Address = tronWeb.address.fromHex(argValue.startsWith("0x") ? argValue : `0x${argValue}`);
|
|
2026
|
+
return {
|
|
2027
|
+
type: input.type,
|
|
2028
|
+
value: base58Address
|
|
2029
|
+
};
|
|
2030
|
+
} catch (e) {
|
|
2031
|
+
return {
|
|
2032
|
+
type: input.type,
|
|
2033
|
+
value: argValue
|
|
2034
|
+
};
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
return {
|
|
2038
|
+
type: input.type,
|
|
2039
|
+
value: argValue
|
|
2040
|
+
};
|
|
2041
|
+
});
|
|
2042
|
+
console.log("[TronLink] Transaction options:", options);
|
|
2043
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
2044
|
+
const functionSelector = params.functionName + "(" + functionAbi.inputs.map((i) => i.type).join(",") + ")";
|
|
2045
|
+
console.log("[TronLink] Function selector:", functionSelector);
|
|
2046
|
+
console.log("[TronLink] Transaction options:", options);
|
|
2047
|
+
console.log("[TronLink] Parameters:", parameter);
|
|
2048
|
+
tx = await retryWithBackoff(
|
|
2049
|
+
() => tronWeb.transactionBuilder.triggerSmartContract(
|
|
2050
|
+
params.address,
|
|
2051
|
+
functionSelector,
|
|
2052
|
+
options,
|
|
2053
|
+
parameter,
|
|
2054
|
+
this.currentAccount.nativeAddress
|
|
2055
|
+
),
|
|
2056
|
+
3,
|
|
2057
|
+
// 最多重试 3 次
|
|
2058
|
+
500
|
|
2059
|
+
// 初始延迟 500ms
|
|
2060
|
+
);
|
|
2061
|
+
}
|
|
1228
2062
|
console.log("[TronLink] Transaction built:", tx);
|
|
1229
2063
|
if (!tx || !tx.transaction) {
|
|
1230
2064
|
throw new Error("Failed to build transaction");
|
|
@@ -1264,6 +2098,7 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1264
2098
|
const maxAttempts = 60;
|
|
1265
2099
|
while (attempts < maxAttempts) {
|
|
1266
2100
|
try {
|
|
2101
|
+
await tronApiRateLimiter.waitForNextCall();
|
|
1267
2102
|
const txInfo = await tronWeb.trx.getTransactionInfo(txHash);
|
|
1268
2103
|
if (txInfo && txInfo.id) {
|
|
1269
2104
|
const receipt = {
|
|
@@ -1391,11 +2226,12 @@ var _TronLinkAdapter = class _TronLinkAdapter extends BrowserWalletAdapter {
|
|
|
1391
2226
|
// Tron 主网链 ID
|
|
1392
2227
|
_TronLinkAdapter.TRON_MAINNET_CHAIN_ID = 195;
|
|
1393
2228
|
var TronLinkAdapter = _TronLinkAdapter;
|
|
2229
|
+
init_types();
|
|
1394
2230
|
var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
1395
2231
|
constructor() {
|
|
1396
2232
|
super(...arguments);
|
|
1397
2233
|
this.type = "private-key" /* PRIVATE_KEY */;
|
|
1398
|
-
this.chainType = ChainType.EVM;
|
|
2234
|
+
this.chainType = exports.ChainType.EVM;
|
|
1399
2235
|
this.name = "Private Key (EVM)";
|
|
1400
2236
|
this.privateKey = null;
|
|
1401
2237
|
this.walletClient = null;
|
|
@@ -1404,28 +2240,29 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1404
2240
|
/**
|
|
1405
2241
|
* 连接(导入私钥)
|
|
1406
2242
|
*/
|
|
1407
|
-
async connect(chainId
|
|
2243
|
+
async connect(chainId) {
|
|
1408
2244
|
if (!this.privateKey) {
|
|
1409
2245
|
throw new Error("Private key not set. Call setPrivateKey() first.");
|
|
1410
2246
|
}
|
|
1411
2247
|
try {
|
|
1412
2248
|
this.setState("connecting" /* CONNECTING */);
|
|
1413
2249
|
const account = accounts.privateKeyToAccount(this.privateKey);
|
|
2250
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId || 1;
|
|
1414
2251
|
this.walletClient = viem.createWalletClient({
|
|
1415
2252
|
account,
|
|
1416
|
-
chain: this.getViemChain(
|
|
2253
|
+
chain: this.getViemChain(targetChainId),
|
|
1417
2254
|
transport: viem.http()
|
|
1418
2255
|
});
|
|
1419
2256
|
this.publicClient = viem.createPublicClient({
|
|
1420
|
-
chain: this.getViemChain(
|
|
2257
|
+
chain: this.getViemChain(targetChainId),
|
|
1421
2258
|
transport: viem.http()
|
|
1422
2259
|
});
|
|
1423
2260
|
const address = formatEVMAddress(account.address);
|
|
1424
2261
|
const accountInfo = {
|
|
1425
|
-
universalAddress: createUniversalAddress(
|
|
2262
|
+
universalAddress: createUniversalAddress(targetChainId, address),
|
|
1426
2263
|
nativeAddress: address,
|
|
1427
|
-
chainId,
|
|
1428
|
-
chainType: ChainType.EVM,
|
|
2264
|
+
chainId: targetChainId,
|
|
2265
|
+
chainType: exports.ChainType.EVM,
|
|
1429
2266
|
isActive: true
|
|
1430
2267
|
};
|
|
1431
2268
|
this.setState("connected" /* CONNECTED */);
|
|
@@ -1636,61 +2473,1622 @@ var EVMPrivateKeyAdapter = class extends WalletAdapter {
|
|
|
1636
2473
|
};
|
|
1637
2474
|
}
|
|
1638
2475
|
};
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
this.
|
|
1644
|
-
this.
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
this.
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
2476
|
+
init_types();
|
|
2477
|
+
var _WalletConnectAdapter = class _WalletConnectAdapter extends WalletAdapter {
|
|
2478
|
+
constructor(projectId) {
|
|
2479
|
+
super();
|
|
2480
|
+
this.type = "walletconnect" /* WALLETCONNECT */;
|
|
2481
|
+
this.chainType = exports.ChainType.EVM;
|
|
2482
|
+
this.name = "WalletConnect";
|
|
2483
|
+
this.icon = "https://avatars.githubusercontent.com/u/37784886";
|
|
2484
|
+
this.provider = null;
|
|
2485
|
+
this.walletClient = null;
|
|
2486
|
+
this.publicClient = null;
|
|
2487
|
+
this.supportedChains = [];
|
|
2488
|
+
/**
|
|
2489
|
+
* Handle accounts changed
|
|
2490
|
+
*/
|
|
2491
|
+
this.handleAccountsChanged = (accounts) => {
|
|
2492
|
+
if (accounts.length === 0) {
|
|
2493
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
2494
|
+
this.setAccount(null);
|
|
2495
|
+
this.emitAccountChanged(null);
|
|
2496
|
+
} else {
|
|
2497
|
+
const address = formatEVMAddress(accounts[0]);
|
|
2498
|
+
const account = {
|
|
2499
|
+
universalAddress: createUniversalAddress(this.currentAccount.chainId, address),
|
|
2500
|
+
nativeAddress: address,
|
|
2501
|
+
chainId: this.currentAccount.chainId,
|
|
2502
|
+
chainType: exports.ChainType.EVM,
|
|
2503
|
+
isActive: true
|
|
2504
|
+
};
|
|
2505
|
+
this.setAccount(account);
|
|
2506
|
+
this.emitAccountChanged(account);
|
|
2507
|
+
}
|
|
2508
|
+
};
|
|
2509
|
+
/**
|
|
2510
|
+
* Handle chain changed
|
|
2511
|
+
*/
|
|
2512
|
+
this.handleChainChanged = (chainIdHex) => {
|
|
2513
|
+
const chainId = parseInt(chainIdHex, 16);
|
|
2514
|
+
if (this.currentAccount) {
|
|
2515
|
+
const account = {
|
|
2516
|
+
...this.currentAccount,
|
|
2517
|
+
chainId,
|
|
2518
|
+
universalAddress: createUniversalAddress(chainId, this.currentAccount.nativeAddress)
|
|
2519
|
+
};
|
|
2520
|
+
this.setAccount(account);
|
|
2521
|
+
this.emitChainChanged(chainId);
|
|
2522
|
+
const viemChain = this.getViemChain(chainId);
|
|
2523
|
+
const chainInfo = getChainInfo(chainId);
|
|
2524
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
2525
|
+
if (this.provider) {
|
|
2526
|
+
this.walletClient = viem.createWalletClient({
|
|
2527
|
+
account: this.currentAccount.nativeAddress,
|
|
2528
|
+
chain: viemChain,
|
|
2529
|
+
transport: viem.custom(this.provider)
|
|
2530
|
+
});
|
|
2531
|
+
this.publicClient = viem.createPublicClient({
|
|
2532
|
+
chain: viemChain,
|
|
2533
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(this.provider)
|
|
2534
|
+
});
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
};
|
|
2538
|
+
/**
|
|
2539
|
+
* Handle disconnect
|
|
2540
|
+
*/
|
|
2541
|
+
this.handleDisconnect = () => {
|
|
2542
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
2543
|
+
this.setAccount(null);
|
|
2544
|
+
if (_WalletConnectAdapter.providerInstance === this.provider) {
|
|
2545
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
2546
|
+
_WalletConnectAdapter.providerProjectId = null;
|
|
2547
|
+
}
|
|
2548
|
+
this.provider = null;
|
|
2549
|
+
this.walletClient = null;
|
|
2550
|
+
this.publicClient = null;
|
|
2551
|
+
this.emitDisconnected();
|
|
2552
|
+
};
|
|
2553
|
+
if (!projectId) {
|
|
2554
|
+
throw new ConfigurationError("WalletConnect projectId is required");
|
|
2555
|
+
}
|
|
2556
|
+
this.projectId = projectId;
|
|
2557
|
+
}
|
|
2558
|
+
/**
|
|
2559
|
+
* Check if WalletConnect is available
|
|
2560
|
+
* WalletConnect is always available (it's a web-based connection)
|
|
2561
|
+
* Also works in Telegram Mini Apps
|
|
2562
|
+
*/
|
|
2563
|
+
async isAvailable() {
|
|
2564
|
+
return typeof window !== "undefined";
|
|
2565
|
+
}
|
|
2566
|
+
/**
|
|
2567
|
+
* Check if running in Telegram environment (Mini App or Web)
|
|
2568
|
+
* Both Telegram Mini App (in client) and Telegram Web (web.telegram.org)
|
|
2569
|
+
* provide window.Telegram.WebApp API, so they are treated the same way.
|
|
2570
|
+
*
|
|
2571
|
+
* Reference: https://docs.reown.com/appkit/integrations/telegram-mini-apps
|
|
2572
|
+
*/
|
|
2573
|
+
isTelegramMiniApp() {
|
|
2574
|
+
if (typeof window === "undefined") return false;
|
|
2575
|
+
const tg = window.Telegram?.WebApp;
|
|
2576
|
+
if (!tg) return false;
|
|
2577
|
+
const platform = tg.platform || "unknown";
|
|
2578
|
+
console.log("[WalletConnect] Telegram environment detected:", {
|
|
2579
|
+
platform,
|
|
2580
|
+
version: tg.version,
|
|
2581
|
+
isMiniApp: platform !== "web",
|
|
2582
|
+
// Mini App if not web platform
|
|
2583
|
+
isWeb: platform === "web"
|
|
2584
|
+
// Telegram Web if web platform
|
|
2585
|
+
});
|
|
2586
|
+
return true;
|
|
2587
|
+
}
|
|
2588
|
+
/**
|
|
2589
|
+
* Get Telegram WebApp instance if available
|
|
2590
|
+
*/
|
|
2591
|
+
getTelegramWebApp() {
|
|
2592
|
+
if (typeof window === "undefined") return null;
|
|
2593
|
+
return window.Telegram?.WebApp || null;
|
|
2594
|
+
}
|
|
2595
|
+
/**
|
|
2596
|
+
* Close Telegram deep link popup (wc:// links)
|
|
2597
|
+
* In Telegram Mini Apps, WalletConnect may open a wc:// deep link popup
|
|
2598
|
+
* that doesn't automatically close after the operation completes.
|
|
2599
|
+
* This method attempts to close it by:
|
|
2600
|
+
* 1. Trying to close any open windows/popups
|
|
2601
|
+
* 2. Using Telegram WebApp API if available
|
|
2602
|
+
* 3. Navigating back or closing the popup
|
|
2603
|
+
*/
|
|
2604
|
+
closeTelegramDeepLinkPopup() {
|
|
2605
|
+
if (!this.isTelegramMiniApp()) {
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2608
|
+
try {
|
|
2609
|
+
const tg = this.getTelegramWebApp();
|
|
2610
|
+
if (!tg) {
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
if (typeof window !== "undefined") {
|
|
2614
|
+
window.focus();
|
|
2615
|
+
if (tg.BackButton && tg.BackButton.isVisible) {
|
|
2616
|
+
console.log("[WalletConnect] Closing Telegram deep link popup via BackButton");
|
|
2617
|
+
}
|
|
2618
|
+
setTimeout(() => {
|
|
2619
|
+
if (document.hasFocus()) {
|
|
2620
|
+
console.log("[WalletConnect] Main window has focus, popup likely closed");
|
|
2621
|
+
} else {
|
|
2622
|
+
window.focus();
|
|
2623
|
+
console.log("[WalletConnect] Attempted to focus main window to close popup");
|
|
2624
|
+
}
|
|
2625
|
+
}, 500);
|
|
2626
|
+
const handleVisibilityChange = () => {
|
|
2627
|
+
if (document.visibilityState === "visible") {
|
|
2628
|
+
console.log("[WalletConnect] Page became visible, popup may have closed");
|
|
2629
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
2630
|
+
}
|
|
2631
|
+
};
|
|
2632
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
2633
|
+
setTimeout(() => {
|
|
2634
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
2635
|
+
}, 2e3);
|
|
2636
|
+
}
|
|
2637
|
+
} catch (error) {
|
|
2638
|
+
console.warn("[WalletConnect] Error closing Telegram deep link popup:", error);
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
/**
|
|
2642
|
+
* Connect wallet
|
|
2643
|
+
*
|
|
2644
|
+
* @param chainId - Single chain ID or array of chain IDs to request
|
|
2645
|
+
* If array is provided, wallet will be requested to connect to multiple chains
|
|
2646
|
+
* When multiple chains are requested, the wallet can switch between them
|
|
2647
|
+
* Default: 1 (Ethereum Mainnet)
|
|
2648
|
+
*
|
|
2649
|
+
* @example
|
|
2650
|
+
* // Single chain
|
|
2651
|
+
* await adapter.connect(1) // Ethereum only
|
|
2652
|
+
*
|
|
2653
|
+
* @example
|
|
2654
|
+
* // Multiple chains
|
|
2655
|
+
* await adapter.connect([1, 56, 137]) // Ethereum, BSC, Polygon
|
|
2656
|
+
*/
|
|
2657
|
+
async connect(chainId) {
|
|
2658
|
+
if (typeof window === "undefined") {
|
|
2659
|
+
throw new Error("WalletConnect requires a browser environment");
|
|
2660
|
+
}
|
|
2661
|
+
if (_WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId) {
|
|
2662
|
+
const existingProvider = _WalletConnectAdapter.providerInstance;
|
|
2663
|
+
if (existingProvider.accounts && existingProvider.accounts.length > 0) {
|
|
2664
|
+
this.provider = existingProvider;
|
|
2665
|
+
let targetChains;
|
|
2666
|
+
if (Array.isArray(chainId)) {
|
|
2667
|
+
targetChains = chainId.length > 0 ? chainId : [1];
|
|
2668
|
+
} else if (chainId) {
|
|
2669
|
+
targetChains = [chainId];
|
|
2670
|
+
} else {
|
|
2671
|
+
targetChains = [1];
|
|
2672
|
+
}
|
|
2673
|
+
const existingChains = this.supportedChains || [];
|
|
2674
|
+
const mergedChains = [.../* @__PURE__ */ new Set([...existingChains, ...targetChains])];
|
|
2675
|
+
this.supportedChains = mergedChains;
|
|
2676
|
+
const currentChainId = existingProvider.chainId || targetChains[0];
|
|
2677
|
+
const address = formatEVMAddress(existingProvider.accounts[0]);
|
|
2678
|
+
const account = {
|
|
2679
|
+
universalAddress: createUniversalAddress(currentChainId, address),
|
|
2680
|
+
nativeAddress: address,
|
|
2681
|
+
chainId: currentChainId,
|
|
2682
|
+
chainType: exports.ChainType.EVM,
|
|
2683
|
+
isActive: true
|
|
2684
|
+
};
|
|
2685
|
+
this.setState("connected" /* CONNECTED */);
|
|
2686
|
+
this.setAccount(account);
|
|
2687
|
+
if (!this.walletClient) {
|
|
2688
|
+
const viemChain = this.getViemChain(currentChainId);
|
|
2689
|
+
this.walletClient = viem.createWalletClient({
|
|
2690
|
+
account: existingProvider.accounts[0],
|
|
2691
|
+
chain: viemChain,
|
|
2692
|
+
transport: viem.custom(existingProvider)
|
|
2693
|
+
});
|
|
2694
|
+
const chainInfo = getChainInfo(currentChainId);
|
|
2695
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
2696
|
+
this.publicClient = viem.createPublicClient({
|
|
2697
|
+
chain: viemChain,
|
|
2698
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(existingProvider)
|
|
2699
|
+
});
|
|
2700
|
+
this.setupEventListeners();
|
|
2701
|
+
}
|
|
2702
|
+
console.log("[WalletConnect] Reusing existing provider session");
|
|
2703
|
+
return account;
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
if (this.state === "connected" /* CONNECTED */ && this.currentAccount && this.provider) {
|
|
2707
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2708
|
+
let targetChains;
|
|
2709
|
+
if (Array.isArray(chainId)) {
|
|
2710
|
+
targetChains = chainId.length > 0 ? chainId : [1];
|
|
2711
|
+
} else if (chainId) {
|
|
2712
|
+
targetChains = [chainId];
|
|
2713
|
+
} else {
|
|
2714
|
+
targetChains = [1];
|
|
2715
|
+
}
|
|
2716
|
+
const existingChains = this.supportedChains || [];
|
|
2717
|
+
const mergedChains = [.../* @__PURE__ */ new Set([...existingChains, ...targetChains])];
|
|
2718
|
+
this.supportedChains = mergedChains;
|
|
2719
|
+
console.log("[WalletConnect] Already connected, reusing existing connection");
|
|
2720
|
+
return this.currentAccount;
|
|
2721
|
+
} else {
|
|
2722
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
2723
|
+
this.setAccount(null);
|
|
2724
|
+
this.provider = null;
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
try {
|
|
2728
|
+
this.setState("connecting" /* CONNECTING */);
|
|
2729
|
+
let targetChains;
|
|
2730
|
+
if (Array.isArray(chainId)) {
|
|
2731
|
+
targetChains = chainId.length > 0 ? chainId : [1];
|
|
2732
|
+
} else if (chainId) {
|
|
2733
|
+
targetChains = [chainId];
|
|
2734
|
+
} else {
|
|
2735
|
+
targetChains = [1];
|
|
2736
|
+
}
|
|
2737
|
+
this.supportedChains = targetChains;
|
|
2738
|
+
const primaryChain = targetChains[0];
|
|
2739
|
+
const optionalChains = targetChains.slice(1);
|
|
2740
|
+
const isTelegram = this.isTelegramMiniApp();
|
|
2741
|
+
const telegramWebApp = this.getTelegramWebApp();
|
|
2742
|
+
let appUrl = "";
|
|
2743
|
+
if (typeof window !== "undefined") {
|
|
2744
|
+
try {
|
|
2745
|
+
if (window.location && window.location.origin) {
|
|
2746
|
+
appUrl = window.location.origin;
|
|
2747
|
+
} else if (window.location && window.location.href) {
|
|
2748
|
+
const url = new URL(window.location.href);
|
|
2749
|
+
appUrl = url.origin;
|
|
2750
|
+
}
|
|
2751
|
+
} catch (error) {
|
|
2752
|
+
console.warn("[WalletConnect] Failed to get origin from window.location:", error);
|
|
2753
|
+
}
|
|
2754
|
+
if (!appUrl) {
|
|
2755
|
+
appUrl = "https://enclave.network";
|
|
2756
|
+
}
|
|
2757
|
+
} else {
|
|
2758
|
+
appUrl = "https://enclave.network";
|
|
2759
|
+
}
|
|
2760
|
+
if (!appUrl || !appUrl.startsWith("http://") && !appUrl.startsWith("https://")) {
|
|
2761
|
+
appUrl = "https://enclave.network";
|
|
2762
|
+
}
|
|
2763
|
+
const icons = [
|
|
2764
|
+
"https://walletconnect.com/walletconnect-logo.svg",
|
|
2765
|
+
"https://avatars.githubusercontent.com/u/37784886"
|
|
2766
|
+
// WalletConnect GitHub avatar
|
|
2767
|
+
];
|
|
2768
|
+
const initOptions = {
|
|
2769
|
+
projectId: this.projectId,
|
|
2770
|
+
chains: [primaryChain],
|
|
2771
|
+
// Primary chain (required)
|
|
2772
|
+
showQrModal: true,
|
|
2773
|
+
// QR modal works in Telegram Mini Apps
|
|
2774
|
+
metadata: {
|
|
2775
|
+
name: "Enclave Wallet SDK",
|
|
2776
|
+
description: "Multi-chain wallet adapter for Enclave",
|
|
2777
|
+
url: appUrl,
|
|
2778
|
+
icons
|
|
2779
|
+
}
|
|
2780
|
+
};
|
|
2781
|
+
if (isTelegram && telegramWebApp) {
|
|
2782
|
+
const platform = telegramWebApp.platform || "unknown";
|
|
2783
|
+
const isMiniApp = platform !== "web";
|
|
2784
|
+
console.log("[WalletConnect] Detected Telegram environment:", {
|
|
2785
|
+
platform,
|
|
2786
|
+
isMiniApp,
|
|
2787
|
+
isWeb: platform === "web"
|
|
2788
|
+
});
|
|
2789
|
+
if (telegramWebApp.isExpanded === false) {
|
|
2790
|
+
telegramWebApp.expand();
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
if (optionalChains.length > 0) {
|
|
2794
|
+
initOptions.optionalChains = optionalChains;
|
|
2795
|
+
} else {
|
|
2796
|
+
initOptions.optionalChains = [primaryChain];
|
|
2797
|
+
}
|
|
2798
|
+
const hasExistingProvider = _WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId;
|
|
2799
|
+
const needsReinit = hasExistingProvider && _WalletConnectAdapter.providerChains !== null && JSON.stringify(_WalletConnectAdapter.providerChains.sort()) !== JSON.stringify(targetChains.sort());
|
|
2800
|
+
if (needsReinit) {
|
|
2801
|
+
console.log("[WalletConnect] Provider initialized with different chains, reinitializing...", {
|
|
2802
|
+
existing: _WalletConnectAdapter.providerChains,
|
|
2803
|
+
requested: targetChains
|
|
2804
|
+
});
|
|
2805
|
+
const existingProvider = _WalletConnectAdapter.providerInstance;
|
|
2806
|
+
if (existingProvider) {
|
|
2807
|
+
try {
|
|
2808
|
+
if (existingProvider.accounts && existingProvider.accounts.length > 0) {
|
|
2809
|
+
await existingProvider.disconnect();
|
|
2810
|
+
}
|
|
2811
|
+
} catch (error) {
|
|
2812
|
+
console.warn("[WalletConnect] Error disconnecting existing provider:", error);
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
2816
|
+
_WalletConnectAdapter.providerChains = null;
|
|
2817
|
+
}
|
|
2818
|
+
if (_WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId) {
|
|
2819
|
+
this.provider = _WalletConnectAdapter.providerInstance;
|
|
2820
|
+
console.log("[WalletConnect] Reusing existing provider instance");
|
|
2821
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2822
|
+
console.log("[WalletConnect] Provider already has accounts, skipping enable()");
|
|
2823
|
+
} else {
|
|
2824
|
+
const hasSession = this.provider.session !== void 0 && this.provider.session !== null;
|
|
2825
|
+
console.log("[WalletConnect] Provider has no accounts, calling enable() to show QR modal");
|
|
2826
|
+
console.log("[WalletConnect] Provider state:", {
|
|
2827
|
+
accounts: this.provider.accounts,
|
|
2828
|
+
chainId: this.provider.chainId,
|
|
2829
|
+
hasSession,
|
|
2830
|
+
sessionTopic: this.provider.session?.topic
|
|
2831
|
+
});
|
|
2832
|
+
if (hasSession && (!this.provider.accounts || this.provider.accounts.length === 0)) {
|
|
2833
|
+
console.log("[WalletConnect] Found stale session, disconnecting before reconnecting...");
|
|
2834
|
+
try {
|
|
2835
|
+
await this.provider.disconnect();
|
|
2836
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2837
|
+
} catch (disconnectError) {
|
|
2838
|
+
console.warn("[WalletConnect] Error disconnecting stale session:", disconnectError);
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
try {
|
|
2842
|
+
console.log("[WalletConnect] Calling enable()...");
|
|
2843
|
+
const enableResult = await this.provider.enable();
|
|
2844
|
+
console.log("[WalletConnect] enable() completed, result:", enableResult);
|
|
2845
|
+
console.log("[WalletConnect] Provider state after enable():", {
|
|
2846
|
+
accounts: this.provider.accounts,
|
|
2847
|
+
chainId: this.provider.chainId,
|
|
2848
|
+
session: this.provider.session ? {
|
|
2849
|
+
topic: this.provider.session.topic,
|
|
2850
|
+
namespaces: this.provider.session.namespaces ? Object.keys(this.provider.session.namespaces) : "none"
|
|
2851
|
+
} : "none"
|
|
2852
|
+
});
|
|
2853
|
+
} catch (error) {
|
|
2854
|
+
console.error("[WalletConnect] enable() error:", error);
|
|
2855
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2856
|
+
throw new ConnectionRejectedError(this.type);
|
|
2857
|
+
}
|
|
2858
|
+
throw error;
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
} else if (_WalletConnectAdapter.providerInstance && _WalletConnectAdapter.providerProjectId === this.projectId) {
|
|
2862
|
+
this.provider = _WalletConnectAdapter.providerInstance;
|
|
2863
|
+
console.log("[WalletConnect] Reusing existing provider instance (not connected)");
|
|
2864
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2865
|
+
console.log("[WalletConnect] Provider already has accounts after init, skipping enable()");
|
|
2866
|
+
} else {
|
|
2867
|
+
const hasSession = this.provider.session !== void 0 && this.provider.session !== null;
|
|
2868
|
+
console.log("[WalletConnect] Provider has no accounts, calling enable() to show QR modal");
|
|
2869
|
+
console.log("[WalletConnect] Provider state:", {
|
|
2870
|
+
accounts: this.provider.accounts,
|
|
2871
|
+
chainId: this.provider.chainId,
|
|
2872
|
+
hasSession,
|
|
2873
|
+
sessionTopic: this.provider.session?.topic
|
|
2874
|
+
});
|
|
2875
|
+
if (hasSession && (!this.provider.accounts || this.provider.accounts.length === 0)) {
|
|
2876
|
+
console.log("[WalletConnect] Found stale session after init, disconnecting before reconnecting...");
|
|
2877
|
+
try {
|
|
2878
|
+
await this.provider.disconnect();
|
|
2879
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2880
|
+
} catch (disconnectError) {
|
|
2881
|
+
console.warn("[WalletConnect] Error disconnecting stale session:", disconnectError);
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
try {
|
|
2885
|
+
await this.provider.enable();
|
|
2886
|
+
} catch (error) {
|
|
2887
|
+
console.error("[WalletConnect] enable() error:", error);
|
|
2888
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2889
|
+
throw new ConnectionRejectedError(this.type);
|
|
2890
|
+
}
|
|
2891
|
+
throw error;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
} else if (_WalletConnectAdapter.isInitializing && _WalletConnectAdapter.initPromise) {
|
|
2895
|
+
console.log("[WalletConnect] Waiting for ongoing initialization...");
|
|
2896
|
+
this.provider = await _WalletConnectAdapter.initPromise;
|
|
2897
|
+
_WalletConnectAdapter.providerInstance = this.provider;
|
|
2898
|
+
_WalletConnectAdapter.providerProjectId = this.projectId;
|
|
2899
|
+
_WalletConnectAdapter.providerChains = targetChains;
|
|
2900
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2901
|
+
console.log("[WalletConnect] Provider already has accounts after init, skipping enable()");
|
|
2902
|
+
} else {
|
|
2903
|
+
try {
|
|
2904
|
+
await this.provider.enable();
|
|
2905
|
+
} catch (error) {
|
|
2906
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2907
|
+
throw new ConnectionRejectedError(this.type);
|
|
2908
|
+
}
|
|
2909
|
+
throw error;
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
} else {
|
|
2913
|
+
console.log("[WalletConnect] Initializing new provider with chains:", {
|
|
2914
|
+
primary: primaryChain,
|
|
2915
|
+
optional: optionalChains,
|
|
2916
|
+
all: targetChains
|
|
2917
|
+
});
|
|
2918
|
+
_WalletConnectAdapter.isInitializing = true;
|
|
2919
|
+
_WalletConnectAdapter.initPromise = EthereumProvider__default.default.init(initOptions);
|
|
2920
|
+
try {
|
|
2921
|
+
this.provider = await _WalletConnectAdapter.initPromise;
|
|
2922
|
+
_WalletConnectAdapter.providerInstance = this.provider;
|
|
2923
|
+
_WalletConnectAdapter.providerProjectId = this.projectId;
|
|
2924
|
+
_WalletConnectAdapter.providerChains = targetChains;
|
|
2925
|
+
if (this.provider.accounts && this.provider.accounts.length > 0) {
|
|
2926
|
+
console.log("[WalletConnect] Provider has restored session, skipping enable()");
|
|
2927
|
+
} else {
|
|
2928
|
+
const hasSession = this.provider.session !== void 0 && this.provider.session !== null;
|
|
2929
|
+
console.log("[WalletConnect] New provider initialized, calling enable() to show QR modal");
|
|
2930
|
+
console.log("[WalletConnect] Provider state:", {
|
|
2931
|
+
accounts: this.provider.accounts,
|
|
2932
|
+
chainId: this.provider.chainId,
|
|
2933
|
+
hasSession,
|
|
2934
|
+
sessionTopic: this.provider.session?.topic
|
|
2935
|
+
});
|
|
2936
|
+
if (hasSession && (!this.provider.accounts || this.provider.accounts.length === 0)) {
|
|
2937
|
+
console.log("[WalletConnect] Found stale session after init, disconnecting before reconnecting...");
|
|
2938
|
+
try {
|
|
2939
|
+
await this.provider.disconnect();
|
|
2940
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2941
|
+
} catch (disconnectError) {
|
|
2942
|
+
console.warn("[WalletConnect] Error disconnecting stale session:", disconnectError);
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
try {
|
|
2946
|
+
await this.provider.enable();
|
|
2947
|
+
} catch (error) {
|
|
2948
|
+
console.error("[WalletConnect] enable() error:", error);
|
|
2949
|
+
if (error.code === 4001 || error.message?.includes("rejected") || error.message?.includes("User rejected")) {
|
|
2950
|
+
throw new ConnectionRejectedError(this.type);
|
|
2951
|
+
}
|
|
2952
|
+
throw error;
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
} finally {
|
|
2956
|
+
_WalletConnectAdapter.isInitializing = false;
|
|
2957
|
+
_WalletConnectAdapter.initPromise = null;
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
let accounts = this.provider.accounts;
|
|
2961
|
+
if (!accounts || accounts.length === 0) {
|
|
2962
|
+
console.log("[WalletConnect] provider.accounts is empty, checking session.namespaces.eip155.accounts...");
|
|
2963
|
+
const session = this.provider.session;
|
|
2964
|
+
if (session && session.namespaces?.eip155?.accounts) {
|
|
2965
|
+
const sessionAccounts = session.namespaces.eip155.accounts.map((acc) => {
|
|
2966
|
+
const parts = acc.split(":");
|
|
2967
|
+
if (parts.length >= 3 && parts[0] === "eip155") {
|
|
2968
|
+
return parts[2];
|
|
2969
|
+
}
|
|
2970
|
+
return null;
|
|
2971
|
+
}).filter((addr) => addr !== null && addr.startsWith("0x"));
|
|
2972
|
+
if (sessionAccounts.length > 0) {
|
|
2973
|
+
const uniqueAccounts = [...new Set(sessionAccounts)];
|
|
2974
|
+
console.log("[WalletConnect] Found accounts in session.namespaces.eip155.accounts:", {
|
|
2975
|
+
raw: session.namespaces.eip155.accounts,
|
|
2976
|
+
extracted: uniqueAccounts,
|
|
2977
|
+
chains: session.namespaces.eip155.chains
|
|
2978
|
+
});
|
|
2979
|
+
accounts = uniqueAccounts;
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
if (!accounts || accounts.length === 0) {
|
|
2984
|
+
console.log("[WalletConnect] Accounts not available, waiting for provider.accounts to populate...");
|
|
2985
|
+
const maxWaitTime = 3e3;
|
|
2986
|
+
const checkInterval = 100;
|
|
2987
|
+
const maxChecks = maxWaitTime / checkInterval;
|
|
2988
|
+
for (let i = 0; i < maxChecks; i++) {
|
|
2989
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
2990
|
+
accounts = this.provider.accounts;
|
|
2991
|
+
if (accounts && accounts.length > 0) {
|
|
2992
|
+
console.log(`[WalletConnect] Accounts available after ${(i + 1) * checkInterval}ms`);
|
|
2993
|
+
break;
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
if (!accounts || accounts.length === 0) {
|
|
2998
|
+
const session = this.provider.session;
|
|
2999
|
+
const providerState = {
|
|
3000
|
+
providerAccounts: this.provider.accounts,
|
|
3001
|
+
providerChainId: this.provider.chainId,
|
|
3002
|
+
session: session ? {
|
|
3003
|
+
exists: true,
|
|
3004
|
+
topic: session.topic,
|
|
3005
|
+
namespaces: session.namespaces ? Object.keys(session.namespaces) : "none",
|
|
3006
|
+
eip155Namespace: session.namespaces?.eip155 ? {
|
|
3007
|
+
accounts: session.namespaces.eip155.accounts,
|
|
3008
|
+
// CAIP-10 format
|
|
3009
|
+
chains: session.namespaces.eip155.chains,
|
|
3010
|
+
// CAIP-2 format
|
|
3011
|
+
methods: session.namespaces.eip155.methods,
|
|
3012
|
+
events: session.namespaces.eip155.events
|
|
3013
|
+
} : "none",
|
|
3014
|
+
// Log full session structure for debugging
|
|
3015
|
+
fullSession: JSON.stringify(session, null, 2)
|
|
3016
|
+
} : "none",
|
|
3017
|
+
// Check if provider has any other properties that might contain accounts
|
|
3018
|
+
providerKeys: Object.keys(this.provider)
|
|
3019
|
+
};
|
|
3020
|
+
console.error("[WalletConnect] No accounts available after enable() and wait", providerState);
|
|
3021
|
+
console.error("[WalletConnect] Full provider object:", this.provider);
|
|
3022
|
+
console.error("[WalletConnect] Full session object:", session);
|
|
3023
|
+
console.error("[WalletConnect] Session namespaces structure:", session?.namespaces);
|
|
3024
|
+
throw new Error("WalletConnect connection established but no accounts available. Please check session.namespaces.eip155.accounts in the console logs above.");
|
|
3025
|
+
}
|
|
3026
|
+
const currentChainId = this.provider.chainId || targetChains[0];
|
|
3027
|
+
const viemChain = this.getViemChain(currentChainId);
|
|
3028
|
+
this.walletClient = viem.createWalletClient({
|
|
3029
|
+
account: accounts[0],
|
|
3030
|
+
chain: viemChain,
|
|
3031
|
+
transport: viem.custom(this.provider)
|
|
3032
|
+
});
|
|
3033
|
+
const chainInfo = getChainInfo(currentChainId);
|
|
3034
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
3035
|
+
this.publicClient = viem.createPublicClient({
|
|
3036
|
+
chain: viemChain,
|
|
3037
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(this.provider)
|
|
3038
|
+
});
|
|
3039
|
+
const address = formatEVMAddress(accounts[0]);
|
|
3040
|
+
const account = {
|
|
3041
|
+
universalAddress: createUniversalAddress(currentChainId, address),
|
|
3042
|
+
nativeAddress: address,
|
|
3043
|
+
chainId: currentChainId,
|
|
3044
|
+
chainType: exports.ChainType.EVM,
|
|
3045
|
+
isActive: true
|
|
3046
|
+
};
|
|
3047
|
+
this.setState("connected" /* CONNECTED */);
|
|
3048
|
+
this.setAccount(account);
|
|
3049
|
+
this.setupEventListeners();
|
|
3050
|
+
return account;
|
|
3051
|
+
} catch (error) {
|
|
3052
|
+
this.setState("error" /* ERROR */);
|
|
3053
|
+
this.setAccount(null);
|
|
3054
|
+
const origin = typeof window !== "undefined" && window.location ? window.location.origin : "";
|
|
3055
|
+
const errorCode = error?.code;
|
|
3056
|
+
const errorMessage = error?.message || String(error);
|
|
3057
|
+
const isOriginNotAllowed = errorCode === 3e3 || /origin not allowed/i.test(errorMessage) || /Unauthorized:\s*origin not allowed/i.test(errorMessage);
|
|
3058
|
+
const session = this.provider?.session;
|
|
3059
|
+
const providerState = this.provider ? {
|
|
3060
|
+
accounts: this.provider.accounts,
|
|
3061
|
+
chainId: this.provider.chainId,
|
|
3062
|
+
session: session ? {
|
|
3063
|
+
exists: true,
|
|
3064
|
+
topic: session.topic,
|
|
3065
|
+
namespaces: session.namespaces ? Object.keys(session.namespaces) : "none",
|
|
3066
|
+
eip155Namespace: session.namespaces?.eip155 ? {
|
|
3067
|
+
accounts: session.namespaces.eip155.accounts,
|
|
3068
|
+
chains: session.namespaces.eip155.chains,
|
|
3069
|
+
methods: session.namespaces.eip155.methods,
|
|
3070
|
+
events: session.namespaces.eip155.events
|
|
3071
|
+
} : "none"
|
|
3072
|
+
} : "none",
|
|
3073
|
+
providerKeys: Object.keys(this.provider)
|
|
3074
|
+
} : "no provider";
|
|
3075
|
+
console.error("[WalletConnect] Connection error:", {
|
|
3076
|
+
error,
|
|
3077
|
+
code: error.code,
|
|
3078
|
+
message: error.message,
|
|
3079
|
+
stack: error.stack,
|
|
3080
|
+
providerState
|
|
3081
|
+
});
|
|
3082
|
+
if (this.provider) {
|
|
3083
|
+
console.error("[WalletConnect] Full provider object:", this.provider);
|
|
3084
|
+
console.error("[WalletConnect] Full session object:", session);
|
|
3085
|
+
}
|
|
3086
|
+
if (error.code === 4001 || error.message && (error.message.includes("User rejected") || error.message.includes("rejected by user") || error.message.includes("User cancelled"))) {
|
|
3087
|
+
throw new ConnectionRejectedError(this.type);
|
|
3088
|
+
}
|
|
3089
|
+
if (isOriginNotAllowed) {
|
|
3090
|
+
throw new ConfigurationError(
|
|
3091
|
+
`WalletConnect relayer rejected this origin (code 3000: Unauthorized: origin not allowed).
|
|
3092
|
+
|
|
3093
|
+
Fix:
|
|
3094
|
+
1) Open WalletConnect Cloud \u2192 your project (${this.projectId})
|
|
3095
|
+
2) Add this site origin to the allowlist:
|
|
3096
|
+
- ${origin || "(unknown origin)"}
|
|
3097
|
+
|
|
3098
|
+
Common dev origins to allow:
|
|
3099
|
+
- http://localhost:5173
|
|
3100
|
+
- http://192.168.0.221:5173 (your LAN dev URL)
|
|
3101
|
+
- https://wallet-test.enclave-hq.com (your Cloudflare Tunnel/custom domain)
|
|
3102
|
+
|
|
3103
|
+
Original error: ${errorMessage}`
|
|
3104
|
+
);
|
|
3105
|
+
}
|
|
3106
|
+
throw error;
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
/**
|
|
3110
|
+
* Disconnect wallet
|
|
3111
|
+
*/
|
|
3112
|
+
async disconnect() {
|
|
3113
|
+
if (this.provider) {
|
|
3114
|
+
try {
|
|
3115
|
+
await this.provider.disconnect();
|
|
3116
|
+
} catch (error) {
|
|
3117
|
+
console.warn("[WalletConnect] Error during disconnect:", error);
|
|
3118
|
+
}
|
|
3119
|
+
if (_WalletConnectAdapter.providerInstance === this.provider) {
|
|
3120
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
3121
|
+
_WalletConnectAdapter.providerProjectId = null;
|
|
3122
|
+
_WalletConnectAdapter.providerChains = null;
|
|
3123
|
+
}
|
|
3124
|
+
this.provider = null;
|
|
3125
|
+
}
|
|
3126
|
+
this.removeEventListeners();
|
|
3127
|
+
this.walletClient = null;
|
|
3128
|
+
this.publicClient = null;
|
|
3129
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
3130
|
+
this.setAccount(null);
|
|
3131
|
+
this.emitDisconnected();
|
|
3132
|
+
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Sign message
|
|
3135
|
+
*/
|
|
3136
|
+
async signMessage(message) {
|
|
3137
|
+
this.ensureConnected();
|
|
3138
|
+
try {
|
|
3139
|
+
if (!this.provider) {
|
|
3140
|
+
throw new Error("Provider not initialized");
|
|
3141
|
+
}
|
|
3142
|
+
const signature = await this.provider.request({
|
|
3143
|
+
method: "personal_sign",
|
|
3144
|
+
params: [message, this.currentAccount.nativeAddress]
|
|
3145
|
+
});
|
|
3146
|
+
this.closeTelegramDeepLinkPopup();
|
|
3147
|
+
return signature;
|
|
3148
|
+
} catch (error) {
|
|
3149
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3150
|
+
throw new SignatureRejectedError();
|
|
3151
|
+
}
|
|
3152
|
+
throw error;
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
/**
|
|
3156
|
+
* Sign TypedData (EIP-712)
|
|
3157
|
+
*/
|
|
3158
|
+
async signTypedData(typedData) {
|
|
3159
|
+
this.ensureConnected();
|
|
3160
|
+
try {
|
|
3161
|
+
if (!this.provider) {
|
|
3162
|
+
throw new Error("Provider not initialized");
|
|
3163
|
+
}
|
|
3164
|
+
const signature = await this.provider.request({
|
|
3165
|
+
method: "eth_signTypedData_v4",
|
|
3166
|
+
params: [this.currentAccount.nativeAddress, JSON.stringify(typedData)]
|
|
3167
|
+
});
|
|
3168
|
+
this.closeTelegramDeepLinkPopup();
|
|
3169
|
+
return signature;
|
|
3170
|
+
} catch (error) {
|
|
3171
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3172
|
+
throw new SignatureRejectedError();
|
|
3173
|
+
}
|
|
3174
|
+
throw error;
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
/**
|
|
3178
|
+
* Sign transaction
|
|
3179
|
+
*/
|
|
3180
|
+
async signTransaction(transaction) {
|
|
3181
|
+
this.ensureConnected();
|
|
3182
|
+
try {
|
|
3183
|
+
if (!this.provider) {
|
|
3184
|
+
throw new Error("Provider not initialized");
|
|
3185
|
+
}
|
|
3186
|
+
const tx = {
|
|
3187
|
+
from: this.currentAccount.nativeAddress,
|
|
3188
|
+
to: transaction.to,
|
|
3189
|
+
value: transaction.value ? `0x${BigInt(transaction.value).toString(16)}` : void 0,
|
|
3190
|
+
data: transaction.data || "0x",
|
|
3191
|
+
gas: transaction.gas ? `0x${BigInt(transaction.gas).toString(16)}` : void 0,
|
|
3192
|
+
gasPrice: transaction.gasPrice && transaction.gasPrice !== "auto" ? `0x${BigInt(transaction.gasPrice).toString(16)}` : void 0,
|
|
3193
|
+
maxFeePerGas: transaction.maxFeePerGas ? `0x${BigInt(transaction.maxFeePerGas).toString(16)}` : void 0,
|
|
3194
|
+
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ? `0x${BigInt(transaction.maxPriorityFeePerGas).toString(16)}` : void 0,
|
|
3195
|
+
nonce: transaction.nonce !== void 0 ? `0x${transaction.nonce.toString(16)}` : void 0,
|
|
3196
|
+
chainId: transaction.chainId || this.currentAccount.chainId
|
|
3197
|
+
};
|
|
3198
|
+
const signature = await this.provider.request({
|
|
3199
|
+
method: "eth_signTransaction",
|
|
3200
|
+
params: [tx]
|
|
3201
|
+
});
|
|
3202
|
+
this.closeTelegramDeepLinkPopup();
|
|
3203
|
+
return signature;
|
|
3204
|
+
} catch (error) {
|
|
3205
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3206
|
+
throw new SignatureRejectedError("Transaction signature was rejected by user");
|
|
3207
|
+
}
|
|
3208
|
+
throw error;
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
/**
|
|
3212
|
+
* Get supported chains from current connection
|
|
3213
|
+
* Returns the chains that were requested during connection
|
|
3214
|
+
*/
|
|
3215
|
+
getSupportedChains() {
|
|
3216
|
+
return [...this.supportedChains];
|
|
3217
|
+
}
|
|
3218
|
+
/**
|
|
3219
|
+
* Switch chain
|
|
3220
|
+
*
|
|
3221
|
+
* Note: WalletConnect v2 with mobile wallets may not support chain switching reliably.
|
|
3222
|
+
* Some wallets may ignore the switch request or fail silently.
|
|
3223
|
+
* It's recommended to include all needed chains in the initial connection.
|
|
3224
|
+
*
|
|
3225
|
+
* Reference: https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces
|
|
3226
|
+
*/
|
|
3227
|
+
async switchChain(chainId) {
|
|
3228
|
+
if (!this.provider) {
|
|
3229
|
+
throw new Error("Provider not initialized");
|
|
3230
|
+
}
|
|
3231
|
+
const session = this.provider.session;
|
|
3232
|
+
const supportedChains = session?.namespaces?.eip155?.chains || [];
|
|
3233
|
+
const targetChainCAIP = `eip155:${chainId}`;
|
|
3234
|
+
const isChainApproved = supportedChains.includes(targetChainCAIP);
|
|
3235
|
+
if (!isChainApproved) {
|
|
3236
|
+
console.warn(`[WalletConnect] Chain ${chainId} (${targetChainCAIP}) not in session approved chains:`, supportedChains);
|
|
3237
|
+
console.warn("[WalletConnect] Chain switching may fail. Consider including all chains in initial connection.");
|
|
3238
|
+
}
|
|
3239
|
+
try {
|
|
3240
|
+
console.log(`[WalletConnect] Attempting to switch to chain ${chainId} (${targetChainCAIP})`);
|
|
3241
|
+
const result = await this.provider.request({
|
|
3242
|
+
method: "wallet_switchEthereumChain",
|
|
3243
|
+
params: [{ chainId: `0x${chainId.toString(16)}` }]
|
|
3244
|
+
});
|
|
3245
|
+
if (result !== null && result !== void 0) {
|
|
3246
|
+
console.warn("[WalletConnect] wallet_switchEthereumChain returned non-null result:", result);
|
|
3247
|
+
}
|
|
3248
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
3249
|
+
const currentChainId = this.provider.chainId;
|
|
3250
|
+
if (currentChainId !== chainId) {
|
|
3251
|
+
console.warn(`[WalletConnect] Chain switch may have failed. Expected ${chainId}, got ${currentChainId}`);
|
|
3252
|
+
console.warn("[WalletConnect] Some mobile wallets may not support chain switching via WalletConnect.");
|
|
3253
|
+
console.warn("[WalletConnect] User may need to manually switch chains in the wallet app.");
|
|
3254
|
+
}
|
|
3255
|
+
if (this.currentAccount) {
|
|
3256
|
+
const updatedAccount = {
|
|
3257
|
+
...this.currentAccount,
|
|
3258
|
+
chainId,
|
|
3259
|
+
universalAddress: createUniversalAddress(chainId, this.currentAccount.nativeAddress)
|
|
3260
|
+
};
|
|
3261
|
+
this.setAccount(updatedAccount);
|
|
3262
|
+
this.emitChainChanged(chainId);
|
|
3263
|
+
const viemChain = this.getViemChain(chainId);
|
|
3264
|
+
const chainInfo = getChainInfo(chainId);
|
|
3265
|
+
const primaryRpcUrl = chainInfo?.rpcUrls[0];
|
|
3266
|
+
this.walletClient = viem.createWalletClient({
|
|
3267
|
+
account: this.currentAccount.nativeAddress,
|
|
3268
|
+
chain: viemChain,
|
|
3269
|
+
transport: viem.custom(this.provider)
|
|
3270
|
+
});
|
|
3271
|
+
this.publicClient = viem.createPublicClient({
|
|
3272
|
+
chain: viemChain,
|
|
3273
|
+
transport: primaryRpcUrl ? viem.http(primaryRpcUrl) : viem.custom(this.provider)
|
|
3274
|
+
});
|
|
3275
|
+
}
|
|
3276
|
+
} catch (error) {
|
|
3277
|
+
console.error("[WalletConnect] Chain switch error:", {
|
|
3278
|
+
chainId,
|
|
3279
|
+
errorCode: error.code,
|
|
3280
|
+
errorMessage: error.message,
|
|
3281
|
+
supportedChains
|
|
3282
|
+
});
|
|
3283
|
+
if (error.code === 4902) {
|
|
3284
|
+
console.log(`[WalletConnect] Chain ${chainId} not found in wallet, attempting to add...`);
|
|
3285
|
+
const chainInfo = getChainInfo(chainId);
|
|
3286
|
+
if (chainInfo) {
|
|
3287
|
+
try {
|
|
3288
|
+
await this.addChain({
|
|
3289
|
+
chainId: chainInfo.id,
|
|
3290
|
+
chainName: chainInfo.name,
|
|
3291
|
+
nativeCurrency: chainInfo.nativeCurrency,
|
|
3292
|
+
rpcUrls: chainInfo.rpcUrls,
|
|
3293
|
+
blockExplorerUrls: chainInfo.blockExplorerUrls
|
|
3294
|
+
});
|
|
3295
|
+
console.log(`[WalletConnect] Chain added, attempting to switch again...`);
|
|
3296
|
+
await this.switchChain(chainId);
|
|
3297
|
+
} catch (addError) {
|
|
3298
|
+
console.error("[WalletConnect] Failed to add chain:", addError);
|
|
3299
|
+
throw new Error(`Failed to add chain ${chainId}: ${addError.message}`);
|
|
3300
|
+
}
|
|
3301
|
+
} else {
|
|
3302
|
+
throw new Error(`Chain ${chainId} not supported`);
|
|
3303
|
+
}
|
|
3304
|
+
} else if (error.code === 4001) {
|
|
3305
|
+
throw new Error("User rejected chain switch");
|
|
3306
|
+
} else if (error.code === 4100) {
|
|
3307
|
+
throw new Error("Wallet does not support wallet_switchEthereumChain. Please switch chains manually in your wallet app.");
|
|
3308
|
+
} else {
|
|
3309
|
+
console.warn("[WalletConnect] Chain switch may not be supported by this wallet. User may need to switch manually.");
|
|
3310
|
+
throw error;
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
/**
|
|
3315
|
+
* Add chain
|
|
3316
|
+
*/
|
|
3317
|
+
async addChain(chainConfig) {
|
|
3318
|
+
if (!this.provider) {
|
|
3319
|
+
throw new Error("Provider not initialized");
|
|
3320
|
+
}
|
|
3321
|
+
await this.provider.request({
|
|
3322
|
+
method: "wallet_addEthereumChain",
|
|
3323
|
+
params: [{
|
|
3324
|
+
chainId: `0x${chainConfig.chainId.toString(16)}`,
|
|
3325
|
+
chainName: chainConfig.chainName,
|
|
3326
|
+
nativeCurrency: chainConfig.nativeCurrency,
|
|
3327
|
+
rpcUrls: chainConfig.rpcUrls,
|
|
3328
|
+
blockExplorerUrls: chainConfig.blockExplorerUrls
|
|
3329
|
+
}]
|
|
3330
|
+
});
|
|
3331
|
+
}
|
|
3332
|
+
/**
|
|
3333
|
+
* Read contract
|
|
3334
|
+
*/
|
|
3335
|
+
async readContract(params) {
|
|
3336
|
+
if (!this.publicClient) {
|
|
3337
|
+
throw new Error("Public client not initialized");
|
|
3338
|
+
}
|
|
3339
|
+
const result = await this.publicClient.readContract({
|
|
3340
|
+
address: params.address,
|
|
3341
|
+
abi: params.abi,
|
|
3342
|
+
functionName: params.functionName,
|
|
3343
|
+
...params.args ? { args: params.args } : {}
|
|
3344
|
+
});
|
|
3345
|
+
return result;
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Write contract
|
|
3349
|
+
*/
|
|
3350
|
+
async writeContract(params) {
|
|
3351
|
+
this.ensureConnected();
|
|
3352
|
+
if (!this.walletClient) {
|
|
3353
|
+
throw new Error("Wallet client not initialized");
|
|
3354
|
+
}
|
|
3355
|
+
try {
|
|
3356
|
+
const txOptions = {
|
|
3357
|
+
address: params.address,
|
|
3358
|
+
abi: params.abi,
|
|
3359
|
+
functionName: params.functionName,
|
|
3360
|
+
...params.args ? { args: params.args } : {},
|
|
3361
|
+
value: params.value ? BigInt(params.value) : void 0,
|
|
3362
|
+
gas: params.gas ? BigInt(params.gas) : void 0
|
|
3363
|
+
};
|
|
3364
|
+
if (params.maxFeePerGas || params.maxPriorityFeePerGas) {
|
|
3365
|
+
if (params.maxFeePerGas) {
|
|
3366
|
+
txOptions.maxFeePerGas = BigInt(params.maxFeePerGas);
|
|
3367
|
+
}
|
|
3368
|
+
if (params.maxPriorityFeePerGas) {
|
|
3369
|
+
txOptions.maxPriorityFeePerGas = BigInt(params.maxPriorityFeePerGas);
|
|
3370
|
+
}
|
|
3371
|
+
} else if (params.gasPrice && params.gasPrice !== "auto") {
|
|
3372
|
+
txOptions.gasPrice = BigInt(params.gasPrice);
|
|
3373
|
+
} else {
|
|
3374
|
+
if (this.publicClient) {
|
|
3375
|
+
try {
|
|
3376
|
+
const feesPerGas = await this.publicClient.estimateFeesPerGas().catch(() => null);
|
|
3377
|
+
if (feesPerGas) {
|
|
3378
|
+
const minPriorityFeeWei = BigInt(1e8);
|
|
3379
|
+
const maxPriorityFeePerGas = feesPerGas.maxPriorityFeePerGas > minPriorityFeeWei ? feesPerGas.maxPriorityFeePerGas : minPriorityFeeWei;
|
|
3380
|
+
const adjustedMaxFeePerGas = feesPerGas.maxFeePerGas > maxPriorityFeePerGas ? feesPerGas.maxFeePerGas : maxPriorityFeePerGas + BigInt(1e9);
|
|
3381
|
+
txOptions.maxFeePerGas = adjustedMaxFeePerGas;
|
|
3382
|
+
txOptions.maxPriorityFeePerGas = maxPriorityFeePerGas;
|
|
3383
|
+
} else {
|
|
3384
|
+
const gasPrice = await this.publicClient.getGasPrice();
|
|
3385
|
+
txOptions.gasPrice = gasPrice;
|
|
3386
|
+
}
|
|
3387
|
+
} catch (err) {
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
const txHash = await this.walletClient.writeContract(txOptions);
|
|
3392
|
+
this.closeTelegramDeepLinkPopup();
|
|
3393
|
+
return txHash;
|
|
3394
|
+
} catch (error) {
|
|
3395
|
+
if (error.code === 4001 || error.message?.includes("rejected")) {
|
|
3396
|
+
throw new SignatureRejectedError("Transaction was rejected by user");
|
|
3397
|
+
}
|
|
3398
|
+
throw error;
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
/**
|
|
3402
|
+
* Estimate gas
|
|
3403
|
+
*/
|
|
3404
|
+
async estimateGas(params) {
|
|
3405
|
+
if (!this.publicClient) {
|
|
3406
|
+
throw new Error("Public client not initialized");
|
|
3407
|
+
}
|
|
3408
|
+
const gas = await this.publicClient.estimateContractGas({
|
|
3409
|
+
address: params.address,
|
|
3410
|
+
abi: params.abi,
|
|
3411
|
+
functionName: params.functionName,
|
|
3412
|
+
...params.args ? { args: params.args } : {},
|
|
3413
|
+
value: params.value ? BigInt(params.value) : void 0,
|
|
3414
|
+
account: this.currentAccount.nativeAddress
|
|
3415
|
+
});
|
|
3416
|
+
return gas;
|
|
3417
|
+
}
|
|
3418
|
+
/**
|
|
3419
|
+
* Wait for transaction
|
|
3420
|
+
*/
|
|
3421
|
+
async waitForTransaction(txHash, confirmations = 1) {
|
|
3422
|
+
if (!this.publicClient) {
|
|
3423
|
+
throw new Error("Public client not initialized");
|
|
3424
|
+
}
|
|
3425
|
+
const receipt = await this.publicClient.waitForTransactionReceipt({
|
|
3426
|
+
hash: txHash,
|
|
3427
|
+
confirmations
|
|
3428
|
+
});
|
|
3429
|
+
if (receipt.status === "reverted") {
|
|
3430
|
+
throw new TransactionFailedError(txHash, "Transaction reverted");
|
|
3431
|
+
}
|
|
3432
|
+
return {
|
|
3433
|
+
transactionHash: receipt.transactionHash,
|
|
3434
|
+
blockNumber: Number(receipt.blockNumber),
|
|
3435
|
+
blockHash: receipt.blockHash,
|
|
3436
|
+
from: receipt.from,
|
|
3437
|
+
to: receipt.to || void 0,
|
|
3438
|
+
status: receipt.status === "success" ? "success" : "failed",
|
|
3439
|
+
gasUsed: receipt.gasUsed.toString(),
|
|
3440
|
+
effectiveGasPrice: receipt.effectiveGasPrice?.toString(),
|
|
3441
|
+
logs: receipt.logs
|
|
3442
|
+
};
|
|
3443
|
+
}
|
|
3444
|
+
/**
|
|
3445
|
+
* Get provider
|
|
3446
|
+
*/
|
|
3447
|
+
getProvider() {
|
|
3448
|
+
return this.provider;
|
|
3449
|
+
}
|
|
3450
|
+
/**
|
|
3451
|
+
* Get signer
|
|
3452
|
+
*/
|
|
3453
|
+
getSigner() {
|
|
3454
|
+
return this.walletClient;
|
|
3455
|
+
}
|
|
3456
|
+
/**
|
|
3457
|
+
* Setup event listeners
|
|
3458
|
+
*/
|
|
3459
|
+
setupEventListeners() {
|
|
3460
|
+
if (!this.provider) return;
|
|
3461
|
+
this.provider.on("accountsChanged", this.handleAccountsChanged);
|
|
3462
|
+
this.provider.on("chainChanged", this.handleChainChanged);
|
|
3463
|
+
this.provider.on("disconnect", this.handleDisconnect);
|
|
3464
|
+
}
|
|
3465
|
+
/**
|
|
3466
|
+
* Remove event listeners
|
|
3467
|
+
*/
|
|
3468
|
+
removeEventListeners() {
|
|
3469
|
+
if (!this.provider) return;
|
|
3470
|
+
this.provider.removeListener("accountsChanged", this.handleAccountsChanged);
|
|
3471
|
+
this.provider.removeListener("chainChanged", this.handleChainChanged);
|
|
3472
|
+
this.provider.removeListener("disconnect", this.handleDisconnect);
|
|
3473
|
+
}
|
|
3474
|
+
/**
|
|
3475
|
+
* Get viem chain config
|
|
3476
|
+
*/
|
|
3477
|
+
getViemChain(chainId) {
|
|
3478
|
+
const chainInfo = getChainInfo(chainId);
|
|
3479
|
+
if (chainInfo) {
|
|
3480
|
+
return {
|
|
3481
|
+
id: chainId,
|
|
3482
|
+
name: chainInfo.name,
|
|
3483
|
+
network: chainInfo.name.toLowerCase().replace(/\s+/g, "-"),
|
|
3484
|
+
nativeCurrency: chainInfo.nativeCurrency,
|
|
3485
|
+
rpcUrls: {
|
|
3486
|
+
default: { http: chainInfo.rpcUrls },
|
|
3487
|
+
public: { http: chainInfo.rpcUrls }
|
|
3488
|
+
},
|
|
3489
|
+
blockExplorers: chainInfo.blockExplorerUrls ? {
|
|
3490
|
+
default: { name: "Explorer", url: chainInfo.blockExplorerUrls[0] }
|
|
3491
|
+
} : void 0
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3494
|
+
return {
|
|
3495
|
+
id: chainId,
|
|
3496
|
+
name: `Chain ${chainId}`,
|
|
3497
|
+
network: `chain-${chainId}`,
|
|
3498
|
+
nativeCurrency: {
|
|
3499
|
+
name: "ETH",
|
|
3500
|
+
symbol: "ETH",
|
|
3501
|
+
decimals: 18
|
|
3502
|
+
},
|
|
3503
|
+
rpcUrls: {
|
|
3504
|
+
default: { http: [] },
|
|
3505
|
+
public: { http: [] }
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
}
|
|
3509
|
+
};
|
|
3510
|
+
// Store supported chains from connection
|
|
3511
|
+
// Static provider instance to avoid multiple initializations
|
|
3512
|
+
_WalletConnectAdapter.providerInstance = null;
|
|
3513
|
+
_WalletConnectAdapter.providerProjectId = null;
|
|
3514
|
+
_WalletConnectAdapter.providerChains = null;
|
|
3515
|
+
// Store the chains used during initialization
|
|
3516
|
+
_WalletConnectAdapter.isInitializing = false;
|
|
3517
|
+
_WalletConnectAdapter.initPromise = null;
|
|
3518
|
+
var WalletConnectAdapter = _WalletConnectAdapter;
|
|
3519
|
+
function loadWalletConnectTronModule() {
|
|
3520
|
+
const here = typeof __filename !== "undefined" ? __filename : url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
3521
|
+
const req = module$1.createRequire(here);
|
|
3522
|
+
const tronBundle = here.endsWith(".mjs") ? "tron.mjs" : "tron.js";
|
|
3523
|
+
return req(path.join(path.dirname(here), tronBundle));
|
|
3524
|
+
}
|
|
3525
|
+
|
|
3526
|
+
// src/adapters/deep-link/adapter.ts
|
|
3527
|
+
init_types();
|
|
3528
|
+
var DeepLinkProviderType = /* @__PURE__ */ ((DeepLinkProviderType2) => {
|
|
3529
|
+
DeepLinkProviderType2["TOKENPOCKET"] = "tokenpocket";
|
|
3530
|
+
DeepLinkProviderType2["TRONLINK"] = "tronlink";
|
|
3531
|
+
DeepLinkProviderType2["IMTOKEN"] = "imtoken";
|
|
3532
|
+
DeepLinkProviderType2["METAMASK"] = "metamask";
|
|
3533
|
+
DeepLinkProviderType2["OKX"] = "okx";
|
|
3534
|
+
return DeepLinkProviderType2;
|
|
3535
|
+
})(DeepLinkProviderType || {});
|
|
3536
|
+
var _DeepLinkAdapter = class _DeepLinkAdapter extends WalletAdapter {
|
|
3537
|
+
constructor(config) {
|
|
3538
|
+
super();
|
|
3539
|
+
this.currentChainId = null;
|
|
3540
|
+
this.currentChainType = null;
|
|
3541
|
+
this.provider = this.createProvider(config);
|
|
3542
|
+
this.name = `${this.provider.name} (Deep Link)`;
|
|
3543
|
+
this.icon = this.provider.icon;
|
|
3544
|
+
if (this.provider.supportedChainTypes.includes(exports.ChainType.EVM)) {
|
|
3545
|
+
this.chainType = exports.ChainType.EVM;
|
|
3546
|
+
this.type = "deep-link-evm" /* DEEP_LINK_EVM */;
|
|
3547
|
+
} else if (this.provider.supportedChainTypes.includes(exports.ChainType.TRON)) {
|
|
3548
|
+
this.chainType = exports.ChainType.TRON;
|
|
3549
|
+
this.type = "deep-link-tron" /* DEEP_LINK_TRON */;
|
|
3550
|
+
} else {
|
|
3551
|
+
this.chainType = exports.ChainType.EVM;
|
|
3552
|
+
this.type = "deep-link-evm" /* DEEP_LINK_EVM */;
|
|
3553
|
+
}
|
|
3554
|
+
if (typeof window !== "undefined") {
|
|
3555
|
+
this.setupCallbackHandler();
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
/**
|
|
3559
|
+
* Create provider instance based on type
|
|
3560
|
+
*/
|
|
3561
|
+
createProvider(config) {
|
|
3562
|
+
switch (config.providerType) {
|
|
3563
|
+
case "tokenpocket" /* TOKENPOCKET */: {
|
|
3564
|
+
const { TokenPocketDeepLinkProvider: TokenPocketDeepLinkProvider2 } = (init_tokenpocket(), __toCommonJS(tokenpocket_exports));
|
|
3565
|
+
return new TokenPocketDeepLinkProvider2({
|
|
3566
|
+
callbackUrl: config.callbackUrl,
|
|
3567
|
+
callbackSchema: config.callbackSchema
|
|
3568
|
+
});
|
|
3569
|
+
}
|
|
3570
|
+
case "tronlink" /* TRONLINK */: {
|
|
3571
|
+
const { TronLinkDeepLinkProvider: TronLinkDeepLinkProvider2 } = (init_tronlink(), __toCommonJS(tronlink_exports));
|
|
3572
|
+
return new TronLinkDeepLinkProvider2();
|
|
3573
|
+
}
|
|
3574
|
+
case "imtoken" /* IMTOKEN */: {
|
|
3575
|
+
const { ImTokenDeepLinkProvider: ImTokenDeepLinkProvider2 } = (init_imtoken(), __toCommonJS(imtoken_exports));
|
|
3576
|
+
return new ImTokenDeepLinkProvider2({
|
|
3577
|
+
callbackUrl: config.callbackUrl,
|
|
3578
|
+
callbackSchema: config.callbackSchema
|
|
3579
|
+
});
|
|
3580
|
+
}
|
|
3581
|
+
case "metamask" /* METAMASK */: {
|
|
3582
|
+
const { MetaMaskDeepLinkProvider: MetaMaskDeepLinkProvider2 } = (init_metamask(), __toCommonJS(metamask_exports));
|
|
3583
|
+
return new MetaMaskDeepLinkProvider2();
|
|
3584
|
+
}
|
|
3585
|
+
case "okx" /* OKX */: {
|
|
3586
|
+
const { OKXDeepLinkProvider: OKXDeepLinkProvider2 } = (init_okx(), __toCommonJS(okx_exports));
|
|
3587
|
+
return new OKXDeepLinkProvider2();
|
|
3588
|
+
}
|
|
3589
|
+
default:
|
|
3590
|
+
throw new Error(`Unsupported deep link provider type: ${config.providerType}`);
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
/**
|
|
3594
|
+
* Setup callback handler for deep link results
|
|
3595
|
+
*/
|
|
3596
|
+
setupCallbackHandler() {
|
|
3597
|
+
if (typeof window === "undefined") {
|
|
3598
|
+
return;
|
|
3599
|
+
}
|
|
3600
|
+
const handleUrlChange = () => {
|
|
3601
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
3602
|
+
const result = this.provider.parseCallbackResult(urlParams);
|
|
3603
|
+
if (result.actionId && _DeepLinkAdapter.pendingActions.has(result.actionId)) {
|
|
3604
|
+
const callback = _DeepLinkAdapter.pendingActions.get(result.actionId);
|
|
3605
|
+
if (result.error) {
|
|
3606
|
+
callback.reject(new Error(result.error));
|
|
3607
|
+
} else if (result.result) {
|
|
3608
|
+
callback.resolve(result.result);
|
|
3609
|
+
}
|
|
3610
|
+
_DeepLinkAdapter.pendingActions.delete(result.actionId);
|
|
3611
|
+
}
|
|
3612
|
+
};
|
|
3613
|
+
window.addEventListener("popstate", handleUrlChange);
|
|
3614
|
+
window.addEventListener("hashchange", handleUrlChange);
|
|
3615
|
+
handleUrlChange();
|
|
3616
|
+
}
|
|
3617
|
+
/**
|
|
3618
|
+
* Check if deep link is available
|
|
3619
|
+
*/
|
|
3620
|
+
async isAvailable() {
|
|
3621
|
+
return this.provider.isAvailable();
|
|
3622
|
+
}
|
|
3623
|
+
/**
|
|
3624
|
+
* Connect to wallet via deep link
|
|
3625
|
+
*
|
|
3626
|
+
* Note: Deep links typically don't support persistent connections
|
|
3627
|
+
* This method may throw ConnectionRejectedError as deep links are
|
|
3628
|
+
* primarily used for signing operations, not connection
|
|
3629
|
+
*/
|
|
3630
|
+
async connect(chainId) {
|
|
3631
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] : chainId || 1;
|
|
3632
|
+
let chainType;
|
|
3633
|
+
if (targetChainId === 195) {
|
|
3634
|
+
chainType = exports.ChainType.TRON;
|
|
3635
|
+
} else {
|
|
3636
|
+
chainType = exports.ChainType.EVM;
|
|
3637
|
+
}
|
|
3638
|
+
if (!this.provider.supportedChainTypes.includes(chainType)) {
|
|
3639
|
+
throw new Error(
|
|
3640
|
+
`Provider ${this.provider.name} does not support chain type ${chainType}`
|
|
3641
|
+
);
|
|
3642
|
+
}
|
|
3643
|
+
if (this.provider.buildConnectLink) {
|
|
3644
|
+
const linkInfo = this.provider.buildConnectLink({
|
|
3645
|
+
chainId: targetChainId,
|
|
3646
|
+
chainType
|
|
3647
|
+
});
|
|
3648
|
+
if (linkInfo.actionId) {
|
|
3649
|
+
return new Promise((resolve, reject) => {
|
|
3650
|
+
_DeepLinkAdapter.pendingActions.set(linkInfo.actionId, {
|
|
3651
|
+
resolve: (result) => {
|
|
3652
|
+
const address = result?.address || result?.account || result;
|
|
3653
|
+
if (!address || typeof address !== "string") {
|
|
3654
|
+
reject(new ConnectionRejectedError("Invalid connection result: no address found"));
|
|
3655
|
+
return;
|
|
3656
|
+
}
|
|
3657
|
+
const account = {
|
|
3658
|
+
universalAddress: createUniversalAddress(targetChainId, address),
|
|
3659
|
+
nativeAddress: address,
|
|
3660
|
+
chainId: targetChainId,
|
|
3661
|
+
chainType,
|
|
3662
|
+
isActive: true
|
|
3663
|
+
};
|
|
3664
|
+
this.setState("connected" /* CONNECTED */);
|
|
3665
|
+
this.setAccount(account);
|
|
3666
|
+
this.emit("connected", account);
|
|
3667
|
+
resolve(account);
|
|
3668
|
+
},
|
|
3669
|
+
reject: (error) => {
|
|
3670
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
3671
|
+
reject(error);
|
|
3672
|
+
}
|
|
3673
|
+
});
|
|
3674
|
+
window.location.href = linkInfo.url;
|
|
3675
|
+
setTimeout(() => {
|
|
3676
|
+
if (_DeepLinkAdapter.pendingActions.has(linkInfo.actionId)) {
|
|
3677
|
+
_DeepLinkAdapter.pendingActions.delete(linkInfo.actionId);
|
|
3678
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
3679
|
+
reject(new ConnectionRejectedError("Deep link connection timeout"));
|
|
3680
|
+
}
|
|
3681
|
+
}, 3e4);
|
|
3682
|
+
});
|
|
3683
|
+
} else {
|
|
3684
|
+
window.location.href = linkInfo.url;
|
|
3685
|
+
throw new ConnectionRejectedError(
|
|
3686
|
+
"Deep link connection initiated. Please complete the connection in your wallet app."
|
|
3687
|
+
);
|
|
3688
|
+
}
|
|
3689
|
+
} else {
|
|
3690
|
+
throw new ConnectionRejectedError(
|
|
3691
|
+
`Deep link connection is not supported by ${this.provider.name}. Deep links are primarily used for signing operations.`
|
|
3692
|
+
);
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
/**
|
|
3696
|
+
* Disconnect from wallet
|
|
3697
|
+
*/
|
|
3698
|
+
async disconnect() {
|
|
3699
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
3700
|
+
this.setAccount(null);
|
|
3701
|
+
this.currentChainId = null;
|
|
3702
|
+
this.currentChainType = null;
|
|
3703
|
+
this.emitDisconnected();
|
|
3704
|
+
}
|
|
3705
|
+
/**
|
|
3706
|
+
* Sign a message
|
|
3707
|
+
*/
|
|
3708
|
+
async signMessage(message) {
|
|
3709
|
+
this.ensureConnected();
|
|
3710
|
+
if (!this.currentChainId || !this.currentChainType) {
|
|
3711
|
+
throw new WalletNotConnectedError(this.type);
|
|
3712
|
+
}
|
|
3713
|
+
const linkInfo = this.provider.buildSignMessageLink({
|
|
3714
|
+
message,
|
|
3715
|
+
chainId: this.currentChainId,
|
|
3716
|
+
chainType: this.currentChainType
|
|
3717
|
+
});
|
|
3718
|
+
if (linkInfo.callbackSchema || linkInfo.callbackUrl) {
|
|
3719
|
+
return new Promise((resolve, reject) => {
|
|
3720
|
+
_DeepLinkAdapter.pendingActions.set(linkInfo.actionId, { resolve, reject });
|
|
3721
|
+
window.location.href = linkInfo.url;
|
|
3722
|
+
setTimeout(() => {
|
|
3723
|
+
if (_DeepLinkAdapter.pendingActions.has(linkInfo.actionId)) {
|
|
3724
|
+
_DeepLinkAdapter.pendingActions.delete(linkInfo.actionId);
|
|
3725
|
+
reject(new SignatureRejectedError("Message signature timeout"));
|
|
3726
|
+
}
|
|
3727
|
+
}, 3e4);
|
|
3728
|
+
});
|
|
3729
|
+
} else {
|
|
3730
|
+
window.location.href = linkInfo.url;
|
|
3731
|
+
throw new SignatureRejectedError(
|
|
3732
|
+
"Deep link signature initiated. Please complete the signature in your wallet app."
|
|
3733
|
+
);
|
|
3734
|
+
}
|
|
3735
|
+
}
|
|
3736
|
+
/**
|
|
3737
|
+
* Sign a transaction
|
|
3738
|
+
*/
|
|
3739
|
+
async signTransaction(transaction) {
|
|
3740
|
+
this.ensureConnected();
|
|
3741
|
+
if (!this.currentChainId || !this.currentChainType) {
|
|
3742
|
+
throw new WalletNotConnectedError(this.type);
|
|
3743
|
+
}
|
|
3744
|
+
const linkInfo = this.provider.buildSignTransactionLink({
|
|
3745
|
+
transaction,
|
|
3746
|
+
chainId: this.currentChainId,
|
|
3747
|
+
chainType: this.currentChainType
|
|
3748
|
+
});
|
|
3749
|
+
if (linkInfo.callbackSchema || linkInfo.callbackUrl) {
|
|
3750
|
+
return new Promise((resolve, reject) => {
|
|
3751
|
+
_DeepLinkAdapter.pendingActions.set(linkInfo.actionId, { resolve, reject });
|
|
3752
|
+
window.location.href = linkInfo.url;
|
|
3753
|
+
setTimeout(() => {
|
|
3754
|
+
if (_DeepLinkAdapter.pendingActions.has(linkInfo.actionId)) {
|
|
3755
|
+
_DeepLinkAdapter.pendingActions.delete(linkInfo.actionId);
|
|
3756
|
+
reject(new SignatureRejectedError("Transaction signature timeout"));
|
|
3757
|
+
}
|
|
3758
|
+
}, 3e4);
|
|
3759
|
+
});
|
|
3760
|
+
} else {
|
|
3761
|
+
window.location.href = linkInfo.url;
|
|
3762
|
+
throw new SignatureRejectedError(
|
|
3763
|
+
"Deep link transaction signature initiated. Please complete the signature in your wallet app."
|
|
3764
|
+
);
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
/**
|
|
3768
|
+
* Get provider (not applicable for deep links)
|
|
3769
|
+
*/
|
|
3770
|
+
getProvider() {
|
|
3771
|
+
return null;
|
|
3772
|
+
}
|
|
3773
|
+
/**
|
|
3774
|
+
* Static method to handle callback from wallet apps
|
|
3775
|
+
* This can be called from anywhere in the application
|
|
3776
|
+
*/
|
|
3777
|
+
static handleCallback() {
|
|
3778
|
+
if (typeof window === "undefined") {
|
|
3779
|
+
return;
|
|
3780
|
+
}
|
|
3781
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
3782
|
+
const actionId = urlParams.get("actionId");
|
|
3783
|
+
if (actionId && _DeepLinkAdapter.pendingActions.has(actionId)) {
|
|
3784
|
+
const callback = _DeepLinkAdapter.pendingActions.get(actionId);
|
|
3785
|
+
const result = urlParams.get("result");
|
|
3786
|
+
const error = urlParams.get("error");
|
|
3787
|
+
if (error) {
|
|
3788
|
+
callback.reject(new Error(error));
|
|
3789
|
+
} else if (result) {
|
|
3790
|
+
try {
|
|
3791
|
+
const parsedResult = JSON.parse(decodeURIComponent(result));
|
|
3792
|
+
callback.resolve(parsedResult);
|
|
3793
|
+
} catch (e) {
|
|
3794
|
+
callback.resolve(result);
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
_DeepLinkAdapter.pendingActions.delete(actionId);
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
/**
|
|
3801
|
+
* Set current account (called after successful connection)
|
|
3802
|
+
*/
|
|
3803
|
+
setAccount(account) {
|
|
3804
|
+
this.currentAccount = account;
|
|
3805
|
+
if (account) {
|
|
3806
|
+
this.currentChainId = account.chainId;
|
|
3807
|
+
this.currentChainType = account.chainType;
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
/**
|
|
3811
|
+
* Emit disconnected event
|
|
3812
|
+
*/
|
|
3813
|
+
emitDisconnected() {
|
|
3814
|
+
this.emit("disconnected");
|
|
3815
|
+
}
|
|
3816
|
+
};
|
|
3817
|
+
// Static map to store pending actions across all instances
|
|
3818
|
+
// Key: actionId, Value: { resolve, reject }
|
|
3819
|
+
_DeepLinkAdapter.pendingActions = /* @__PURE__ */ new Map();
|
|
3820
|
+
var DeepLinkAdapter = _DeepLinkAdapter;
|
|
3821
|
+
|
|
3822
|
+
// src/core/adapter-registry.ts
|
|
3823
|
+
var AdapterRegistry = class {
|
|
3824
|
+
constructor(config = {}) {
|
|
3825
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
3826
|
+
this.config = config;
|
|
3827
|
+
this.registerDefaultAdapters();
|
|
3828
|
+
}
|
|
3829
|
+
/**
|
|
3830
|
+
* Register default adapters
|
|
3831
|
+
*/
|
|
3832
|
+
registerDefaultAdapters() {
|
|
3833
|
+
this.register("metamask" /* METAMASK */, () => new MetaMaskAdapter());
|
|
3834
|
+
this.register("private-key" /* PRIVATE_KEY */, () => new EVMPrivateKeyAdapter());
|
|
3835
|
+
if (this.config.walletConnectProjectId) {
|
|
3836
|
+
this.register(
|
|
3837
|
+
"walletconnect" /* WALLETCONNECT */,
|
|
3838
|
+
() => new WalletConnectAdapter(this.config.walletConnectProjectId)
|
|
3839
|
+
);
|
|
3840
|
+
this.register("walletconnect-tron" /* WALLETCONNECT_TRON */, () => {
|
|
3841
|
+
const { WalletConnectTronAdapter } = loadWalletConnectTronModule();
|
|
3842
|
+
return new WalletConnectTronAdapter(this.config.walletConnectProjectId);
|
|
3843
|
+
});
|
|
3844
|
+
}
|
|
3845
|
+
this.register("tronlink" /* TRONLINK */, () => new TronLinkAdapter());
|
|
3846
|
+
this.register(
|
|
3847
|
+
"deep-link-evm" /* DEEP_LINK_EVM */,
|
|
3848
|
+
() => new DeepLinkAdapter({
|
|
3849
|
+
providerType: "tokenpocket" /* TOKENPOCKET */
|
|
3850
|
+
})
|
|
3851
|
+
);
|
|
3852
|
+
this.register(
|
|
3853
|
+
"deep-link-tron" /* DEEP_LINK_TRON */,
|
|
3854
|
+
() => new DeepLinkAdapter({
|
|
3855
|
+
providerType: "tokenpocket" /* TOKENPOCKET */
|
|
3856
|
+
})
|
|
3857
|
+
);
|
|
3858
|
+
}
|
|
3859
|
+
/**
|
|
3860
|
+
* Register adapter
|
|
3861
|
+
*/
|
|
3862
|
+
register(type, factory) {
|
|
3863
|
+
this.adapters.set(type, factory);
|
|
3864
|
+
}
|
|
3865
|
+
/**
|
|
3866
|
+
* Get adapter
|
|
3867
|
+
*/
|
|
3868
|
+
getAdapter(type) {
|
|
3869
|
+
const factory = this.adapters.get(type);
|
|
3870
|
+
if (!factory) {
|
|
3871
|
+
return null;
|
|
3872
|
+
}
|
|
3873
|
+
return factory();
|
|
3874
|
+
}
|
|
3875
|
+
/**
|
|
3876
|
+
* Check if adapter is registered
|
|
3877
|
+
*/
|
|
3878
|
+
has(type) {
|
|
3879
|
+
return this.adapters.has(type);
|
|
3880
|
+
}
|
|
3881
|
+
/**
|
|
1677
3882
|
* Get all registered adapter types
|
|
1678
3883
|
*/
|
|
1679
|
-
getRegisteredTypes() {
|
|
1680
|
-
return Array.from(this.adapters.keys());
|
|
3884
|
+
getRegisteredTypes() {
|
|
3885
|
+
return Array.from(this.adapters.keys());
|
|
3886
|
+
}
|
|
3887
|
+
/**
|
|
3888
|
+
* 根据链类型获取适配器类型列表
|
|
3889
|
+
*/
|
|
3890
|
+
getAdapterTypesByChainType(chainType) {
|
|
3891
|
+
const types = [];
|
|
3892
|
+
for (const type of this.adapters.keys()) {
|
|
3893
|
+
const adapter = this.getAdapter(type);
|
|
3894
|
+
if (adapter && adapter.chainType === chainType) {
|
|
3895
|
+
types.push(type);
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
return types;
|
|
3899
|
+
}
|
|
3900
|
+
};
|
|
3901
|
+
|
|
3902
|
+
// src/core/wallet-manager.ts
|
|
3903
|
+
init_types();
|
|
3904
|
+
var QRCodeSignStatus = /* @__PURE__ */ ((QRCodeSignStatus2) => {
|
|
3905
|
+
QRCodeSignStatus2["WAITING"] = "waiting";
|
|
3906
|
+
QRCodeSignStatus2["PENDING"] = "pending";
|
|
3907
|
+
QRCodeSignStatus2["SUCCESS"] = "success";
|
|
3908
|
+
QRCodeSignStatus2["FAILED"] = "failed";
|
|
3909
|
+
QRCodeSignStatus2["TIMEOUT"] = "timeout";
|
|
3910
|
+
QRCodeSignStatus2["CANCELLED"] = "cancelled";
|
|
3911
|
+
return QRCodeSignStatus2;
|
|
3912
|
+
})(QRCodeSignStatus || {});
|
|
3913
|
+
var QRCodeSigner = class {
|
|
3914
|
+
constructor(config) {
|
|
3915
|
+
this.pollTimer = null;
|
|
3916
|
+
this.timeoutTimer = null;
|
|
3917
|
+
this.status = "waiting" /* WAITING */;
|
|
3918
|
+
this.qrCodeDataUrl = null;
|
|
3919
|
+
this.result = null;
|
|
3920
|
+
this.config = {
|
|
3921
|
+
requestId: config.requestId,
|
|
3922
|
+
requestUrl: config.requestUrl,
|
|
3923
|
+
pollUrl: config.pollUrl || "",
|
|
3924
|
+
pollInterval: config.pollInterval || 2e3,
|
|
3925
|
+
timeout: config.timeout || 3e5,
|
|
3926
|
+
// 5 minutes
|
|
3927
|
+
pollFn: config.pollFn
|
|
3928
|
+
};
|
|
3929
|
+
}
|
|
3930
|
+
/**
|
|
3931
|
+
* 生成二维码图片(Data URL)
|
|
3932
|
+
*/
|
|
3933
|
+
async generateQRCode(options) {
|
|
3934
|
+
if (this.qrCodeDataUrl) {
|
|
3935
|
+
return this.qrCodeDataUrl;
|
|
3936
|
+
}
|
|
3937
|
+
try {
|
|
3938
|
+
const qrCodeOptions = {
|
|
3939
|
+
width: options?.width || 300,
|
|
3940
|
+
margin: options?.margin || 2,
|
|
3941
|
+
color: {
|
|
3942
|
+
dark: options?.color?.dark || "#000000",
|
|
3943
|
+
light: options?.color?.light || "#FFFFFF"
|
|
3944
|
+
}
|
|
3945
|
+
};
|
|
3946
|
+
this.qrCodeDataUrl = await QRCode__default.default.toDataURL(this.config.requestUrl, qrCodeOptions);
|
|
3947
|
+
return this.qrCodeDataUrl;
|
|
3948
|
+
} catch (error) {
|
|
3949
|
+
throw new Error(`Failed to generate QR code: ${error instanceof Error ? error.message : String(error)}`);
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
/**
|
|
3953
|
+
* 开始轮询签名结果
|
|
3954
|
+
*/
|
|
3955
|
+
async startPolling(onStatusChange, onResult) {
|
|
3956
|
+
if (this.status === "success" /* SUCCESS */ && this.result?.signature) {
|
|
3957
|
+
return this.result.signature;
|
|
3958
|
+
}
|
|
3959
|
+
if (this.status === "cancelled" /* CANCELLED */ || this.status === "timeout" /* TIMEOUT */) {
|
|
3960
|
+
throw new SignatureRejectedError("Signature request was cancelled or timed out");
|
|
3961
|
+
}
|
|
3962
|
+
this.timeoutTimer = setTimeout(() => {
|
|
3963
|
+
this.stopPolling();
|
|
3964
|
+
this.status = "timeout" /* TIMEOUT */;
|
|
3965
|
+
onStatusChange?.(this.status);
|
|
3966
|
+
throw new SignatureRejectedError("Signature request timed out");
|
|
3967
|
+
}, this.config.timeout);
|
|
3968
|
+
return new Promise((resolve, reject) => {
|
|
3969
|
+
const poll = async () => {
|
|
3970
|
+
try {
|
|
3971
|
+
let result = null;
|
|
3972
|
+
if (this.config.pollFn) {
|
|
3973
|
+
result = await this.config.pollFn(this.config.requestId);
|
|
3974
|
+
} else if (this.config.pollUrl) {
|
|
3975
|
+
result = await this.defaultPoll(this.config.requestId);
|
|
3976
|
+
} else {
|
|
3977
|
+
return;
|
|
3978
|
+
}
|
|
3979
|
+
if (result?.completed) {
|
|
3980
|
+
this.stopPolling();
|
|
3981
|
+
this.result = result;
|
|
3982
|
+
if (result.signature) {
|
|
3983
|
+
this.status = "success" /* SUCCESS */;
|
|
3984
|
+
onStatusChange?.(this.status);
|
|
3985
|
+
onResult?.(result);
|
|
3986
|
+
resolve(result.signature);
|
|
3987
|
+
} else if (result.error) {
|
|
3988
|
+
this.status = "failed" /* FAILED */;
|
|
3989
|
+
onStatusChange?.(this.status);
|
|
3990
|
+
reject(new SignatureRejectedError(result.error));
|
|
3991
|
+
}
|
|
3992
|
+
} else if (result) {
|
|
3993
|
+
if (this.status === "waiting" /* WAITING */) {
|
|
3994
|
+
this.status = "pending" /* PENDING */;
|
|
3995
|
+
onStatusChange?.(this.status);
|
|
3996
|
+
}
|
|
3997
|
+
this.pollTimer = setTimeout(poll, this.config.pollInterval);
|
|
3998
|
+
} else {
|
|
3999
|
+
this.pollTimer = setTimeout(poll, this.config.pollInterval);
|
|
4000
|
+
}
|
|
4001
|
+
} catch (error) {
|
|
4002
|
+
this.stopPolling();
|
|
4003
|
+
this.status = "failed" /* FAILED */;
|
|
4004
|
+
onStatusChange?.(this.status);
|
|
4005
|
+
reject(error);
|
|
4006
|
+
}
|
|
4007
|
+
};
|
|
4008
|
+
poll();
|
|
4009
|
+
});
|
|
1681
4010
|
}
|
|
1682
4011
|
/**
|
|
1683
|
-
*
|
|
4012
|
+
* 默认 HTTP 轮询函数
|
|
1684
4013
|
*/
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
4014
|
+
async defaultPoll(requestId) {
|
|
4015
|
+
if (!this.config.pollUrl) {
|
|
4016
|
+
return null;
|
|
4017
|
+
}
|
|
4018
|
+
try {
|
|
4019
|
+
const url = `${this.config.pollUrl}?requestId=${encodeURIComponent(requestId)}`;
|
|
4020
|
+
const response = await fetch(url, {
|
|
4021
|
+
method: "GET",
|
|
4022
|
+
headers: {
|
|
4023
|
+
"Content-Type": "application/json"
|
|
4024
|
+
}
|
|
4025
|
+
});
|
|
4026
|
+
if (!response.ok) {
|
|
4027
|
+
if (response.status === 404) {
|
|
4028
|
+
return null;
|
|
4029
|
+
}
|
|
4030
|
+
throw new NetworkError(`Poll request failed: ${response.statusText}`);
|
|
4031
|
+
}
|
|
4032
|
+
const data = await response.json();
|
|
4033
|
+
return {
|
|
4034
|
+
completed: data.completed === true,
|
|
4035
|
+
signature: data.signature,
|
|
4036
|
+
error: data.error,
|
|
4037
|
+
signer: data.signer
|
|
4038
|
+
};
|
|
4039
|
+
} catch (error) {
|
|
4040
|
+
if (error instanceof NetworkError) {
|
|
4041
|
+
throw error;
|
|
1691
4042
|
}
|
|
4043
|
+
return null;
|
|
1692
4044
|
}
|
|
1693
|
-
|
|
4045
|
+
}
|
|
4046
|
+
/**
|
|
4047
|
+
* 停止轮询
|
|
4048
|
+
*/
|
|
4049
|
+
stopPolling() {
|
|
4050
|
+
if (this.pollTimer) {
|
|
4051
|
+
clearTimeout(this.pollTimer);
|
|
4052
|
+
this.pollTimer = null;
|
|
4053
|
+
}
|
|
4054
|
+
if (this.timeoutTimer) {
|
|
4055
|
+
clearTimeout(this.timeoutTimer);
|
|
4056
|
+
this.timeoutTimer = null;
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
/**
|
|
4060
|
+
* 取消签名请求
|
|
4061
|
+
*/
|
|
4062
|
+
cancel() {
|
|
4063
|
+
this.stopPolling();
|
|
4064
|
+
this.status = "cancelled" /* CANCELLED */;
|
|
4065
|
+
}
|
|
4066
|
+
/**
|
|
4067
|
+
* 获取当前状态
|
|
4068
|
+
*/
|
|
4069
|
+
getStatus() {
|
|
4070
|
+
return this.status;
|
|
4071
|
+
}
|
|
4072
|
+
/**
|
|
4073
|
+
* 获取二维码 URL
|
|
4074
|
+
*/
|
|
4075
|
+
getQRCodeUrl() {
|
|
4076
|
+
return this.config.requestUrl;
|
|
4077
|
+
}
|
|
4078
|
+
/**
|
|
4079
|
+
* 获取结果
|
|
4080
|
+
*/
|
|
4081
|
+
getResult() {
|
|
4082
|
+
return this.result;
|
|
4083
|
+
}
|
|
4084
|
+
/**
|
|
4085
|
+
* 清理资源
|
|
4086
|
+
*/
|
|
4087
|
+
cleanup() {
|
|
4088
|
+
this.stopPolling();
|
|
4089
|
+
this.qrCodeDataUrl = null;
|
|
4090
|
+
this.result = null;
|
|
4091
|
+
this.status = "waiting" /* WAITING */;
|
|
1694
4092
|
}
|
|
1695
4093
|
};
|
|
1696
4094
|
|
|
@@ -1709,9 +4107,15 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1709
4107
|
defaultTronChainId: config.defaultTronChainId ?? 195,
|
|
1710
4108
|
walletConnectProjectId: config.walletConnectProjectId ?? ""
|
|
1711
4109
|
};
|
|
1712
|
-
this.registry = new AdapterRegistry();
|
|
4110
|
+
this.registry = new AdapterRegistry(this.config);
|
|
1713
4111
|
}
|
|
1714
4112
|
// ===== Connection Management =====
|
|
4113
|
+
/**
|
|
4114
|
+
* Check if adapter is registered for a wallet type
|
|
4115
|
+
*/
|
|
4116
|
+
hasAdapter(type) {
|
|
4117
|
+
return this.registry.has(type);
|
|
4118
|
+
}
|
|
1715
4119
|
/**
|
|
1716
4120
|
* Connect primary wallet
|
|
1717
4121
|
*/
|
|
@@ -1778,7 +4182,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1778
4182
|
this.connectedWallets.delete(chainType);
|
|
1779
4183
|
this.primaryWallet = null;
|
|
1780
4184
|
if (this.config.enableStorage) {
|
|
1781
|
-
this.
|
|
4185
|
+
this.clearStorage();
|
|
1782
4186
|
}
|
|
1783
4187
|
this.emit("disconnected");
|
|
1784
4188
|
}
|
|
@@ -1867,6 +4271,35 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1867
4271
|
}
|
|
1868
4272
|
return adapter.signMessage(message);
|
|
1869
4273
|
}
|
|
4274
|
+
/**
|
|
4275
|
+
* Create QR code signer for message signing
|
|
4276
|
+
*
|
|
4277
|
+
* This method creates a QR code signer that can be used to display a QR code
|
|
4278
|
+
* for users to scan with their wallet app to sign a message.
|
|
4279
|
+
*
|
|
4280
|
+
* @param message - Message to sign
|
|
4281
|
+
* @param config - QR code signer configuration
|
|
4282
|
+
* @returns QRCodeSigner instance
|
|
4283
|
+
*
|
|
4284
|
+
* @example
|
|
4285
|
+
* ```typescript
|
|
4286
|
+
* const signer = walletManager.createQRCodeSigner('Hello World', {
|
|
4287
|
+
* requestId: 'sign-123',
|
|
4288
|
+
* requestUrl: 'https://example.com/sign?requestId=sign-123&message=Hello%20World',
|
|
4289
|
+
* pollUrl: 'https://api.example.com/sign/status',
|
|
4290
|
+
* })
|
|
4291
|
+
*
|
|
4292
|
+
* const qrCodeUrl = await signer.generateQRCode()
|
|
4293
|
+
* const signature = await signer.startPolling()
|
|
4294
|
+
* ```
|
|
4295
|
+
*/
|
|
4296
|
+
createQRCodeSigner(message, config) {
|
|
4297
|
+
return new QRCodeSigner({
|
|
4298
|
+
...config,
|
|
4299
|
+
// Encode message in request URL if not already encoded
|
|
4300
|
+
requestUrl: config.requestUrl.includes(encodeURIComponent(message)) ? config.requestUrl : `${config.requestUrl}${config.requestUrl.includes("?") ? "&" : "?"}message=${encodeURIComponent(message)}`
|
|
4301
|
+
});
|
|
4302
|
+
}
|
|
1870
4303
|
/**
|
|
1871
4304
|
* Sign TypedData (EVM only)
|
|
1872
4305
|
*/
|
|
@@ -1931,6 +4364,41 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
1931
4364
|
throw error;
|
|
1932
4365
|
}
|
|
1933
4366
|
}
|
|
4367
|
+
/**
|
|
4368
|
+
* Request account switch (opens wallet account selector)
|
|
4369
|
+
* @param targetAddress Optional target address to verify after switching
|
|
4370
|
+
* @returns The new account after switching
|
|
4371
|
+
*/
|
|
4372
|
+
async requestSwitchAccount(targetAddress) {
|
|
4373
|
+
if (!this.primaryWallet) {
|
|
4374
|
+
throw new WalletNotConnectedError();
|
|
4375
|
+
}
|
|
4376
|
+
if (!this.primaryWallet.requestSwitchAccount) {
|
|
4377
|
+
throw new Error(`Account switching not supported by ${this.primaryWallet.type}`);
|
|
4378
|
+
}
|
|
4379
|
+
const account = await this.primaryWallet.requestSwitchAccount(targetAddress);
|
|
4380
|
+
if (this.config.enableStorage) {
|
|
4381
|
+
this.saveToStorage();
|
|
4382
|
+
}
|
|
4383
|
+
return account;
|
|
4384
|
+
}
|
|
4385
|
+
/**
|
|
4386
|
+
* Ensure the current account matches the target address
|
|
4387
|
+
* If not matching, request account switch
|
|
4388
|
+
* @param targetAddress The address that should be active
|
|
4389
|
+
* @returns The account (either existing or after switch)
|
|
4390
|
+
*/
|
|
4391
|
+
async ensureAccount(targetAddress) {
|
|
4392
|
+
const currentAccount = this.getPrimaryAccount();
|
|
4393
|
+
if (!currentAccount) {
|
|
4394
|
+
throw new WalletNotConnectedError();
|
|
4395
|
+
}
|
|
4396
|
+
if (currentAccount.nativeAddress.toLowerCase() === targetAddress.toLowerCase()) {
|
|
4397
|
+
return currentAccount;
|
|
4398
|
+
}
|
|
4399
|
+
console.log(`[WalletManager] Current account ${currentAccount.nativeAddress} doesn't match target ${targetAddress}, requesting switch...`);
|
|
4400
|
+
return this.requestSwitchAccount(targetAddress);
|
|
4401
|
+
}
|
|
1934
4402
|
// ===== Contract Calls =====
|
|
1935
4403
|
/**
|
|
1936
4404
|
* Read contract
|
|
@@ -2125,7 +4593,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
2125
4593
|
return null;
|
|
2126
4594
|
}
|
|
2127
4595
|
console.debug("[WalletManager] Wallet is available, attempting restoration");
|
|
2128
|
-
if (adapter.chainType === ChainType.EVM && data.primaryWalletType === "metamask" /* METAMASK */) {
|
|
4596
|
+
if (adapter.chainType === exports.ChainType.EVM && data.primaryWalletType === "metamask" /* METAMASK */) {
|
|
2129
4597
|
try {
|
|
2130
4598
|
const provider = typeof window !== "undefined" ? window.ethereum : null;
|
|
2131
4599
|
if (provider) {
|
|
@@ -2162,7 +4630,7 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
2162
4630
|
console.debug("Silent connection failed, trying normal connection:", silentError);
|
|
2163
4631
|
}
|
|
2164
4632
|
}
|
|
2165
|
-
if (adapter.chainType === ChainType.TRON && data.primaryWalletType === "tronlink" /* TRONLINK */) {
|
|
4633
|
+
if (adapter.chainType === exports.ChainType.TRON && data.primaryWalletType === "tronlink" /* TRONLINK */) {
|
|
2166
4634
|
try {
|
|
2167
4635
|
const tronWeb = adapter.getTronWeb?.();
|
|
2168
4636
|
if (tronWeb && tronWeb.defaultAddress?.base58) {
|
|
@@ -2177,6 +4645,29 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
2177
4645
|
console.debug("Silent TronLink connection failed:", silentError);
|
|
2178
4646
|
}
|
|
2179
4647
|
}
|
|
4648
|
+
if (data.primaryWalletType === "walletconnect-tron" /* WALLETCONNECT_TRON */) {
|
|
4649
|
+
try {
|
|
4650
|
+
const wcAdapter = adapter;
|
|
4651
|
+
if (typeof wcAdapter.restoreSession === "function") {
|
|
4652
|
+
console.debug("[WalletManager] Attempting to restore WalletConnect Tron session...");
|
|
4653
|
+
const account2 = await wcAdapter.restoreSession(data.primaryChainId);
|
|
4654
|
+
if (account2) {
|
|
4655
|
+
console.debug("[WalletManager] WalletConnect Tron session restored successfully");
|
|
4656
|
+
this.setPrimaryWallet(adapter);
|
|
4657
|
+
this.connectedWallets.set(adapter.chainType, adapter);
|
|
4658
|
+
this.setupAdapterListeners(adapter, true);
|
|
4659
|
+
this.emit("accountChanged", account2);
|
|
4660
|
+
return account2;
|
|
4661
|
+
} else {
|
|
4662
|
+
console.debug("[WalletManager] No valid WalletConnect Tron session found");
|
|
4663
|
+
return null;
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
} catch (restoreError) {
|
|
4667
|
+
console.debug("[WalletManager] WalletConnect Tron restore failed:", restoreError);
|
|
4668
|
+
return null;
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
2180
4671
|
const account = await adapter.connect(data.primaryChainId);
|
|
2181
4672
|
this.setPrimaryWallet(adapter);
|
|
2182
4673
|
this.connectedWallets.set(adapter.chainType, adapter);
|
|
@@ -2223,7 +4714,466 @@ var WalletManager = class extends TypedEventEmitter {
|
|
|
2223
4714
|
}
|
|
2224
4715
|
};
|
|
2225
4716
|
|
|
4717
|
+
// src/index.ts
|
|
4718
|
+
init_types();
|
|
4719
|
+
init_tokenpocket();
|
|
4720
|
+
init_tronlink();
|
|
4721
|
+
init_imtoken();
|
|
4722
|
+
init_metamask();
|
|
4723
|
+
init_okx();
|
|
4724
|
+
|
|
4725
|
+
// src/adapters/tron/deep-link.ts
|
|
4726
|
+
init_types();
|
|
4727
|
+
var DeepLinkWalletType = /* @__PURE__ */ ((DeepLinkWalletType2) => {
|
|
4728
|
+
DeepLinkWalletType2["TOKENPOCKET"] = "tokenpocket";
|
|
4729
|
+
DeepLinkWalletType2["TRONLINK"] = "tronlink";
|
|
4730
|
+
return DeepLinkWalletType2;
|
|
4731
|
+
})(DeepLinkWalletType || {});
|
|
4732
|
+
var _TronDeepLinkAdapter = class _TronDeepLinkAdapter extends WalletAdapter {
|
|
4733
|
+
constructor(walletType = "tokenpocket" /* TOKENPOCKET */, options) {
|
|
4734
|
+
super();
|
|
4735
|
+
this.type = "tronlink" /* TRONLINK */;
|
|
4736
|
+
// Reuse TRONLINK type for now
|
|
4737
|
+
this.chainType = exports.ChainType.TRON;
|
|
4738
|
+
this.pendingActions = /* @__PURE__ */ new Map();
|
|
4739
|
+
this.walletType = walletType;
|
|
4740
|
+
this.callbackUrl = options?.callbackUrl;
|
|
4741
|
+
this.callbackSchema = options?.callbackSchema;
|
|
4742
|
+
if (walletType === "tokenpocket" /* TOKENPOCKET */) {
|
|
4743
|
+
this.name = "TokenPocket (Deep Link)";
|
|
4744
|
+
this.icon = "https://tokenpocket.pro/icon.png";
|
|
4745
|
+
} else if (walletType === "tronlink" /* TRONLINK */) {
|
|
4746
|
+
this.name = "TronLink (Deep Link)";
|
|
4747
|
+
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
4748
|
+
} else {
|
|
4749
|
+
this.name = "TRON Deep Link";
|
|
4750
|
+
this.icon = "https://www.tronlink.org/static/logoIcon.svg";
|
|
4751
|
+
}
|
|
4752
|
+
if (walletType === "tokenpocket" /* TOKENPOCKET */ && typeof window !== "undefined") {
|
|
4753
|
+
this.setupCallbackHandler();
|
|
4754
|
+
}
|
|
4755
|
+
}
|
|
4756
|
+
/**
|
|
4757
|
+
* Setup callback handler for TokenPocket deep link results
|
|
4758
|
+
*
|
|
4759
|
+
* According to TokenPocket docs:
|
|
4760
|
+
* - callbackUrl: Wallet sends result to this URL (server-side callback)
|
|
4761
|
+
* - callbackSchema: Wallet launches H5 app through this schema (client-side callback)
|
|
4762
|
+
*
|
|
4763
|
+
* For H5 apps, we use callbackSchema to receive results in the same page
|
|
4764
|
+
*/
|
|
4765
|
+
setupCallbackHandler() {
|
|
4766
|
+
if (typeof window === "undefined") {
|
|
4767
|
+
return;
|
|
4768
|
+
}
|
|
4769
|
+
document.addEventListener("visibilitychange", () => {
|
|
4770
|
+
if (document.visibilityState === "visible") {
|
|
4771
|
+
console.log("[TronDeepLink] Page became visible, user may have returned from wallet app");
|
|
4772
|
+
this.checkCallbackFromUrl();
|
|
4773
|
+
}
|
|
4774
|
+
});
|
|
4775
|
+
this.checkCallbackFromUrl();
|
|
4776
|
+
}
|
|
4777
|
+
/**
|
|
4778
|
+
* Check if callback result is in URL parameters
|
|
4779
|
+
* TokenPocket may append callback results to URL when using callbackSchema
|
|
4780
|
+
*/
|
|
4781
|
+
checkCallbackFromUrl() {
|
|
4782
|
+
if (typeof window === "undefined") {
|
|
4783
|
+
return;
|
|
4784
|
+
}
|
|
4785
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
4786
|
+
const actionId = urlParams.get("actionId");
|
|
4787
|
+
const result = urlParams.get("result");
|
|
4788
|
+
const error = urlParams.get("error");
|
|
4789
|
+
if (actionId && this.pendingActions.has(actionId)) {
|
|
4790
|
+
const { resolve, reject } = this.pendingActions.get(actionId);
|
|
4791
|
+
if (error) {
|
|
4792
|
+
reject(new Error(error));
|
|
4793
|
+
} else if (result) {
|
|
4794
|
+
try {
|
|
4795
|
+
const parsedResult = JSON.parse(decodeURIComponent(result));
|
|
4796
|
+
resolve(parsedResult);
|
|
4797
|
+
} catch (e) {
|
|
4798
|
+
resolve(result);
|
|
4799
|
+
}
|
|
4800
|
+
}
|
|
4801
|
+
this.pendingActions.delete(actionId);
|
|
4802
|
+
const newUrl = window.location.pathname;
|
|
4803
|
+
window.history.replaceState({}, "", newUrl);
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4806
|
+
/**
|
|
4807
|
+
* Check if deep link is available (mobile device or Telegram Mini App)
|
|
4808
|
+
*
|
|
4809
|
+
* Note: In Telegram Mini App, we're more lenient - even if platform detection
|
|
4810
|
+
* fails, deep links may still work, so the caller should handle Telegram Mini App
|
|
4811
|
+
* separately if needed.
|
|
4812
|
+
*/
|
|
4813
|
+
async isAvailable() {
|
|
4814
|
+
if (typeof window === "undefined") {
|
|
4815
|
+
return false;
|
|
4816
|
+
}
|
|
4817
|
+
const isTelegramMiniApp = !!(window.Telegram && window.Telegram.WebApp);
|
|
4818
|
+
if (isTelegramMiniApp) {
|
|
4819
|
+
const platform = window.Telegram.WebApp.platform || "unknown";
|
|
4820
|
+
const version = window.Telegram.WebApp.version || "unknown";
|
|
4821
|
+
console.log(`[TronDeepLink] Telegram Mini App detected, platform: ${platform}, version: ${version}`);
|
|
4822
|
+
if (platform === "unknown") {
|
|
4823
|
+
const userAgent = navigator.userAgent || "";
|
|
4824
|
+
if (/iPhone|iPad|iPod/i.test(userAgent)) {
|
|
4825
|
+
console.log(`[TronDeepLink] Detected iOS from user agent`);
|
|
4826
|
+
} else if (/Android/i.test(userAgent)) {
|
|
4827
|
+
console.log(`[TronDeepLink] Detected Android from user agent`);
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
return true;
|
|
4831
|
+
}
|
|
4832
|
+
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
4833
|
+
navigator.userAgent
|
|
4834
|
+
);
|
|
4835
|
+
return isMobile;
|
|
4836
|
+
}
|
|
4837
|
+
/**
|
|
4838
|
+
* Connect wallet via deep link
|
|
4839
|
+
*
|
|
4840
|
+
* IMPORTANT: Deep links for TRON wallets are primarily for SIGNING, not connection.
|
|
4841
|
+
* TokenPocket and TronLink deep links support:
|
|
4842
|
+
* - Signing transactions: tron:signTransaction-version=1.0&protocol=TokenPocket&network=tron&chain_id=195&data={...}
|
|
4843
|
+
* - Signing messages: tron:signMessage-version=1.0&protocol=TokenPocket&network=tron&chain_id=195&data={...}
|
|
4844
|
+
*
|
|
4845
|
+
* For CONNECTION, you should use:
|
|
4846
|
+
* - WalletConnect (recommended for mobile)
|
|
4847
|
+
* - Browser extension (TronWeb/TronLink)
|
|
4848
|
+
*
|
|
4849
|
+
* Note: You can sign directly using signMessage() or signTransaction() without calling connect() first.
|
|
4850
|
+
* The wallet app will open and use the user's account automatically.
|
|
4851
|
+
*
|
|
4852
|
+
* This method attempts to open the wallet app, but cannot establish a connection
|
|
4853
|
+
* or retrieve the wallet address directly. The user must complete connection
|
|
4854
|
+
* through WalletConnect or browser extension after opening the app.
|
|
4855
|
+
*/
|
|
4856
|
+
async connect(chainId) {
|
|
4857
|
+
if (typeof window === "undefined") {
|
|
4858
|
+
throw new Error("Deep link requires a browser environment");
|
|
4859
|
+
}
|
|
4860
|
+
const targetChainId = Array.isArray(chainId) ? chainId[0] || _TronDeepLinkAdapter.TRON_MAINNET_CHAIN_ID : chainId || _TronDeepLinkAdapter.TRON_MAINNET_CHAIN_ID;
|
|
4861
|
+
try {
|
|
4862
|
+
this.setState("connecting" /* CONNECTING */);
|
|
4863
|
+
const isAvailable = await this.isAvailable();
|
|
4864
|
+
if (!isAvailable) {
|
|
4865
|
+
const isTelegram = !!(window.Telegram && window.Telegram.WebApp);
|
|
4866
|
+
if (isTelegram) {
|
|
4867
|
+
const platform = window.Telegram?.WebApp?.platform || "unknown";
|
|
4868
|
+
throw new Error(
|
|
4869
|
+
`Deep link is not available in Telegram Mini App on ${platform} platform. Please use WalletConnect or browser extension, or test on a mobile device.`
|
|
4870
|
+
);
|
|
4871
|
+
} else {
|
|
4872
|
+
throw new Error("Deep link is only available on mobile devices or Telegram Mini App. Please use WalletConnect or browser extension.");
|
|
4873
|
+
}
|
|
4874
|
+
}
|
|
4875
|
+
let deepLinkUrl = "";
|
|
4876
|
+
if (this.walletType === "tokenpocket" /* TOKENPOCKET */) {
|
|
4877
|
+
const actionId = `web-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
4878
|
+
const param = {
|
|
4879
|
+
action: "login",
|
|
4880
|
+
// Login action to open wallet
|
|
4881
|
+
actionId,
|
|
4882
|
+
blockchains: [{
|
|
4883
|
+
chainId: String(targetChainId),
|
|
4884
|
+
network: "tron"
|
|
4885
|
+
}],
|
|
4886
|
+
dappName: "Enclave Wallet SDK",
|
|
4887
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
4888
|
+
protocol: "TokenPocket",
|
|
4889
|
+
version: "1.0",
|
|
4890
|
+
expired: 1602
|
|
4891
|
+
// 30 minutes
|
|
4892
|
+
};
|
|
4893
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
4894
|
+
deepLinkUrl = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
4895
|
+
} else if (this.walletType === "tronlink" /* TRONLINK */) {
|
|
4896
|
+
deepLinkUrl = `tronlink://open?action=connect&network=tron`;
|
|
4897
|
+
}
|
|
4898
|
+
if (!deepLinkUrl) {
|
|
4899
|
+
throw new Error(`Unsupported wallet type: ${this.walletType}`);
|
|
4900
|
+
}
|
|
4901
|
+
console.log(`[TronDeepLink] ===== Connect via Deep Link =====`);
|
|
4902
|
+
console.log(`[TronDeepLink] Wallet Type:`, this.walletType);
|
|
4903
|
+
console.log(`[TronDeepLink] Chain ID:`, targetChainId);
|
|
4904
|
+
console.log(`[TronDeepLink] Deep Link URL:`, deepLinkUrl);
|
|
4905
|
+
console.log(`[TronDeepLink] Note: Deep links are for signing, not connection. After opening the app, please use WalletConnect to establish connection.`);
|
|
4906
|
+
console.log(`[TronDeepLink] ==================================`);
|
|
4907
|
+
window.location.href = deepLinkUrl;
|
|
4908
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
4909
|
+
throw new ConnectionRejectedError(
|
|
4910
|
+
`\u5DF2\u6253\u5F00 ${this.walletType === "tokenpocket" /* TOKENPOCKET */ ? "TokenPocket" : "TronLink"} \u5E94\u7528\u3002
|
|
4911
|
+
|
|
4912
|
+
\u6CE8\u610F\uFF1A\u6DF1\u5EA6\u94FE\u63A5\u4E3B\u8981\u7528\u4E8E\u7B7E\u540D\u4EA4\u6613\uFF0C\u4E0D\u80FD\u76F4\u63A5\u5EFA\u7ACB\u8FDE\u63A5\u3002
|
|
4913
|
+
|
|
4914
|
+
\u8BF7\u4F7F\u7528\u4EE5\u4E0B\u65B9\u5F0F\u5B8C\u6210\u8FDE\u63A5\uFF1A
|
|
4915
|
+
1. \u5728\u94B1\u5305\u5E94\u7528\u4E2D\u4F7F\u7528 WalletConnect \u626B\u63CF\u4E8C\u7EF4\u7801
|
|
4916
|
+
2. \u6216\u4F7F\u7528\u6D4F\u89C8\u5668\u6269\u5C55\uFF08\u5982 TronLink\uFF09\u8FDE\u63A5
|
|
4917
|
+
|
|
4918
|
+
Deep link opened ${this.walletType} app. Please use WalletConnect or browser extension to complete the connection.`
|
|
4919
|
+
);
|
|
4920
|
+
} catch (error) {
|
|
4921
|
+
this.setState("error" /* ERROR */);
|
|
4922
|
+
this.setAccount(null);
|
|
4923
|
+
if (error instanceof ConnectionRejectedError) {
|
|
4924
|
+
throw error;
|
|
4925
|
+
}
|
|
4926
|
+
throw new Error(`Failed to open ${this.walletType} via deep link: ${error.message}`);
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
/**
|
|
4930
|
+
* Disconnect wallet
|
|
4931
|
+
*/
|
|
4932
|
+
async disconnect() {
|
|
4933
|
+
this.setState("disconnected" /* DISCONNECTED */);
|
|
4934
|
+
this.setAccount(null);
|
|
4935
|
+
}
|
|
4936
|
+
/**
|
|
4937
|
+
* Sign message via deep link
|
|
4938
|
+
*
|
|
4939
|
+
* TokenPocket deep link format for signing:
|
|
4940
|
+
* tron:signMessage-version=1.0&protocol=TokenPocket&network=tron&chain_id=195&data={message}
|
|
4941
|
+
*
|
|
4942
|
+
* Reference: https://help.tokenpocket.pro/developer-cn/scan-protocol/tron
|
|
4943
|
+
*
|
|
4944
|
+
* Note: Deep links can sign directly without establishing a connection first.
|
|
4945
|
+
* The wallet app will open and use the user's account to sign the message.
|
|
4946
|
+
* The signature result will be returned via callback URL or app-to-app communication.
|
|
4947
|
+
*/
|
|
4948
|
+
async signMessage(message) {
|
|
4949
|
+
if (typeof window === "undefined") {
|
|
4950
|
+
throw new Error("Deep link requires a browser environment");
|
|
4951
|
+
}
|
|
4952
|
+
const isAvailable = await this.isAvailable();
|
|
4953
|
+
if (!isAvailable) {
|
|
4954
|
+
const isTelegram = !!(window.Telegram && window.Telegram.WebApp);
|
|
4955
|
+
if (isTelegram) {
|
|
4956
|
+
const platform = window.Telegram?.WebApp?.platform || "unknown";
|
|
4957
|
+
throw new Error(
|
|
4958
|
+
`Deep link signing is not available in Telegram Mini App on ${platform} platform. Please use WalletConnect or test on a mobile device.`
|
|
4959
|
+
);
|
|
4960
|
+
} else {
|
|
4961
|
+
throw new Error("Deep link signing is only available on mobile devices or Telegram Mini App.");
|
|
4962
|
+
}
|
|
4963
|
+
}
|
|
4964
|
+
let deepLinkUrl = "";
|
|
4965
|
+
if (this.walletType === "tokenpocket" /* TOKENPOCKET */) {
|
|
4966
|
+
const actionId = `web-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
4967
|
+
const param = {
|
|
4968
|
+
action: "sign",
|
|
4969
|
+
actionId,
|
|
4970
|
+
message,
|
|
4971
|
+
hash: false,
|
|
4972
|
+
signType: "ethPersonalSign",
|
|
4973
|
+
// For TRON, we use ethPersonalSign as it's similar
|
|
4974
|
+
memo: "TRON message signature",
|
|
4975
|
+
blockchains: [{
|
|
4976
|
+
chainId: "195",
|
|
4977
|
+
// TRON Mainnet chain ID as string
|
|
4978
|
+
network: "tron"
|
|
4979
|
+
}],
|
|
4980
|
+
dappName: "Enclave Wallet SDK",
|
|
4981
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
4982
|
+
protocol: "TokenPocket",
|
|
4983
|
+
version: "1.1.8",
|
|
4984
|
+
expired: 0
|
|
4985
|
+
// No expiration
|
|
4986
|
+
// callbackUrl: optional, if you want to receive callback
|
|
4987
|
+
// callbackSchema: optional, custom schema for callback
|
|
4988
|
+
};
|
|
4989
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
4990
|
+
deepLinkUrl = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
4991
|
+
console.log(`[TronDeepLink] Using TokenPocket tpoutside:// format for signMessage`);
|
|
4992
|
+
console.log(`[TronDeepLink] Param object:`, param);
|
|
4993
|
+
} else if (this.walletType === "tronlink" /* TRONLINK */) {
|
|
4994
|
+
const encodedMessage = encodeURIComponent(message);
|
|
4995
|
+
deepLinkUrl = `tronlink://signMessage?message=${encodedMessage}`;
|
|
4996
|
+
}
|
|
4997
|
+
if (!deepLinkUrl) {
|
|
4998
|
+
throw new MethodNotSupportedError("signMessage", this.type);
|
|
4999
|
+
}
|
|
5000
|
+
console.log(`[TronDeepLink] ===== Sign Message via Deep Link =====`);
|
|
5001
|
+
console.log(`[TronDeepLink] Wallet Type:`, this.walletType);
|
|
5002
|
+
console.log(`[TronDeepLink] Message:`, message);
|
|
5003
|
+
console.log(`[TronDeepLink] Deep Link URL:`, deepLinkUrl);
|
|
5004
|
+
console.log(`[TronDeepLink] Full URL length:`, deepLinkUrl.length);
|
|
5005
|
+
console.log(`[TronDeepLink] ========================================`);
|
|
5006
|
+
window.location.href = deepLinkUrl;
|
|
5007
|
+
throw new Error(
|
|
5008
|
+
`Deep link opened ${this.walletType} for signing. The signature will be handled by the wallet app. This adapter cannot retrieve the signature directly from deep links. Consider using WalletConnect or browser extension for programmatic signing.`
|
|
5009
|
+
);
|
|
5010
|
+
}
|
|
5011
|
+
/**
|
|
5012
|
+
* Sign transaction via deep link
|
|
5013
|
+
*
|
|
5014
|
+
* TokenPocket deep link format:
|
|
5015
|
+
* tron:signTransaction-version=1.0&protocol=TokenPocket&network=tron&chain_id=195&data={transaction}
|
|
5016
|
+
*
|
|
5017
|
+
* Reference: https://help.tokenpocket.pro/developer-cn/scan-protocol/tron
|
|
5018
|
+
*
|
|
5019
|
+
* Note: Deep links can sign directly without establishing a connection first.
|
|
5020
|
+
* The wallet app will open and use the user's account to sign the transaction.
|
|
5021
|
+
* The transaction data should be a JSON string containing the TRON transaction object.
|
|
5022
|
+
* The signature result will be returned via callback URL or app-to-app communication.
|
|
5023
|
+
*/
|
|
5024
|
+
async signTransaction(transaction) {
|
|
5025
|
+
if (typeof window === "undefined") {
|
|
5026
|
+
throw new Error("Deep link requires a browser environment");
|
|
5027
|
+
}
|
|
5028
|
+
const isAvailable = await this.isAvailable();
|
|
5029
|
+
if (!isAvailable) {
|
|
5030
|
+
const isTelegram = !!(window.Telegram && window.Telegram.WebApp);
|
|
5031
|
+
if (isTelegram) {
|
|
5032
|
+
const platform = window.Telegram?.WebApp?.platform || "unknown";
|
|
5033
|
+
throw new Error(
|
|
5034
|
+
`Deep link signing is not available in Telegram Mini App on ${platform} platform. Please use WalletConnect or test on a mobile device.`
|
|
5035
|
+
);
|
|
5036
|
+
} else {
|
|
5037
|
+
throw new Error("Deep link signing is only available on mobile devices or Telegram Mini App.");
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
let deepLinkUrl = "";
|
|
5041
|
+
let actionId = "";
|
|
5042
|
+
let param = null;
|
|
5043
|
+
if (this.walletType === "tokenpocket" /* TOKENPOCKET */) {
|
|
5044
|
+
actionId = `web-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
5045
|
+
let transactionData;
|
|
5046
|
+
if (typeof transaction === "string") {
|
|
5047
|
+
transactionData = transaction;
|
|
5048
|
+
} else if (transaction.raw_data_hex) {
|
|
5049
|
+
transactionData = JSON.stringify(transaction);
|
|
5050
|
+
} else {
|
|
5051
|
+
transactionData = JSON.stringify(transaction);
|
|
5052
|
+
}
|
|
5053
|
+
param = {
|
|
5054
|
+
action: "pushTransaction",
|
|
5055
|
+
actionId,
|
|
5056
|
+
txData: transactionData,
|
|
5057
|
+
// Transaction data as JSON string
|
|
5058
|
+
blockchains: [{
|
|
5059
|
+
chainId: "195",
|
|
5060
|
+
// TRON Mainnet chain ID as string
|
|
5061
|
+
network: "tron"
|
|
5062
|
+
}],
|
|
5063
|
+
dappName: "Enclave Wallet SDK",
|
|
5064
|
+
dappIcon: "https://walletconnect.com/walletconnect-logo.svg",
|
|
5065
|
+
protocol: "TokenPocket",
|
|
5066
|
+
version: "1.1.8",
|
|
5067
|
+
expired: 0
|
|
5068
|
+
// No expiration
|
|
5069
|
+
};
|
|
5070
|
+
if (this.callbackSchema) {
|
|
5071
|
+
param.callbackSchema = this.callbackSchema;
|
|
5072
|
+
} else if (this.callbackUrl) {
|
|
5073
|
+
param.callbackUrl = this.callbackUrl;
|
|
5074
|
+
} else {
|
|
5075
|
+
if (typeof window !== "undefined" && window.location) {
|
|
5076
|
+
param.callbackSchema = `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
|
5077
|
+
}
|
|
5078
|
+
}
|
|
5079
|
+
const encodedParam = encodeURIComponent(JSON.stringify(param));
|
|
5080
|
+
deepLinkUrl = `tpoutside://pull.activity?param=${encodedParam}`;
|
|
5081
|
+
console.log(`[TronDeepLink] Using TokenPocket tpoutside:// format for signTransaction`);
|
|
5082
|
+
console.log(`[TronDeepLink] Param object (without txData):`, { ...param, txData: "[TRANSACTION DATA]" });
|
|
5083
|
+
} else if (this.walletType === "tronlink" /* TRONLINK */) {
|
|
5084
|
+
const transactionData = typeof transaction === "string" ? transaction : JSON.stringify(transaction);
|
|
5085
|
+
const encodedData = encodeURIComponent(transactionData);
|
|
5086
|
+
deepLinkUrl = `tronlink://signTransaction?transaction=${encodedData}`;
|
|
5087
|
+
}
|
|
5088
|
+
if (!deepLinkUrl) {
|
|
5089
|
+
throw new MethodNotSupportedError("signTransaction", this.type);
|
|
5090
|
+
}
|
|
5091
|
+
console.log(`[TronDeepLink] ===== Sign Transaction via Deep Link =====`);
|
|
5092
|
+
console.log(`[TronDeepLink] Wallet Type:`, this.walletType);
|
|
5093
|
+
console.log(`[TronDeepLink] Transaction:`, transaction);
|
|
5094
|
+
console.log(`[TronDeepLink] Transaction keys:`, transaction ? Object.keys(transaction) : "N/A");
|
|
5095
|
+
if (transaction && typeof transaction === "object") {
|
|
5096
|
+
console.log(`[TronDeepLink] Transaction has raw_data:`, !!transaction.raw_data);
|
|
5097
|
+
console.log(`[TronDeepLink] Transaction has raw_data_hex:`, !!transaction.raw_data_hex);
|
|
5098
|
+
console.log(`[TronDeepLink] Transaction has txID:`, !!transaction.txID);
|
|
5099
|
+
}
|
|
5100
|
+
if (actionId) {
|
|
5101
|
+
console.log(`[TronDeepLink] Action ID:`, actionId);
|
|
5102
|
+
}
|
|
5103
|
+
if (param) {
|
|
5104
|
+
console.log(`[TronDeepLink] Callback Schema:`, param.callbackSchema || param.callbackUrl || "None");
|
|
5105
|
+
}
|
|
5106
|
+
console.log(`[TronDeepLink] Deep Link URL:`, deepLinkUrl);
|
|
5107
|
+
console.log(`[TronDeepLink] Full URL length:`, deepLinkUrl.length);
|
|
5108
|
+
if (deepLinkUrl.length > 200) {
|
|
5109
|
+
console.log(`[TronDeepLink] URL (first 200 chars):`, deepLinkUrl.substring(0, 200) + "...");
|
|
5110
|
+
console.log(`[TronDeepLink] URL (last 100 chars):`, "..." + deepLinkUrl.substring(deepLinkUrl.length - 100));
|
|
5111
|
+
}
|
|
5112
|
+
console.log(`[TronDeepLink] ===========================================`);
|
|
5113
|
+
if (this.walletType === "tokenpocket" /* TOKENPOCKET */ && param && param.callbackSchema) {
|
|
5114
|
+
return new Promise((resolve, reject) => {
|
|
5115
|
+
this.pendingActions.set(actionId, { resolve, reject });
|
|
5116
|
+
window.location.href = deepLinkUrl;
|
|
5117
|
+
setTimeout(() => {
|
|
5118
|
+
if (this.pendingActions.has(actionId)) {
|
|
5119
|
+
this.pendingActions.delete(actionId);
|
|
5120
|
+
reject(new Error("Transaction signature timeout: No response from wallet app"));
|
|
5121
|
+
}
|
|
5122
|
+
}, 3e4);
|
|
5123
|
+
});
|
|
5124
|
+
}
|
|
5125
|
+
window.location.href = deepLinkUrl;
|
|
5126
|
+
throw new SignatureRejectedError(
|
|
5127
|
+
`\u5DF2\u6253\u5F00 ${this.walletType === "tokenpocket" /* TOKENPOCKET */ ? "TokenPocket" : "TronLink"} \u8FDB\u884C\u4EA4\u6613\u7B7E\u540D\u3002
|
|
5128
|
+
|
|
5129
|
+
\u6CE8\u610F\uFF1A\u6DF1\u5EA6\u94FE\u63A5\u65E0\u6CD5\u76F4\u63A5\u8FD4\u56DE\u7B7E\u540D\u7ED3\u679C\u3002
|
|
5130
|
+
|
|
5131
|
+
\u7B7E\u540D\u7ED3\u679C\u5C06\u901A\u8FC7\u4EE5\u4E0B\u65B9\u5F0F\u8FD4\u56DE\uFF1A
|
|
5132
|
+
1. \u94B1\u5305\u5E94\u7528\u7684\u56DE\u8C03 URL
|
|
5133
|
+
2. \u5E94\u7528\u95F4\u901A\u4FE1\uFF08App-to-App\uFF09
|
|
5134
|
+
|
|
5135
|
+
\u5982\u9700\u7A0B\u5E8F\u5316\u83B7\u53D6\u7B7E\u540D\uFF0C\u8BF7\u4F7F\u7528 WalletConnect \u6216\u6D4F\u89C8\u5668\u6269\u5C55\u3002
|
|
5136
|
+
|
|
5137
|
+
Deep link opened ${this.walletType} for transaction signing. The signature will be handled by the wallet app via callback. For programmatic signing, use WalletConnect or browser extension.`
|
|
5138
|
+
);
|
|
5139
|
+
}
|
|
5140
|
+
/**
|
|
5141
|
+
* Read contract (not supported via deep link)
|
|
5142
|
+
*/
|
|
5143
|
+
async readContract(_params) {
|
|
5144
|
+
throw new MethodNotSupportedError("readContract", this.type);
|
|
5145
|
+
}
|
|
5146
|
+
/**
|
|
5147
|
+
* Write contract (not supported via deep link)
|
|
5148
|
+
*/
|
|
5149
|
+
async writeContract(_params) {
|
|
5150
|
+
throw new MethodNotSupportedError("writeContract", this.type);
|
|
5151
|
+
}
|
|
5152
|
+
/**
|
|
5153
|
+
* Estimate gas (not supported)
|
|
5154
|
+
*/
|
|
5155
|
+
async estimateGas(_params) {
|
|
5156
|
+
throw new MethodNotSupportedError("estimateGas", this.type);
|
|
5157
|
+
}
|
|
5158
|
+
/**
|
|
5159
|
+
* Wait for transaction (not supported)
|
|
5160
|
+
*/
|
|
5161
|
+
async waitForTransaction(_txHash, _confirmations) {
|
|
5162
|
+
throw new MethodNotSupportedError("waitForTransaction", this.type);
|
|
5163
|
+
}
|
|
5164
|
+
/**
|
|
5165
|
+
* Get provider (not applicable for deep links)
|
|
5166
|
+
*/
|
|
5167
|
+
getProvider() {
|
|
5168
|
+
return null;
|
|
5169
|
+
}
|
|
5170
|
+
};
|
|
5171
|
+
// TRON Mainnet chain ID
|
|
5172
|
+
_TronDeepLinkAdapter.TRON_MAINNET_CHAIN_ID = 195;
|
|
5173
|
+
var TronDeepLinkAdapter = _TronDeepLinkAdapter;
|
|
5174
|
+
|
|
2226
5175
|
// src/auth/message-generator.ts
|
|
5176
|
+
init_types();
|
|
2227
5177
|
var AuthMessageGenerator = class {
|
|
2228
5178
|
constructor(domain) {
|
|
2229
5179
|
this.domain = domain;
|
|
@@ -2233,7 +5183,7 @@ var AuthMessageGenerator = class {
|
|
|
2233
5183
|
*/
|
|
2234
5184
|
generateAuthMessage(chainType, nonce, chainId, timestamp = Date.now(), statement) {
|
|
2235
5185
|
switch (chainType) {
|
|
2236
|
-
case ChainType.EVM:
|
|
5186
|
+
case exports.ChainType.EVM:
|
|
2237
5187
|
return this.generateEIP191Message({
|
|
2238
5188
|
domain: this.domain,
|
|
2239
5189
|
nonce,
|
|
@@ -2241,7 +5191,7 @@ var AuthMessageGenerator = class {
|
|
|
2241
5191
|
timestamp,
|
|
2242
5192
|
statement
|
|
2243
5193
|
});
|
|
2244
|
-
case ChainType.TRON:
|
|
5194
|
+
case exports.ChainType.TRON:
|
|
2245
5195
|
return this.generateTIP191Message({
|
|
2246
5196
|
domain: this.domain,
|
|
2247
5197
|
nonce,
|
|
@@ -2298,15 +5248,18 @@ var AuthMessageGenerator = class {
|
|
|
2298
5248
|
return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
2299
5249
|
}
|
|
2300
5250
|
};
|
|
5251
|
+
|
|
5252
|
+
// src/auth/signature-verifier.ts
|
|
5253
|
+
init_types();
|
|
2301
5254
|
var SignatureVerifier = class {
|
|
2302
5255
|
/**
|
|
2303
5256
|
* 验证签名
|
|
2304
5257
|
*/
|
|
2305
5258
|
async verifySignature(message, signature, expectedAddress, chainType) {
|
|
2306
5259
|
switch (chainType) {
|
|
2307
|
-
case ChainType.EVM:
|
|
5260
|
+
case exports.ChainType.EVM:
|
|
2308
5261
|
return this.verifyEIP191Signature(message, signature, expectedAddress);
|
|
2309
|
-
case ChainType.TRON:
|
|
5262
|
+
case exports.ChainType.TRON:
|
|
2310
5263
|
return this.verifyTIP191Signature(message, signature, expectedAddress);
|
|
2311
5264
|
default:
|
|
2312
5265
|
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
@@ -2339,12 +5292,16 @@ var SignatureVerifier = class {
|
|
|
2339
5292
|
}
|
|
2340
5293
|
};
|
|
2341
5294
|
|
|
5295
|
+
// src/detection/detector.ts
|
|
5296
|
+
init_types();
|
|
5297
|
+
|
|
2342
5298
|
// src/detection/supported-wallets.ts
|
|
5299
|
+
init_types();
|
|
2343
5300
|
var SUPPORTED_WALLETS = {
|
|
2344
5301
|
["metamask" /* METAMASK */]: {
|
|
2345
5302
|
type: "metamask" /* METAMASK */,
|
|
2346
5303
|
name: "MetaMask",
|
|
2347
|
-
chainType: ChainType.EVM,
|
|
5304
|
+
chainType: exports.ChainType.EVM,
|
|
2348
5305
|
icon: "https://upload.wikimedia.org/wikipedia/commons/3/36/MetaMask_Fox.svg",
|
|
2349
5306
|
downloadUrl: "https://metamask.io/download/",
|
|
2350
5307
|
description: "The most popular Ethereum wallet"
|
|
@@ -2352,7 +5309,7 @@ var SUPPORTED_WALLETS = {
|
|
|
2352
5309
|
["walletconnect" /* WALLETCONNECT */]: {
|
|
2353
5310
|
type: "walletconnect" /* WALLETCONNECT */,
|
|
2354
5311
|
name: "WalletConnect",
|
|
2355
|
-
chainType: ChainType.EVM,
|
|
5312
|
+
chainType: exports.ChainType.EVM,
|
|
2356
5313
|
icon: "https://avatars.githubusercontent.com/u/37784886",
|
|
2357
5314
|
downloadUrl: "https://walletconnect.com/",
|
|
2358
5315
|
description: "Connect to 170+ wallets"
|
|
@@ -2360,7 +5317,7 @@ var SUPPORTED_WALLETS = {
|
|
|
2360
5317
|
["coinbase-wallet" /* COINBASE_WALLET */]: {
|
|
2361
5318
|
type: "coinbase-wallet" /* COINBASE_WALLET */,
|
|
2362
5319
|
name: "Coinbase Wallet",
|
|
2363
|
-
chainType: ChainType.EVM,
|
|
5320
|
+
chainType: exports.ChainType.EVM,
|
|
2364
5321
|
icon: "https://www.coinbase.com/img/favicon/favicon-96x96.png",
|
|
2365
5322
|
downloadUrl: "https://www.coinbase.com/wallet",
|
|
2366
5323
|
description: "Coinbase self-custody wallet"
|
|
@@ -2368,7 +5325,7 @@ var SUPPORTED_WALLETS = {
|
|
|
2368
5325
|
["tronlink" /* TRONLINK */]: {
|
|
2369
5326
|
type: "tronlink" /* TRONLINK */,
|
|
2370
5327
|
name: "TronWeb",
|
|
2371
|
-
chainType: ChainType.TRON,
|
|
5328
|
+
chainType: exports.ChainType.TRON,
|
|
2372
5329
|
icon: "https://www.tronlink.org/static/logoIcon.svg",
|
|
2373
5330
|
downloadUrl: "https://www.tronlink.org/",
|
|
2374
5331
|
description: "TronWeb \u517C\u5BB9\u94B1\u5305\uFF08\u652F\u6301 TronLink\u3001TokenPocket \u7B49\uFF09"
|
|
@@ -2376,16 +5333,30 @@ var SUPPORTED_WALLETS = {
|
|
|
2376
5333
|
["walletconnect-tron" /* WALLETCONNECT_TRON */]: {
|
|
2377
5334
|
type: "walletconnect-tron" /* WALLETCONNECT_TRON */,
|
|
2378
5335
|
name: "WalletConnect (Tron)",
|
|
2379
|
-
chainType: ChainType.TRON,
|
|
5336
|
+
chainType: exports.ChainType.TRON,
|
|
2380
5337
|
downloadUrl: "https://walletconnect.com/",
|
|
2381
5338
|
description: "WalletConnect for Tron"
|
|
2382
5339
|
},
|
|
2383
5340
|
["private-key" /* PRIVATE_KEY */]: {
|
|
2384
5341
|
type: "private-key" /* PRIVATE_KEY */,
|
|
2385
5342
|
name: "Private Key",
|
|
2386
|
-
chainType: ChainType.EVM,
|
|
5343
|
+
chainType: exports.ChainType.EVM,
|
|
2387
5344
|
// 可以用于任何链
|
|
2388
5345
|
description: "Import wallet using private key (for development)"
|
|
5346
|
+
},
|
|
5347
|
+
["deep-link-evm" /* DEEP_LINK_EVM */]: {
|
|
5348
|
+
type: "deep-link-evm" /* DEEP_LINK_EVM */,
|
|
5349
|
+
name: "Deep Link (EVM)",
|
|
5350
|
+
chainType: exports.ChainType.EVM,
|
|
5351
|
+
icon: "https://tokenpocket.pro/icon.png",
|
|
5352
|
+
description: "Deep link connection for EVM chains (TokenPocket, ImToken, etc.)"
|
|
5353
|
+
},
|
|
5354
|
+
["deep-link-tron" /* DEEP_LINK_TRON */]: {
|
|
5355
|
+
type: "deep-link-tron" /* DEEP_LINK_TRON */,
|
|
5356
|
+
name: "Deep Link (TRON)",
|
|
5357
|
+
chainType: exports.ChainType.TRON,
|
|
5358
|
+
icon: "https://tokenpocket.pro/icon.png",
|
|
5359
|
+
description: "Deep link connection for TRON chain (TokenPocket, TronLink, etc.)"
|
|
2389
5360
|
}
|
|
2390
5361
|
};
|
|
2391
5362
|
function getWalletMetadata(type) {
|
|
@@ -2393,12 +5364,12 @@ function getWalletMetadata(type) {
|
|
|
2393
5364
|
}
|
|
2394
5365
|
function getEVMWallets() {
|
|
2395
5366
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
2396
|
-
(wallet) => wallet.chainType === ChainType.EVM
|
|
5367
|
+
(wallet) => wallet.chainType === exports.ChainType.EVM
|
|
2397
5368
|
);
|
|
2398
5369
|
}
|
|
2399
5370
|
function getTronWallets() {
|
|
2400
5371
|
return Object.values(SUPPORTED_WALLETS).filter(
|
|
2401
|
-
(wallet) => wallet.chainType === ChainType.TRON
|
|
5372
|
+
(wallet) => wallet.chainType === exports.ChainType.TRON
|
|
2402
5373
|
);
|
|
2403
5374
|
}
|
|
2404
5375
|
|
|
@@ -2408,7 +5379,7 @@ var WalletDetector = class {
|
|
|
2408
5379
|
* Detect all wallet availability
|
|
2409
5380
|
*/
|
|
2410
5381
|
async detectAllWallets() {
|
|
2411
|
-
const walletTypes = Object.values(WalletType).filter(
|
|
5382
|
+
const walletTypes = Object.values(exports.WalletType).filter(
|
|
2412
5383
|
(type) => type !== "private-key" /* PRIVATE_KEY */
|
|
2413
5384
|
// Private key wallet does not need detection
|
|
2414
5385
|
);
|
|
@@ -2425,7 +5396,7 @@ var WalletDetector = class {
|
|
|
2425
5396
|
if (!metadata) {
|
|
2426
5397
|
return {
|
|
2427
5398
|
walletType,
|
|
2428
|
-
chainType: ChainType.EVM,
|
|
5399
|
+
chainType: exports.ChainType.EVM,
|
|
2429
5400
|
// Default
|
|
2430
5401
|
isAvailable: false,
|
|
2431
5402
|
detected: false
|
|
@@ -2533,11 +5504,12 @@ function shortenTronAddress(address, chars = 4) {
|
|
|
2533
5504
|
}
|
|
2534
5505
|
|
|
2535
5506
|
// src/utils/validation.ts
|
|
5507
|
+
init_types();
|
|
2536
5508
|
function validateAddress(address, chainType) {
|
|
2537
5509
|
switch (chainType) {
|
|
2538
|
-
case ChainType.EVM:
|
|
5510
|
+
case exports.ChainType.EVM:
|
|
2539
5511
|
return isValidEVMAddress(address);
|
|
2540
|
-
case ChainType.TRON:
|
|
5512
|
+
case exports.ChainType.TRON:
|
|
2541
5513
|
return isValidTronAddress(address);
|
|
2542
5514
|
default:
|
|
2543
5515
|
return false;
|
|
@@ -2558,9 +5530,9 @@ function isValidSignature(signature) {
|
|
|
2558
5530
|
}
|
|
2559
5531
|
function isValidTransactionHash(txHash, chainType) {
|
|
2560
5532
|
switch (chainType) {
|
|
2561
|
-
case ChainType.EVM:
|
|
5533
|
+
case exports.ChainType.EVM:
|
|
2562
5534
|
return /^0x[0-9a-fA-F]{64}$/.test(txHash);
|
|
2563
|
-
case ChainType.TRON:
|
|
5535
|
+
case exports.ChainType.TRON:
|
|
2564
5536
|
return /^[0-9a-fA-F]{64}$/.test(txHash);
|
|
2565
5537
|
default:
|
|
2566
5538
|
return false;
|
|
@@ -2607,26 +5579,30 @@ exports.AuthMessageGenerator = AuthMessageGenerator;
|
|
|
2607
5579
|
exports.BrowserWalletAdapter = BrowserWalletAdapter;
|
|
2608
5580
|
exports.CHAIN_INFO = CHAIN_INFO;
|
|
2609
5581
|
exports.ChainNotSupportedError = ChainNotSupportedError;
|
|
2610
|
-
exports.ChainType = ChainType;
|
|
2611
5582
|
exports.ConfigurationError = ConfigurationError;
|
|
2612
5583
|
exports.ConnectionRejectedError = ConnectionRejectedError;
|
|
5584
|
+
exports.DeepLinkAdapter = DeepLinkAdapter;
|
|
5585
|
+
exports.DeepLinkProviderType = DeepLinkProviderType;
|
|
5586
|
+
exports.DeepLinkWalletType = DeepLinkWalletType;
|
|
2613
5587
|
exports.EVMPrivateKeyAdapter = EVMPrivateKeyAdapter;
|
|
2614
5588
|
exports.MetaMaskAdapter = MetaMaskAdapter;
|
|
2615
5589
|
exports.MethodNotSupportedError = MethodNotSupportedError;
|
|
2616
5590
|
exports.NetworkError = NetworkError;
|
|
5591
|
+
exports.QRCodeSignStatus = QRCodeSignStatus;
|
|
5592
|
+
exports.QRCodeSigner = QRCodeSigner;
|
|
2617
5593
|
exports.SUPPORTED_WALLETS = SUPPORTED_WALLETS;
|
|
2618
5594
|
exports.SignatureRejectedError = SignatureRejectedError;
|
|
2619
5595
|
exports.SignatureVerifier = SignatureVerifier;
|
|
2620
5596
|
exports.TransactionFailedError = TransactionFailedError;
|
|
5597
|
+
exports.TronDeepLinkAdapter = TronDeepLinkAdapter;
|
|
2621
5598
|
exports.TronLinkAdapter = TronLinkAdapter;
|
|
2622
5599
|
exports.WalletAdapter = WalletAdapter;
|
|
5600
|
+
exports.WalletConnectAdapter = WalletConnectAdapter;
|
|
2623
5601
|
exports.WalletDetector = WalletDetector;
|
|
2624
5602
|
exports.WalletManager = WalletManager;
|
|
2625
5603
|
exports.WalletNotAvailableError = WalletNotAvailableError;
|
|
2626
5604
|
exports.WalletNotConnectedError = WalletNotConnectedError;
|
|
2627
5605
|
exports.WalletSDKError = WalletSDKError;
|
|
2628
|
-
exports.WalletState = WalletState;
|
|
2629
|
-
exports.WalletType = WalletType;
|
|
2630
5606
|
exports.compareEVMAddresses = compareEVMAddresses;
|
|
2631
5607
|
exports.compareTronAddresses = compareTronAddresses;
|
|
2632
5608
|
exports.compareUniversalAddresses = compareUniversalAddresses;
|