tronlink-signer 0.1.2 → 0.1.4

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 CHANGED
@@ -17,7 +17,8 @@ const signer = new TronSigner();
17
17
  await signer.start();
18
18
 
19
19
  const { address, network } = await signer.connectWallet();
20
- const { txId } = await signer.sendTrx("TXxx...", 1);
20
+ const { txId, status } = await signer.sendTrx("TXxx...", 1); // status: "success" | "pending" | "failed"
21
+ const { txId: txId2, status: s2 } = await signer.signTransaction(tx, "nile", true); // broadcast + auto-confirm
21
22
  const { balance } = await signer.getBalance("TXxx...");
22
23
 
23
24
  await signer.stop();
@@ -41,37 +42,39 @@ Stops the server and clears all pending requests.
41
42
 
42
43
  Returns the current configuration.
43
44
 
44
- ### `signer.connectWallet(network?: TronNetwork): Promise<{ address: string; network: string }>`
45
+ ### `signer.connectWallet(network?, options?): Promise<{ address: string; network: string }>`
45
46
 
46
47
  Opens the browser to connect TronLink and retrieve the wallet address and current network. If the wallet is already connected (same browser tab still open), auto-completes without user interaction.
47
48
 
48
- ### `signer.sendTrx(to, amount, network?): Promise<{ txId: string }>`
49
+ ### `signer.sendTrx(to, amount, network?, options?): Promise<BroadcastResult>`
49
50
 
50
- Sends TRX to a recipient address. Opens a browser approval page for the user to confirm.
51
+ Sends TRX to a recipient address. Opens a browser approval page for the user to confirm. Returns `{ txId, status, error? }` where `status` is `"success"`, `"pending"`, or `"failed"` (see [Broadcast Result](#broadcast-result)).
51
52
 
52
53
  | Parameter | Type | Description |
53
54
  | --------- | ---- | ----------- |
54
55
  | `to` | `string` | Recipient Tron address (base58) |
55
- | `amount` | `number` | Amount of TRX to send |
56
+ | `amount` | `string \| number` | Amount of TRX to send |
56
57
  | `network` | `TronNetwork` | Optional network override |
58
+ | `options` | `SignerOptions` | Optional — pass `{ signal }` to enable cancellation |
57
59
 
58
- ### `signer.sendTrc20(contractAddress, to, amount, decimals?, network?): Promise<{ txId: string }>`
60
+ ### `signer.sendTrc20(contractAddress, to, amount, decimals?, network?, options?): Promise<BroadcastResult>`
59
61
 
60
- Sends TRC20 tokens. Opens a browser approval page.
62
+ Sends TRC20 tokens. Opens a browser approval page. Returns `{ txId, status, error? }` — see [Broadcast Result](#broadcast-result).
61
63
 
62
64
  | Parameter | Type | Description |
63
65
  | --------- | ---- | ----------- |
64
66
  | `contractAddress` | `string` | TRC20 token contract address |
65
67
  | `to` | `string` | Recipient Tron address (base58) |
66
68
  | `amount` | `string` | Amount in human-readable units (e.g., `"1.5"` for 1.5 USDT). Decimals conversion is automatic. |
67
- | `decimals` | `number` | Token decimals (default: 6) |
69
+ | `decimals` | `number` | Optional. Token decimals. Omit to auto-detect via the contract's `decimals()` view (recommended — avoids 10^N magnitude errors on non-6dp tokens like USDD/SUN/JST). |
68
70
  | `network` | `TronNetwork` | Optional network override |
71
+ | `options` | `SignerOptions` | Optional — pass `{ signal }` to enable cancellation |
69
72
 
70
- ### `signer.signMessage(message, network?): Promise<{ signature: string }>`
73
+ ### `signer.signMessage(message, network?, options?): Promise<{ signature: string }>`
71
74
 
72
75
  Signs a plain text message.
73
76
 
74
- ### `signer.signTypedData(typedData, network?): Promise<{ signature: string }>`
77
+ ### `signer.signTypedData(typedData, network?, options?): Promise<{ signature: string }>`
75
78
 
76
79
  Signs EIP-712 typed data.
77
80
 
@@ -86,28 +89,108 @@ const { signature } = await signer.signTypedData({
86
89
  });
87
90
  ```
88
91
 
89
- ### `signer.signTransaction(transaction, network?, broadcast?): Promise<{ signedTransaction: Record<string, unknown>; txId?: string }>`
92
+ ### `signer.signTransaction(transaction, network?, broadcast?, options?): Promise<{ signedTransaction; txId?; status?; error? }>`
90
93
 
91
- Signs a raw transaction. When `broadcast` is `true`, the signed transaction is also broadcast on-chain via TronLink and the `txId` is returned.
94
+ Signs a raw transaction. When `broadcast` is `true`, the signed transaction is broadcast on-chain via TronLink and the SDK automatically polls for on-chain confirmation — see [Broadcast Result](#broadcast-result) for the possible `status` values.
92
95
 
93
96
  | Parameter | Type | Description |
94
97
  | --------- | ---- | ----------- |
95
98
  | `transaction` | `Record<string, unknown>` | Raw transaction object to sign |
96
99
  | `network` | `TronNetwork` | Optional network override |
97
100
  | `broadcast` | `boolean` | Whether to broadcast after signing (default: `false`) |
101
+ | `options` | `SignerOptions` | Optional — cancellation, confirmation control, broadcast callback |
98
102
 
99
103
  ```ts
100
104
  // Sign only
101
105
  const { signedTransaction } = await signer.signTransaction(tx);
102
106
 
103
- // Sign and broadcast
104
- const { signedTransaction, txId } = await signer.signTransaction(tx, "nile", true);
107
+ // Sign, broadcast, and wait for confirmation (default)
108
+ const { signedTransaction, txId, status, error } = await signer.signTransaction(tx, "nile", true);
109
+ // status === "success" — confirmed on-chain
110
+ // status === "pending" — broadcast succeeded but not confirmed within timeout
111
+ // status === "failed" — on-chain execution failed; `error` carries the reason
112
+
113
+ // Broadcast without waiting for confirmation
114
+ const result = await signer.signTransaction(tx, "nile", true, { confirm: false });
115
+
116
+ // Get notified as soon as the tx enters the mempool
117
+ const result = await signer.signTransaction(tx, "nile", true, {
118
+ onBroadcasted: ({ txId }) => console.log("Broadcast:", txId),
119
+ });
105
120
  ```
106
121
 
122
+ ### Broadcast Result
123
+
124
+ Broadcasting methods (`sendTrx`, `sendTrc20`, and `signTransaction` with `broadcast: true`) return a `BroadcastResult`:
125
+
126
+ ```ts
127
+ interface BroadcastResult {
128
+ txId: string;
129
+ status: "success" | "pending" | "failed";
130
+ error?: string; // set when status === "failed"
131
+ }
132
+ ```
133
+
134
+ `"failed"` means the transaction reached the chain but execution failed (e.g. `OUT_OF_ENERGY`, Solidity revert). **It is not thrown** — inspect `status` instead. The SDK only throws when broadcast itself never happened (signature error, user rejection, network unreachable, etc.).
135
+
136
+ ### `signer.waitForTransaction(txId, network?, options?): Promise<{ status; error? }>`
137
+
138
+ Polls the network for transaction confirmation. Returns `{ status: "success" }` when confirmed, `{ status: "pending" }` on timeout, or `{ status: "failed", error }` when the transaction reverted / ran out of energy.
139
+
140
+ | Parameter | Type | Description |
141
+ | --------- | ---- | ----------- |
142
+ | `txId` | `string` | Transaction ID to monitor |
143
+ | `network` | `TronNetwork` | Optional network override |
144
+ | `options` | `WaitForTransactionOptions` | Optional — `timeoutMs` (default: 30000), `signal` |
145
+
146
+ ```ts
147
+ const { status, error } = await signer.waitForTransaction(txId, "nile");
148
+ if (status === "success") console.log("Confirmed on-chain");
149
+ else if (status === "failed") console.warn("Execution failed:", error);
150
+ ```
151
+
152
+ > **Note:** When using `signTransaction` with `broadcast: true`, confirmation polling is automatic — you don't need to call `waitForTransaction` separately unless you set `confirm: false`.
153
+
107
154
  ### `signer.getBalance(address, network?): Promise<{ balance: string; balanceSun: number }>`
108
155
 
109
156
  Gets TRX balance for an address. No browser approval needed.
110
157
 
158
+ ### `signer.onBrowserDisconnect`
159
+
160
+ Setter for a callback that fires when the approval page is closed or loses connection (heartbeat timeout). Useful for cleanup or re-prompting the user.
161
+
162
+ ```ts
163
+ signer.onBrowserDisconnect = () => {
164
+ console.log("Browser approval page was closed");
165
+ };
166
+ ```
167
+
168
+ ### Cancellation & Options
169
+
170
+ All signing methods accept an optional `SignerOptions`:
171
+
172
+ | Option | Type | Description |
173
+ | ------ | ---- | ----------- |
174
+ | `signal` | `AbortSignal` | Cancels the pending request. If already aborted, the browser page is not opened. |
175
+ | `confirm` | `boolean` | Wait for on-chain confirmation after broadcast (default: `true`). Only applies when `broadcast: true`. |
176
+ | `confirmTimeoutMs` | `number` | Max time (ms) to wait for confirmation (default: `30000`). |
177
+ | `onBroadcasted` | `(info) => void` | Fires after the tx enters the mempool (before confirmation). Callback errors are swallowed. |
178
+
179
+ ```ts
180
+ const controller = new AbortController();
181
+
182
+ // Cancel after 30 seconds
183
+ setTimeout(() => controller.abort(), 30_000);
184
+
185
+ try {
186
+ const { txId } = await signer.sendTrx("TXxx...", 1, undefined, {
187
+ signal: controller.signal,
188
+ });
189
+ } catch (e) {
190
+ // e.message === "CANCELLED_BY_CALLER"
191
+ }
192
+ ```
193
+
111
194
  ## How It Works
112
195
 
113
196
  1. Your code calls a signing method (e.g., `signMessage`)
@@ -156,6 +239,26 @@ interface NetworkConfig {
156
239
  fullHost: string;
157
240
  explorerUrl: string;
158
241
  }
242
+
243
+ interface SignerOptions {
244
+ signal?: AbortSignal;
245
+ confirm?: boolean;
246
+ confirmTimeoutMs?: number;
247
+ onBroadcasted?: (info: { txId: string; signedTransaction: Record<string, unknown> }) => void;
248
+ }
249
+
250
+ interface WaitForTransactionOptions {
251
+ timeoutMs?: number;
252
+ signal?: AbortSignal;
253
+ }
254
+
255
+ type BroadcastStatus = "success" | "pending" | "failed";
256
+
257
+ interface BroadcastResult {
258
+ txId: string;
259
+ status: BroadcastStatus;
260
+ error?: string;
261
+ }
159
262
  ```
160
263
 
161
264
  ## Exports
@@ -171,8 +274,10 @@ export { NETWORKS, DEFAULT_HTTP_PORT, REQUEST_TIMEOUT_MS, loadConfig } from "./c
171
274
  export type {
172
275
  TronNetwork, NetworkConfig, AppConfig,
173
276
  PendingRequestType, PendingRequest,
174
- ConnectData, SendTrxData, SendTrc20Data,
277
+ SendTrxData, SendTrc20Data,
175
278
  SignMessageData, SignTypedDataData, SignTransactionData,
279
+ SignerOptions, WaitForTransactionOptions,
280
+ BroadcastStatus, BroadcastResult,
176
281
  } from "./types.js";
177
282
  ```
178
283
 
package/dist/index.d.ts CHANGED
@@ -14,13 +14,13 @@ interface PendingRequest<T = unknown> {
14
14
  }
15
15
  interface SendTrxData {
16
16
  to: string;
17
- amount: number;
17
+ amount: string | number;
18
18
  }
19
19
  interface SendTrc20Data {
20
20
  contractAddress: string;
21
21
  to: string;
22
22
  amount: string;
23
- decimals: number;
23
+ decimals?: number;
24
24
  }
25
25
  interface SignMessageData {
26
26
  message: string;
@@ -32,47 +32,107 @@ interface SignTransactionData {
32
32
  transaction: Record<string, unknown>;
33
33
  broadcast?: boolean;
34
34
  }
35
+ type BroadcastStatus = "success" | "pending" | "failed";
36
+ interface BroadcastResult {
37
+ txId: string;
38
+ status: BroadcastStatus;
39
+ /** Failure reason when status === "failed". */
40
+ error?: string;
41
+ }
35
42
  interface AppConfig {
36
43
  network: TronNetwork;
37
44
  httpPort: number;
38
45
  apiKey?: string;
39
46
  }
47
+ interface SignerOptions {
48
+ signal?: AbortSignal;
49
+ /** Wait for on-chain execution result after broadcast. Default: true. Only applies to broadcasting operations. */
50
+ confirm?: boolean;
51
+ /** Max time to wait for confirmation, in ms. Default: 30000. */
52
+ confirmTimeoutMs?: number;
53
+ /**
54
+ * Fires after the transaction has been broadcast to the Tron network
55
+ * (txId in mempool, not yet confirmed on-chain). Use this to start your
56
+ * own monitoring in parallel with the SDK's polling. Callback errors are swallowed.
57
+ */
58
+ onBroadcasted?: (info: {
59
+ txId: string;
60
+ signedTransaction: Record<string, unknown>;
61
+ }) => void;
62
+ }
63
+ interface WaitForTransactionOptions {
64
+ timeoutMs?: number;
65
+ signal?: AbortSignal;
66
+ }
40
67
 
41
68
  declare class TronSigner {
42
69
  private config;
43
70
  private pendingStore;
44
71
  private httpServer;
45
72
  private tronWeb;
73
+ private browserWatchTimer;
74
+ private _onBrowserDisconnect;
75
+ private _onWalletChanged;
76
+ private connectedWallet;
77
+ private broadcastListeners;
78
+ set onBrowserDisconnect(cb: (() => void) | null);
79
+ /**
80
+ * Fires when the user switches account/network or disconnects inside TronLink.
81
+ * All pending requests have already been rejected with "WALLET_CHANGED: <reason>"
82
+ * and the internal connectedWallet cache has been invalidated by the time this
83
+ * callback runs. Reasons: "account" | "network" | "disconnect".
84
+ */
85
+ set onWalletChanged(cb: ((reason: string) => void) | null);
46
86
  constructor();
87
+ /** Register a listener that fires the moment the browser reports a successful broadcast
88
+ * (before on-chain confirmation). Auto-removed when `promise` settles. */
89
+ private registerBroadcastListener;
47
90
  start(): Promise<void>;
48
91
  private getPort;
49
92
  stop(): Promise<void>;
50
93
  getConfig(): AppConfig;
51
94
  private resolveNetwork;
52
- connectWallet(network?: TronNetwork): Promise<{
95
+ private confirmIfNeeded;
96
+ /** @returns true if the signal was already aborted */
97
+ private attachAbortSignal;
98
+ connectWallet(network?: TronNetwork, options?: SignerOptions): Promise<{
53
99
  address: string;
54
100
  network: string;
55
101
  }>;
56
- sendTrx(to: string, amount: number, network?: TronNetwork): Promise<{
57
- txId: string;
58
- }>;
59
- sendTrc20(contractAddress: string, to: string, amount: string, decimals?: number, network?: TronNetwork): Promise<{
60
- txId: string;
61
- }>;
62
- signMessage(message: string, network?: TronNetwork): Promise<{
102
+ /**
103
+ * Returns the most recently connected wallet (cached in-memory).
104
+ * Cleared when the approval page disconnects (heartbeat timeout).
105
+ * Callers should treat this as a cache, not ground truth — the user may
106
+ * have switched accounts inside TronLink and the SDK has no way to know.
107
+ * To force a fresh read, call connectWallet() instead.
108
+ */
109
+ getConnectedWallet(): {
110
+ address: string;
111
+ network: TronNetwork;
112
+ } | null;
113
+ sendTrx(to: string, amount: string | number, network?: TronNetwork, options?: SignerOptions): Promise<BroadcastResult>;
114
+ sendTrc20(contractAddress: string, to: string, amount: string, decimals?: number, network?: TronNetwork, options?: SignerOptions): Promise<BroadcastResult>;
115
+ signMessage(message: string, network?: TronNetwork, options?: SignerOptions): Promise<{
63
116
  signature: string;
64
117
  }>;
65
- signTypedData(typedData: Record<string, unknown>, network?: TronNetwork): Promise<{
118
+ signTypedData(typedData: Record<string, unknown>, network?: TronNetwork, options?: SignerOptions): Promise<{
66
119
  signature: string;
67
120
  }>;
68
- signTransaction(transaction: Record<string, unknown>, network?: TronNetwork, broadcast?: boolean): Promise<{
121
+ signTransaction(transaction: Record<string, unknown>, network?: TronNetwork, broadcast?: boolean, options?: SignerOptions): Promise<{
69
122
  signedTransaction: Record<string, unknown>;
70
123
  txId?: string;
124
+ status?: BroadcastStatus;
125
+ error?: string;
71
126
  }>;
72
127
  getBalance(address: string, network?: TronNetwork): Promise<{
73
128
  balance: string;
74
129
  balanceSun: number;
75
130
  }>;
131
+ private getTronWebFor;
132
+ waitForTransaction(txId: string, network?: TronNetwork, options?: WaitForTransactionOptions): Promise<{
133
+ status: BroadcastStatus;
134
+ error?: string;
135
+ }>;
76
136
  }
77
137
 
78
138
  declare const NETWORKS: Record<TronNetwork, NetworkConfig>;
@@ -80,4 +140,4 @@ declare const DEFAULT_HTTP_PORT = 3386;
80
140
  declare const REQUEST_TIMEOUT_MS: number;
81
141
  declare function loadConfig(): AppConfig;
82
142
 
83
- export { type AppConfig, DEFAULT_HTTP_PORT, NETWORKS, type NetworkConfig, type PendingRequest, type PendingRequestType, REQUEST_TIMEOUT_MS, type SendTrc20Data, type SendTrxData, type SignMessageData, type SignTransactionData, type SignTypedDataData, type TronNetwork, TronSigner, loadConfig };
143
+ export { type AppConfig, type BroadcastResult, type BroadcastStatus, DEFAULT_HTTP_PORT, NETWORKS, type NetworkConfig, type PendingRequest, type PendingRequestType, REQUEST_TIMEOUT_MS, type SendTrc20Data, type SendTrxData, type SignMessageData, type SignTransactionData, type SignTypedDataData, type SignerOptions, type TronNetwork, TronSigner, type WaitForTransactionOptions, loadConfig };