trx.ts 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467
  1. import { TronWeb } from '../tronweb.js';
  2. import utils from '../utils/index.js';
  3. import { keccak256, toUtf8Bytes, recoverAddress, SigningKey, Signature } from '../utils/ethersUtils.js';
  4. import { ADDRESS_PREFIX } from '../utils/address.js';
  5. import { Validator } from '../paramValidator/index.js';
  6. import { txCheck } from '../utils/transaction.js';
  7. import { ecRecover } from '../utils/crypto.js';
  8. import { Block, GetTransactionResponse } from '../types/APIResponse.js';
  9. import {
  10. Token,
  11. Account,
  12. AccountNetMessage,
  13. Witness,
  14. TransactionSignWeight,
  15. BroadcastReturn,
  16. AddressOptions,
  17. Proposal,
  18. ChainParameter,
  19. BroadcastHexReturn,
  20. AccountResourceMessage,
  21. Address,
  22. Exchange,
  23. TransactionInfo,
  24. } from '../types/Trx.js';
  25. import { SignedTransaction, Transaction } from '../types/Transaction.js';
  26. import { TypedDataDomain, TypedDataField } from '../utils/typedData.js';
  27. import { Resource } from '../types/TransactionBuilder.js';
  28. const TRX_MESSAGE_HEADER = '\x19TRON Signed Message:\n32';
  29. // it should be: '\x15TRON Signed Message:\n32';
  30. const ETH_MESSAGE_HEADER = '\x19Ethereum Signed Message:\n32';
  31. function toHex(value: string) {
  32. return TronWeb.address.toHex(value);
  33. }
  34. type SignedStringOrSignedTransaction<T extends string | Transaction | SignedTransaction> = T extends string
  35. ? string
  36. : SignedTransaction & T;
  37. export class Trx {
  38. private tronWeb: TronWeb;
  39. private cache: { contracts: Record<string, any> };
  40. private validator: Validator;
  41. signMessage;
  42. sendAsset;
  43. send;
  44. sendTrx;
  45. broadcast;
  46. broadcastHex;
  47. signTransaction;
  48. constructor(tronWeb: TronWeb) {
  49. this.tronWeb = tronWeb;
  50. this.cache = {
  51. contracts: {},
  52. };
  53. this.validator = new Validator();
  54. this.signMessage = this.sign;
  55. this.sendAsset = this.sendToken;
  56. this.send = this.sendTransaction;
  57. this.sendTrx = this.sendTransaction;
  58. this.broadcast = this.sendRawTransaction;
  59. this.broadcastHex = this.sendHexTransaction;
  60. this.signTransaction = this.sign;
  61. }
  62. _parseToken(token: any): Token {
  63. return {
  64. ...token,
  65. name: this.tronWeb.toUtf8(token.name),
  66. abbr: token.abbr && this.tronWeb.toUtf8(token.abbr),
  67. description: token.description && this.tronWeb.toUtf8(token.description),
  68. url: token.url && this.tronWeb.toUtf8(token.url),
  69. };
  70. }
  71. getCurrentBlock(): Promise<Block> {
  72. return this.tronWeb.fullNode.request('wallet/getnowblock');
  73. }
  74. getConfirmedCurrentBlock(): Promise<Block> {
  75. return this.tronWeb.solidityNode.request('walletsolidity/getnowblock');
  76. }
  77. async getBlock(block: 'earliest' | 'latest' | number | string | false = this.tronWeb.defaultBlock): Promise<Block> {
  78. if (block === false) {
  79. throw new Error('No block identifier provided');
  80. }
  81. if (block == 'earliest') block = 0;
  82. if (block == 'latest') return this.getCurrentBlock();
  83. if (isNaN(+block) && utils.isHex(block.toString())) return this.getBlockByHash(block as string);
  84. return this.getBlockByNumber(block as number);
  85. }
  86. async getBlockByHash(blockHash: string): Promise<Block> {
  87. const block = await this.tronWeb.fullNode.request<Block>(
  88. 'wallet/getblockbyid',
  89. {
  90. value: blockHash,
  91. },
  92. 'post'
  93. );
  94. if (!Object.keys(block).length) {
  95. throw new Error('Block not found');
  96. }
  97. return block;
  98. }
  99. async getBlockByNumber(blockID: number): Promise<Block> {
  100. if (!utils.isInteger(blockID) || blockID < 0) {
  101. throw new Error('Invalid block number provided');
  102. }
  103. return this.tronWeb.fullNode
  104. .request<Block>(
  105. 'wallet/getblockbynum',
  106. {
  107. num: parseInt(blockID),
  108. },
  109. 'post'
  110. )
  111. .then((block) => {
  112. if (!Object.keys(block).length) {
  113. throw new Error('Block not found');
  114. }
  115. return block;
  116. });
  117. }
  118. async getBlockTransactionCount(
  119. block: 'earliest' | 'latest' | number | string | false = this.tronWeb.defaultBlock
  120. ): Promise<number> {
  121. const { transactions = [] } = await this.getBlock(block);
  122. return transactions.length;
  123. }
  124. async getTransactionFromBlock(
  125. block: 'earliest' | 'latest' | number | string | false = this.tronWeb.defaultBlock,
  126. index: number
  127. ): Promise<GetTransactionResponse> {
  128. const { transactions } = await this.getBlock(block);
  129. if (!transactions) {
  130. throw new Error('Transaction not found in block');
  131. }
  132. if (index >= 0 && index < transactions.length) return transactions[index];
  133. else throw new Error('Invalid transaction index provided');
  134. }
  135. async getTransactionsFromBlock(
  136. block: 'earliest' | 'latest' | number | string | false = this.tronWeb.defaultBlock
  137. ): Promise<GetTransactionResponse[]> {
  138. const { transactions } = await this.getBlock(block);
  139. if (!transactions) {
  140. throw new Error('Transaction not found in block');
  141. }
  142. return transactions;
  143. }
  144. async getTransaction(transactionID: string): Promise<GetTransactionResponse> {
  145. const transaction = await this.tronWeb.fullNode.request<GetTransactionResponse>(
  146. 'wallet/gettransactionbyid',
  147. {
  148. value: transactionID,
  149. },
  150. 'post'
  151. );
  152. if (!Object.keys(transaction).length) {
  153. throw new Error('Transaction not found');
  154. }
  155. return transaction;
  156. }
  157. async getConfirmedTransaction(transactionID: string): Promise<GetTransactionResponse> {
  158. const transaction = await this.tronWeb.solidityNode.request<GetTransactionResponse>(
  159. 'walletsolidity/gettransactionbyid',
  160. {
  161. value: transactionID,
  162. },
  163. 'post'
  164. );
  165. if (!Object.keys(transaction).length) {
  166. throw new Error('Transaction not found');
  167. }
  168. return transaction;
  169. }
  170. getUnconfirmedTransactionInfo(transactionID: string): Promise<TransactionInfo> {
  171. return this.tronWeb.fullNode.request('wallet/gettransactioninfobyid', { value: transactionID }, 'post');
  172. }
  173. getTransactionInfo(transactionID: string): Promise<TransactionInfo> {
  174. return this.tronWeb.solidityNode.request('walletsolidity/gettransactioninfobyid', { value: transactionID }, 'post');
  175. }
  176. getTransactionsToAddress(address = this.tronWeb.defaultAddress.hex, limit = 30, offset = 0): Promise<GetTransactionResponse[]> {
  177. return this.getTransactionsRelated(this.tronWeb.address.toHex(address as string), 'to', limit, offset);
  178. }
  179. getTransactionsFromAddress(address = this.tronWeb.defaultAddress.hex, limit = 30, offset = 0): Promise<GetTransactionResponse[]> {
  180. return this.getTransactionsRelated(this.tronWeb.address.toHex(address as string), 'from', limit, offset);
  181. }
  182. async getTransactionsRelated(
  183. address = this.tronWeb.defaultAddress.hex,
  184. direction = 'all',
  185. limit = 30,
  186. offset = 0
  187. ): Promise<GetTransactionResponse[]> {
  188. if (this.tronWeb.fullnodeSatisfies('>=4.1.1')) {
  189. throw new Error('This api is not supported any more');
  190. }
  191. if (!['to', 'from', 'all'].includes(direction)) {
  192. throw new Error('Invalid direction provided: Expected "to", "from" or "all"');
  193. }
  194. if (direction == 'all') {
  195. const [from, to] = await Promise.all([
  196. this.getTransactionsRelated(address, 'from', limit, offset),
  197. this.getTransactionsRelated(address, 'to', limit, offset),
  198. ]);
  199. return [
  200. ...from.map((tx) => (((tx as any).direction = 'from'), tx)),
  201. ...to.map((tx) => (((tx as any).direction = 'to'), tx)),
  202. ].sort((a, b) => {
  203. return b.raw_data.timestamp - a.raw_data.timestamp;
  204. });
  205. }
  206. if (!this.tronWeb.isAddress(address as string)) {
  207. throw new Error('Invalid address provided');
  208. }
  209. if (!utils.isInteger(limit) || limit < 0 || (offset && limit < 1)) {
  210. throw new Error('Invalid limit provided');
  211. }
  212. if (!utils.isInteger(offset) || offset < 0) {
  213. throw new Error('Invalid offset provided');
  214. }
  215. address = this.tronWeb.address.toHex(address as string);
  216. return this.tronWeb.solidityNode
  217. .request<{ transaction: GetTransactionResponse[] }>(
  218. `walletextension/gettransactions${direction}this`,
  219. {
  220. account: {
  221. address,
  222. },
  223. offset,
  224. limit,
  225. },
  226. 'post'
  227. )
  228. .then(({ transaction }) => {
  229. return transaction;
  230. });
  231. }
  232. async getAccount(address = this.tronWeb.defaultAddress.hex): Promise<Account> {
  233. if (!this.tronWeb.isAddress(address as Address)) {
  234. throw new Error('Invalid address provided');
  235. }
  236. address = this.tronWeb.address.toHex(address as string);
  237. return this.tronWeb.solidityNode.request(
  238. 'walletsolidity/getaccount',
  239. {
  240. address,
  241. },
  242. 'post'
  243. );
  244. }
  245. getAccountById(id: string): Promise<Account> {
  246. return this.getAccountInfoById(id, { confirmed: true });
  247. }
  248. async getAccountInfoById(id: string, options: { confirmed: boolean }): Promise<Account> {
  249. this.validator.notValid([
  250. {
  251. name: 'accountId',
  252. type: 'hex',
  253. value: id,
  254. },
  255. {
  256. name: 'accountId',
  257. type: 'string',
  258. lte: 32,
  259. gte: 8,
  260. value: id,
  261. },
  262. ]);
  263. if (id.startsWith('0x')) {
  264. id = id.slice(2);
  265. }
  266. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode'].request(
  267. `wallet${options.confirmed ? 'solidity' : ''}/getaccountbyid`,
  268. {
  269. account_id: id,
  270. },
  271. 'post'
  272. );
  273. }
  274. async getBalance(address = this.tronWeb.defaultAddress.hex): Promise<number> {
  275. const { balance = 0 } = await this.getAccount(address);
  276. return balance;
  277. }
  278. async getUnconfirmedAccount(address = this.tronWeb.defaultAddress.hex): Promise<Account> {
  279. if (!this.tronWeb.isAddress(address as Address)) {
  280. throw new Error('Invalid address provided');
  281. }
  282. address = this.tronWeb.address.toHex(address as string);
  283. return this.tronWeb.fullNode.request(
  284. 'wallet/getaccount',
  285. {
  286. address,
  287. },
  288. 'post'
  289. );
  290. }
  291. getUnconfirmedAccountById(id: string): Promise<Account> {
  292. return this.getAccountInfoById(id, { confirmed: false });
  293. }
  294. async getUnconfirmedBalance(address = this.tronWeb.defaultAddress.hex): Promise<number> {
  295. const { balance = 0 } = await this.getUnconfirmedAccount(address);
  296. return balance;
  297. }
  298. async getBandwidth(address = this.tronWeb.defaultAddress.hex): Promise<number> {
  299. if (!this.tronWeb.isAddress(address as Address)) {
  300. throw new Error('Invalid address provided');
  301. }
  302. address = this.tronWeb.address.toHex(address as string);
  303. return this.tronWeb.fullNode
  304. .request<AccountNetMessage>(
  305. 'wallet/getaccountnet',
  306. {
  307. address,
  308. },
  309. 'post'
  310. )
  311. .then(({ freeNetUsed = 0, freeNetLimit = 0, NetUsed = 0, NetLimit = 0 }) => {
  312. return freeNetLimit - freeNetUsed + (NetLimit - NetUsed);
  313. });
  314. }
  315. async getTokensIssuedByAddress(address = this.tronWeb.defaultAddress.hex): Promise<Record<string, Token>> {
  316. if (!this.tronWeb.isAddress(address as Address)) {
  317. throw new Error('Invalid address provided');
  318. }
  319. address = this.tronWeb.address.toHex(address as string);
  320. return this.tronWeb.fullNode
  321. .request<{ assetIssue: Token[] }>(
  322. 'wallet/getassetissuebyaccount',
  323. {
  324. address,
  325. },
  326. 'post'
  327. )
  328. .then(({ assetIssue }) => {
  329. if (!assetIssue) return {};
  330. const tokens = assetIssue
  331. .map((token) => {
  332. return this._parseToken(token);
  333. })
  334. .reduce((tokens, token) => {
  335. return (tokens[token.name] = token), tokens;
  336. }, {} as Record<string, Token>);
  337. return tokens;
  338. });
  339. }
  340. async getTokenFromID(tokenID: string | number): Promise<Token> {
  341. if (utils.isInteger(tokenID)) tokenID = tokenID.toString();
  342. if (!utils.isString(tokenID) || !tokenID.length) {
  343. throw new Error('Invalid token ID provided');
  344. }
  345. return this.tronWeb.fullNode
  346. .request<Token>(
  347. 'wallet/getassetissuebyname',
  348. {
  349. value: this.tronWeb.fromUtf8(tokenID),
  350. },
  351. 'post'
  352. )
  353. .then((token) => {
  354. if (!token.name) {
  355. throw new Error('Token does not exist');
  356. }
  357. return this._parseToken(token);
  358. });
  359. }
  360. async listNodes(): Promise<string[]> {
  361. const { nodes = [] } = await this.tronWeb.fullNode.request<{ nodes: { address: { host: string; port: number } }[] }>(
  362. 'wallet/listnodes'
  363. );
  364. return nodes.map(({ address: { host, port } }) => `${this.tronWeb.toUtf8(host)}:${port}`);
  365. }
  366. async getBlockRange(start = 0, end = 30): Promise<Block[]> {
  367. if (!utils.isInteger(start) || start < 0) {
  368. throw new Error('Invalid start of range provided');
  369. }
  370. if (!utils.isInteger(end) || end < start) {
  371. throw new Error('Invalid end of range provided');
  372. }
  373. if (end + 1 - start > 100) {
  374. throw new Error('Invalid range size, which should be no more than 100.');
  375. }
  376. return this.tronWeb.fullNode
  377. .request<{ block: Block[] }>(
  378. 'wallet/getblockbylimitnext',
  379. {
  380. startNum: parseInt(start),
  381. endNum: parseInt(end) + 1,
  382. },
  383. 'post'
  384. )
  385. .then(({ block = [] }) => block);
  386. }
  387. async listSuperRepresentatives(): Promise<Witness[]> {
  388. const { witnesses = [] } = await this.tronWeb.fullNode.request<{ witnesses: Witness[] }>('wallet/listwitnesses');
  389. return witnesses;
  390. }
  391. async listTokens(limit = 0, offset = 0): Promise<Token[]> {
  392. if (!utils.isInteger(limit) || limit < 0 || (offset && limit < 1)) {
  393. throw new Error('Invalid limit provided');
  394. }
  395. if (!utils.isInteger(offset) || offset < 0) {
  396. throw new Error('Invalid offset provided');
  397. }
  398. if (!limit) {
  399. return this.tronWeb.fullNode
  400. .request<{ assetIssue: Token[] }>('wallet/getassetissuelist')
  401. .then(({ assetIssue = [] }) => assetIssue.map((token) => this._parseToken(token)));
  402. }
  403. return this.tronWeb.fullNode
  404. .request<{ assetIssue: Token[] }>(
  405. 'wallet/getpaginatedassetissuelist',
  406. {
  407. offset: parseInt(offset),
  408. limit: parseInt(limit),
  409. },
  410. 'post'
  411. )
  412. .then(({ assetIssue = [] }) => assetIssue.map((token) => this._parseToken(token)));
  413. }
  414. async timeUntilNextVoteCycle(): Promise<number> {
  415. const { num = -1 } = await this.tronWeb.fullNode.request<{ num: number }>('wallet/getnextmaintenancetime');
  416. if (num == -1) {
  417. throw new Error('Failed to get time until next vote cycle');
  418. }
  419. return Math.floor(num / 1000);
  420. }
  421. async getContract(contractAddress: string): Promise<any> {
  422. if (!this.tronWeb.isAddress(contractAddress)) {
  423. throw new Error('Invalid contract address provided');
  424. }
  425. if (this.cache.contracts[contractAddress]) {
  426. return this.cache.contracts[contractAddress];
  427. }
  428. contractAddress = this.tronWeb.address.toHex(contractAddress);
  429. const contract = await this.tronWeb.fullNode.request<any>('wallet/getcontract', {
  430. value: contractAddress,
  431. });
  432. if (contract.Error) {
  433. throw new Error('Contract does not exist');
  434. }
  435. this.cache.contracts[contractAddress] = contract;
  436. return contract;
  437. }
  438. ecRecover(transaction: SignedTransaction) {
  439. return Trx.ecRecover(transaction);
  440. }
  441. static ecRecover(transaction: SignedTransaction): Address | Address[] {
  442. if (!txCheck(transaction)) {
  443. throw new Error('Invalid transaction');
  444. }
  445. if (!transaction.signature?.length) {
  446. throw new Error('Transaction is not signed');
  447. }
  448. if (transaction.signature.length === 1) {
  449. const tronAddress = ecRecover(transaction.txID, transaction.signature[0]);
  450. return TronWeb.address.fromHex(tronAddress);
  451. }
  452. return transaction.signature.map((sig) => {
  453. const tronAddress = ecRecover(transaction.txID, sig);
  454. return TronWeb.address.fromHex(tronAddress);
  455. });
  456. }
  457. async verifyMessage(message: string, signature: string, address = this.tronWeb.defaultAddress.base58, useTronHeader = true) {
  458. if (!utils.isHex(message)) {
  459. throw new Error('Expected hex message input');
  460. }
  461. if (Trx.verifySignature(message, address as string, signature, useTronHeader)) {
  462. return true;
  463. }
  464. throw new Error('Signature does not match');
  465. }
  466. static verifySignature(message: string, address: string, signature: string, useTronHeader = true) {
  467. message = message.replace(/^0x/, '');
  468. const messageBytes = [
  469. ...toUtf8Bytes(useTronHeader ? TRX_MESSAGE_HEADER : ETH_MESSAGE_HEADER),
  470. ...utils.code.hexStr2byteArray(message),
  471. ];
  472. const messageDigest = keccak256(new Uint8Array(messageBytes));
  473. const recovered = recoverAddress(messageDigest, Signature.from(`0x${signature.replace(/^0x/, '')}`));
  474. const tronAddress = ADDRESS_PREFIX + recovered.substr(2);
  475. const base58Address = TronWeb.address.fromHex(tronAddress);
  476. return base58Address == TronWeb.address.fromHex(address);
  477. }
  478. async verifyMessageV2(message: string | Uint8Array | Array<number>, signature: string) {
  479. return Trx.verifyMessageV2(message, signature);
  480. }
  481. static verifyMessageV2(message: string | Uint8Array | Array<number>, signature: string) {
  482. return utils.message.verifyMessage(message, signature);
  483. }
  484. verifyTypedData(
  485. domain: TypedDataDomain,
  486. types: Record<string, TypedDataField[]>,
  487. value: Record<string, any>,
  488. signature: string,
  489. address = this.tronWeb.defaultAddress.base58
  490. ) {
  491. if (Trx.verifyTypedData(domain, types, value, signature, address as string)) return true;
  492. throw new Error('Signature does not match');
  493. }
  494. static verifyTypedData(
  495. domain: TypedDataDomain,
  496. types: Record<string, TypedDataField[]>,
  497. value: Record<string, any>,
  498. signature: string,
  499. address: string
  500. ) {
  501. const messageDigest = utils._TypedDataEncoder.hash(domain, types, value);
  502. const recovered = recoverAddress(messageDigest, Signature.from(`0x${signature.replace(/^0x/, '')}`));
  503. const tronAddress = ADDRESS_PREFIX + recovered.substr(2);
  504. const base58Address = TronWeb.address.fromHex(tronAddress);
  505. return base58Address == TronWeb.address.fromHex(address);
  506. }
  507. async sign<T extends SignedTransaction | Transaction | string>(
  508. transaction: T,
  509. privateKey = this.tronWeb.defaultPrivateKey,
  510. useTronHeader = true,
  511. multisig = false
  512. ): Promise<SignedStringOrSignedTransaction<T>> {
  513. // Message signing
  514. if (utils.isString(transaction)) {
  515. if (!utils.isHex(transaction)) {
  516. throw new Error('Expected hex message input');
  517. }
  518. return Trx.signString(transaction, privateKey as string, useTronHeader) as SignedStringOrSignedTransaction<T>;
  519. }
  520. if (!utils.isObject(transaction)) {
  521. throw new Error('Invalid transaction provided');
  522. }
  523. if (!multisig && (transaction as SignedTransaction).signature) {
  524. throw new Error('Transaction is already signed');
  525. }
  526. if (!multisig) {
  527. const address = this.tronWeb.address
  528. .toHex(this.tronWeb.address.fromPrivateKey(privateKey as string) as string)
  529. .toLowerCase();
  530. if (address !== this.tronWeb.address.toHex(transaction.raw_data.contract[0].parameter.value.owner_address)) {
  531. throw new Error('Private key does not match address in transaction');
  532. }
  533. if (!txCheck(transaction)) {
  534. throw new Error('Invalid transaction');
  535. }
  536. }
  537. return utils.crypto.signTransaction(privateKey as string, transaction) as SignedStringOrSignedTransaction<T>;
  538. }
  539. static signString(message: string, privateKey: string, useTronHeader = true) {
  540. message = message.replace(/^0x/, '');
  541. const value = `0x${privateKey.replace(/^0x/, '')}`;
  542. const signingKey = new SigningKey(value);
  543. const messageBytes = [
  544. ...toUtf8Bytes(useTronHeader ? TRX_MESSAGE_HEADER : ETH_MESSAGE_HEADER),
  545. ...utils.code.hexStr2byteArray(message),
  546. ];
  547. const messageDigest = keccak256(new Uint8Array(messageBytes));
  548. const signature = signingKey.sign(messageDigest);
  549. const signatureHex = ['0x', signature.r.substring(2), signature.s.substring(2), Number(signature.v).toString(16)].join(
  550. ''
  551. );
  552. return signatureHex;
  553. }
  554. /**
  555. * sign message v2 for verified header length
  556. *
  557. * @param {message to be signed, should be Bytes or string} message
  558. * @param {privateKey for signature} privateKey
  559. * @param {reserved} options
  560. */
  561. signMessageV2(message: string | Uint8Array | Array<number>, privateKey = this.tronWeb.defaultPrivateKey) {
  562. return Trx.signMessageV2(message, privateKey as string);
  563. }
  564. static signMessageV2(message: string | Uint8Array | Array<number>, privateKey: string) {
  565. return utils.message.signMessage(message, privateKey);
  566. }
  567. _signTypedData(
  568. domain: TypedDataDomain,
  569. types: Record<string, TypedDataField[]>,
  570. value: Record<string, any>,
  571. privateKey = this.tronWeb.defaultPrivateKey
  572. ) {
  573. return Trx._signTypedData(domain, types, value, privateKey as string);
  574. }
  575. static _signTypedData(
  576. domain: TypedDataDomain,
  577. types: Record<string, TypedDataField[]>,
  578. value: Record<string, any>,
  579. privateKey: string
  580. ) {
  581. return utils.crypto._signTypedData(domain, types, value, privateKey);
  582. }
  583. async multiSign(transaction: Transaction, privateKey = this.tronWeb.defaultPrivateKey, permissionId = 0) {
  584. if (!utils.isObject(transaction) || !transaction.raw_data || !transaction.raw_data.contract) {
  585. throw new Error('Invalid transaction provided');
  586. }
  587. // If owner permission or permission id exists in transaction, do sign directly
  588. // If no permission id inside transaction or user passes permission id, use old way to reset permission id
  589. if (!transaction.raw_data.contract[0].Permission_id && permissionId > 0) {
  590. // set permission id
  591. transaction.raw_data.contract[0].Permission_id = permissionId;
  592. // check if private key insides permission list
  593. const address = this.tronWeb.address
  594. .toHex(this.tronWeb.address.fromPrivateKey(privateKey as string) as string)
  595. .toLowerCase();
  596. const signWeight = await this.getSignWeight(transaction, permissionId);
  597. if (signWeight.result.code === 'PERMISSION_ERROR') {
  598. throw new Error(signWeight.result.message);
  599. }
  600. let foundKey = false;
  601. signWeight.permission.keys.map((key) => {
  602. if (key.address === address) foundKey = true;
  603. });
  604. if (!foundKey) {
  605. throw new Error(privateKey + ' has no permission to sign');
  606. }
  607. if (signWeight.approved_list && signWeight.approved_list.indexOf(address) != -1) {
  608. throw new Error(privateKey + ' already sign transaction');
  609. }
  610. // reset transaction
  611. if (signWeight.transaction && signWeight.transaction.transaction) {
  612. transaction = signWeight.transaction.transaction;
  613. if (permissionId > 0) {
  614. transaction.raw_data.contract[0].Permission_id = permissionId;
  615. }
  616. } else {
  617. throw new Error('Invalid transaction provided');
  618. }
  619. }
  620. // sign
  621. if (!txCheck(transaction)) {
  622. throw new Error('Invalid transaction');
  623. }
  624. return utils.crypto.signTransaction(privateKey as string, transaction);
  625. }
  626. async getApprovedList(transaction: Transaction): Promise<{ approved_list: string[] }> {
  627. if (!utils.isObject(transaction)) {
  628. throw new Error('Invalid transaction provided');
  629. }
  630. return this.tronWeb.fullNode.request('wallet/getapprovedlist', transaction, 'post');
  631. }
  632. async getSignWeight(transaction: Transaction, permissionId?: number): Promise<TransactionSignWeight> {
  633. if (!utils.isObject(transaction) || !transaction.raw_data || !transaction.raw_data.contract)
  634. throw new Error('Invalid transaction provided');
  635. if (utils.isInteger(permissionId)) {
  636. transaction.raw_data.contract[0].Permission_id = parseInt(permissionId);
  637. } else if (typeof transaction.raw_data.contract[0].Permission_id !== 'number') {
  638. transaction.raw_data.contract[0].Permission_id = 0;
  639. }
  640. return this.tronWeb.fullNode.request('wallet/getsignweight', transaction, 'post');
  641. }
  642. async sendRawTransaction<T extends SignedTransaction>(signedTransaction: T): Promise<BroadcastReturn<T>> {
  643. if (!utils.isObject(signedTransaction)) {
  644. throw new Error('Invalid transaction provided');
  645. }
  646. if (!signedTransaction.signature || !utils.isArray(signedTransaction.signature)) {
  647. throw new Error('Transaction is not signed');
  648. }
  649. const result = await this.tronWeb.fullNode.request<Omit<BroadcastReturn<T>, 'transaction'>>(
  650. 'wallet/broadcasttransaction',
  651. signedTransaction,
  652. 'post'
  653. );
  654. return {
  655. ...result,
  656. transaction: signedTransaction,
  657. };
  658. }
  659. async sendHexTransaction(signedHexTransaction: string) {
  660. if (!utils.isHex(signedHexTransaction)) {
  661. throw new Error('Invalid hex transaction provided');
  662. }
  663. const params = {
  664. transaction: signedHexTransaction,
  665. };
  666. const result = await this.tronWeb.fullNode.request<BroadcastHexReturn>('wallet/broadcasthex', params, 'post');
  667. if (result.result) {
  668. return {
  669. ...result,
  670. transaction: JSON.parse(result.transaction) as Transaction,
  671. hexTransaction: signedHexTransaction,
  672. };
  673. }
  674. return result;
  675. }
  676. async sendTransaction(to: string, amount: number, options: AddressOptions = {}): Promise<BroadcastReturn<SignedTransaction>> {
  677. if (typeof options === 'string') options = { privateKey: options };
  678. if (!this.tronWeb.isAddress(to)) {
  679. throw new Error('Invalid recipient provided');
  680. }
  681. if (!utils.isInteger(amount) || amount <= 0) {
  682. throw new Error('Invalid amount provided');
  683. }
  684. options = {
  685. privateKey: this.tronWeb.defaultPrivateKey as string,
  686. address: this.tronWeb.defaultAddress.hex as string,
  687. ...options,
  688. };
  689. if (!options.privateKey && !options.address) {
  690. throw new Error('Function requires either a private key or address to be set');
  691. }
  692. const address = options.privateKey ? this.tronWeb.address.fromPrivateKey(options.privateKey) : options.address;
  693. const transaction = await this.tronWeb.transactionBuilder.sendTrx(to, amount, address as Address);
  694. const signedTransaction = await this.sign(transaction, options.privateKey);
  695. const result = await this.sendRawTransaction(signedTransaction);
  696. return result;
  697. }
  698. async sendToken(
  699. to: string,
  700. amount: number,
  701. tokenID: string | number,
  702. options: AddressOptions = {}
  703. ): Promise<BroadcastReturn<SignedTransaction>> {
  704. if (typeof options === 'string') options = { privateKey: options };
  705. if (!this.tronWeb.isAddress(to)) {
  706. throw new Error('Invalid recipient provided');
  707. }
  708. if (!utils.isInteger(amount) || amount <= 0) {
  709. throw new Error('Invalid amount provided');
  710. }
  711. if (utils.isInteger(tokenID)) tokenID = tokenID.toString();
  712. if (!utils.isString(tokenID)) {
  713. throw new Error('Invalid token ID provided');
  714. }
  715. options = {
  716. privateKey: this.tronWeb.defaultPrivateKey as string,
  717. address: this.tronWeb.defaultAddress.hex as string,
  718. ...options,
  719. };
  720. if (!options.privateKey && !options.address) {
  721. throw new Error('Function requires either a private key or address to be set');
  722. }
  723. const address = options.privateKey ? this.tronWeb.address.fromPrivateKey(options.privateKey) : options.address;
  724. const transaction = await this.tronWeb.transactionBuilder.sendToken(to, amount, tokenID, address as Address);
  725. const signedTransaction = await this.sign(transaction, options.privateKey);
  726. const result = await this.sendRawTransaction(signedTransaction);
  727. return result;
  728. }
  729. /**
  730. * Freezes an amount of TRX.
  731. * Will give bandwidth OR Energy and TRON Power(voting rights)
  732. * to the owner of the frozen tokens.
  733. *
  734. * @param amount - is the number of frozen trx
  735. * @param duration - is the duration in days to be frozen
  736. * @param resource - is the type, must be either "ENERGY" or "BANDWIDTH"
  737. * @param options
  738. */
  739. async freezeBalance(
  740. amount = 0,
  741. duration = 3,
  742. resource: Resource = 'BANDWIDTH',
  743. options: AddressOptions = {},
  744. receiverAddress?: string
  745. ): Promise<BroadcastReturn<SignedTransaction>> {
  746. if (typeof options === 'string') options = { privateKey: options };
  747. if (!['BANDWIDTH', 'ENERGY'].includes(resource)) {
  748. throw new Error('Invalid resource provided: Expected "BANDWIDTH" or "ENERGY"');
  749. }
  750. if (!utils.isInteger(amount) || amount <= 0) {
  751. throw new Error('Invalid amount provided');
  752. }
  753. if (!utils.isInteger(duration) || duration < 3) {
  754. throw new Error('Invalid duration provided, minimum of 3 days');
  755. }
  756. options = {
  757. privateKey: this.tronWeb.defaultPrivateKey as string,
  758. address: this.tronWeb.defaultAddress.hex as string,
  759. ...options,
  760. };
  761. if (!options.privateKey && !options.address) {
  762. throw new Error('Function requires either a private key or address to be set');
  763. }
  764. const address = options.privateKey ? this.tronWeb.address.fromPrivateKey(options.privateKey) : options.address;
  765. const freezeBalance = await this.tronWeb.transactionBuilder.freezeBalance(
  766. amount,
  767. duration,
  768. resource,
  769. address as Address,
  770. receiverAddress
  771. );
  772. const signedTransaction = await this.sign(freezeBalance, options.privateKey);
  773. const result = await this.sendRawTransaction(signedTransaction);
  774. return result;
  775. }
  776. /**
  777. * Unfreeze TRX that has passed the minimum freeze duration.
  778. * Unfreezing will remove bandwidth and TRON Power.
  779. *
  780. * @param resource - is the type, must be either "ENERGY" or "BANDWIDTH"
  781. * @param options
  782. */
  783. async unfreezeBalance(
  784. resource: Resource = 'BANDWIDTH',
  785. options: AddressOptions = {},
  786. receiverAddress: string
  787. ): Promise<BroadcastReturn<SignedTransaction>> {
  788. if (typeof options === 'string') options = { privateKey: options };
  789. if (!['BANDWIDTH', 'ENERGY'].includes(resource)) {
  790. throw new Error('Invalid resource provided: Expected "BANDWIDTH" or "ENERGY"');
  791. }
  792. options = {
  793. privateKey: this.tronWeb.defaultPrivateKey as string,
  794. address: this.tronWeb.defaultAddress.hex as string,
  795. ...options,
  796. };
  797. if (!options.privateKey && !options.address) {
  798. throw new Error('Function requires either a private key or address to be set');
  799. }
  800. const address = options.privateKey ? this.tronWeb.address.fromPrivateKey(options.privateKey) : options.address;
  801. const unfreezeBalance = await this.tronWeb.transactionBuilder.unfreezeBalance(
  802. resource,
  803. address as Address,
  804. receiverAddress
  805. );
  806. const signedTransaction = await this.sign(unfreezeBalance, options.privateKey);
  807. const result = await this.sendRawTransaction(signedTransaction);
  808. return result;
  809. }
  810. /**
  811. * Modify account name
  812. * Note: Username is allowed to edit only once.
  813. *
  814. * @param privateKey - Account private Key
  815. * @param accountName - name of the account
  816. *
  817. * @return modified Transaction Object
  818. */
  819. async updateAccount(accountName: string, options: AddressOptions = {}): Promise<BroadcastReturn<SignedTransaction>> {
  820. if (typeof options === 'string') options = { privateKey: options };
  821. if (!utils.isString(accountName) || !accountName.length) {
  822. throw new Error('Name must be a string');
  823. }
  824. options = {
  825. privateKey: this.tronWeb.defaultPrivateKey as string,
  826. address: this.tronWeb.defaultAddress.hex as string,
  827. ...options,
  828. };
  829. if (!options.privateKey && !options.address) throw Error('Function requires either a private key or address to be set');
  830. const address = options.privateKey ? this.tronWeb.address.fromPrivateKey(options.privateKey) : options.address;
  831. const updateAccount = await this.tronWeb.transactionBuilder.updateAccount(accountName, address as Address);
  832. const signedTransaction = await this.sign(updateAccount, options.privateKey);
  833. const result = await this.sendRawTransaction(signedTransaction);
  834. return result;
  835. }
  836. /**
  837. * Gets a network modification proposal by ID.
  838. */
  839. async getProposal(proposalID: number): Promise<Proposal> {
  840. if (!utils.isInteger(proposalID) || proposalID < 0) {
  841. throw new Error('Invalid proposalID provided');
  842. }
  843. return this.tronWeb.fullNode.request(
  844. 'wallet/getproposalbyid',
  845. {
  846. id: parseInt(proposalID),
  847. },
  848. 'post'
  849. );
  850. }
  851. /**
  852. * Lists all network modification proposals.
  853. */
  854. async listProposals(): Promise<Proposal[]> {
  855. const { proposals = [] } = await this.tronWeb.fullNode.request<{ proposals: Proposal[] }>(
  856. 'wallet/listproposals',
  857. {},
  858. 'post'
  859. );
  860. return proposals;
  861. }
  862. /**
  863. * Lists all parameters available for network modification proposals.
  864. */
  865. async getChainParameters(): Promise<ChainParameter[]> {
  866. const { chainParameter = [] } = await this.tronWeb.fullNode.request<{ chainParameter: ChainParameter[] }>(
  867. 'wallet/getchainparameters',
  868. {},
  869. 'post'
  870. );
  871. return chainParameter;
  872. }
  873. /**
  874. * Get the account resources
  875. */
  876. async getAccountResources(address = this.tronWeb.defaultAddress.hex): Promise<AccountResourceMessage> {
  877. if (!this.tronWeb.isAddress(address as Address)) {
  878. throw new Error('Invalid address provided');
  879. }
  880. return this.tronWeb.fullNode.request(
  881. 'wallet/getaccountresource',
  882. {
  883. address: this.tronWeb.address.toHex(address as string),
  884. },
  885. 'post'
  886. );
  887. }
  888. /**
  889. * Query the amount of resources of a specific resourceType delegated by fromAddress to toAddress
  890. */
  891. async getDelegatedResourceV2(
  892. fromAddress = this.tronWeb.defaultAddress.hex,
  893. toAddress = this.tronWeb.defaultAddress.hex,
  894. options = { confirmed: true }
  895. ): Promise<{
  896. delegatedResource: {
  897. from: string;
  898. to: string;
  899. frozen_balance_for_bandwidth: number;
  900. frozen_balance_for_energy: number;
  901. expire_time_for_bandwidth: number;
  902. expire_time_for_energy: number;
  903. };
  904. }> {
  905. if (!this.tronWeb.isAddress(fromAddress as Address)) {
  906. throw new Error('Invalid address provided');
  907. }
  908. if (!this.tronWeb.isAddress(toAddress as Address)) {
  909. throw new Error('Invalid address provided');
  910. }
  911. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode'].request(
  912. `wallet${options.confirmed ? 'solidity' : ''}/getdelegatedresourcev2`,
  913. {
  914. fromAddress: toHex(fromAddress as string),
  915. toAddress: toHex(toAddress as string),
  916. },
  917. 'post'
  918. );
  919. }
  920. /**
  921. * Query the resource delegation index by an account
  922. */
  923. async getDelegatedResourceAccountIndexV2(
  924. address = this.tronWeb.defaultAddress.hex,
  925. options = { confirmed: true }
  926. ): Promise<{
  927. account: Address;
  928. fromAccounts: Address[];
  929. toAccounts: Address[];
  930. }> {
  931. if (!this.tronWeb.isAddress(address as Address)) {
  932. throw new Error('Invalid address provided');
  933. }
  934. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode'].request(
  935. `wallet${options.confirmed ? 'solidity' : ''}/getdelegatedresourceaccountindexv2`,
  936. {
  937. value: toHex(address as Address),
  938. },
  939. 'post'
  940. );
  941. }
  942. /**
  943. * Query the amount of delegatable resources of the specified resource Type for target address, unit is sun.
  944. */
  945. async getCanDelegatedMaxSize(
  946. address = this.tronWeb.defaultAddress.hex,
  947. resource: Resource = 'BANDWIDTH',
  948. options = { confirmed: true }
  949. ): Promise<{
  950. max_size: number;
  951. }> {
  952. if (!this.tronWeb.isAddress(address as Address)) {
  953. throw new Error('Invalid address provided');
  954. }
  955. this.validator.notValid([
  956. {
  957. name: 'resource',
  958. type: 'resource',
  959. value: resource,
  960. msg: 'Invalid resource provided: Expected "BANDWIDTH" or "ENERGY"',
  961. },
  962. ]);
  963. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode'].request(
  964. `wallet${options.confirmed ? 'solidity' : ''}/getcandelegatedmaxsize`,
  965. {
  966. owner_address: toHex(address as Address),
  967. type: resource === 'ENERGY' ? 1 : 0,
  968. },
  969. 'post'
  970. );
  971. }
  972. /**
  973. * Remaining times of available unstaking API
  974. */
  975. async getAvailableUnfreezeCount(
  976. address = this.tronWeb.defaultAddress.hex,
  977. options = { confirmed: true }
  978. ): Promise<{
  979. count: number;
  980. }> {
  981. if (!this.tronWeb.isAddress(address as Address)) {
  982. throw new Error('Invalid address provided');
  983. }
  984. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode'].request(
  985. `wallet${options.confirmed ? 'solidity' : ''}/getavailableunfreezecount`,
  986. {
  987. owner_address: toHex(address as Address),
  988. },
  989. 'post'
  990. );
  991. }
  992. /**
  993. * Query the withdrawable balance at the specified timestamp
  994. */
  995. async getCanWithdrawUnfreezeAmount(
  996. address = this.tronWeb.defaultAddress.hex,
  997. timestamp = Date.now(),
  998. options = { confirmed: true }
  999. ): Promise<{
  1000. amount: number;
  1001. }> {
  1002. if (!this.tronWeb.isAddress(address as Address)) {
  1003. throw new Error('Invalid address provided');
  1004. }
  1005. if (!utils.isInteger(timestamp) || timestamp < 0) {
  1006. throw new Error('Invalid timestamp provided');
  1007. }
  1008. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode'].request(
  1009. `wallet${options.confirmed ? 'solidity' : ''}/getcanwithdrawunfreezeamount`,
  1010. {
  1011. owner_address: toHex(address as Address),
  1012. timestamp: timestamp,
  1013. },
  1014. 'post'
  1015. );
  1016. }
  1017. /**
  1018. * Get the exchange ID.
  1019. */
  1020. async getExchangeByID(exchangeID: number): Promise<Exchange> {
  1021. if (!utils.isInteger(exchangeID) || exchangeID < 0) {
  1022. throw new Error('Invalid exchangeID provided');
  1023. }
  1024. return this.tronWeb.fullNode.request(
  1025. 'wallet/getexchangebyid',
  1026. {
  1027. id: exchangeID,
  1028. },
  1029. 'post'
  1030. );
  1031. }
  1032. /**
  1033. * Lists the exchanges
  1034. */
  1035. async listExchanges() {
  1036. return this.tronWeb.fullNode
  1037. .request<{ exchanges: Exchange[] }>('wallet/listexchanges', {}, 'post')
  1038. .then(({ exchanges = [] }) => exchanges);
  1039. }
  1040. /**
  1041. * Lists all network modification proposals.
  1042. */
  1043. async listExchangesPaginated(limit = 10, offset = 0) {
  1044. return this.tronWeb.fullNode
  1045. .request<{ exchanges: Exchange[] }>(
  1046. 'wallet/getpaginatedexchangelist',
  1047. {
  1048. limit,
  1049. offset,
  1050. },
  1051. 'post'
  1052. )
  1053. .then(({ exchanges = [] }) => exchanges);
  1054. }
  1055. /**
  1056. * Get info about thre node
  1057. */
  1058. async getNodeInfo(): Promise<{
  1059. beginSyncNum: number;
  1060. block: string;
  1061. solidityBlock: string;
  1062. currentConnectCount: number;
  1063. activeConnectCount: number;
  1064. passiveConnectCount: number;
  1065. totalFlow: number;
  1066. peerInfoList: {
  1067. lastSyncBlock: string;
  1068. remainNum: number;
  1069. lastBlockUpdateTime: number;
  1070. syncFlag: boolean;
  1071. headBlockTimeWeBothHave: number;
  1072. needSyncFromPeer: boolean;
  1073. needSyncFromUs: boolean;
  1074. host: string;
  1075. port: number;
  1076. nodeId: string;
  1077. connectTime: number;
  1078. avgLatency: number;
  1079. syncToFetchSize: number;
  1080. syncToFetchSizePeekNum: number;
  1081. syncBlockRequestedSize: number;
  1082. unFetchSynNum: number;
  1083. blockInPorcSize: number;
  1084. headBlockWeBothHave: string;
  1085. isActive: boolean;
  1086. score: number;
  1087. nodeCount: number;
  1088. inFlow: number;
  1089. disconnectTimes: number;
  1090. localDisconnectReason: string;
  1091. remoteDisconnectReason: string;
  1092. };
  1093. configNodeInfo: {
  1094. codeVersion: string;
  1095. p2pVersion: string;
  1096. listenPort: number;
  1097. discoverEnable: boolean;
  1098. activeNodeSize: number;
  1099. passiveNodeSize: number;
  1100. sendNodeSize: number;
  1101. maxConnectCount: number;
  1102. sameIpMaxConnectCount: number;
  1103. backupListenPort: number;
  1104. backupMemberSize: number;
  1105. backupPriority: number;
  1106. dbVersion: number;
  1107. minParticipationRate: number;
  1108. supportConstant: boolean;
  1109. minTimeRatio: number;
  1110. maxTimeRatio: number;
  1111. allowCreationOfContracts: number;
  1112. allowAdaptiveEnergy: number;
  1113. };
  1114. machineInfo: {
  1115. threadCount: number;
  1116. deadLockThreadCount: number;
  1117. cpuCount: number;
  1118. totalMemory: number;
  1119. freeMemory: number;
  1120. cpuRate: number;
  1121. javaVersion: string;
  1122. osName: string;
  1123. jvmTotalMemory: number;
  1124. jvmFreeMemory: number;
  1125. processCpuRate: number;
  1126. memoryDescInfoList: {
  1127. name: string;
  1128. initSize: number;
  1129. useSize: number;
  1130. maxSize: number;
  1131. useRate: number;
  1132. };
  1133. deadLockThreadInfoList: {
  1134. name: string;
  1135. lockName: string;
  1136. lockOwner: string;
  1137. state: string;
  1138. blockTime: number;
  1139. waitTime: number;
  1140. stackTrace: string;
  1141. };
  1142. };
  1143. cheatWitnessInfoMap: Map<string, string>;
  1144. }> {
  1145. return this.tronWeb.fullNode.request('wallet/getnodeinfo', {}, 'post');
  1146. }
  1147. async getTokenListByName(tokenID: string | number): Promise<Token | Token[]> {
  1148. if (utils.isInteger(tokenID)) tokenID = tokenID.toString();
  1149. if (!utils.isString(tokenID) || !tokenID.length) {
  1150. throw new Error('Invalid token ID provided');
  1151. }
  1152. return this.tronWeb.fullNode
  1153. .request<({ assetIssue: Token[] } & { name: undefined }) | (Token & { assetIssue: undefined })>(
  1154. 'wallet/getassetissuelistbyname',
  1155. {
  1156. value: this.tronWeb.fromUtf8(tokenID),
  1157. },
  1158. 'post'
  1159. )
  1160. .then((token) => {
  1161. if (Array.isArray(token.assetIssue)) {
  1162. return token.assetIssue.map((t) => this._parseToken(t));
  1163. } else if (!token.name) {
  1164. throw new Error('Token does not exist');
  1165. }
  1166. return this._parseToken(token);
  1167. });
  1168. }
  1169. getTokenByID(tokenID: number | string): Promise<Token> {
  1170. if (utils.isInteger(tokenID)) tokenID = tokenID.toString();
  1171. if (!utils.isString(tokenID) || !tokenID.length) {
  1172. throw new Error('Invalid token ID provided');
  1173. }
  1174. return this.tronWeb.fullNode
  1175. .request<Token>(
  1176. 'wallet/getassetissuebyid',
  1177. {
  1178. value: tokenID,
  1179. },
  1180. 'post'
  1181. )
  1182. .then((token) => {
  1183. if (!token.name) {
  1184. throw new Error('Token does not exist');
  1185. }
  1186. return this._parseToken(token);
  1187. });
  1188. }
  1189. async getReward(address: Address, options: { confirmed?: boolean } = {}) {
  1190. options.confirmed = true;
  1191. return this._getReward(address, options);
  1192. }
  1193. async getUnconfirmedReward(address: Address, options: { confirmed?: boolean } = {}) {
  1194. options.confirmed = false;
  1195. return this._getReward(address, options);
  1196. }
  1197. async getBrokerage(address: Address, options: { confirmed?: boolean } = {}) {
  1198. options.confirmed = true;
  1199. return this._getBrokerage(address, options);
  1200. }
  1201. async getUnconfirmedBrokerage(address: Address, options: { confirmed?: boolean } = {}) {
  1202. options.confirmed = false;
  1203. return this._getBrokerage(address, options);
  1204. }
  1205. async _getReward(address = this.tronWeb.defaultAddress.hex, options: { confirmed?: boolean }): Promise<number> {
  1206. this.validator.notValid([
  1207. {
  1208. name: 'origin',
  1209. type: 'address',
  1210. value: address,
  1211. },
  1212. ]);
  1213. const data = {
  1214. address: toHex(address as Address),
  1215. };
  1216. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode']
  1217. .request<{ reward?: number }>(`wallet${options.confirmed ? 'solidity' : ''}/getReward`, data, 'post')
  1218. .then((result = { reward: undefined }) => {
  1219. if (typeof result.reward === 'undefined') {
  1220. throw new Error('Not found.');
  1221. }
  1222. return result.reward;
  1223. });
  1224. }
  1225. private async _getBrokerage(address = this.tronWeb.defaultAddress.hex, options: { confirmed?: boolean }): Promise<number> {
  1226. this.validator.notValid([
  1227. {
  1228. name: 'origin',
  1229. type: 'address',
  1230. value: address,
  1231. },
  1232. ]);
  1233. const data = {
  1234. address: toHex(address as Address),
  1235. };
  1236. return this.tronWeb[options.confirmed ? 'solidityNode' : 'fullNode']
  1237. .request<{ brokerage?: number }>(`wallet${options.confirmed ? 'solidity' : ''}/getBrokerage`, data, 'post')
  1238. .then((result = {}) => {
  1239. if (typeof result.brokerage === 'undefined') {
  1240. throw new Error('Not found.');
  1241. }
  1242. return result.brokerage;
  1243. });
  1244. }
  1245. async getBandwidthPrices(): Promise<string> {
  1246. return this.tronWeb.fullNode.request<{ prices?: string }>('wallet/getbandwidthprices', {}, 'post')
  1247. .then((result = {}) => {
  1248. if (typeof result.prices === 'undefined') {
  1249. throw new Error('Not found.');
  1250. }
  1251. return result.prices;
  1252. });
  1253. }
  1254. async getEnergyPrices(): Promise<string> {
  1255. return this.tronWeb.fullNode.request<{ prices?: string }>('wallet/getenergyprices', {}, 'post')
  1256. .then((result = {}) => {
  1257. if (typeof result.prices === 'undefined') {
  1258. throw new Error('Not found.');
  1259. }
  1260. return result.prices;
  1261. });
  1262. }
  1263. }