@meshconnect/uwc-tron-connector 0.1.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/dist/events/state-machine.d.ts +26 -0
- package/dist/events/state-machine.d.ts.map +1 -0
- package/dist/events/state-machine.js +21 -0
- package/dist/events/state-machine.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/rest/abi.d.ts +23 -0
- package/dist/rest/abi.d.ts.map +1 -0
- package/dist/rest/abi.js +28 -0
- package/dist/rest/abi.js.map +1 -0
- package/dist/rest/address.d.ts +45 -0
- package/dist/rest/address.d.ts.map +1 -0
- package/dist/rest/address.js +124 -0
- package/dist/rest/address.js.map +1 -0
- package/dist/rest/trongrid-client.d.ts +57 -0
- package/dist/rest/trongrid-client.d.ts.map +1 -0
- package/dist/rest/trongrid-client.js +133 -0
- package/dist/rest/trongrid-client.js.map +1 -0
- package/dist/shared/error-utils.d.ts +9 -0
- package/dist/shared/error-utils.d.ts.map +1 -0
- package/dist/shared/error-utils.js +52 -0
- package/dist/shared/error-utils.js.map +1 -0
- package/dist/tron-connector.d.ts +85 -0
- package/dist/tron-connector.d.ts.map +1 -0
- package/dist/tron-connector.js +456 -0
- package/dist/tron-connector.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/wallets/base.d.ts +87 -0
- package/dist/wallets/base.d.ts.map +1 -0
- package/dist/wallets/base.js +118 -0
- package/dist/wallets/base.js.map +1 -0
- package/dist/wallets/bitget.d.ts +8 -0
- package/dist/wallets/bitget.d.ts.map +1 -0
- package/dist/wallets/bitget.js +14 -0
- package/dist/wallets/bitget.js.map +1 -0
- package/dist/wallets/okx.d.ts +4 -0
- package/dist/wallets/okx.d.ts.map +1 -0
- package/dist/wallets/okx.js +10 -0
- package/dist/wallets/okx.js.map +1 -0
- package/dist/wallets/registry.d.ts +8 -0
- package/dist/wallets/registry.d.ts.map +1 -0
- package/dist/wallets/registry.js +18 -0
- package/dist/wallets/registry.js.map +1 -0
- package/dist/wallets/tokenpocket.d.ts +9 -0
- package/dist/wallets/tokenpocket.d.ts.map +1 -0
- package/dist/wallets/tokenpocket.js +15 -0
- package/dist/wallets/tokenpocket.js.map +1 -0
- package/dist/wallets/tronlink.d.ts +8 -0
- package/dist/wallets/tronlink.d.ts.map +1 -0
- package/dist/wallets/tronlink.js +15 -0
- package/dist/wallets/tronlink.js.map +1 -0
- package/dist/wallets/trust.d.ts +9 -0
- package/dist/wallets/trust.d.ts.map +1 -0
- package/dist/wallets/trust.js +15 -0
- package/dist/wallets/trust.js.map +1 -0
- package/package.json +34 -0
- package/src/events/state-machine.ts +44 -0
- package/src/index.ts +17 -0
- package/src/rest/abi.test.ts +25 -0
- package/src/rest/abi.ts +33 -0
- package/src/rest/address.test.ts +55 -0
- package/src/rest/address.ts +140 -0
- package/src/rest/trongrid-client.test.ts +169 -0
- package/src/rest/trongrid-client.ts +205 -0
- package/src/shared/error-utils.ts +60 -0
- package/src/tron-connector.test.ts +612 -0
- package/src/tron-connector.ts +568 -0
- package/src/types.ts +11 -0
- package/src/wallets/base.ts +184 -0
- package/src/wallets/bitget.ts +17 -0
- package/src/wallets/okx.ts +10 -0
- package/src/wallets/registry.ts +26 -0
- package/src/wallets/tokenpocket.ts +15 -0
- package/src/wallets/tronlink.ts +15 -0
- package/src/wallets/trust.ts +18 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal connection state machine + subscription surface.
|
|
3
|
+
*
|
|
4
|
+
* The connector exposes a single `onStateChange` callback rather than the
|
|
5
|
+
* full wallet event set — enough for `core` to react to disconnects and
|
|
6
|
+
* account changes without leaking per-wallet event shapes.
|
|
7
|
+
*/
|
|
8
|
+
import type { TronWalletId } from '@meshconnect/uwc-types';
|
|
9
|
+
export type TronConnectionStatus = 'disconnected' | 'connecting' | 'connected';
|
|
10
|
+
export interface TronConnectionState {
|
|
11
|
+
status: TronConnectionStatus;
|
|
12
|
+
/** Active wallet id, when connected/connecting. */
|
|
13
|
+
walletId?: TronWalletId;
|
|
14
|
+
/** Active account address (base58), when connected. */
|
|
15
|
+
address?: string;
|
|
16
|
+
}
|
|
17
|
+
export type TronStateListener = (state: TronConnectionState) => void;
|
|
18
|
+
export declare class TronStateMachine {
|
|
19
|
+
private state;
|
|
20
|
+
private readonly listeners;
|
|
21
|
+
get(): TronConnectionState;
|
|
22
|
+
set(next: TronConnectionState): void;
|
|
23
|
+
/** Subscribe to state transitions. Returns an unsubscribe function. */
|
|
24
|
+
subscribe(listener: TronStateListener): () => void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=state-machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.d.ts","sourceRoot":"","sources":["../../src/events/state-machine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAE1D,MAAM,MAAM,oBAAoB,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,CAAA;AAE9E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,mDAAmD;IACnD,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAA;AAEpE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,KAAK,CAAkD;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+B;IAEzD,GAAG,IAAI,mBAAmB;IAI1B,GAAG,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI;IAOpC,uEAAuE;IACvE,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI;CAMnD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class TronStateMachine {
|
|
2
|
+
state = { status: 'disconnected' };
|
|
3
|
+
listeners = new Set();
|
|
4
|
+
get() {
|
|
5
|
+
return this.state;
|
|
6
|
+
}
|
|
7
|
+
set(next) {
|
|
8
|
+
this.state = next;
|
|
9
|
+
for (const listener of this.listeners) {
|
|
10
|
+
listener(next);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Subscribe to state transitions. Returns an unsubscribe function. */
|
|
14
|
+
subscribe(listener) {
|
|
15
|
+
this.listeners.add(listener);
|
|
16
|
+
return () => {
|
|
17
|
+
this.listeners.delete(listener);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=state-machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.js","sourceRoot":"","sources":["../../src/events/state-machine.ts"],"names":[],"mappings":"AAqBA,MAAM,OAAO,gBAAgB;IACnB,KAAK,GAAwB,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IAC9C,SAAS,GAAG,IAAI,GAAG,EAAqB,CAAA;IAEzD,GAAG;QACD,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED,GAAG,CAAC,IAAyB;QAC3B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAChB,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,SAAS,CAAC,QAA2B;QACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC5B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACjC,CAAC,CAAA;IACH,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { TronConnector } from './tron-connector';
|
|
2
|
+
export { ALL_TRON_WALLET_IDS, TRON_WALLET_REGISTRY, isTronWalletId } from './wallets/registry';
|
|
3
|
+
export type { TronWalletWrapper, InjectedTronProvider } from './wallets/base';
|
|
4
|
+
export type { TronConnectionState, TronConnectionStatus, TronStateListener } from './events/state-machine';
|
|
5
|
+
export type { UnsignedTronTransaction, SignedTronTransaction } from './rest/trongrid-client';
|
|
6
|
+
export type { TronConnectorConfig, TronGridConfig, TronWalletId } from './types';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACf,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAC7E,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EACV,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,wBAAwB,CAAA;AAC/B,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACf,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ABI-encode the arguments for `transfer(address,uint256)` (TRC20 / TEP-20).
|
|
3
|
+
*
|
|
4
|
+
* The full-node `/wallet/triggersmartcontract` endpoint takes the function
|
|
5
|
+
* selector as a literal string and the *arguments* as a hex `parameter` blob.
|
|
6
|
+
* Each argument is left-padded to a 32-byte (64-hex-char) word:
|
|
7
|
+
* - address: the bare 20-byte body, left-padded to 32 bytes.
|
|
8
|
+
* - uint256: the amount, left-padded to 32 bytes.
|
|
9
|
+
*
|
|
10
|
+
* @param to recipient address (base58 or hex)
|
|
11
|
+
* @param amount token amount in base units
|
|
12
|
+
* @returns 128-hex-char parameter string (no `0x` prefix)
|
|
13
|
+
*/
|
|
14
|
+
export declare function encodeTrc20TransferParams(to: string, amount: number | bigint): string;
|
|
15
|
+
/** Function selector string the full node hashes for a TRC20 transfer. */
|
|
16
|
+
export declare const TRC20_TRANSFER_SELECTOR = "transfer(address,uint256)";
|
|
17
|
+
/**
|
|
18
|
+
* The 4-byte selector (8 hex chars) for `transfer(address,uint256)` —
|
|
19
|
+
* `keccak256("transfer(address,uint256)")[:4]`, same as ERC-20. Used to
|
|
20
|
+
* reconstruct and verify the full call data the node built before signing.
|
|
21
|
+
*/
|
|
22
|
+
export declare const TRC20_TRANSFER_SELECTOR_HASH = "a9059cbb";
|
|
23
|
+
//# sourceMappingURL=abi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abi.d.ts","sourceRoot":"","sources":["../../src/rest/abi.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,CAIR;AAED,0EAA0E;AAC1E,eAAO,MAAM,uBAAuB,8BAA8B,CAAA;AAElE;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,aAAa,CAAA"}
|
package/dist/rest/abi.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { tronAddressToEvmHex } from './address';
|
|
2
|
+
/**
|
|
3
|
+
* ABI-encode the arguments for `transfer(address,uint256)` (TRC20 / TEP-20).
|
|
4
|
+
*
|
|
5
|
+
* The full-node `/wallet/triggersmartcontract` endpoint takes the function
|
|
6
|
+
* selector as a literal string and the *arguments* as a hex `parameter` blob.
|
|
7
|
+
* Each argument is left-padded to a 32-byte (64-hex-char) word:
|
|
8
|
+
* - address: the bare 20-byte body, left-padded to 32 bytes.
|
|
9
|
+
* - uint256: the amount, left-padded to 32 bytes.
|
|
10
|
+
*
|
|
11
|
+
* @param to recipient address (base58 or hex)
|
|
12
|
+
* @param amount token amount in base units
|
|
13
|
+
* @returns 128-hex-char parameter string (no `0x` prefix)
|
|
14
|
+
*/
|
|
15
|
+
export function encodeTrc20TransferParams(to, amount) {
|
|
16
|
+
const addressWord = tronAddressToEvmHex(to).padStart(64, '0');
|
|
17
|
+
const amountWord = BigInt(amount).toString(16).padStart(64, '0');
|
|
18
|
+
return addressWord + amountWord;
|
|
19
|
+
}
|
|
20
|
+
/** Function selector string the full node hashes for a TRC20 transfer. */
|
|
21
|
+
export const TRC20_TRANSFER_SELECTOR = 'transfer(address,uint256)';
|
|
22
|
+
/**
|
|
23
|
+
* The 4-byte selector (8 hex chars) for `transfer(address,uint256)` —
|
|
24
|
+
* `keccak256("transfer(address,uint256)")[:4]`, same as ERC-20. Used to
|
|
25
|
+
* reconstruct and verify the full call data the node built before signing.
|
|
26
|
+
*/
|
|
27
|
+
export const TRC20_TRANSFER_SELECTOR_HASH = 'a9059cbb';
|
|
28
|
+
//# sourceMappingURL=abi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abi.js","sourceRoot":"","sources":["../../src/rest/abi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAE/C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,yBAAyB,CACvC,EAAU,EACV,MAAuB;IAEvB,MAAM,WAAW,GAAG,mBAAmB,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;IAC7D,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;IAChE,OAAO,WAAW,GAAG,UAAU,CAAA;AACjC,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,MAAM,uBAAuB,GAAG,2BAA2B,CAAA;AAElE;;;;GAIG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,UAAU,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tron address utilities — base58check ↔ hex, dependency-free.
|
|
3
|
+
*
|
|
4
|
+
* A Tron address has two on-the-wire forms:
|
|
5
|
+
* - base58check (`T...`): Base58Check of `0x41 ‖ <20-byte body> ‖ <4-byte checksum>`.
|
|
6
|
+
* - hex (`41` + 40 hex chars): the 21-byte payload (`0x41` prefix + 20-byte body).
|
|
7
|
+
*
|
|
8
|
+
* The full-node HTTP API accepts base58 directly when `visible: true` is set, so
|
|
9
|
+
* build/broadcast never needs conversion. The one place we DO need it is the
|
|
10
|
+
* TRC20 ABI parameter, which encodes the recipient as the bare 20-byte body.
|
|
11
|
+
*
|
|
12
|
+
* Decoding base58 is pure bigint math (no hashing), so the conversion helpers
|
|
13
|
+
* (`tronAddressToHex` / `tronAddressToEvmHex`) stay synchronous and do NOT
|
|
14
|
+
* verify the 4-byte checksum — that's the hot path used for already-validated
|
|
15
|
+
* addresses. Checksum verification is provided separately by the async
|
|
16
|
+
* `assertValidTronChecksum` (SubtleCrypto), which the connector calls on the
|
|
17
|
+
* TRC20 recipient — the one case the node never validates (it's encoded as raw
|
|
18
|
+
* hex, not sent as base58).
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Convert a base58 Tron address (`T...`) to its 21-byte hex form
|
|
22
|
+
* (`41` + 40 hex chars). Already-hex input (with or without `0x`) is normalised
|
|
23
|
+
* and returned as-is.
|
|
24
|
+
*/
|
|
25
|
+
export declare function tronAddressToHex(address: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Convert a Tron address to its bare 20-byte EVM-style hex body (no `0x41`
|
|
28
|
+
* prefix, no `0x`). This is the form used inside TRC20 ABI parameters.
|
|
29
|
+
*/
|
|
30
|
+
export declare function tronAddressToEvmHex(address: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Validate a base58 Tron address's 0x41 prefix and 4-byte Base58Check checksum
|
|
33
|
+
* (first 4 bytes of `sha256(sha256(payload))`). Throws on mismatch.
|
|
34
|
+
*
|
|
35
|
+
* This matters for the TRC20 recipient: native transfers send the address as
|
|
36
|
+
* base58 with `visible:true`, so the node validates it — but TRC20 encodes the
|
|
37
|
+
* recipient as a raw 20-byte hex word, so the node never sees the base58 form.
|
|
38
|
+
* Without this check a typo'd-but-structurally-valid address would silently
|
|
39
|
+
* send funds to the wrong, unrecoverable destination.
|
|
40
|
+
*
|
|
41
|
+
* Hex inputs carry no base58 checksum, so they pass through unchecked.
|
|
42
|
+
* Async because it uses SubtleCrypto for SHA-256 (no hashing dependency).
|
|
43
|
+
*/
|
|
44
|
+
export declare function assertValidTronChecksum(address: string): Promise<void>;
|
|
45
|
+
//# sourceMappingURL=address.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../../src/rest/address.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAyCH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBxD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB5E"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tron address utilities — base58check ↔ hex, dependency-free.
|
|
3
|
+
*
|
|
4
|
+
* A Tron address has two on-the-wire forms:
|
|
5
|
+
* - base58check (`T...`): Base58Check of `0x41 ‖ <20-byte body> ‖ <4-byte checksum>`.
|
|
6
|
+
* - hex (`41` + 40 hex chars): the 21-byte payload (`0x41` prefix + 20-byte body).
|
|
7
|
+
*
|
|
8
|
+
* The full-node HTTP API accepts base58 directly when `visible: true` is set, so
|
|
9
|
+
* build/broadcast never needs conversion. The one place we DO need it is the
|
|
10
|
+
* TRC20 ABI parameter, which encodes the recipient as the bare 20-byte body.
|
|
11
|
+
*
|
|
12
|
+
* Decoding base58 is pure bigint math (no hashing), so the conversion helpers
|
|
13
|
+
* (`tronAddressToHex` / `tronAddressToEvmHex`) stay synchronous and do NOT
|
|
14
|
+
* verify the 4-byte checksum — that's the hot path used for already-validated
|
|
15
|
+
* addresses. Checksum verification is provided separately by the async
|
|
16
|
+
* `assertValidTronChecksum` (SubtleCrypto), which the connector calls on the
|
|
17
|
+
* TRC20 recipient — the one case the node never validates (it's encoded as raw
|
|
18
|
+
* hex, not sent as base58).
|
|
19
|
+
*/
|
|
20
|
+
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
21
|
+
/** Decode a Base58 string to bytes (big-endian). Throws on invalid characters. */
|
|
22
|
+
function base58Decode(input) {
|
|
23
|
+
if (input.length === 0)
|
|
24
|
+
throw new Error('tron address: empty base58 string');
|
|
25
|
+
let value = 0n;
|
|
26
|
+
for (const char of input) {
|
|
27
|
+
const index = BASE58_ALPHABET.indexOf(char);
|
|
28
|
+
if (index === -1) {
|
|
29
|
+
throw new Error(`tron address: invalid base58 character "${char}"`);
|
|
30
|
+
}
|
|
31
|
+
value = value * 58n + BigInt(index);
|
|
32
|
+
}
|
|
33
|
+
const bytes = [];
|
|
34
|
+
while (value > 0n) {
|
|
35
|
+
bytes.unshift(Number(value & 0xffn));
|
|
36
|
+
value >>= 8n;
|
|
37
|
+
}
|
|
38
|
+
// Each leading '1' in base58 represents a leading zero byte.
|
|
39
|
+
for (const char of input) {
|
|
40
|
+
if (char !== '1')
|
|
41
|
+
break;
|
|
42
|
+
bytes.unshift(0);
|
|
43
|
+
}
|
|
44
|
+
return Uint8Array.from(bytes);
|
|
45
|
+
}
|
|
46
|
+
function toHex(bytes) {
|
|
47
|
+
let out = '';
|
|
48
|
+
for (const byte of bytes) {
|
|
49
|
+
out += byte.toString(16).padStart(2, '0');
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Convert a base58 Tron address (`T...`) to its 21-byte hex form
|
|
55
|
+
* (`41` + 40 hex chars). Already-hex input (with or without `0x`) is normalised
|
|
56
|
+
* and returned as-is.
|
|
57
|
+
*/
|
|
58
|
+
export function tronAddressToHex(address) {
|
|
59
|
+
// Accept hex passthrough so callers can mix forms.
|
|
60
|
+
const stripped = address.startsWith('0x') ? address.slice(2) : address;
|
|
61
|
+
if (/^41[0-9a-fA-F]{40}$/.test(stripped)) {
|
|
62
|
+
return stripped.toLowerCase();
|
|
63
|
+
}
|
|
64
|
+
const decoded = base58Decode(address);
|
|
65
|
+
// 25 bytes = 21-byte payload (0x41 + 20-byte body) + 4-byte checksum.
|
|
66
|
+
if (decoded.length !== 25) {
|
|
67
|
+
throw new Error(`tron address: expected 25 bytes after base58 decode, got ${decoded.length}`);
|
|
68
|
+
}
|
|
69
|
+
const payload = decoded.subarray(0, 21);
|
|
70
|
+
if (payload[0] !== 0x41) {
|
|
71
|
+
throw new Error('tron address: missing 0x41 Tron address prefix');
|
|
72
|
+
}
|
|
73
|
+
return toHex(payload);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Convert a Tron address to its bare 20-byte EVM-style hex body (no `0x41`
|
|
77
|
+
* prefix, no `0x`). This is the form used inside TRC20 ABI parameters.
|
|
78
|
+
*/
|
|
79
|
+
export function tronAddressToEvmHex(address) {
|
|
80
|
+
return tronAddressToHex(address).slice(2);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* SHA-256 via SubtleCrypto. Re-wraps the input with `Uint8Array.from` so it is
|
|
84
|
+
* an ArrayBuffer-backed view (satisfies `digest`'s `BufferSource` param without
|
|
85
|
+
* naming the DOM type, which our lint's `no-undef` doesn't recognize).
|
|
86
|
+
*/
|
|
87
|
+
async function sha256(bytes) {
|
|
88
|
+
const digest = await crypto.subtle.digest('SHA-256', Uint8Array.from(bytes));
|
|
89
|
+
return new Uint8Array(digest);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Validate a base58 Tron address's 0x41 prefix and 4-byte Base58Check checksum
|
|
93
|
+
* (first 4 bytes of `sha256(sha256(payload))`). Throws on mismatch.
|
|
94
|
+
*
|
|
95
|
+
* This matters for the TRC20 recipient: native transfers send the address as
|
|
96
|
+
* base58 with `visible:true`, so the node validates it — but TRC20 encodes the
|
|
97
|
+
* recipient as a raw 20-byte hex word, so the node never sees the base58 form.
|
|
98
|
+
* Without this check a typo'd-but-structurally-valid address would silently
|
|
99
|
+
* send funds to the wrong, unrecoverable destination.
|
|
100
|
+
*
|
|
101
|
+
* Hex inputs carry no base58 checksum, so they pass through unchecked.
|
|
102
|
+
* Async because it uses SubtleCrypto for SHA-256 (no hashing dependency).
|
|
103
|
+
*/
|
|
104
|
+
export async function assertValidTronChecksum(address) {
|
|
105
|
+
const stripped = address.startsWith('0x') ? address.slice(2) : address;
|
|
106
|
+
if (/^41[0-9a-fA-F]{40}$/.test(stripped))
|
|
107
|
+
return; // hex form: no checksum to verify
|
|
108
|
+
const decoded = base58Decode(address);
|
|
109
|
+
if (decoded.length !== 25) {
|
|
110
|
+
throw new Error(`tron address: expected 25 bytes after base58 decode, got ${decoded.length}`);
|
|
111
|
+
}
|
|
112
|
+
const payload = decoded.subarray(0, 21);
|
|
113
|
+
if (payload[0] !== 0x41) {
|
|
114
|
+
throw new Error('tron address: missing 0x41 Tron address prefix');
|
|
115
|
+
}
|
|
116
|
+
const expected = decoded.subarray(21, 25);
|
|
117
|
+
const round2 = await sha256(await sha256(payload));
|
|
118
|
+
for (let i = 0; i < 4; i++) {
|
|
119
|
+
if (round2[i] !== expected[i]) {
|
|
120
|
+
throw new Error('tron address: base58 checksum mismatch (possible typo in recipient address)');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.js","sourceRoot":"","sources":["../../src/rest/address.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { NetworkId, TronGridConfig } from '@meshconnect/uwc-types';
|
|
2
|
+
/**
|
|
3
|
+
* The minimal shape of an unsigned Tron transaction returned by
|
|
4
|
+
* `/wallet/createtransaction` and `/wallet/triggersmartcontract`.
|
|
5
|
+
*
|
|
6
|
+
* Only `txID` + `raw_data*` are load-bearing for sign/broadcast; the struct
|
|
7
|
+
* carries more fields that pass through opaquely. Typed loosely on purpose so
|
|
8
|
+
* a node-version change to the surrounding shape doesn't break the contract.
|
|
9
|
+
*/
|
|
10
|
+
export interface UnsignedTronTransaction {
|
|
11
|
+
txID?: string;
|
|
12
|
+
raw_data?: unknown;
|
|
13
|
+
raw_data_hex?: string;
|
|
14
|
+
visible?: boolean;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** A transaction with the wallet's signature appended, ready to broadcast. */
|
|
18
|
+
export interface SignedTronTransaction extends UnsignedTronTransaction {
|
|
19
|
+
signature?: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Thin `fetch` wrapper over the three Tron full-node HTTP endpoints this
|
|
23
|
+
* connector needs. No SDK, no `tronweb` — the `/wallet/*` paths are the Tron
|
|
24
|
+
* full-node API standard, identical across TronGrid and any full node.
|
|
25
|
+
*/
|
|
26
|
+
export declare class TronGridClient {
|
|
27
|
+
private readonly baseUrl;
|
|
28
|
+
private readonly apiKey;
|
|
29
|
+
private readonly feeLimitSun;
|
|
30
|
+
constructor(networkId: NetworkId, config?: TronGridConfig);
|
|
31
|
+
/** Build an unsigned native TRX transfer. Amounts are in SUN. */
|
|
32
|
+
createTransaction(params: {
|
|
33
|
+
from: string;
|
|
34
|
+
to: string;
|
|
35
|
+
amount: number;
|
|
36
|
+
}): Promise<UnsignedTronTransaction>;
|
|
37
|
+
/** Build an unsigned TRC20 `transfer(address,uint256)` transaction. */
|
|
38
|
+
createTrc20Transfer(params: {
|
|
39
|
+
from: string;
|
|
40
|
+
to: string;
|
|
41
|
+
amount: number;
|
|
42
|
+
contractAddress: string;
|
|
43
|
+
}): Promise<UnsignedTronTransaction>;
|
|
44
|
+
/** Broadcast a signed transaction. Returns the on-chain txid. */
|
|
45
|
+
broadcastTransaction(signed: SignedTronTransaction): Promise<string>;
|
|
46
|
+
private post;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Full nodes often return `message` as hex-encoded ASCII
|
|
50
|
+
* (e.g. `"434f4e54524143545f56414c4944415445..."`). Decode when it looks like
|
|
51
|
+
* hex AND the result is printable ASCII; otherwise pass the string through
|
|
52
|
+
* unchanged. The printable check avoids mangling a message that happens to be
|
|
53
|
+
* an all-hex, even-length word (e.g. `"deadbeef"`), which would decode to
|
|
54
|
+
* non-printable bytes.
|
|
55
|
+
*/
|
|
56
|
+
export declare function decodeHexMessage(message: string | undefined): string;
|
|
57
|
+
//# sourceMappingURL=trongrid-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trongrid-client.d.ts","sourceRoot":"","sources":["../../src/rest/trongrid-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGvE;;;;;;;GAOG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAmBD;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;gBAExB,SAAS,EAAE,SAAS,EAAE,MAAM,GAAE,cAAmB;IAmC7D,iEAAiE;IAC3D,iBAAiB,CAAC,MAAM,EAAE;QAC9B,IAAI,EAAE,MAAM,CAAA;QACZ,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;KACf,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAmBpC,uEAAuE;IACjE,mBAAmB,CAAC,MAAM,EAAE;QAChC,IAAI,EAAE,MAAM,CAAA;QACZ,EAAE,EAAE,MAAM,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,eAAe,EAAE,MAAM,CAAA;KACxB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAyBpC,iEAAiE;IAC3D,oBAAoB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;YAsB5D,IAAI;CAkBnB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAYpE"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { encodeTrc20TransferParams, TRC20_TRANSFER_SELECTOR } from './abi';
|
|
2
|
+
const DEFAULT_ENDPOINTS = {
|
|
3
|
+
'tron:0x2b6653dc': 'https://api.trongrid.io', // Mainnet
|
|
4
|
+
'tron:0x94a9059e': 'https://api.shasta.trongrid.io', // Shasta testnet
|
|
5
|
+
'tron:0xcd8690dc': 'https://nile.trongrid.io' // Nile testnet
|
|
6
|
+
};
|
|
7
|
+
const DEFAULT_FEE_LIMIT_SUN = 100_000_000; // 100 TRX
|
|
8
|
+
/**
|
|
9
|
+
* Thin `fetch` wrapper over the three Tron full-node HTTP endpoints this
|
|
10
|
+
* connector needs. No SDK, no `tronweb` — the `/wallet/*` paths are the Tron
|
|
11
|
+
* full-node API standard, identical across TronGrid and any full node.
|
|
12
|
+
*/
|
|
13
|
+
export class TronGridClient {
|
|
14
|
+
baseUrl;
|
|
15
|
+
apiKey;
|
|
16
|
+
feeLimitSun;
|
|
17
|
+
constructor(networkId, config = {}) {
|
|
18
|
+
const url = config.endpoints?.[networkId] ?? DEFAULT_ENDPOINTS[networkId];
|
|
19
|
+
if (!url) {
|
|
20
|
+
throw new Error(`tron-connector: no full-node endpoint configured for network "${networkId}". ` +
|
|
21
|
+
`Pass one via TronConnectorConfig.tronGrid.endpoints.`);
|
|
22
|
+
}
|
|
23
|
+
// Reject plaintext endpoints: we send the TRON-PRO-API-KEY header and the
|
|
24
|
+
// unsigned tx in the body, so an `http://` host would leak both. Allow
|
|
25
|
+
// loopback http for local dev nodes (e.g. a tron-quickstart container).
|
|
26
|
+
if (/^http:\/\//i.test(url) &&
|
|
27
|
+
!/^http:\/\/(localhost|127\.0\.0\.1)/i.test(url)) {
|
|
28
|
+
throw new Error(`tron-connector: refusing non-https endpoint "${url}" (would send the API key + tx in cleartext)`);
|
|
29
|
+
}
|
|
30
|
+
// Normalise away trailing slashes so path concatenation is predictable.
|
|
31
|
+
// Done with a plain loop (no regex) to avoid any backtracking concern.
|
|
32
|
+
let base = url;
|
|
33
|
+
while (base.endsWith('/'))
|
|
34
|
+
base = base.slice(0, -1);
|
|
35
|
+
this.baseUrl = base;
|
|
36
|
+
this.apiKey = config.apiKey;
|
|
37
|
+
const feeLimit = config.feeLimitSun ?? DEFAULT_FEE_LIMIT_SUN;
|
|
38
|
+
if (!Number.isInteger(feeLimit) || feeLimit <= 0) {
|
|
39
|
+
throw new Error(`tron-connector: feeLimitSun must be a positive integer (SUN), got ${feeLimit}`);
|
|
40
|
+
}
|
|
41
|
+
this.feeLimitSun = feeLimit;
|
|
42
|
+
}
|
|
43
|
+
/** Build an unsigned native TRX transfer. Amounts are in SUN. */
|
|
44
|
+
async createTransaction(params) {
|
|
45
|
+
const tx = await this.post('/wallet/createtransaction', {
|
|
46
|
+
owner_address: params.from,
|
|
47
|
+
to_address: params.to,
|
|
48
|
+
amount: params.amount,
|
|
49
|
+
visible: true
|
|
50
|
+
});
|
|
51
|
+
if (tx.Error) {
|
|
52
|
+
throw new Error(`tron-connector: createtransaction failed — ${tx.Error}`);
|
|
53
|
+
}
|
|
54
|
+
if (!tx.txID) {
|
|
55
|
+
throw new Error('tron-connector: createtransaction returned no txID');
|
|
56
|
+
}
|
|
57
|
+
return tx;
|
|
58
|
+
}
|
|
59
|
+
/** Build an unsigned TRC20 `transfer(address,uint256)` transaction. */
|
|
60
|
+
async createTrc20Transfer(params) {
|
|
61
|
+
const response = await this.post('/wallet/triggersmartcontract', {
|
|
62
|
+
owner_address: params.from,
|
|
63
|
+
contract_address: params.contractAddress,
|
|
64
|
+
function_selector: TRC20_TRANSFER_SELECTOR,
|
|
65
|
+
parameter: encodeTrc20TransferParams(params.to, params.amount),
|
|
66
|
+
fee_limit: this.feeLimitSun,
|
|
67
|
+
call_value: 0,
|
|
68
|
+
visible: true
|
|
69
|
+
});
|
|
70
|
+
if (!response.result?.result || !response.transaction?.txID) {
|
|
71
|
+
throw new Error(`tron-connector: triggersmartcontract failed — ${decodeHexMessage(response.result?.message) ||
|
|
72
|
+
response.result?.code ||
|
|
73
|
+
'unknown error'}`);
|
|
74
|
+
}
|
|
75
|
+
return response.transaction;
|
|
76
|
+
}
|
|
77
|
+
/** Broadcast a signed transaction. Returns the on-chain txid. */
|
|
78
|
+
async broadcastTransaction(signed) {
|
|
79
|
+
const response = await this.post('/wallet/broadcasttransaction', signed);
|
|
80
|
+
// The node returns `{ result: false, message: <hex> }` on rejection even
|
|
81
|
+
// when a txid is echoed back — treat anything other than `result: true` as
|
|
82
|
+
// failure.
|
|
83
|
+
if (response.result !== true) {
|
|
84
|
+
throw new Error(decodeHexMessage(response.message) ||
|
|
85
|
+
response.code ||
|
|
86
|
+
'tron-connector: broadcast rejected by node');
|
|
87
|
+
}
|
|
88
|
+
const txid = response.txid ?? response.transaction?.txID ?? signed.txID;
|
|
89
|
+
if (!txid) {
|
|
90
|
+
throw new Error('tron-connector: broadcast returned no txid');
|
|
91
|
+
}
|
|
92
|
+
return txid;
|
|
93
|
+
}
|
|
94
|
+
async post(path, body) {
|
|
95
|
+
const headers = {
|
|
96
|
+
'Content-Type': 'application/json'
|
|
97
|
+
};
|
|
98
|
+
if (this.apiKey)
|
|
99
|
+
headers['TRON-PRO-API-KEY'] = this.apiKey;
|
|
100
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers,
|
|
103
|
+
body: JSON.stringify(body)
|
|
104
|
+
});
|
|
105
|
+
if (!response.ok) {
|
|
106
|
+
throw new Error(`tron-connector: ${path} responded ${response.status} ${response.statusText}`);
|
|
107
|
+
}
|
|
108
|
+
return (await response.json());
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Full nodes often return `message` as hex-encoded ASCII
|
|
113
|
+
* (e.g. `"434f4e54524143545f56414c4944415445..."`). Decode when it looks like
|
|
114
|
+
* hex AND the result is printable ASCII; otherwise pass the string through
|
|
115
|
+
* unchanged. The printable check avoids mangling a message that happens to be
|
|
116
|
+
* an all-hex, even-length word (e.g. `"deadbeef"`), which would decode to
|
|
117
|
+
* non-printable bytes.
|
|
118
|
+
*/
|
|
119
|
+
export function decodeHexMessage(message) {
|
|
120
|
+
if (!message)
|
|
121
|
+
return '';
|
|
122
|
+
if (!/^[0-9a-fA-F]+$/.test(message) || message.length % 2 !== 0) {
|
|
123
|
+
return message;
|
|
124
|
+
}
|
|
125
|
+
let decoded = '';
|
|
126
|
+
for (let i = 0; i < message.length; i += 2) {
|
|
127
|
+
decoded += String.fromCharCode(parseInt(message.slice(i, i + 2), 16));
|
|
128
|
+
}
|
|
129
|
+
// Printable ASCII (incl. common whitespace) → it was hex-encoded text.
|
|
130
|
+
// Anything else → the input was more likely a literal string; keep it.
|
|
131
|
+
return /^[\x20-\x7e\t\n\r]*$/.test(decoded) ? decoded : message;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=trongrid-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trongrid-client.js","sourceRoot":"","sources":["../../src/rest/trongrid-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translate an unknown error (from a wallet `request`/`sign` call or a node
|
|
3
|
+
* response) into a `WalletConnectorError`. User-rejection signals are tagged
|
|
4
|
+
* `type: 'rejected'`; everything else is `type: 'unknown'`.
|
|
5
|
+
*
|
|
6
|
+
* Throws — never returns.
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseError(error: unknown): never;
|
|
9
|
+
//# sourceMappingURL=error-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-utils.d.ts","sourceRoot":"","sources":["../../src/shared/error-utils.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CA+BhD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { WalletConnectorError } from '@meshconnect/uwc-types';
|
|
2
|
+
const REJECTION_PATTERNS = [
|
|
3
|
+
'user rejected',
|
|
4
|
+
'user denied',
|
|
5
|
+
'user cancelled',
|
|
6
|
+
'user canceled',
|
|
7
|
+
'rejected by user',
|
|
8
|
+
'denied by user',
|
|
9
|
+
'cancelled by user',
|
|
10
|
+
'canceled by user',
|
|
11
|
+
'user disapproved',
|
|
12
|
+
'user declined',
|
|
13
|
+
'action_rejected',
|
|
14
|
+
'reject request',
|
|
15
|
+
'user rejects',
|
|
16
|
+
'wallet rejected',
|
|
17
|
+
'confirmation declined'
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Translate an unknown error (from a wallet `request`/`sign` call or a node
|
|
21
|
+
* response) into a `WalletConnectorError`. User-rejection signals are tagged
|
|
22
|
+
* `type: 'rejected'`; everything else is `type: 'unknown'`.
|
|
23
|
+
*
|
|
24
|
+
* Throws — never returns.
|
|
25
|
+
*/
|
|
26
|
+
export function parseError(error) {
|
|
27
|
+
if (error instanceof WalletConnectorError)
|
|
28
|
+
throw error;
|
|
29
|
+
let message = '';
|
|
30
|
+
let isRejected = false;
|
|
31
|
+
if (error && typeof error === 'object') {
|
|
32
|
+
const errObj = error;
|
|
33
|
+
// 4001 is the de-facto user-rejected code across injected wallets.
|
|
34
|
+
if (errObj.code === 4001 || errObj.code === 'ACTION_REJECTED') {
|
|
35
|
+
isRejected = true;
|
|
36
|
+
}
|
|
37
|
+
message = errObj.message ?? errObj.error?.message ?? String(error);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
message = String(error);
|
|
41
|
+
}
|
|
42
|
+
if (!isRejected) {
|
|
43
|
+
const lower = message.toLowerCase();
|
|
44
|
+
isRejected = REJECTION_PATTERNS.some(pattern => lower.includes(pattern));
|
|
45
|
+
}
|
|
46
|
+
const walletError = {
|
|
47
|
+
type: isRejected ? 'rejected' : 'unknown',
|
|
48
|
+
message
|
|
49
|
+
};
|
|
50
|
+
throw new WalletConnectorError(walletError);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=error-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-utils.js","sourceRoot":"","sources":["../../src/shared/error-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAE7D,MAAM,kBAAkB,GAAG;IACzB,eAAe;IACf,aAAa;IACb,gBAAgB;IAChB,eAAe;IACf,kBAAkB;IAClB,gBAAgB;IAChB,mBAAmB;IACnB,kBAAkB;IAClB,kBAAkB;IAClB,eAAe;IACf,iBAAiB;IACjB,gBAAgB;IAChB,cAAc;IACd,iBAAiB;IACjB,uBAAuB;CACxB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,KAAK,YAAY,oBAAoB;QAAE,MAAM,KAAK,CAAA;IAEtD,IAAI,OAAO,GAAG,EAAE,CAAA;IAChB,IAAI,UAAU,GAAG,KAAK,CAAA;IAEtB,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,KAId,CAAA;QACD,mEAAmE;QACnE,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC9D,UAAU,GAAG,IAAI,CAAA;QACnB,CAAC;QACD,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAA;IACpE,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;QACnC,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IAC1E,CAAC;IAED,MAAM,WAAW,GAAgB;QAC/B,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;QACzC,OAAO;KACR,CAAA;IACD,MAAM,IAAI,oBAAoB,CAAC,WAAW,CAAC,CAAA;AAC7C,CAAC"}
|