@zebec-network/tron-transfer-sdk 1.0.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 +589 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +9 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/services.d.ts +23 -0
- package/dist/services.d.ts.map +1 -0
- package/dist/services.js +148 -0
- package/dist/services.js.map +1 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +35 -0
- package/dist/utils.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
# @zebec-network/tron-transfer-sdk
|
|
2
|
+
|
|
3
|
+
A small TypeScript SDK for sending **TRX** (TRON's native coin) and **TRC-20 tokens** such as **USDT** from one TRON address to another, on either **mainnet** or **testnet** (Nile or Shasta).
|
|
4
|
+
|
|
5
|
+
It wraps [TronWeb](https://tronweb.network) with two functions, `transferTrx` and `transferToken`. Each one takes care of the fiddly parts of a transfer:
|
|
6
|
+
|
|
7
|
+
- **Unit conversion.** You pass amounts in whole units (`"10"` TRX, `"2.5"` USDT). The SDK converts them to on-chain units with exact integer math, so there are no floating-point rounding errors.
|
|
8
|
+
- **Pre-flight checks.** Addresses, amounts and the sender's balance are checked before anything is sent. This matters for tokens: a TRC-20 transfer that fails on-chain still burns TRX in fees.
|
|
9
|
+
- **Build, sign, broadcast.** The transaction is signed locally with the private key from your `.env`. The key never leaves your machine.
|
|
10
|
+
- **Confirmation.** By default the SDK waits until the transaction is in a block and verifies it actually succeeded. The network accepting a transaction does not mean it executed, especially for token transfers.
|
|
11
|
+
- **Readable errors.** Node error messages are decoded, and every failure after broadcast carries the transaction ID.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Contents
|
|
16
|
+
|
|
17
|
+
- [Requirements](#requirements)
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Configuration](#configuration)
|
|
20
|
+
- [Quick start](#quick-start)
|
|
21
|
+
- [API reference](#api-reference)
|
|
22
|
+
- [Types](#types)
|
|
23
|
+
- [How a transfer works](#how-a-transfer-works)
|
|
24
|
+
- [Fees and resources](#fees-and-resources)
|
|
25
|
+
- [Error handling](#error-handling)
|
|
26
|
+
- [Networks and token addresses](#networks-and-token-addresses)
|
|
27
|
+
- [Example CLI](#example-cli)
|
|
28
|
+
- [Development](#development)
|
|
29
|
+
- [Project structure](#project-structure)
|
|
30
|
+
- [Dependencies](#dependencies)
|
|
31
|
+
- [Security](#security)
|
|
32
|
+
- [Troubleshooting](#troubleshooting)
|
|
33
|
+
- [References](#references)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Requirements
|
|
38
|
+
|
|
39
|
+
| Requirement | Version / notes |
|
|
40
|
+
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
41
|
+
| Node.js | **20 or newer** (developed and tested on Node 26) |
|
|
42
|
+
| Package format | **ES modules only** (`"type": "module"`). Load it with `import`, not `require()`. |
|
|
43
|
+
| TypeScript | Optional for consumers. If you use it, set `"moduleResolution"` to `"nodenext"`, `"node16"` or `"bundler"`, and turn on `"skipLibCheck": true` (see below). |
|
|
44
|
+
| A TRON account | Its hex private key, funded with TRX for fees (and holding the token, for token transfers) |
|
|
45
|
+
| TronGrid key | **Required for mainnet** (`api.trongrid.io`); optional on testnets. Get one at [trongrid.io](https://www.trongrid.io). |
|
|
46
|
+
|
|
47
|
+
> **Why `skipLibCheck`?** TronWeb's bundled type definitions don't pass strict type-checking under `nodenext` resolution. Your own code is still fully checked; this only skips checking the `.d.ts` files inside `node_modules`.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm install @zebec-network/tron-transfer-sdk
|
|
55
|
+
# or
|
|
56
|
+
yarn add @zebec-network/tron-transfer-sdk
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then import it:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { transferTrx, transferToken } from '@zebec-network/tron-transfer-sdk';
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
To work on the SDK itself, see [Development](#development).
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
The SDK reads its settings from environment variables. It loads a `.env` file from the **current working directory** automatically when it's imported, via `dotenv`. Variables already set in the real environment take precedence over `.env`, so you can also configure it without a file (for example in CI or a container).
|
|
72
|
+
|
|
73
|
+
Copy the template and fill in your values:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cp .env.example .env
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Variables
|
|
80
|
+
|
|
81
|
+
**General**
|
|
82
|
+
|
|
83
|
+
| Variable | Required | Default | Description |
|
|
84
|
+
| -------------------- | -------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `TRON_NETWORK` | No | `testnet` | Which network calls use when they don't pass `network`: `testnet` or `mainnet`. Not in `.env.example`; add it only to change the default. |
|
|
86
|
+
| `TRON_FEE_LIMIT_SUN` | No | `100000000` | Max TRX, in SUN, that one token transfer may burn for energy. `100000000` SUN = 100 TRX. |
|
|
87
|
+
|
|
88
|
+
**Per network.** Replace `<NET>` with `TESTNET` or `MAINNET`:
|
|
89
|
+
|
|
90
|
+
| Variable | Required | Description |
|
|
91
|
+
| -------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
92
|
+
| `TRON_<NET>_FULL_HOST` | Yes | Full-node URL, e.g. `https://nile.trongrid.io` or `https://api.trongrid.io`. |
|
|
93
|
+
| `TRON_<NET>_PRIVATE_KEY` | Yes | Sender's private key: 64 hex characters. A leading `0x` is accepted and stripped. |
|
|
94
|
+
| `TRON_<NET>_API_KEY` | Mainnet on TronGrid: yes | TronGrid API key, sent as the `TRON-PRO-API-KEY` header. Keyless mainnet requests to `api.trongrid.io` get HTTP 429, so the SDK refuses to run without one. |
|
|
95
|
+
| `TRON_<NET>_USDT_CONTRACT` | No | Default token for `transferToken` when no `tokenAddress` is passed. |
|
|
96
|
+
|
|
97
|
+
**Tests only**
|
|
98
|
+
|
|
99
|
+
| Variable | Description |
|
|
100
|
+
| --------------------- | --------------------------------------------------------------------------------------- |
|
|
101
|
+
| `TRON_TEST_NETWORK` | Network the tests use: `testnet` (default) or `mainnet`. Mainnet tests move real funds. |
|
|
102
|
+
| `TRON_TEST_RECIPIENT` | Address that receives the live transfers when `TRON_TEST_NETWORK=testnet`. |
|
|
103
|
+
| `TRON_MAIN_RECIPIENT` | Address that receives the live transfers when `TRON_TEST_NETWORK=mainnet`. |
|
|
104
|
+
|
|
105
|
+
### Example `.env` for Nile testnet
|
|
106
|
+
|
|
107
|
+
```dotenv
|
|
108
|
+
TRON_TEST_NETWORK=testnet
|
|
109
|
+
TRON_FEE_LIMIT_SUN=100000000
|
|
110
|
+
|
|
111
|
+
TRON_TESTNET_FULL_HOST=https://nile.trongrid.io
|
|
112
|
+
TRON_TESTNET_API_KEY=
|
|
113
|
+
TRON_TESTNET_PRIVATE_KEY=<64-hex-char private key>
|
|
114
|
+
TRON_TESTNET_USDT_CONTRACT=TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf
|
|
115
|
+
|
|
116
|
+
TRON_MAINNET_FULL_HOST=https://api.trongrid.io
|
|
117
|
+
TRON_MAINNET_API_KEY=<your TronGrid key>
|
|
118
|
+
TRON_MAINNET_PRIVATE_KEY=
|
|
119
|
+
TRON_MAINNET_USDT_CONTRACT=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
|
|
120
|
+
|
|
121
|
+
TRON_TEST_RECIPIENT=<a second testnet address>
|
|
122
|
+
TRON_MAIN_RECIPIENT=<a second mainnet address, only for mainnet test runs>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Configuration is read on **every call**, so each call checks only the network it uses. You can leave the mainnet key empty while working on testnet.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Quick start
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { transferTrx, transferToken, TronTransferError } from '@zebec-network/tron-transfer-sdk';
|
|
133
|
+
|
|
134
|
+
// Send 10 TRX on the network set by TRON_NETWORK
|
|
135
|
+
const trx = await transferTrx({ to: 'TXYZ...recipient', amount: '10' });
|
|
136
|
+
console.log(trx.txid, trx.blockNumber, trx.feeSun);
|
|
137
|
+
|
|
138
|
+
// Send 5 USDT (uses TRON_<NET>_USDT_CONTRACT)
|
|
139
|
+
const usdt = await transferToken({ to: 'TXYZ...recipient', amount: '5' });
|
|
140
|
+
|
|
141
|
+
// Send any other TRC-20 token, explicitly on mainnet
|
|
142
|
+
await transferToken({
|
|
143
|
+
to: 'TXYZ...recipient',
|
|
144
|
+
amount: '1.25',
|
|
145
|
+
tokenAddress: 'T...tokenContract',
|
|
146
|
+
network: 'mainnet',
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Handle failures
|
|
150
|
+
try {
|
|
151
|
+
await transferTrx({ to: 'TXYZ...recipient', amount: '1' });
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error instanceof TronTransferError && error.txid) {
|
|
154
|
+
// The transaction reached the network; look it up before retrying.
|
|
155
|
+
console.error(`Failed after broadcast: ${error.txid}`);
|
|
156
|
+
}
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## API reference
|
|
164
|
+
|
|
165
|
+
Everything below is exported from the package root.
|
|
166
|
+
|
|
167
|
+
### `transferTrx(params)`
|
|
168
|
+
|
|
169
|
+
Sends native TRX from the account configured for the network.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
function transferTrx(params: TransferTrxParams): Promise<TransferResult>;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| Param | Type | Default | Description |
|
|
176
|
+
| ----------------------- | ------------------------ | -------------- | --------------------------------------------------- |
|
|
177
|
+
| `to` | `string` | required | Recipient base58 address (`T...`). |
|
|
178
|
+
| `amount` | `string \| number` | required | Amount in **TRX**, not SUN. Up to 6 decimal places. |
|
|
179
|
+
| `network` | `'testnet' \| 'mainnet'` | `TRON_NETWORK` | Network for this call. |
|
|
180
|
+
| `waitForConfirmation` | `boolean` | `true` | Wait for the block and verify success. |
|
|
181
|
+
| `confirmationTimeoutMs` | `number` | `60000` | How long to wait for confirmation. |
|
|
182
|
+
|
|
183
|
+
Before sending, it checks that:
|
|
184
|
+
|
|
185
|
+
- `to` is a valid address and isn't the sender;
|
|
186
|
+
- `amount` is positive and has at most 6 decimals;
|
|
187
|
+
- the sender's TRX balance is at least `amount`.
|
|
188
|
+
|
|
189
|
+
The balance check reads the full node's latest state, not the roughly one-minute-old "solidified" state that `trx.getBalance()` returns. It doesn't account for fees, so a transfer of your entire balance can still be rejected by the node if bandwidth has to be paid for.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
await transferTrx({ to: 'TXYZ...', amount: '0.5' }); // 500,000 SUN
|
|
193
|
+
await transferTrx({ to: 'TXYZ...', amount: 12 }); // 12 TRX
|
|
194
|
+
await transferTrx({ to: 'TXYZ...', amount: '1', waitForConfirmation: false }); // return right after broadcast
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### `transferToken(params)`
|
|
198
|
+
|
|
199
|
+
Sends a TRC-20 token by calling its `transfer(address,uint256)` function. The default token is the USDT contract configured for the network.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
function transferToken(params: TransferTokenParams): Promise<TransferResult>;
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
| Param | Type | Default | Description |
|
|
206
|
+
| ----------------------- | ------------------------ | -------------------------- | ---------------------------------------------------------- |
|
|
207
|
+
| `to` | `string` | required | Recipient base58 address. |
|
|
208
|
+
| `amount` | `string \| number` | required | Amount in **whole tokens** (e.g. `"5"` USDT). |
|
|
209
|
+
| `tokenAddress` | `string` | `TRON_<NET>_USDT_CONTRACT` | TRC-20 contract address. |
|
|
210
|
+
| `feeLimitSun` | `number` | `TRON_FEE_LIMIT_SUN` | Max TRX (in SUN) this transfer may burn for energy. |
|
|
211
|
+
| `network` | `'testnet' \| 'mainnet'` | `TRON_NETWORK` | Network for this call. |
|
|
212
|
+
| `waitForConfirmation` | `boolean` | `true` | Wait for the block and verify the contract call succeeded. |
|
|
213
|
+
| `confirmationTimeoutMs` | `number` | `60000` | How long to wait for confirmation. |
|
|
214
|
+
|
|
215
|
+
Before sending, it:
|
|
216
|
+
|
|
217
|
+
1. validates `to` and `tokenAddress`;
|
|
218
|
+
2. reads the token's `decimals()` from the contract, so any TRC-20 token works, not only 6-decimal ones;
|
|
219
|
+
3. converts `amount` using those decimals, rejecting amounts with too many decimal places;
|
|
220
|
+
4. reads `balanceOf(sender)` and refuses if the balance is too low.
|
|
221
|
+
|
|
222
|
+
The sender also needs **TRX** to pay for energy; see [Fees and resources](#fees-and-resources).
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
await transferToken({ to: 'TXYZ...', amount: '5' }); // 5 USDT
|
|
226
|
+
await transferToken({ to: 'TXYZ...', amount: '0.25', tokenAddress: 'T...' }); // any TRC-20
|
|
227
|
+
await transferToken({ to: 'TXYZ...', amount: '100', feeLimitSun: 30_000_000 }); // cap fees at 30 TRX
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### `TronTransferError`
|
|
231
|
+
|
|
232
|
+
The error class for transfer failures. It extends `Error` and adds:
|
|
233
|
+
|
|
234
|
+
| Property | Type | Description |
|
|
235
|
+
| -------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
236
|
+
| `txid` | `string \| undefined` | Set when the transaction **reached the network**. If present, fees may have been charged; check the transaction before retrying. |
|
|
237
|
+
|
|
238
|
+
The `message` includes the txid when there is one. See [Error handling](#error-handling) for the full list of failures.
|
|
239
|
+
|
|
240
|
+
### `loadConfig(network?)`
|
|
241
|
+
|
|
242
|
+
Reads and validates configuration from the environment. `transferTrx` and `transferToken` call it for you; it's exported for advanced use.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
function loadConfig(network?: TronNetwork): NetworkConfig;
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
It defaults to `TRON_NETWORK`, and throws `Error` on missing or invalid variables.
|
|
249
|
+
|
|
250
|
+
### `createTronWeb(config)`
|
|
251
|
+
|
|
252
|
+
Creates a TronWeb instance from a `NetworkConfig`, with the private key and API key header set. Use it to call TronWeb directly for anything the SDK doesn't cover:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
import { createTronWeb, loadConfig } from '@zebec-network/tron-transfer-sdk';
|
|
256
|
+
|
|
257
|
+
const tronWeb = createTronWeb(loadConfig('testnet'));
|
|
258
|
+
const account = await tronWeb.trx.getAccount('TXYZ...');
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
function createTronWeb(config: NetworkConfig): TronWeb;
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### `toBaseUnits(amount, decimals)`
|
|
266
|
+
|
|
267
|
+
Converts a human-readable amount into the smallest unit using exact `bigint` math. This is the same conversion the transfer functions use.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
function toBaseUnits(amount: Amount, decimals: number): bigint;
|
|
271
|
+
|
|
272
|
+
toBaseUnits('1.5', 6); // 1500000n
|
|
273
|
+
toBaseUnits(10, 6); // 10000000n
|
|
274
|
+
toBaseUnits('0.000001', 6); // 1n
|
|
275
|
+
toBaseUnits('1.0000001', 6); // throws: more than 6 decimal places
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
It rejects zero, negative, non-numeric and over-precise amounts. It also rejects numbers that JavaScript prints in exponent form (such as `1e21`); pass those as strings.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Types
|
|
283
|
+
|
|
284
|
+
All types are exported from the package root.
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
type TronNetwork = 'mainnet' | 'testnet';
|
|
288
|
+
|
|
289
|
+
/** Human-readable amount, e.g. "10" TRX or "2.5" USDT. Prefer strings to avoid float rounding. */
|
|
290
|
+
type Amount = string | number;
|
|
291
|
+
|
|
292
|
+
interface TransferOptions {
|
|
293
|
+
network?: TronNetwork; // default: TRON_NETWORK
|
|
294
|
+
waitForConfirmation?: boolean; // default: true
|
|
295
|
+
confirmationTimeoutMs?: number; // default: 60_000
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
interface TransferTrxParams extends TransferOptions {
|
|
299
|
+
to: string;
|
|
300
|
+
amount: Amount; // in TRX
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
interface TransferTokenParams extends TransferOptions {
|
|
304
|
+
to: string;
|
|
305
|
+
amount: Amount; // in whole tokens
|
|
306
|
+
tokenAddress?: string; // default: TRON_<NET>_USDT_CONTRACT
|
|
307
|
+
feeLimitSun?: number; // default: TRON_FEE_LIMIT_SUN
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
interface TransferResult {
|
|
311
|
+
txid: string;
|
|
312
|
+
network: TronNetwork;
|
|
313
|
+
from: string; // sender, derived from the private key
|
|
314
|
+
to: string;
|
|
315
|
+
rawAmount: string; // smallest unit: SUN for TRX, base units for tokens
|
|
316
|
+
confirmed: boolean; // false when waitForConfirmation is false
|
|
317
|
+
blockNumber?: number; // set when confirmed
|
|
318
|
+
feeSun?: number; // total fee paid, in SUN; set when confirmed
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
interface NetworkConfig {
|
|
322
|
+
network: TronNetwork;
|
|
323
|
+
fullHost: string;
|
|
324
|
+
apiKey: string | undefined;
|
|
325
|
+
privateKey: string;
|
|
326
|
+
usdtContract: string | undefined;
|
|
327
|
+
feeLimitSun: number;
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
`rawAmount` is a string because token base units can exceed JavaScript's safe integer range. Use `BigInt(result.rawAmount)` to do arithmetic on it.
|
|
332
|
+
|
|
333
|
+
Example result:
|
|
334
|
+
|
|
335
|
+
```json
|
|
336
|
+
{
|
|
337
|
+
"txid": "1a7cdfebe0d9dd0d6cfdeba64d6d8d7acd06be7f38dfa4e34bbfa6850f54b170",
|
|
338
|
+
"network": "testnet",
|
|
339
|
+
"from": "TVrt71K6kXpYx8mPdBbadEYZVikTWwFuv6",
|
|
340
|
+
"to": "TADdZ38GMHSebqx9bxAqGdZth2zWNMcGBa",
|
|
341
|
+
"rawAmount": "1",
|
|
342
|
+
"confirmed": true,
|
|
343
|
+
"blockNumber": 71387491,
|
|
344
|
+
"feeSun": 265000
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## How a transfer works
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
load config ─► validate inputs ─► check balance ─► build tx ─► sign locally ─► broadcast ─► wait for block ─► verify result
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
1. **Load config** for the network and derive the sender address from the private key.
|
|
357
|
+
2. **Validate** the recipient, the amount, and (for tokens) the contract address and its `decimals()`.
|
|
358
|
+
3. **Check balance:** TRX via the full node, tokens via `balanceOf`.
|
|
359
|
+
4. **Build** the transaction: `transactionBuilder.sendTrx` for TRX, or `transactionBuilder.triggerSmartContract` calling `transfer(address,uint256)` for tokens.
|
|
360
|
+
5. **Sign** it locally with `trx.sign`. The private key is never sent anywhere.
|
|
361
|
+
6. **Broadcast** it with `trx.sendRawTransaction`. If the node rejects it, the SDK throws with the decoded reason.
|
|
362
|
+
7. **Wait for confirmation.** The SDK polls `getUnconfirmedTransactionInfo` every ~3 s (one TRON block) until the transaction appears in a block, up to `confirmationTimeoutMs`.
|
|
363
|
+
8. **Verify.** If the transaction failed on-chain (for example a token contract revert or running out of energy), the SDK throws a `TronTransferError` with the txid.
|
|
364
|
+
|
|
365
|
+
### Why confirmation is on by default
|
|
366
|
+
|
|
367
|
+
A successful broadcast only means a node **accepted** the transaction. For a TRC-20 transfer, the contract call can still **revert** when it executes, and the TRX spent on energy is burned anyway. Only after the transaction is in a block can you tell whether it succeeded. With `waitForConfirmation: false` you get back `{ txid, confirmed: false }` right away, and checking the outcome is up to you.
|
|
368
|
+
|
|
369
|
+
"Confirmed" here means **included in a block**. TRON considers a block irreversible ("solidified") after roughly 19 more blocks, about a minute. For high-value flows, you may want to wait for that too, using TronWeb's `trx.getTransactionInfo`.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Fees and resources
|
|
374
|
+
|
|
375
|
+
TRON charges fees in two resources. Each account gets some bandwidth free every day; beyond that, fees are paid by **burning TRX** from the sender.
|
|
376
|
+
|
|
377
|
+
| Resource | Used by | If you don't have enough |
|
|
378
|
+
| ------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
379
|
+
| **Bandwidth** | Every transaction (roughly proportional to its size) | TRX is burned. Accounts get free bandwidth daily; after that, a TRX transfer costs about 0.27 TRX. |
|
|
380
|
+
| **Energy** | Smart-contract calls, i.e. token transfers | TRX is burned, capped by `feeLimitSun`. Staking TRX for energy avoids this. |
|
|
381
|
+
|
|
382
|
+
Things to keep in mind:
|
|
383
|
+
|
|
384
|
+
- **Token transfers need TRX.** A USDT transfer typically uses roughly 65k energy to an address that already holds USDT, and roughly double that to one that doesn't. If the sender has no staked energy, that is paid for in TRX, and the amount depends on the network's current energy price.
|
|
385
|
+
- **`feeLimitSun` is a ceiling, not a price.** If a contract call needs more energy than the limit allows, it fails with `OUT_OF_ENERGY` and the TRX spent so far is still burned. The default of 100 TRX is generous for USDT.
|
|
386
|
+
- **New accounts cost extra.** Sending TRX to an address that has never been used creates it on-chain. This costs the sender an extra ~1 TRX, plus a little bandwidth.
|
|
387
|
+
- `TransferResult.feeSun` reports the **total** fee actually paid (bandwidth + energy), in SUN.
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Error handling
|
|
392
|
+
|
|
393
|
+
There are two error types:
|
|
394
|
+
|
|
395
|
+
- **`TronTransferError`**: anything about the transfer itself (addresses, balances, broadcast, on-chain result).
|
|
396
|
+
- **Plain `Error`**: configuration problems (from `loadConfig`) and invalid amounts (from `toBaseUnits`). These are thrown before anything touches the network.
|
|
397
|
+
|
|
398
|
+
| When | Message (abridged) | Type | `txid` set? |
|
|
399
|
+
| ------------ | ----------------------------------------------------------------- | ------------------- | ----------- |
|
|
400
|
+
| Config | `Missing required environment variable …` | `Error` | – |
|
|
401
|
+
| Config | `… PRIVATE_KEY must be a 64-character hex string.` | `Error` | – |
|
|
402
|
+
| Config | `TRON_NETWORK must be "mainnet" or "testnet" …` | `Error` | – |
|
|
403
|
+
| Config | `TRON_FEE_LIMIT_SUN must be a positive integer …` | `Error` | – |
|
|
404
|
+
| Amount | `Invalid amount …` / `Amount must be greater than zero …` | `Error` | – |
|
|
405
|
+
| Amount | `Amount … has more than N decimal places.` | `Error` | – |
|
|
406
|
+
| Validation | `Invalid recipient address …` | `TronTransferError` | No |
|
|
407
|
+
| Validation | `Recipient address is the same as the sender address.` | `TronTransferError` | No |
|
|
408
|
+
| Validation | `Invalid token contract address …` | `TronTransferError` | No |
|
|
409
|
+
| Validation | `No token address given and TRON_<NET>_USDT_CONTRACT is not set.` | `TronTransferError` | No |
|
|
410
|
+
| Validation | `Call to decimals() on … failed … Is this a TRC-20 contract …?` | `TronTransferError` | No |
|
|
411
|
+
| Balance | `Insufficient TRX balance …` / `Insufficient token balance …` | `TronTransferError` | No |
|
|
412
|
+
| Build | `Failed to build token transfer: …` | `TronTransferError` | No |
|
|
413
|
+
| Broadcast | `Broadcast rejected: <code> <reason>` | `TronTransferError` | Yes |
|
|
414
|
+
| On-chain | `Transaction failed on-chain: <reason>` | `TronTransferError` | Yes |
|
|
415
|
+
| Confirmation | `Transaction was broadcast but not confirmed within …` | `TronTransferError` | Yes |
|
|
416
|
+
|
|
417
|
+
Guidance for retries:
|
|
418
|
+
|
|
419
|
+
- **No `txid`:** nothing was sent and no fees were charged. It's safe to fix the problem and retry.
|
|
420
|
+
- **`txid` set:** the transaction reached the network. For a confirmation timeout, it may still succeed. **Look the txid up on an explorer (or with `trx.getTransactionInfo`) before retrying**, or you may send twice.
|
|
421
|
+
|
|
422
|
+
Errors from TronWeb or the network itself, such as connection failures, HTTP 429 rate limiting, or an unreachable node, are passed through unchanged.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Networks and token addresses
|
|
427
|
+
|
|
428
|
+
| Network | Full host | USDT contract | Explorer | Faucet |
|
|
429
|
+
| ------------------ | -------------------------------- | ------------------------------------ | -------------------------------------------------- | ----------------------------------------------- |
|
|
430
|
+
| **Mainnet** | `https://api.trongrid.io` | `TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t` | [tronscan.org](https://tronscan.org) | – |
|
|
431
|
+
| **Nile** testnet | `https://nile.trongrid.io` | `TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf` | [nile.tronscan.org](https://nile.tronscan.org) | [nileex.io](https://nileex.io/join/getJoinPage) |
|
|
432
|
+
| **Shasta** testnet | `https://api.shasta.trongrid.io` | `TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs` | [shasta.tronscan.org](https://shasta.tronscan.org) | [shasta.tronex.io](https://shasta.tronex.io) |
|
|
433
|
+
|
|
434
|
+
The SDK has one `testnet` slot. Choose Nile or Shasta by setting `TRON_TESTNET_FULL_HOST` and `TRON_TESTNET_USDT_CONTRACT` to the matching pair. Testnet tokens have no real value.
|
|
435
|
+
|
|
436
|
+
Always double-check a mainnet token contract address against the issuer or [tronscan.org](https://tronscan.org). Tokens sent to the wrong contract or address can't be recovered.
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Example CLI
|
|
441
|
+
|
|
442
|
+
[`examples/transfer.ts`](examples/transfer.ts) is a small command-line wrapper around both functions. It runs directly from TypeScript through ts-node, so no build is needed, and it uses the network set by `TRON_NETWORK`.
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
npm run example -- trx <toAddress> <amount>
|
|
446
|
+
npm run example -- token <toAddress> <amount> [tokenAddress]
|
|
447
|
+
|
|
448
|
+
# e.g.
|
|
449
|
+
npm run example -- trx TADdZ38GMHSebqx9bxAqGdZth2zWNMcGBa 1
|
|
450
|
+
npm run example -- token TADdZ38GMHSebqx9bxAqGdZth2zWNMcGBa 2.5
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
It prints the `TransferResult` as JSON, or the error message with a non-zero exit code. **These are real transfers** on whichever network is configured.
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## Development
|
|
458
|
+
|
|
459
|
+
Clone the repository and install dependencies:
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
git clone https://github.com/Zebec-Fintech-Labs/tron-transfer-sdk.git
|
|
463
|
+
cd tron-transfer-sdk
|
|
464
|
+
npm install
|
|
465
|
+
cp .env.example .env
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Scripts
|
|
469
|
+
|
|
470
|
+
| Script | Description |
|
|
471
|
+
| ------------------- | --------------------------------------------------------------------------------------- |
|
|
472
|
+
| `npm run build` | Cleans `dist/` and compiles `src/` into it (JS, `.d.ts`, source maps). |
|
|
473
|
+
| `npm run clean` | Removes the `dist/` directory. |
|
|
474
|
+
| `npm run format` | Formats the codebase with Prettier. |
|
|
475
|
+
| `npm test` | Runs the Mocha test suite via ts-mocha, against the network set by `TRON_TEST_NETWORK`. |
|
|
476
|
+
| `npm run typecheck` | Type-checks `src/`, `test/` and `examples/`. |
|
|
477
|
+
| `npm run example` | Runs the [example CLI](#example-cli). |
|
|
478
|
+
|
|
479
|
+
### Running tests
|
|
480
|
+
|
|
481
|
+
The tests use **Mocha** through **ts-mocha**, with Node's built-in `node:assert`. They make **live transfers** on the network set by `TRON_TEST_NETWORK` (default `testnet`); there are no mocks.
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
npm test
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
They need these variables in `.env` (see [Configuration](#configuration)):
|
|
488
|
+
|
|
489
|
+
| Test network | Required variables |
|
|
490
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
491
|
+
| `testnet` (default) | `TRON_TESTNET_FULL_HOST`, `TRON_TESTNET_PRIVATE_KEY` (sender funded with TRX, plus USDT from the faucet), `TRON_TESTNET_USDT_CONTRACT`, `TRON_TEST_RECIPIENT` |
|
|
492
|
+
| `mainnet` | `TRON_TEST_NETWORK=mainnet`, `TRON_MAINNET_FULL_HOST`, `TRON_MAINNET_API_KEY`, `TRON_MAINNET_PRIVATE_KEY`, `TRON_MAINNET_USDT_CONTRACT`, `TRON_MAIN_RECIPIENT` |
|
|
493
|
+
|
|
494
|
+
Use a recipient you control so you can reuse the funds. **On mainnet the tests spend real TRX and USDT.**
|
|
495
|
+
|
|
496
|
+
What's covered (19 tests):
|
|
497
|
+
|
|
498
|
+
| File | Live transfers | Validation (nothing is sent) |
|
|
499
|
+
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
500
|
+
| [`test/transferTrx.test.ts`](test/transferTrx.test.ts) | 0.5 TRX with recipient balance check; 0.5 TRX as a number; `waitForConfirmation: false` | Bad address, self-send, zero / negative / non-numeric / over-precise amounts, insufficient balance |
|
|
501
|
+
| [`test/transferToken.test.ts`](test/transferToken.test.ts) | 0.5 USDT via the default contract with balance check; 0.25 USDT via explicit `tokenAddress`; `waitForConfirmation: false` | Bad recipient, self-send, bad token address, non-TRC-20 address, too many decimals, insufficient balance |
|
|
502
|
+
|
|
503
|
+
- **Cost per run:** about 1 TRX and 0.75 USDT go to the recipient, plus network fees (up to ~0.3 TRX per TRX transfer once the sender's free bandwidth is used up; USDT transfers also burn TRX for energy unless the sender has staked energy).
|
|
504
|
+
- **Duration:** about 25 s.
|
|
505
|
+
- The test files run one after the other with a generous timeout (`-t 1000000`), since each live transfer waits for a block.
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Project structure
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
tron-transfer-sdk/
|
|
513
|
+
├── src/
|
|
514
|
+
│ ├── index.ts # Public exports
|
|
515
|
+
│ ├── services.ts # transferTrx, transferToken, TronTransferError
|
|
516
|
+
│ ├── config.ts # Env loading and validation (loadConfig)
|
|
517
|
+
│ ├── client.ts # TronWeb instance factory (createTronWeb)
|
|
518
|
+
│ ├── types.ts # Public parameter and result types
|
|
519
|
+
│ └── utils.ts # Exact amount conversion (toBaseUnits)
|
|
520
|
+
├── test/
|
|
521
|
+
│ ├── helpers.ts # Shared test setup and balance readers
|
|
522
|
+
│ ├── transferTrx.test.ts
|
|
523
|
+
│ └── transferToken.test.ts
|
|
524
|
+
├── examples/
|
|
525
|
+
│ └── transfer.ts # Example CLI
|
|
526
|
+
├── dist/ # Build output (the only folder that gets published)
|
|
527
|
+
├── .env.example # Configuration template
|
|
528
|
+
├── .mocharc.json # Mocha: test paths + ts-node ESM loader
|
|
529
|
+
├── .prettierrc.json # Formatting rules
|
|
530
|
+
├── tsconfig.json # Type-checking for src, test, examples (editor, typecheck, tests)
|
|
531
|
+
└── tsconfig.build.json # Build config: src/ → dist/
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## Dependencies
|
|
537
|
+
|
|
538
|
+
### Runtime
|
|
539
|
+
|
|
540
|
+
| Package | Why |
|
|
541
|
+
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
|
|
542
|
+
| [`tronweb`](https://www.npmjs.com/package/tronweb) `^6.5.1` | The official TRON JavaScript SDK: builds, signs and broadcasts transactions, and talks to full nodes. |
|
|
543
|
+
| [`dotenv`](https://www.npmjs.com/package/dotenv) `^18` | Loads `.env` when the SDK is imported. |
|
|
544
|
+
|
|
545
|
+
### Development
|
|
546
|
+
|
|
547
|
+
| Package | Why |
|
|
548
|
+
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
549
|
+
| `typescript` `^6` | Compiler. **Pinned to 6** because ts-node (and so ts-mocha) needs TypeScript's JavaScript API, which TypeScript 7 no longer ships. |
|
|
550
|
+
| `ts-node` | Runs TypeScript directly for the tests and the example CLI. |
|
|
551
|
+
| `mocha` `^11`, `ts-mocha` | Test runner. Mocha stays on 11 because ts-mocha doesn't support 12 yet. |
|
|
552
|
+
| `@types/mocha`, `@types/node` | Type definitions. |
|
|
553
|
+
| `prettier` | Code formatting. |
|
|
554
|
+
| `rimraf` | Cross-platform `dist/` cleanup. |
|
|
555
|
+
|
|
556
|
+
### A note on the test setup
|
|
557
|
+
|
|
558
|
+
The package is ESM (`"type": "module"`). ts-mocha on its own only sets up a CommonJS hook, which Mocha bypasses when it loads ES-module test files. [`.mocharc.json`](.mocharc.json) therefore also registers `ts-node/esm` as a Node loader. It silences two harmless warnings that loader triggers on recent Node versions (`ExperimentalWarning` and `DEP0180`).
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## Troubleshooting
|
|
563
|
+
|
|
564
|
+
| Symptom | Likely cause and fix |
|
|
565
|
+
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
566
|
+
| `Missing required environment variable TRON_…` | `.env` isn't in the **current working directory** of the process, or the variable is empty. Run from the folder containing `.env`, or set the variable in the environment. |
|
|
567
|
+
| HTTP 429 / rate-limit errors on mainnet | Set `TRON_MAINNET_API_KEY`. |
|
|
568
|
+
| `Insufficient TRX balance` right after funding the account | The new funds haven't reached the node yet. Wait one or two blocks (~6 s) and retry. |
|
|
569
|
+
| `Call to decimals() on … failed` | The token address isn't a TRC-20 contract **on the selected network**. A common mistake is using the mainnet USDT address on testnet, or vice versa. |
|
|
570
|
+
| `Transaction failed on-chain: OUT_OF_ENERGY` | `feeLimitSun` was too low, or the sender ran out of TRX for energy. Raise the limit or add TRX, and check the txid. |
|
|
571
|
+
| `Transaction was broadcast but not confirmed within …` | The network is slow or congested. Look up the txid **before** retrying; it may still succeed. |
|
|
572
|
+
| `Broadcast rejected: … balance is not sufficient` | The balance covers the amount but not the fees. Leave some TRX for bandwidth and energy. |
|
|
573
|
+
| TypeScript errors inside `node_modules/tronweb/...` | Enable `"skipLibCheck": true` in your tsconfig. |
|
|
574
|
+
| `ERR_REQUIRE_ESM` or `require() of ES Module` | The package is ESM-only. Use `import`, or dynamic `import()` from CommonJS. |
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## References
|
|
579
|
+
|
|
580
|
+
- [Source repository](https://github.com/Zebec-Fintech-Labs/tron-transfer-sdk) ([issues](https://github.com/Zebec-Fintech-Labs/tron-transfer-sdk/issues))
|
|
581
|
+
- [TRON: Send your first transaction](https://developers.tron.network/docs/send-first-transaction)
|
|
582
|
+
- [TRON: TRC-20 contract interaction](https://developers.tron.network/docs/trc20-contract-interaction)
|
|
583
|
+
- [TRON: Resource model (bandwidth and energy)](https://developers.tron.network/docs/resource-model)
|
|
584
|
+
- [TronWeb documentation](https://tronweb.network/docu/docs/intro)
|
|
585
|
+
- [TronGrid (API keys)](https://www.trongrid.io)
|
|
586
|
+
|
|
587
|
+
## License
|
|
588
|
+
|
|
589
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAM5D"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TronWeb } from 'tronweb';
|
|
2
|
+
export function createTronWeb(config) {
|
|
3
|
+
return new TronWeb({
|
|
4
|
+
fullHost: config.fullHost,
|
|
5
|
+
privateKey: config.privateKey,
|
|
6
|
+
...(config.apiKey ? { headers: { 'TRON-PRO-API-KEY': config.apiKey } } : {}),
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,OAAO,IAAI,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7E,CAAC,CAAC;AACL,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
export type TronNetwork = 'mainnet' | 'testnet';
|
|
3
|
+
export interface NetworkConfig {
|
|
4
|
+
network: TronNetwork;
|
|
5
|
+
fullHost: string;
|
|
6
|
+
apiKey: string | undefined;
|
|
7
|
+
privateKey: string;
|
|
8
|
+
usdtContract: string | undefined;
|
|
9
|
+
feeLimitSun: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Reads the configuration for a network from environment variables.
|
|
13
|
+
* Defaults to the network named by TRON_NETWORK.
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadConfig(network?: TronNetwork): NetworkConfig;
|
|
16
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAEvB,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;CACrB;AAkCD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,WAAmD,GAAG,aAAa,CAuBtG"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
const DEFAULT_FEE_LIMIT_SUN = 100_000_000; // 100 TRX
|
|
3
|
+
function readEnv(name) {
|
|
4
|
+
const value = process.env[name]?.trim();
|
|
5
|
+
return value ? value : undefined;
|
|
6
|
+
}
|
|
7
|
+
function requireEnv(name) {
|
|
8
|
+
const value = readEnv(name);
|
|
9
|
+
if (!value) {
|
|
10
|
+
throw new Error(`Missing required environment variable ${name}. See .env.example.`);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function parseNetwork(value) {
|
|
15
|
+
const network = (value ?? 'testnet').toLowerCase();
|
|
16
|
+
if (network !== 'mainnet' && network !== 'testnet') {
|
|
17
|
+
throw new Error(`TRON_NETWORK must be "mainnet" or "testnet", got "${value}".`);
|
|
18
|
+
}
|
|
19
|
+
return network;
|
|
20
|
+
}
|
|
21
|
+
function parseFeeLimit(value) {
|
|
22
|
+
if (value === undefined)
|
|
23
|
+
return DEFAULT_FEE_LIMIT_SUN;
|
|
24
|
+
const feeLimit = Number(value);
|
|
25
|
+
if (!Number.isSafeInteger(feeLimit) || feeLimit <= 0) {
|
|
26
|
+
throw new Error(`TRON_FEE_LIMIT_SUN must be a positive integer (in SUN), got "${value}".`);
|
|
27
|
+
}
|
|
28
|
+
return feeLimit;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Reads the configuration for a network from environment variables.
|
|
32
|
+
* Defaults to the network named by TRON_NETWORK.
|
|
33
|
+
*/
|
|
34
|
+
export function loadConfig(network = parseNetwork(readEnv('TRON_NETWORK'))) {
|
|
35
|
+
const prefix = `TRON_${network.toUpperCase()}`;
|
|
36
|
+
const privateKey = requireEnv(`${prefix}_PRIVATE_KEY`).replace(/^0x/i, '');
|
|
37
|
+
if (!/^[0-9a-fA-F]{64}$/.test(privateKey)) {
|
|
38
|
+
throw new Error(`${prefix}_PRIVATE_KEY must be a 64-character hex string.`);
|
|
39
|
+
}
|
|
40
|
+
const fullHost = requireEnv(`${prefix}_FULL_HOST`);
|
|
41
|
+
const apiKey = readEnv(`${prefix}_API_KEY`);
|
|
42
|
+
if (network === 'mainnet' && !apiKey && /(^|\.)trongrid\.io$/i.test(new URL(fullHost).hostname)) {
|
|
43
|
+
// Keyless TronGrid mainnet requests get HTTP 429 after a few calls, often mid-transfer.
|
|
44
|
+
throw new Error(`${prefix}_API_KEY is required for ${fullHost}. Get one at https://www.trongrid.io.`);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
network,
|
|
48
|
+
fullHost,
|
|
49
|
+
apiKey,
|
|
50
|
+
privateKey,
|
|
51
|
+
usdtContract: readEnv(`${prefix}_USDT_CONTRACT`),
|
|
52
|
+
feeLimitSun: parseFeeLimit(readEnv('TRON_FEE_LIMIT_SUN')),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AAavB,MAAM,qBAAqB,GAAG,WAAW,CAAC,CAAC,UAAU;AAErD,SAAS,OAAO,CAAC,IAAY;IAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IACxC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACnC,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,qBAAqB,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB;IAC7C,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IACnD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,qDAAqD,KAAK,IAAI,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB;IAC9C,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,qBAAqB,CAAC;IACtD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,gEAAgE,KAAK,IAAI,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAAuB,YAAY,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACrF,MAAM,MAAM,GAAG,QAAQ,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;IAC/C,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,MAAM,cAAc,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAE3E,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,iDAAiD,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,MAAM,YAAY,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,MAAM,UAAU,CAAC,CAAC;IAC5C,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM,IAAI,sBAAsB,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChG,wFAAwF;QACxF,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,4BAA4B,QAAQ,uCAAuC,CAAC,CAAC;IACxG,CAAC;IAED,OAAO;QACL,OAAO;QACP,QAAQ;QACR,MAAM;QACN,UAAU;QACV,YAAY,EAAE,OAAO,CAAC,GAAG,MAAM,gBAAgB,CAAC;QAChD,WAAW,EAAE,aAAa,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;KAC1D,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { transferTrx, transferToken, TronTransferError } from './services.js';
|
|
2
|
+
export { loadConfig } from './config.js';
|
|
3
|
+
export type { NetworkConfig, TronNetwork } from './config.js';
|
|
4
|
+
export { createTronWeb } from './client.js';
|
|
5
|
+
export { toBaseUnits } from './utils.js';
|
|
6
|
+
export type { Amount, TransferOptions, TransferResult, TransferTokenParams, TransferTrxParams } from './types.js';
|
|
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,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TransferResult, TransferTokenParams, TransferTrxParams } from './types.js';
|
|
2
|
+
/** Thrown for any failed transfer. `txid` is set when the transaction reached the network. */
|
|
3
|
+
export declare class TronTransferError extends Error {
|
|
4
|
+
readonly txid: string | undefined;
|
|
5
|
+
constructor(message: string, txid?: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Sends native TRX from the account configured in .env.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* await transferTrx({ to: 'TXYZ...', amount: '10' }); // 10 TRX
|
|
12
|
+
*/
|
|
13
|
+
export declare function transferTrx(params: TransferTrxParams): Promise<TransferResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Sends a TRC-20 token (USDT by default) from the account configured in .env.
|
|
16
|
+
* The sender needs TRX to pay for energy; up to `feeLimitSun` may be burned.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* await transferToken({ to: 'TXYZ...', amount: '5' }); // 5 USDT
|
|
20
|
+
* await transferToken({ to: 'TXYZ...', amount: '1.25', tokenAddress: 'T...' }); // any TRC-20
|
|
21
|
+
*/
|
|
22
|
+
export declare function transferToken(params: TransferTokenParams): Promise<TransferResult>;
|
|
23
|
+
//# sourceMappingURL=services.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAmB,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAO1G,8FAA8F;AAC9F,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;gBAEtB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAK3C;AAqHD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAqBpF;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAwCxF"}
|
package/dist/services.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { TronWeb } from 'tronweb';
|
|
2
|
+
import { createTronWeb } from './client.js';
|
|
3
|
+
import { loadConfig } from './config.js';
|
|
4
|
+
import { sleep, toBaseUnits } from './utils.js';
|
|
5
|
+
const TRX_DECIMALS = 6; // 1 TRX = 1,000,000 SUN
|
|
6
|
+
const DEFAULT_CONFIRMATION_TIMEOUT_MS = 60_000;
|
|
7
|
+
const CONFIRMATION_POLL_INTERVAL_MS = 3_000; // roughly one TRON block
|
|
8
|
+
/** Thrown for any failed transfer. `txid` is set when the transaction reached the network. */
|
|
9
|
+
export class TronTransferError extends Error {
|
|
10
|
+
txid;
|
|
11
|
+
constructor(message, txid) {
|
|
12
|
+
super(txid ? `${message} (txid: ${txid})` : message);
|
|
13
|
+
this.name = 'TronTransferError';
|
|
14
|
+
this.txid = txid;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function openSession(network) {
|
|
18
|
+
const config = loadConfig(network);
|
|
19
|
+
const from = TronWeb.address.fromPrivateKey(config.privateKey);
|
|
20
|
+
if (!from) {
|
|
21
|
+
throw new TronTransferError('Could not derive an address from the configured private key.');
|
|
22
|
+
}
|
|
23
|
+
return { config, tronWeb: createTronWeb(config), from };
|
|
24
|
+
}
|
|
25
|
+
function assertRecipient(to, from) {
|
|
26
|
+
if (!TronWeb.isAddress(to)) {
|
|
27
|
+
throw new TronTransferError(`Invalid recipient address "${to}".`);
|
|
28
|
+
}
|
|
29
|
+
if (TronWeb.address.toHex(to) === TronWeb.address.toHex(from)) {
|
|
30
|
+
throw new TronTransferError('Recipient address is the same as the sender address.');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Node error messages are often hex-encoded UTF-8; decode them when possible. */
|
|
34
|
+
function decodeNodeMessage(message) {
|
|
35
|
+
if (!message)
|
|
36
|
+
return 'unknown error';
|
|
37
|
+
if (/^[0-9a-fA-F]+$/.test(message) && message.length % 2 === 0) {
|
|
38
|
+
return Buffer.from(message, 'hex').toString('utf8');
|
|
39
|
+
}
|
|
40
|
+
return message;
|
|
41
|
+
}
|
|
42
|
+
async function signAndBroadcast(tronWeb, transaction) {
|
|
43
|
+
const signed = (await tronWeb.trx.sign(transaction));
|
|
44
|
+
const broadcast = await tronWeb.trx.sendRawTransaction(signed);
|
|
45
|
+
if (!broadcast.result) {
|
|
46
|
+
throw new TronTransferError(`Broadcast rejected: ${broadcast.code ?? 'ERROR'} ${decodeNodeMessage(broadcast.message)}`, broadcast.txid || signed.txID);
|
|
47
|
+
}
|
|
48
|
+
return broadcast.txid || signed.txID;
|
|
49
|
+
}
|
|
50
|
+
/** Polls until the transaction is in a block, then throws if it failed on-chain. */
|
|
51
|
+
async function waitForConfirmation(tronWeb, txid, timeoutMs) {
|
|
52
|
+
const deadline = Date.now() + timeoutMs;
|
|
53
|
+
while (Date.now() < deadline) {
|
|
54
|
+
await sleep(CONFIRMATION_POLL_INTERVAL_MS);
|
|
55
|
+
const info = await tronWeb.trx.getUnconfirmedTransactionInfo(txid);
|
|
56
|
+
if (!info?.id)
|
|
57
|
+
continue;
|
|
58
|
+
const receiptResult = info.receipt?.result;
|
|
59
|
+
if (info.result === 'FAILED' || (receiptResult && receiptResult !== 'SUCCESS')) {
|
|
60
|
+
const reason = decodeNodeMessage(info.resMessage) || receiptResult || 'FAILED';
|
|
61
|
+
throw new TronTransferError(`Transaction failed on-chain: ${reason}`, txid);
|
|
62
|
+
}
|
|
63
|
+
return info;
|
|
64
|
+
}
|
|
65
|
+
throw new TronTransferError(`Transaction was broadcast but not confirmed within ${timeoutMs}ms. Check its status before retrying to avoid a double send`, txid);
|
|
66
|
+
}
|
|
67
|
+
async function finalize(session, txid, to, rawAmount, options) {
|
|
68
|
+
const result = {
|
|
69
|
+
txid,
|
|
70
|
+
network: session.config.network,
|
|
71
|
+
from: session.from,
|
|
72
|
+
to,
|
|
73
|
+
rawAmount: rawAmount.toString(),
|
|
74
|
+
confirmed: false,
|
|
75
|
+
};
|
|
76
|
+
if (options.waitForConfirmation === false)
|
|
77
|
+
return result;
|
|
78
|
+
const info = await waitForConfirmation(session.tronWeb, txid, options.confirmationTimeoutMs ?? DEFAULT_CONFIRMATION_TIMEOUT_MS);
|
|
79
|
+
return { ...result, confirmed: true, blockNumber: info.blockNumber, feeSun: info.fee ?? 0 };
|
|
80
|
+
}
|
|
81
|
+
async function callConstant(session, contractAddress, functionSelector, parameters = []) {
|
|
82
|
+
const response = await session.tronWeb.transactionBuilder.triggerConstantContract(contractAddress, functionSelector, {}, parameters, session.from);
|
|
83
|
+
const hex = response.constant_result?.[0];
|
|
84
|
+
if (!response.result?.result || typeof hex !== 'string' || hex.length === 0) {
|
|
85
|
+
throw new TronTransferError(`Call to ${functionSelector} on ${contractAddress} failed: ${decodeNodeMessage(response.result?.message)}. Is this a TRC-20 contract on the ${session.config.network}?`);
|
|
86
|
+
}
|
|
87
|
+
return BigInt(`0x${hex}`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Sends native TRX from the account configured in .env.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* await transferTrx({ to: 'TXYZ...', amount: '10' }); // 10 TRX
|
|
94
|
+
*/
|
|
95
|
+
export async function transferTrx(params) {
|
|
96
|
+
const session = openSession(params.network);
|
|
97
|
+
const { tronWeb, from } = session;
|
|
98
|
+
assertRecipient(params.to, from);
|
|
99
|
+
const amountSun = toBaseUnits(params.amount, TRX_DECIMALS);
|
|
100
|
+
if (amountSun > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
101
|
+
throw new TronTransferError(`Amount ${params.amount} TRX is too large.`);
|
|
102
|
+
}
|
|
103
|
+
// getBalance() reads solidified state (~1 min behind); use the full node's latest view instead.
|
|
104
|
+
const balanceSun = BigInt(await tronWeb.trx.getUnconfirmedBalance(from));
|
|
105
|
+
if (balanceSun < amountSun) {
|
|
106
|
+
throw new TronTransferError(`Insufficient TRX balance: have ${balanceSun} SUN, need ${amountSun} SUN (plus fees if bandwidth is exhausted).`);
|
|
107
|
+
}
|
|
108
|
+
const transaction = await tronWeb.transactionBuilder.sendTrx(params.to, Number(amountSun), from);
|
|
109
|
+
const txid = await signAndBroadcast(tronWeb, transaction);
|
|
110
|
+
return finalize(session, txid, params.to, amountSun, params);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Sends a TRC-20 token (USDT by default) from the account configured in .env.
|
|
114
|
+
* The sender needs TRX to pay for energy; up to `feeLimitSun` may be burned.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* await transferToken({ to: 'TXYZ...', amount: '5' }); // 5 USDT
|
|
118
|
+
* await transferToken({ to: 'TXYZ...', amount: '1.25', tokenAddress: 'T...' }); // any TRC-20
|
|
119
|
+
*/
|
|
120
|
+
export async function transferToken(params) {
|
|
121
|
+
const session = openSession(params.network);
|
|
122
|
+
const { tronWeb, from, config } = session;
|
|
123
|
+
assertRecipient(params.to, from);
|
|
124
|
+
const tokenAddress = params.tokenAddress ?? config.usdtContract;
|
|
125
|
+
if (!tokenAddress) {
|
|
126
|
+
throw new TronTransferError(`No token address given and TRON_${config.network.toUpperCase()}_USDT_CONTRACT is not set.`);
|
|
127
|
+
}
|
|
128
|
+
if (!TronWeb.isAddress(tokenAddress)) {
|
|
129
|
+
throw new TronTransferError(`Invalid token contract address "${tokenAddress}".`);
|
|
130
|
+
}
|
|
131
|
+
const decimals = Number(await callConstant(session, tokenAddress, 'decimals()'));
|
|
132
|
+
const amount = toBaseUnits(params.amount, decimals);
|
|
133
|
+
// A TRC-20 transfer that reverts still burns energy, so check the balance up front.
|
|
134
|
+
const balance = await callConstant(session, tokenAddress, 'balanceOf(address)', [{ type: 'address', value: from }]);
|
|
135
|
+
if (balance < amount) {
|
|
136
|
+
throw new TronTransferError(`Insufficient token balance: have ${balance}, need ${amount} (base units).`);
|
|
137
|
+
}
|
|
138
|
+
const { result, transaction } = await tronWeb.transactionBuilder.triggerSmartContract(tokenAddress, 'transfer(address,uint256)', { feeLimit: params.feeLimitSun ?? config.feeLimitSun, callValue: 0 }, [
|
|
139
|
+
{ type: 'address', value: params.to },
|
|
140
|
+
{ type: 'uint256', value: amount.toString() },
|
|
141
|
+
], from);
|
|
142
|
+
if (!result?.result) {
|
|
143
|
+
throw new TronTransferError(`Failed to build token transfer: ${decodeNodeMessage(result?.message)}`);
|
|
144
|
+
}
|
|
145
|
+
const txid = await signAndBroadcast(tronWeb, transaction);
|
|
146
|
+
return finalize(session, txid, params.to, amount, params);
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=services.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { TronNetwork } from './config.js';
|
|
2
|
+
/** Human-readable amount, e.g. "10" TRX or "2.5" USDT. Strings avoid floating-point rounding. */
|
|
3
|
+
export type Amount = string | number;
|
|
4
|
+
export interface TransferOptions {
|
|
5
|
+
/** Network to use. Defaults to TRON_NETWORK from .env. */
|
|
6
|
+
network?: TronNetwork;
|
|
7
|
+
/**
|
|
8
|
+
* Wait until the transaction is included in a block and check it succeeded.
|
|
9
|
+
* Broadcast success alone does not mean a TRC-20 transfer executed. Default: true.
|
|
10
|
+
*/
|
|
11
|
+
waitForConfirmation?: boolean;
|
|
12
|
+
/** How long to wait for confirmation, in milliseconds. Default: 60_000. */
|
|
13
|
+
confirmationTimeoutMs?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface TransferTrxParams extends TransferOptions {
|
|
16
|
+
/** Recipient base58 address (T...). */
|
|
17
|
+
to: string;
|
|
18
|
+
/** Amount in TRX (not SUN). */
|
|
19
|
+
amount: Amount;
|
|
20
|
+
}
|
|
21
|
+
export interface TransferTokenParams extends TransferOptions {
|
|
22
|
+
/** Recipient base58 address (T...). */
|
|
23
|
+
to: string;
|
|
24
|
+
/** Amount in whole tokens (e.g. "5" USDT), converted using the token's decimals. */
|
|
25
|
+
amount: Amount;
|
|
26
|
+
/** TRC-20 contract address. Defaults to the USDT contract configured for the network. */
|
|
27
|
+
tokenAddress?: string;
|
|
28
|
+
/** Max TRX (in SUN) to burn for energy. Defaults to TRON_FEE_LIMIT_SUN. */
|
|
29
|
+
feeLimitSun?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface TransferResult {
|
|
32
|
+
txid: string;
|
|
33
|
+
network: TronNetwork;
|
|
34
|
+
from: string;
|
|
35
|
+
to: string;
|
|
36
|
+
/** Amount in the smallest unit (SUN for TRX, token base units for TRC-20). */
|
|
37
|
+
rawAmount: string;
|
|
38
|
+
/** True once the transaction is confirmed in a block; false if confirmation was not awaited. */
|
|
39
|
+
confirmed: boolean;
|
|
40
|
+
/** Block number, when confirmed. */
|
|
41
|
+
blockNumber?: number;
|
|
42
|
+
/** Total fee paid in SUN, when confirmed. */
|
|
43
|
+
feeSun?: number;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,iGAAiG;AACjG,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErC,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IAC1D,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,oFAAoF;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,SAAS,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Amount } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a human-readable amount into the smallest unit using exact integer math,
|
|
4
|
+
* e.g. toBaseUnits("1.5", 6) === 1_500_000n.
|
|
5
|
+
*/
|
|
6
|
+
export declare function toBaseUnits(amount: Amount, decimals: number): bigint;
|
|
7
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAmBpE;AAaD,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a human-readable amount into the smallest unit using exact integer math,
|
|
3
|
+
* e.g. toBaseUnits("1.5", 6) === 1_500_000n.
|
|
4
|
+
*/
|
|
5
|
+
export function toBaseUnits(amount, decimals) {
|
|
6
|
+
const text = typeof amount === 'number' ? numberToPlainString(amount) : amount.trim();
|
|
7
|
+
const match = /^(\d+)(?:\.(\d*))?$/.exec(text);
|
|
8
|
+
if (!match) {
|
|
9
|
+
throw new Error(`Invalid amount "${amount}". Use a positive decimal like "10" or "0.5".`);
|
|
10
|
+
}
|
|
11
|
+
const whole = match[1] ?? '0';
|
|
12
|
+
const fraction = match[2] ?? '';
|
|
13
|
+
if (fraction.length > decimals) {
|
|
14
|
+
throw new Error(`Amount "${amount}" has more than ${decimals} decimal places.`);
|
|
15
|
+
}
|
|
16
|
+
const units = BigInt(whole + fraction.padEnd(decimals, '0'));
|
|
17
|
+
if (units <= 0n) {
|
|
18
|
+
throw new Error(`Amount must be greater than zero, got "${amount}".`);
|
|
19
|
+
}
|
|
20
|
+
return units;
|
|
21
|
+
}
|
|
22
|
+
function numberToPlainString(value) {
|
|
23
|
+
if (!Number.isFinite(value)) {
|
|
24
|
+
throw new Error(`Invalid amount ${value}.`);
|
|
25
|
+
}
|
|
26
|
+
const text = String(value);
|
|
27
|
+
if (/e/i.test(text)) {
|
|
28
|
+
throw new Error(`Amount ${value} is too large or small for a number; pass it as a string instead.`);
|
|
29
|
+
}
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
export function sleep(ms) {
|
|
33
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,QAAgB;IAC1D,MAAM,IAAI,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAEtF,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,+CAA+C,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,QAAQ,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,mBAAmB,QAAQ,kBAAkB,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7D,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,0CAA0C,MAAM,IAAI,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,GAAG,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,UAAU,KAAK,mEAAmE,CAAC,CAAC;IACtG,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zebec-network/tron-transfer-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Minimal SDK for transferring TRX and TRC-20 tokens (e.g. USDT) on TRON mainnet and testnet",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/mocha": "^10.0.10",
|
|
14
|
+
"@types/node": "^26.6.3",
|
|
15
|
+
"mocha": "^11.7.5",
|
|
16
|
+
"prettier": "^3.9.9",
|
|
17
|
+
"rimraf": "^6.1.3",
|
|
18
|
+
"ts-mocha": "^11.1.0",
|
|
19
|
+
"ts-node": "^10.9.2",
|
|
20
|
+
"typescript": "^6.0.3"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
27
|
+
"clean": "rimraf ./dist",
|
|
28
|
+
"format": "prettier --write .",
|
|
29
|
+
"test": "ts-mocha -p ./tsconfig.json -t 1000000",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"example": "node --loader ts-node/esm --disable-warning=ExperimentalWarning --disable-warning=DEP0180 examples/transfer.ts"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"dotenv": "^18.0.4",
|
|
35
|
+
"tronweb": "^6.5.1"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/Zebec-Fintech-Labs/tron-transfer-sdk.git"
|
|
40
|
+
}
|
|
41
|
+
}
|