@tronweb3/tronwallet-adapter-trust 1.0.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/lib/cjs/adapter.js +141 -55
- package/lib/cjs/adapter.js.map +1 -1
- package/lib/esm/adapter.js +142 -56
- package/lib/esm/adapter.js.map +1 -1
- package/lib/types/adapter.d.ts +19 -16
- package/lib/types/adapter.d.ts.map +1 -1
- package/lib/umd/index.js +1048 -248
- package/lib/umd/index.min.js +1 -1
- package/package.json +53 -53
- package/src/adapter.ts +138 -67
package/src/adapter.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
Adapter,
|
|
3
2
|
AdapterState,
|
|
4
3
|
isInBrowser,
|
|
5
4
|
WalletReadyState,
|
|
@@ -9,6 +8,9 @@ import {
|
|
|
9
8
|
WalletConnectionError,
|
|
10
9
|
WalletSignTransactionError,
|
|
11
10
|
WalletGetNetworkError,
|
|
11
|
+
AddonAdapter,
|
|
12
|
+
WalletError,
|
|
13
|
+
assertConnectAddress,
|
|
12
14
|
} from '@tronweb3/tronwallet-abstract-adapter';
|
|
13
15
|
import type {
|
|
14
16
|
Transaction,
|
|
@@ -33,23 +35,11 @@ declare global {
|
|
|
33
35
|
}
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
export
|
|
37
|
-
/**
|
|
38
|
-
* Timeout in millisecond for checking if Trust wallet exists.
|
|
39
|
-
* Default is 2 * 1000ms
|
|
40
|
-
*/
|
|
41
|
-
checkTimeout?: number;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Set if open app using DeepLink.
|
|
45
|
-
* Default is true.
|
|
46
|
-
*/
|
|
47
|
-
openAppWithDeeplink?: boolean;
|
|
48
|
-
}
|
|
38
|
+
export type TrustAdapterConfig = BaseAdapterConfig;
|
|
49
39
|
|
|
50
40
|
export const TrustAdapterName = 'Trust' as AdapterName<'Trust'>;
|
|
51
41
|
|
|
52
|
-
export class TrustAdapter extends
|
|
42
|
+
export class TrustAdapter extends AddonAdapter {
|
|
53
43
|
name = TrustAdapterName;
|
|
54
44
|
url = 'https://trustwallet.com';
|
|
55
45
|
icon =
|
|
@@ -64,17 +54,10 @@ export class TrustAdapter extends Adapter {
|
|
|
64
54
|
private _address: string | null;
|
|
65
55
|
|
|
66
56
|
constructor(config: TrustAdapterConfig = {}) {
|
|
67
|
-
super();
|
|
68
|
-
const { checkTimeout = 2 * 1000, openUrlWhenWalletNotFound = true, openAppWithDeeplink = true } = config;
|
|
69
|
-
|
|
70
|
-
if (typeof checkTimeout !== 'number') {
|
|
71
|
-
throw new Error('[TrustAdapter] config.checkTimeout should be a number');
|
|
72
|
-
}
|
|
57
|
+
super(config);
|
|
73
58
|
|
|
74
59
|
this.config = {
|
|
75
|
-
|
|
76
|
-
openAppWithDeeplink,
|
|
77
|
-
openUrlWhenWalletNotFound,
|
|
60
|
+
...this.commonConfig,
|
|
78
61
|
};
|
|
79
62
|
this._connecting = false;
|
|
80
63
|
this._wallet = null;
|
|
@@ -87,7 +70,11 @@ export class TrustAdapter extends Adapter {
|
|
|
87
70
|
}
|
|
88
71
|
if (supportTrust()) {
|
|
89
72
|
this._readyState = WalletReadyState.Found;
|
|
90
|
-
this._updateWallet()
|
|
73
|
+
this._updateWallet().then(() => {
|
|
74
|
+
if (this.connected) {
|
|
75
|
+
this.emit('connect', this.address || '');
|
|
76
|
+
}
|
|
77
|
+
});
|
|
91
78
|
} else {
|
|
92
79
|
this._checkWallet().then(() => {
|
|
93
80
|
if (this.connected) {
|
|
@@ -134,45 +121,34 @@ export class TrustAdapter extends Adapter {
|
|
|
134
121
|
}
|
|
135
122
|
}
|
|
136
123
|
|
|
137
|
-
async
|
|
124
|
+
protected async _connect(): Promise<void> {
|
|
138
125
|
try {
|
|
139
|
-
this.
|
|
140
|
-
if (this.connected || this.connecting) return;
|
|
141
|
-
await this._checkWallet();
|
|
142
|
-
if (this.state === AdapterState.NotFound) {
|
|
143
|
-
if (this.config.openUrlWhenWalletNotFound !== false && isInBrowser()) {
|
|
144
|
-
window.open(this.url, '_blank');
|
|
145
|
-
}
|
|
146
|
-
throw new WalletNotFoundError();
|
|
147
|
-
}
|
|
126
|
+
if (!(await this._beforeConnect())) return;
|
|
148
127
|
if (!this._wallet) return;
|
|
149
128
|
this._connecting = true;
|
|
150
129
|
const wallet = this._wallet as TronLinkWallet;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
throw new WalletConnectionError('The user rejected connection.');
|
|
163
|
-
}
|
|
164
|
-
} catch (error: any) {
|
|
165
|
-
throw new WalletConnectionError(error?.message, error);
|
|
130
|
+
const res = await wallet.request({ method: 'tron_requestAccounts' });
|
|
131
|
+
if (!res) {
|
|
132
|
+
throw new WalletConnectionError('Request connect error.');
|
|
133
|
+
}
|
|
134
|
+
if (res.code === 4000) {
|
|
135
|
+
throw new WalletConnectionError(
|
|
136
|
+
'The same DApp has already initiated a request to connect to trustwallet, and the pop-up window has not been closed.'
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
if (res.code === 4001) {
|
|
140
|
+
throw new WalletConnectionError('The user rejected connection.');
|
|
166
141
|
}
|
|
167
142
|
|
|
168
|
-
const address = wallet.tronWeb.defaultAddress?.base58
|
|
143
|
+
const address = assertConnectAddress(wallet.tronWeb.defaultAddress?.base58);
|
|
169
144
|
this.setAddress(address);
|
|
170
145
|
this.setState(AdapterState.Connected);
|
|
171
146
|
this._listenEvent();
|
|
172
147
|
this.connected && this.emit('connect', this.address || '');
|
|
173
148
|
} catch (error: any) {
|
|
174
|
-
|
|
175
|
-
|
|
149
|
+
const err = error instanceof WalletError ? error : new WalletConnectionError(error?.message, error);
|
|
150
|
+
this.emit('error', err);
|
|
151
|
+
throw err;
|
|
176
152
|
} finally {
|
|
177
153
|
this._connecting = false;
|
|
178
154
|
}
|
|
@@ -265,20 +241,59 @@ export class TrustAdapter extends Adapter {
|
|
|
265
241
|
}
|
|
266
242
|
|
|
267
243
|
private _stopListenEvent() {
|
|
244
|
+
this._eventGeneration++;
|
|
245
|
+
if (this._accountsChangedTimer) {
|
|
246
|
+
clearTimeout(this._accountsChangedTimer);
|
|
247
|
+
this._accountsChangedTimer = null;
|
|
248
|
+
}
|
|
268
249
|
window.removeEventListener('message', this.messageHandler);
|
|
269
250
|
}
|
|
270
251
|
|
|
271
|
-
private
|
|
252
|
+
private _accountsChangedTimer: ReturnType<typeof setTimeout> | null = null;
|
|
253
|
+
/**
|
|
254
|
+
* Incremented whenever the listening session ends. Deferred `accountsChanged`
|
|
255
|
+
* work and the awaited `connect` handler capture the value before they yield and
|
|
256
|
+
* abandon themselves if it no longer matches, so an event that started before
|
|
257
|
+
* `disconnect()` cannot write state after it.
|
|
258
|
+
*/
|
|
259
|
+
private _eventGeneration = 0;
|
|
260
|
+
|
|
261
|
+
private messageHandler = async (e: TronLinkMessageEvent) => {
|
|
262
|
+
if (e.origin !== window.location.origin) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
272
266
|
const message = e.data?.message;
|
|
273
267
|
if (!message) {
|
|
274
268
|
return;
|
|
275
269
|
}
|
|
276
270
|
if (message.action === 'accountsChanged') {
|
|
277
|
-
|
|
271
|
+
if (this._accountsChangedTimer) {
|
|
272
|
+
clearTimeout(this._accountsChangedTimer);
|
|
273
|
+
}
|
|
274
|
+
const generation = this._eventGeneration;
|
|
275
|
+
this._accountsChangedTimer = setTimeout(async () => {
|
|
276
|
+
this._accountsChangedTimer = null;
|
|
277
|
+
if (generation !== this._eventGeneration) return;
|
|
278
278
|
const preAddr = this.address || '';
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
279
|
+
const curAddr = (message.data as AccountsChangedEventData).address || '';
|
|
280
|
+
// An empty account is a disconnection, not a connection to the empty
|
|
281
|
+
// address. Going Connected here leaves `connected === true` with no
|
|
282
|
+
// address, and the block below then emits `disconnect` against a state
|
|
283
|
+
// that still says Connected.
|
|
284
|
+
if (curAddr && (this._wallet as TronLinkWallet)?.ready) {
|
|
285
|
+
try {
|
|
286
|
+
await this.checkSecurity();
|
|
287
|
+
} catch {
|
|
288
|
+
if (generation !== this._eventGeneration) return;
|
|
289
|
+
this.setAddress(null);
|
|
290
|
+
this.setState(AdapterState.Disconnect);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// `checkSecurity()` was awaited, so the session may have ended while it
|
|
294
|
+
// was pending — re-check before writing any state.
|
|
295
|
+
if (generation !== this._eventGeneration) return;
|
|
296
|
+
this.setAddress(curAddr);
|
|
282
297
|
this.setState(AdapterState.Connected);
|
|
283
298
|
} else {
|
|
284
299
|
this.setAddress(null);
|
|
@@ -295,9 +310,31 @@ export class TrustAdapter extends Adapter {
|
|
|
295
310
|
}
|
|
296
311
|
}, 200);
|
|
297
312
|
} else if (message.action === 'connect') {
|
|
313
|
+
const generation = this._eventGeneration;
|
|
314
|
+
// Trust may post a `connect` message before the address is available;
|
|
315
|
+
// ignore it so we don't report a connection (and emit connect) with no address.
|
|
316
|
+
if (!(this._wallet as TronLinkWallet).tronWeb?.defaultAddress?.base58) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
await this.checkSecurity();
|
|
321
|
+
} catch {
|
|
322
|
+
// A stale rejection must not tear down a session that has since been
|
|
323
|
+
// re-established, so the generation is honoured on this path too.
|
|
324
|
+
if (generation !== this._eventGeneration) return;
|
|
325
|
+
this.setAddress(null);
|
|
326
|
+
this.setState(AdapterState.Disconnect);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
// `checkSecurity()` was awaited, so the session may have ended while it
|
|
330
|
+
// was pending — re-check before writing any state.
|
|
331
|
+
if (generation !== this._eventGeneration) return;
|
|
332
|
+
// Re-read after the await: the account may have changed or been cleared
|
|
333
|
+
// while the check was pending.
|
|
334
|
+
const address = (this._wallet as TronLinkWallet).tronWeb?.defaultAddress?.base58 || '';
|
|
335
|
+
if (!address) return;
|
|
298
336
|
const isCurConnected = this.connected;
|
|
299
337
|
const preAddress = this.address || '';
|
|
300
|
-
const address = (this._wallet as TronLinkWallet).tronWeb?.defaultAddress?.base58 || '';
|
|
301
338
|
this.setAddress(address);
|
|
302
339
|
this.setState(AdapterState.Connected);
|
|
303
340
|
if (!isCurConnected) {
|
|
@@ -321,12 +358,24 @@ export class TrustAdapter extends Adapter {
|
|
|
321
358
|
}
|
|
322
359
|
}
|
|
323
360
|
|
|
361
|
+
protected _openAppByDeepLinkIfNeed(): boolean {
|
|
362
|
+
if (this.config.openAppWithDeeplink === false) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
return openTrustWallet();
|
|
366
|
+
}
|
|
367
|
+
|
|
324
368
|
private _checkPromise: Promise<boolean> | null = null;
|
|
369
|
+
/**
|
|
370
|
+
* Detection polls for the full `checkTimeout` only once. Later attempts re-check a
|
|
371
|
+
* single time, so retrying is free when the wallet is genuinely absent.
|
|
372
|
+
*/
|
|
373
|
+
private _hasRunInitialDetection = false;
|
|
325
374
|
/**
|
|
326
375
|
* check if wallet exists by interval, the promise only resolve when wallet detected or timeout
|
|
327
376
|
* @returns if trustwallet exists
|
|
328
377
|
*/
|
|
329
|
-
|
|
378
|
+
protected _checkWallet(): Promise<boolean> {
|
|
330
379
|
if (this.readyState === WalletReadyState.Found) {
|
|
331
380
|
return Promise.resolve(true);
|
|
332
381
|
}
|
|
@@ -334,10 +383,11 @@ export class TrustAdapter extends Adapter {
|
|
|
334
383
|
return this._checkPromise;
|
|
335
384
|
}
|
|
336
385
|
const interval = 100;
|
|
337
|
-
const maxTimes = Math.floor(this.config.checkTimeout / interval);
|
|
386
|
+
const maxTimes = this._hasRunInitialDetection ? 0 : Math.floor(this.config.checkTimeout / interval);
|
|
387
|
+
this._hasRunInitialDetection = true;
|
|
338
388
|
let times = 0,
|
|
339
389
|
timer: ReturnType<typeof setInterval>;
|
|
340
|
-
|
|
390
|
+
const detection = new Promise<boolean>((resolve) => {
|
|
341
391
|
const check = () => {
|
|
342
392
|
times++;
|
|
343
393
|
const isSupport = supportTrust();
|
|
@@ -352,17 +402,38 @@ export class TrustAdapter extends Adapter {
|
|
|
352
402
|
timer = setInterval(check, interval);
|
|
353
403
|
check();
|
|
354
404
|
});
|
|
355
|
-
|
|
405
|
+
this._checkPromise = detection;
|
|
406
|
+
// Never cache a failed detection. The extension may inject late, be switched on at
|
|
407
|
+
// runtime, or a mobile WebView may still be initialising — in all of those cases the
|
|
408
|
+
// next call has to look again instead of replaying the old negative answer.
|
|
409
|
+
void detection.then((found) => {
|
|
410
|
+
if (!found && this._checkPromise === detection) {
|
|
411
|
+
this._checkPromise = null;
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
return detection;
|
|
356
415
|
}
|
|
357
416
|
|
|
358
|
-
private _updateWallet = () => {
|
|
359
|
-
let state
|
|
360
|
-
let address
|
|
417
|
+
private _updateWallet = async () => {
|
|
418
|
+
let state;
|
|
419
|
+
let address;
|
|
361
420
|
if (supportTrust()) {
|
|
362
421
|
this._wallet = window.trustwallet!.tronLink;
|
|
363
422
|
this._listenEvent();
|
|
364
423
|
address = this._wallet.tronWeb?.defaultAddress?.base58 || null;
|
|
365
|
-
|
|
424
|
+
if (address) {
|
|
425
|
+
// Only run the security check once the wallet is actually connected.
|
|
426
|
+
try {
|
|
427
|
+
await this.checkSecurity();
|
|
428
|
+
} catch {
|
|
429
|
+
this.setAddress(null);
|
|
430
|
+
this.setState(AdapterState.Disconnect);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
state = AdapterState.Connected;
|
|
434
|
+
} else {
|
|
435
|
+
state = AdapterState.Disconnect;
|
|
436
|
+
}
|
|
366
437
|
} else {
|
|
367
438
|
this._wallet = null;
|
|
368
439
|
address = null;
|