tronlink-signer 0.1.1 → 0.1.3

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
@@ -16,8 +16,9 @@ import { TronSigner } from "tronlink-signer";
16
16
  const signer = new TronSigner();
17
17
  await signer.start();
18
18
 
19
- const { address } = await signer.connectWallet();
19
+ const { address, network } = await signer.connectWallet();
20
20
  const { txId } = await signer.sendTrx("TXxx...", 1);
21
+ const { txId: txId2, status } = 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,21 +42,22 @@ 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 }>`
45
+ ### `signer.connectWallet(network?, options?): Promise<{ address: string; network: string }>`
45
46
 
46
- Opens the browser to connect TronLink and retrieve the wallet address.
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<{ txId: string }>`
49
50
 
50
51
  Sends TRX to a recipient address. Opens a browser approval page for the user to confirm.
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<{ txId: string }>`
59
61
 
60
62
  Sends TRC20 tokens. Opens a browser approval page.
61
63
 
@@ -63,15 +65,16 @@ Sends TRC20 tokens. Opens a browser approval page.
63
65
  | --------- | ---- | ----------- |
64
66
  | `contractAddress` | `string` | TRC20 token contract address |
65
67
  | `to` | `string` | Recipient Tron address (base58) |
66
- | `amount` | `string` | Amount in smallest unit |
68
+ | `amount` | `string` | Amount in human-readable units (e.g., `"1.5"` for 1.5 USDT). Decimals conversion is automatic. |
67
69
  | `decimals` | `number` | Token decimals (default: 6) |
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,25 +89,107 @@ const { signature } = await signer.signTypedData({
86
89
  });
87
90
  ```
88
91
 
89
- ### `signer.signTransaction(transaction, network?): Promise<{ signedTransaction: Record<string, unknown> }>`
92
+ ### `signer.signTransaction(transaction, network?, broadcast?, options?): Promise<{ signedTransaction; txId?; status? }>`
90
93
 
91
- Signs a raw transaction without broadcasting it.
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 (returns `status: "success"` or `"pending"`).
95
+
96
+ | Parameter | Type | Description |
97
+ | --------- | ---- | ----------- |
98
+ | `transaction` | `Record<string, unknown>` | Raw transaction object to sign |
99
+ | `network` | `TronNetwork` | Optional network override |
100
+ | `broadcast` | `boolean` | Whether to broadcast after signing (default: `false`) |
101
+ | `options` | `SignerOptions` | Optional — cancellation, confirmation control, broadcast callback |
102
+
103
+ ```ts
104
+ // Sign only
105
+ const { signedTransaction } = await signer.signTransaction(tx);
106
+
107
+ // Sign, broadcast, and wait for confirmation (default)
108
+ const { signedTransaction, txId, status } = await signer.signTransaction(tx, "nile", true);
109
+ // status === "success" — confirmed on-chain
110
+ // status === "pending" — broadcast succeeded but not confirmed within timeout
111
+
112
+ // Broadcast without waiting for confirmation
113
+ const result = await signer.signTransaction(tx, "nile", true, { confirm: false });
114
+
115
+ // Get notified as soon as the tx enters the mempool
116
+ const result = await signer.signTransaction(tx, "nile", true, {
117
+ onBroadcasted: ({ txId }) => console.log("Broadcast:", txId),
118
+ });
119
+ ```
120
+
121
+ ### `signer.waitForTransaction(txId, network?, options?): Promise<"success" | "pending">`
122
+
123
+ Polls the network for transaction confirmation. Returns `"success"` when the transaction is confirmed on-chain, or `"pending"` if the timeout is reached. Throws if the transaction execution failed (e.g., `OUT_OF_ENERGY`, Solidity revert).
124
+
125
+ | Parameter | Type | Description |
126
+ | --------- | ---- | ----------- |
127
+ | `txId` | `string` | Transaction ID to monitor |
128
+ | `network` | `TronNetwork` | Optional network override |
129
+ | `options` | `WaitForTransactionOptions` | Optional — `timeoutMs` (default: 30000), `signal` |
130
+
131
+ ```ts
132
+ const status = await signer.waitForTransaction(txId, "nile");
133
+ if (status === "success") {
134
+ console.log("Confirmed on-chain");
135
+ }
136
+ ```
137
+
138
+ > **Note:** When using `signTransaction` with `broadcast: true`, confirmation polling is automatic — you don't need to call `waitForTransaction` separately unless you set `confirm: false`.
92
139
 
93
140
  ### `signer.getBalance(address, network?): Promise<{ balance: string; balanceSun: number }>`
94
141
 
95
142
  Gets TRX balance for an address. No browser approval needed.
96
143
 
144
+ ### `signer.onBrowserDisconnect`
145
+
146
+ 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.
147
+
148
+ ```ts
149
+ signer.onBrowserDisconnect = () => {
150
+ console.log("Browser approval page was closed");
151
+ };
152
+ ```
153
+
154
+ ### Cancellation & Options
155
+
156
+ All signing methods accept an optional `SignerOptions`:
157
+
158
+ | Option | Type | Description |
159
+ | ------ | ---- | ----------- |
160
+ | `signal` | `AbortSignal` | Cancels the pending request. If already aborted, the browser page is not opened. |
161
+ | `confirm` | `boolean` | Wait for on-chain confirmation after broadcast (default: `true`). Only applies when `broadcast: true`. |
162
+ | `confirmTimeoutMs` | `number` | Max time (ms) to wait for confirmation (default: `30000`). |
163
+ | `onBroadcasted` | `(info) => void` | Fires after the tx enters the mempool (before confirmation). Callback errors are swallowed. |
164
+
165
+ ```ts
166
+ const controller = new AbortController();
167
+
168
+ // Cancel after 30 seconds
169
+ setTimeout(() => controller.abort(), 30_000);
170
+
171
+ try {
172
+ const { txId } = await signer.sendTrx("TXxx...", 1, undefined, {
173
+ signal: controller.signal,
174
+ });
175
+ } catch (e) {
176
+ // e.message === "CANCELLED_BY_CALLER"
177
+ }
178
+ ```
179
+
97
180
  ## How It Works
98
181
 
99
182
  1. Your code calls a signing method (e.g., `signMessage`)
100
- 2. A local HTTP server starts on port 3386 and the browser opens an approval page
183
+ 2. A local HTTP server starts on port 3386 and a **single browser tab** opens the approval page
101
184
  3. The approval page discovers the wallet via **TIP-6963** protocol (fallback to `window.tron`)
102
185
  4. Auto-unlocks wallet and switches network if needed
103
- 5. User reviews and clicks Approve / Reject
104
- 6. TronLink handles signing in the browser
105
- 7. The result is returned to your code
186
+ 5. For `connectWallet`, if the wallet is already connected, it auto-completes without user interaction
187
+ 6. For signing/sending, the user reviews the transaction details and clicks Approve / Reject
188
+ 7. The approval page parses transaction types (TRX transfer, TRC20, TRC721 NFT, stake, delegate, vote, etc.) into human-readable display
189
+ 8. TronLink handles signing in the browser
190
+ 9. The result is returned to your code — the page stays open and polls for the next request
106
191
 
107
- The local server binds to `127.0.0.1` only. If port 3386 is in use, it auto-increments. Requests timeout after 5 minutes.
192
+ All subsequent operations reuse the same browser tab. Each server session has a unique ID — old browser tabs from previous sessions are automatically invalidated. The page detects server disconnection via heartbeat and shows a session expired message. The local server binds to `127.0.0.1` only. If port 3386 is in use, it auto-increments. Requests timeout after 5 minutes. The server gracefully shuts down on process exit (SIGINT/SIGTERM).
108
193
 
109
194
  ## Networks
110
195
 
@@ -140,6 +225,18 @@ interface NetworkConfig {
140
225
  fullHost: string;
141
226
  explorerUrl: string;
142
227
  }
228
+
229
+ interface SignerOptions {
230
+ signal?: AbortSignal;
231
+ confirm?: boolean;
232
+ confirmTimeoutMs?: number;
233
+ onBroadcasted?: (info: { txId: string; signedTransaction: Record<string, unknown> }) => void;
234
+ }
235
+
236
+ interface WaitForTransactionOptions {
237
+ timeoutMs?: number;
238
+ signal?: AbortSignal;
239
+ }
143
240
  ```
144
241
 
145
242
  ## Exports
@@ -157,6 +254,7 @@ export type {
157
254
  PendingRequestType, PendingRequest,
158
255
  ConnectData, SendTrxData, SendTrc20Data,
159
256
  SignMessageData, SignTypedDataData, SignTransactionData,
257
+ SignerOptions, WaitForTransactionOptions,
160
258
  } from "./types.js";
161
259
  ```
162
260
 
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ 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;
@@ -30,46 +30,97 @@ interface SignTypedDataData {
30
30
  }
31
31
  interface SignTransactionData {
32
32
  transaction: Record<string, unknown>;
33
+ broadcast?: boolean;
33
34
  }
34
35
  interface AppConfig {
35
36
  network: TronNetwork;
36
37
  httpPort: number;
37
38
  apiKey?: string;
38
39
  }
40
+ interface SignerOptions {
41
+ signal?: AbortSignal;
42
+ /** Wait for on-chain execution result after broadcast. Default: true. Only applies to broadcasting operations. */
43
+ confirm?: boolean;
44
+ /** Max time to wait for confirmation, in ms. Default: 30000. */
45
+ confirmTimeoutMs?: number;
46
+ /**
47
+ * Fires after the transaction has been broadcast to the Tron network
48
+ * (txId in mempool, not yet confirmed on-chain). Use this to start your
49
+ * own monitoring in parallel with the SDK's polling. Callback errors are swallowed.
50
+ */
51
+ onBroadcasted?: (info: {
52
+ txId: string;
53
+ signedTransaction: Record<string, unknown>;
54
+ }) => void;
55
+ }
56
+ interface WaitForTransactionOptions {
57
+ timeoutMs?: number;
58
+ signal?: AbortSignal;
59
+ }
39
60
 
40
61
  declare class TronSigner {
41
62
  private config;
42
63
  private pendingStore;
43
64
  private httpServer;
44
65
  private tronWeb;
66
+ private browserWatchTimer;
67
+ private _onBrowserDisconnect;
68
+ private _onWalletChanged;
69
+ private connectedWallet;
70
+ set onBrowserDisconnect(cb: (() => void) | null);
71
+ /**
72
+ * Fires when the user switches account/network or disconnects inside TronLink.
73
+ * All pending requests have already been rejected with "WALLET_CHANGED: <reason>"
74
+ * and the internal connectedWallet cache has been invalidated by the time this
75
+ * callback runs. Reasons: "account" | "network" | "disconnect".
76
+ */
77
+ set onWalletChanged(cb: ((reason: string) => void) | null);
45
78
  constructor();
46
79
  start(): Promise<void>;
47
80
  private getPort;
48
81
  stop(): Promise<void>;
49
82
  getConfig(): AppConfig;
50
83
  private resolveNetwork;
51
- connectWallet(network?: TronNetwork): Promise<{
84
+ /** @returns true if the signal was already aborted */
85
+ private attachAbortSignal;
86
+ connectWallet(network?: TronNetwork, options?: SignerOptions): Promise<{
52
87
  address: string;
88
+ network: string;
53
89
  }>;
54
- sendTrx(to: string, amount: number, network?: TronNetwork): Promise<{
90
+ /**
91
+ * Returns the most recently connected wallet (cached in-memory).
92
+ * Cleared when the approval page disconnects (heartbeat timeout).
93
+ * Callers should treat this as a cache, not ground truth — the user may
94
+ * have switched accounts inside TronLink and the SDK has no way to know.
95
+ * To force a fresh read, call connectWallet() instead.
96
+ */
97
+ getConnectedWallet(): {
98
+ address: string;
99
+ network: TronNetwork;
100
+ } | null;
101
+ sendTrx(to: string, amount: string | number, network?: TronNetwork, options?: SignerOptions): Promise<{
55
102
  txId: string;
56
103
  }>;
57
- sendTrc20(contractAddress: string, to: string, amount: string, decimals?: number, network?: TronNetwork): Promise<{
104
+ sendTrc20(contractAddress: string, to: string, amount: string, decimals?: number, network?: TronNetwork, options?: SignerOptions): Promise<{
58
105
  txId: string;
59
106
  }>;
60
- signMessage(message: string, network?: TronNetwork): Promise<{
107
+ signMessage(message: string, network?: TronNetwork, options?: SignerOptions): Promise<{
61
108
  signature: string;
62
109
  }>;
63
- signTypedData(typedData: Record<string, unknown>, network?: TronNetwork): Promise<{
110
+ signTypedData(typedData: Record<string, unknown>, network?: TronNetwork, options?: SignerOptions): Promise<{
64
111
  signature: string;
65
112
  }>;
66
- signTransaction(transaction: Record<string, unknown>, network?: TronNetwork): Promise<{
113
+ signTransaction(transaction: Record<string, unknown>, network?: TronNetwork, broadcast?: boolean, options?: SignerOptions): Promise<{
67
114
  signedTransaction: Record<string, unknown>;
115
+ txId?: string;
116
+ status?: "success" | "pending";
68
117
  }>;
69
118
  getBalance(address: string, network?: TronNetwork): Promise<{
70
119
  balance: string;
71
120
  balanceSun: number;
72
121
  }>;
122
+ private getTronWebFor;
123
+ waitForTransaction(txId: string, network?: TronNetwork, options?: WaitForTransactionOptions): Promise<"success" | "pending">;
73
124
  }
74
125
 
75
126
  declare const NETWORKS: Record<TronNetwork, NetworkConfig>;
@@ -77,4 +128,4 @@ declare const DEFAULT_HTTP_PORT = 3386;
77
128
  declare const REQUEST_TIMEOUT_MS: number;
78
129
  declare function loadConfig(): AppConfig;
79
130
 
80
- 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 };
131
+ 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 SignerOptions, type TronNetwork, TronSigner, type WaitForTransactionOptions, loadConfig };