@hiero-ledger/sdk 2.80.0 → 2.81.0-beta.1

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.
Files changed (182) hide show
  1. package/README.md +34 -7
  2. package/dist/umd.js +2213 -318
  3. package/dist/umd.js.map +1 -0
  4. package/dist/umd.min.js +6 -5
  5. package/dist/umd.min.js.map +1 -0
  6. package/lib/Executable.cjs +7 -4
  7. package/lib/Executable.js +1 -1
  8. package/lib/Executable.js.map +1 -1
  9. package/lib/PublicKey.cjs +45 -26
  10. package/lib/PublicKey.d.ts +12 -0
  11. package/lib/PublicKey.js +1 -1
  12. package/lib/PublicKey.js.map +1 -1
  13. package/lib/RequestType.cjs +19 -1
  14. package/lib/RequestType.d.ts +2 -0
  15. package/lib/RequestType.js +1 -1
  16. package/lib/RequestType.js.map +1 -1
  17. package/lib/Status.cjs +203 -252
  18. package/lib/Status.d.ts +8 -6
  19. package/lib/Status.js +1 -1
  20. package/lib/Status.js.map +1 -1
  21. package/lib/Transfer.cjs +25 -2
  22. package/lib/Transfer.d.ts +4 -0
  23. package/lib/Transfer.js +1 -1
  24. package/lib/Transfer.js.map +1 -1
  25. package/lib/account/AccountCreateTransaction.cjs +38 -0
  26. package/lib/account/AccountCreateTransaction.d.ts +21 -0
  27. package/lib/account/AccountCreateTransaction.js +1 -1
  28. package/lib/account/AccountCreateTransaction.js.map +1 -1
  29. package/lib/account/AccountUpdateTransaction.cjs +74 -1
  30. package/lib/account/AccountUpdateTransaction.d.ts +43 -0
  31. package/lib/account/AccountUpdateTransaction.js +1 -1
  32. package/lib/account/AccountUpdateTransaction.js.map +1 -1
  33. package/lib/account/TransferTransaction.cjs +57 -9
  34. package/lib/account/TransferTransaction.d.ts +31 -1
  35. package/lib/account/TransferTransaction.js +1 -1
  36. package/lib/account/TransferTransaction.js.map +1 -1
  37. package/lib/browser.js +1 -1
  38. package/lib/client/Client.cjs +38 -0
  39. package/lib/client/Client.d.ts +30 -0
  40. package/lib/client/Client.js +1 -1
  41. package/lib/client/Client.js.map +1 -1
  42. package/lib/client/addressbooks/mainnet.cjs +1 -1
  43. package/lib/client/addressbooks/mainnet.d.ts +1 -1
  44. package/lib/client/addressbooks/mainnet.js +1 -1
  45. package/lib/client/addressbooks/mainnet.js.map +1 -1
  46. package/lib/client/addressbooks/previewnet.cjs +1 -1
  47. package/lib/client/addressbooks/previewnet.d.ts +1 -1
  48. package/lib/client/addressbooks/previewnet.js +1 -1
  49. package/lib/client/addressbooks/previewnet.js.map +1 -1
  50. package/lib/client/addressbooks/testnet.cjs +1 -1
  51. package/lib/client/addressbooks/testnet.d.ts +1 -1
  52. package/lib/client/addressbooks/testnet.js +1 -1
  53. package/lib/client/addressbooks/testnet.js.map +1 -1
  54. package/lib/contract/ContractCreateTransaction.cjs +37 -1
  55. package/lib/contract/ContractCreateTransaction.d.ts +21 -0
  56. package/lib/contract/ContractCreateTransaction.js +1 -1
  57. package/lib/contract/ContractCreateTransaction.js.map +1 -1
  58. package/lib/contract/ContractUpdateTransaction.cjs +74 -1
  59. package/lib/contract/ContractUpdateTransaction.d.ts +43 -0
  60. package/lib/contract/ContractUpdateTransaction.js +1 -1
  61. package/lib/contract/ContractUpdateTransaction.js.map +1 -1
  62. package/lib/exports.cjs +103 -0
  63. package/lib/exports.d.ts +13 -0
  64. package/lib/exports.js +1 -1
  65. package/lib/exports.js.map +1 -1
  66. package/lib/hooks/EvmHook.cjs +84 -0
  67. package/lib/hooks/EvmHook.d.ts +51 -0
  68. package/lib/hooks/EvmHook.js +2 -0
  69. package/lib/hooks/EvmHook.js.map +1 -0
  70. package/lib/hooks/EvmHookCall.cjs +103 -0
  71. package/lib/hooks/EvmHookCall.d.ts +69 -0
  72. package/lib/hooks/EvmHookCall.js +2 -0
  73. package/lib/hooks/EvmHookCall.js.map +1 -0
  74. package/lib/hooks/EvmHookMappingEntry.cjs +135 -0
  75. package/lib/hooks/EvmHookMappingEntry.d.ts +84 -0
  76. package/lib/hooks/EvmHookMappingEntry.js +2 -0
  77. package/lib/hooks/EvmHookMappingEntry.js.map +1 -0
  78. package/lib/hooks/EvmHookStorageUpdate.cjs +238 -0
  79. package/lib/hooks/EvmHookStorageUpdate.d.ts +144 -0
  80. package/lib/hooks/EvmHookStorageUpdate.js +2 -0
  81. package/lib/hooks/EvmHookStorageUpdate.js.map +1 -0
  82. package/lib/hooks/FungibleHookCall.cjs +67 -0
  83. package/lib/hooks/FungibleHookCall.d.ts +50 -0
  84. package/lib/hooks/FungibleHookCall.js +2 -0
  85. package/lib/hooks/FungibleHookCall.js.map +1 -0
  86. package/lib/hooks/FungibleHookType.cjs +11 -0
  87. package/lib/hooks/FungibleHookType.d.ts +5 -0
  88. package/lib/hooks/FungibleHookType.js +2 -0
  89. package/lib/hooks/FungibleHookType.js.map +1 -0
  90. package/lib/hooks/HookCall.cjs +99 -0
  91. package/lib/hooks/HookCall.d.ts +64 -0
  92. package/lib/hooks/HookCall.js +2 -0
  93. package/lib/hooks/HookCall.js.map +1 -0
  94. package/lib/hooks/HookCreationDetails.cjs +149 -0
  95. package/lib/hooks/HookCreationDetails.d.ts +91 -0
  96. package/lib/hooks/HookCreationDetails.js +2 -0
  97. package/lib/hooks/HookCreationDetails.js.map +1 -0
  98. package/lib/hooks/HookEntityId.cjs +67 -0
  99. package/lib/hooks/HookEntityId.d.ts +41 -0
  100. package/lib/hooks/HookEntityId.js +2 -0
  101. package/lib/hooks/HookEntityId.js.map +1 -0
  102. package/lib/hooks/HookExtensionPoint.cjs +31 -0
  103. package/lib/hooks/HookExtensionPoint.d.ts +16 -0
  104. package/lib/hooks/HookExtensionPoint.js +2 -0
  105. package/lib/hooks/HookExtensionPoint.js.map +1 -0
  106. package/lib/hooks/HookId.cjs +101 -0
  107. package/lib/hooks/HookId.d.ts +63 -0
  108. package/lib/hooks/HookId.js +2 -0
  109. package/lib/hooks/HookId.js.map +1 -0
  110. package/lib/hooks/HookStoreTransaction.cjs +157 -0
  111. package/lib/hooks/HookStoreTransaction.d.ts +77 -0
  112. package/lib/hooks/HookStoreTransaction.js +2 -0
  113. package/lib/hooks/HookStoreTransaction.js.map +1 -0
  114. package/lib/hooks/NftHookCall.cjs +67 -0
  115. package/lib/hooks/NftHookCall.d.ts +50 -0
  116. package/lib/hooks/NftHookCall.js +2 -0
  117. package/lib/hooks/NftHookCall.js.map +1 -0
  118. package/lib/hooks/NftHookType.cjs +13 -0
  119. package/lib/hooks/NftHookType.d.ts +7 -0
  120. package/lib/hooks/NftHookType.js +2 -0
  121. package/lib/hooks/NftHookType.js.map +1 -0
  122. package/lib/index.js +1 -1
  123. package/lib/native.js +1 -1
  124. package/lib/token/AbstractTokenTransferTransaction.cjs +17 -5
  125. package/lib/token/AbstractTokenTransferTransaction.d.ts +13 -2
  126. package/lib/token/AbstractTokenTransferTransaction.js +1 -1
  127. package/lib/token/AbstractTokenTransferTransaction.js.map +1 -1
  128. package/lib/token/TokenAirdropTransaction.cjs +1 -1
  129. package/lib/token/TokenAirdropTransaction.js +1 -1
  130. package/lib/token/TokenAirdropTransaction.js.map +1 -1
  131. package/lib/token/TokenNftTransfer.cjs +51 -2
  132. package/lib/token/TokenNftTransfer.d.ts +7 -0
  133. package/lib/token/TokenNftTransfer.js +1 -1
  134. package/lib/token/TokenNftTransfer.js.map +1 -1
  135. package/lib/token/TokenTransfer.cjs +26 -2
  136. package/lib/token/TokenTransfer.d.ts +4 -0
  137. package/lib/token/TokenTransfer.js +1 -1
  138. package/lib/token/TokenTransfer.js.map +1 -1
  139. package/lib/transaction/Transaction.cjs +2 -1
  140. package/lib/transaction/Transaction.js +1 -1
  141. package/lib/transaction/Transaction.js.map +1 -1
  142. package/lib/transaction/TransactionResponse.cjs +82 -9
  143. package/lib/transaction/TransactionResponse.d.ts +33 -2
  144. package/lib/transaction/TransactionResponse.js +1 -1
  145. package/lib/transaction/TransactionResponse.js.map +1 -1
  146. package/lib/version.js +1 -1
  147. package/package.json +15 -13
  148. package/src/Executable.js +10 -7
  149. package/src/PublicKey.js +53 -36
  150. package/src/RequestType.js +18 -0
  151. package/src/Status.js +201 -252
  152. package/src/Transfer.js +33 -1
  153. package/src/account/AccountCreateTransaction.js +39 -0
  154. package/src/account/AccountUpdateTransaction.js +78 -0
  155. package/src/account/TransferTransaction.js +84 -8
  156. package/src/client/Client.js +38 -0
  157. package/src/client/addressbooks/mainnet.js +1 -1
  158. package/src/client/addressbooks/previewnet.js +1 -1
  159. package/src/client/addressbooks/testnet.js +1 -1
  160. package/src/contract/ContractCreateTransaction.js +37 -0
  161. package/src/contract/ContractUpdateTransaction.js +80 -0
  162. package/src/exports.js +17 -0
  163. package/src/hooks/EvmHook.js +83 -0
  164. package/src/hooks/EvmHookCall.js +100 -0
  165. package/src/hooks/EvmHookMappingEntry.js +140 -0
  166. package/src/hooks/EvmHookStorageUpdate.js +257 -0
  167. package/src/hooks/FungibleHookCall.js +65 -0
  168. package/src/hooks/FungibleHookType.js +6 -0
  169. package/src/hooks/HookCall.js +97 -0
  170. package/src/hooks/HookCreationDetails.js +155 -0
  171. package/src/hooks/HookEntityId.js +67 -0
  172. package/src/hooks/HookExtensionPoint.js +25 -0
  173. package/src/hooks/HookId.js +102 -0
  174. package/src/hooks/HookStoreTransaction.js +185 -0
  175. package/src/hooks/NftHookCall.js +64 -0
  176. package/src/hooks/NftHookType.js +8 -0
  177. package/src/token/AbstractTokenTransferTransaction.js +16 -1
  178. package/src/token/TokenAirdropTransaction.js +1 -0
  179. package/src/token/TokenNftTransfer.js +68 -1
  180. package/src/token/TokenTransfer.js +34 -1
  181. package/src/transaction/Transaction.js +3 -0
  182. package/src/transaction/TransactionResponse.js +98 -13
@@ -50,6 +50,7 @@ class TransactionResponse {
50
50
  * @param {TransactionId} props.transactionId
51
51
  * @param {Transaction} [props.transaction]
52
52
  * @param {Logger | null} [props.logger]
53
+ * @param {AccountId[]} [props.transactionNodeAccountIds]
53
54
  */
54
55
  constructor(props) {
55
56
  /** @readonly */
@@ -60,6 +61,14 @@ class TransactionResponse {
60
61
  this.transactionId = props.transactionId;
61
62
  this.transaction = props.transaction;
62
63
  this.logger = props.logger;
64
+
65
+ /**
66
+ * The node account IDs that were configured on the transaction.
67
+ * Used for receipt query failover when allowReceiptNodeFailover is enabled.
68
+ * @internal
69
+ * @type {AccountId[] | undefined}
70
+ */
71
+ this.transactionNodeAccountIds = props.transactionNodeAccountIds;
63
72
  }
64
73
 
65
74
  /**
@@ -81,7 +90,7 @@ class TransactionResponse {
81
90
  async getReceipt(client) {
82
91
  let receipt;
83
92
  try {
84
- receipt = await this.getReceiptQuery().execute(client);
93
+ receipt = await this.getReceiptQuery(client).execute(client);
85
94
  } catch (err) {
86
95
  if (err instanceof _ReceiptStatusError.default && err.status === _Status.default.ThrottledAtConsensus) {
87
96
  this.logger?.info("Transaction throttled at consensus");
@@ -108,7 +117,7 @@ class TransactionResponse {
108
117
  */
109
118
  async getRecord(client) {
110
119
  await this.getReceipt(client);
111
- return this.getRecordQuery().execute(client);
120
+ return this.getRecordQuery(client).execute(client);
112
121
  }
113
122
 
114
123
  /**
@@ -120,10 +129,10 @@ class TransactionResponse {
120
129
  async getVerboseRecord(client) {
121
130
  try {
122
131
  // The receipt needs to be called in order to wait for transaction to be included in the consensus. Otherwise we are going to get "DUPLICATE_TRANSACTION".
123
- await this.getReceiptQuery().execute(client);
124
- return this.getRecordQuery().execute(client);
132
+ await this.getReceiptQuery(client).execute(client);
133
+ return this.getRecordQuery(client).execute(client);
125
134
  } catch (e) {
126
- return this.getRecordQuery().execute(client);
135
+ return this.getRecordQuery(client).execute(client);
127
136
  }
128
137
  }
129
138
 
@@ -153,17 +162,81 @@ class TransactionResponse {
153
162
  }
154
163
 
155
164
  /**
165
+ * Create a receipt query for this transaction.
166
+ *
167
+ * By default, the query is pinned to the submitting node only. If the client has
168
+ * `allowReceiptNodeFailover` enabled, the query can fail over to other nodes while
169
+ * still starting with the submitting node first.
170
+ *
171
+ * When failover is enabled, the node list is determined by:
172
+ * 1. Transaction's configured nodes (if transaction had specific nodes set), or
173
+ * 2. Client's network nodes (as fallback)
174
+ *
175
+ * @param {Client} [client] - Optional client to enable failover behavior
156
176
  * @returns {TransactionReceiptQuery}
157
177
  */
158
- getReceiptQuery() {
159
- return new _TransactionReceiptQuery.default().setTransactionId(this.transactionId).setNodeAccountIds([this.nodeId]);
178
+ getReceiptQuery(client) {
179
+ const query = new _TransactionReceiptQuery.default().setTransactionId(this.transactionId);
180
+
181
+ // If client is provided and failover is enabled, construct a node list
182
+ // that starts with the submitting node followed by other nodes
183
+ if (client != null && client.allowReceiptNodeFailover) {
184
+ // Use transaction's configured nodes if available, otherwise use client network
185
+ const availableNodes = this.transactionNodeAccountIds != null && this.transactionNodeAccountIds.length > 0 ? this.transactionNodeAccountIds : client._network.getNodeAccountIdsForExecute();
186
+
187
+ // Build node list: [submittedNode, ...otherNodes] without duplicates
188
+ const nodeList = [this.nodeId];
189
+ for (const node of availableNodes) {
190
+ // Only add if it's not the submitting node (avoid duplicates)
191
+ if (!node.equals(this.nodeId)) {
192
+ nodeList.push(node);
193
+ }
194
+ }
195
+ query.setNodeAccountIds(nodeList);
196
+ } else {
197
+ // Default behavior: pin to submitting node only
198
+ query.setNodeAccountIds([this.nodeId]);
199
+ }
200
+ return query;
160
201
  }
161
202
 
162
203
  /**
204
+ * Create a record query for this transaction.
205
+ *
206
+ * By default, the query is pinned to the submitting node only. If the client has
207
+ * `allowReceiptNodeFailover` enabled, the query can fail over to other nodes while
208
+ * still starting with the submitting node first.
209
+ *
210
+ * When failover is enabled, the node list is determined by:
211
+ * 1. Transaction's configured nodes (if transaction had specific nodes set), or
212
+ * 2. Client's network nodes (as fallback)
213
+ *
214
+ * @param {Client} [client] - Optional client to enable failover behavior
163
215
  * @returns {TransactionRecordQuery}
164
216
  */
165
- getRecordQuery() {
166
- return new _TransactionRecordQuery.default().setTransactionId(this.transactionId).setNodeAccountIds([this.nodeId]);
217
+ getRecordQuery(client) {
218
+ const query = new _TransactionRecordQuery.default().setTransactionId(this.transactionId);
219
+
220
+ // If client is provided and failover is enabled, construct a node list
221
+ // that starts with the submitting node followed by other nodes
222
+ if (client != null && client.allowReceiptNodeFailover) {
223
+ // Use transaction's configured nodes if available, otherwise use client network
224
+ const availableNodes = this.transactionNodeAccountIds != null && this.transactionNodeAccountIds.length > 0 ? this.transactionNodeAccountIds : client._network.getNodeAccountIdsForExecute();
225
+
226
+ // Build node list: [submittedNode, ...otherNodes] without duplicates
227
+ const nodeList = [this.nodeId];
228
+ for (const node of availableNodes) {
229
+ // Only add if it's not the submitting node (avoid duplicates)
230
+ if (!node.equals(this.nodeId)) {
231
+ nodeList.push(node);
232
+ }
233
+ }
234
+ query.setNodeAccountIds(nodeList);
235
+ } else {
236
+ // Default behavior: pin to submitting node only
237
+ query.setNodeAccountIds([this.nodeId]);
238
+ }
239
+ return query;
167
240
  }
168
241
 
169
242
  /**
@@ -35,6 +35,7 @@ export default class TransactionResponse {
35
35
  * @param {TransactionId} props.transactionId
36
36
  * @param {Transaction} [props.transaction]
37
37
  * @param {Logger | null} [props.logger]
38
+ * @param {AccountId[]} [props.transactionNodeAccountIds]
38
39
  */
39
40
  constructor(props: {
40
41
  nodeId: AccountId;
@@ -42,6 +43,7 @@ export default class TransactionResponse {
42
43
  transactionId: TransactionId;
43
44
  transaction?: import("./Transaction.js").default | undefined;
44
45
  logger?: import("../logger/Logger.js").default | null | undefined;
46
+ transactionNodeAccountIds?: AccountId[] | undefined;
45
47
  });
46
48
  /** @readonly */
47
49
  readonly nodeId: AccountId;
@@ -50,6 +52,13 @@ export default class TransactionResponse {
50
52
  transactionId: TransactionId;
51
53
  transaction: import("./Transaction.js").default | undefined;
52
54
  logger: import("../logger/Logger.js").default | null | undefined;
55
+ /**
56
+ * The node account IDs that were configured on the transaction.
57
+ * Used for receipt query failover when allowReceiptNodeFailover is enabled.
58
+ * @internal
59
+ * @type {AccountId[] | undefined}
60
+ */
61
+ transactionNodeAccountIds: AccountId[] | undefined;
53
62
  /**
54
63
  * @param {Client} client
55
64
  * @returns {Promise<TransactionReceipt>}
@@ -80,13 +89,35 @@ export default class TransactionResponse {
80
89
  */
81
90
  getRecordWithSigner(signer: Signer): Promise<TransactionRecord>;
82
91
  /**
92
+ * Create a receipt query for this transaction.
93
+ *
94
+ * By default, the query is pinned to the submitting node only. If the client has
95
+ * `allowReceiptNodeFailover` enabled, the query can fail over to other nodes while
96
+ * still starting with the submitting node first.
97
+ *
98
+ * When failover is enabled, the node list is determined by:
99
+ * 1. Transaction's configured nodes (if transaction had specific nodes set), or
100
+ * 2. Client's network nodes (as fallback)
101
+ *
102
+ * @param {Client} [client] - Optional client to enable failover behavior
83
103
  * @returns {TransactionReceiptQuery}
84
104
  */
85
- getReceiptQuery(): TransactionReceiptQuery;
105
+ getReceiptQuery(client?: Client): TransactionReceiptQuery;
86
106
  /**
107
+ * Create a record query for this transaction.
108
+ *
109
+ * By default, the query is pinned to the submitting node only. If the client has
110
+ * `allowReceiptNodeFailover` enabled, the query can fail over to other nodes while
111
+ * still starting with the submitting node first.
112
+ *
113
+ * When failover is enabled, the node list is determined by:
114
+ * 1. Transaction's configured nodes (if transaction had specific nodes set), or
115
+ * 2. Client's network nodes (as fallback)
116
+ *
117
+ * @param {Client} [client] - Optional client to enable failover behavior
87
118
  * @returns {TransactionRecordQuery}
88
119
  */
89
- getRecordQuery(): TransactionRecordQuery;
120
+ getRecordQuery(client?: Client): TransactionRecordQuery;
90
121
  /**
91
122
  * @returns {TransactionResponseJSON}
92
123
  */
@@ -1,2 +1,2 @@
1
- import t from"../ReceiptStatusError.js";import r from"../Status.js";import e from"./TransactionReceiptQuery.js";import n from"./TransactionRecordQuery.js";import s from"../account/AccountId.js";import a from"./TransactionId.js";import{decode as o,encode as i}from"../encoding/hex.js";import{wait as c}from"../util.js";class h{constructor(t){this.nodeId=t.nodeId,this.transactionHash=t.transactionHash,this.transactionId=t.transactionId,this.transaction=t.transaction,this.logger=t.logger}static fromJSON(t){return new h({nodeId:s.fromString(t.nodeId),transactionHash:o(t.transactionHash),transactionId:a.fromString(t.transactionId)})}async getReceipt(e){let n;try{n=await this.getReceiptQuery().execute(e)}catch(n){if(n instanceof t&&n.status===r.ThrottledAtConsensus)return this.logger?.info("Transaction throttled at consensus"),this._retryTransaction(e);throw n}if(n.status!==r.Success&&n.status!==r.FeeScheduleFilePartUploaded)throw new t({transactionReceipt:n,status:n.status,transactionId:this.transactionId});return n}async getRecord(t){return await this.getReceipt(t),this.getRecordQuery().execute(t)}async getVerboseRecord(t){try{return await this.getReceiptQuery().execute(t),this.getRecordQuery().execute(t)}catch(r){return this.getRecordQuery().execute(t)}}async getReceiptWithSigner(e){const n=await this.getReceiptQuery().executeWithSigner(e);if(n.status!==r.Success)throw new t({transactionReceipt:n,status:n.status,transactionId:this.transactionId});return n}async getRecordWithSigner(t){return await this.getReceiptWithSigner(t),this.getRecordQuery().executeWithSigner(t)}getReceiptQuery(){return(new e).setTransactionId(this.transactionId).setNodeAccountIds([this.nodeId])}getRecordQuery(){return(new n).setTransactionId(this.transactionId).setNodeAccountIds([this.nodeId])}toJSON(){return{nodeId:this.nodeId.toString(),transactionHash:i(this.transactionHash),transactionId:this.transactionId.toString()}}async _retryTransaction(n){if(!this.transaction)throw new Error("If you retry transaction you should have the transaction set");if(n.operatorAccountId?.toString()!==this.transaction.transactionId?.accountId?.toString())throw new Error("Retry mechanism is not supported when tx id is not generated by the operator account");if(null===n.operatorAccountId)throw new Error("Operator account is not set");let s=250;for(let a=0;a<5;a++){if(this.logger?.trace(`Transaction throttled, retry attempt ${a}`),this.transaction?._resetTransaction(n),null==this.transaction||null==this.transaction.transactionId)throw new Error("Transaction or Transaction ID is null after reset");this.transactionId=this.transaction.transactionId,a>0&&(await c(Math.min(s,16e3)),s*=2);try{this.transaction._resetTransaction(n);const t=await this.transaction.execute(n),s=await(new e).setTransactionId(t.transactionId).setNodeAccountIds([t.nodeId]).execute(n);if(s.status!==r.ThrottledAtConsensus)return this.logger?.info(`Transaction throttle retry succeeded after attempt ${a}`),s}catch(e){if(e instanceof t&&e.status===r.ThrottledAtConsensus){this.logger?.info("Transaction throttled at consensus");continue}throw this.logger?.error(`An error occurred after throttle retry: ${e instanceof Error?e.message:String(e)}`),e}}throw this.logger?.error("Transaction throttle retry failed after maximum attempts"),new Error("Transaction retry failed after maximum attempts")}toString(){return JSON.stringify(this.toJSON())}}export{h as default};
1
+ import t from"../ReceiptStatusError.js";import e from"../Status.js";import n from"./TransactionReceiptQuery.js";import r from"./TransactionRecordQuery.js";import o from"../account/AccountId.js";import s from"./TransactionId.js";import{decode as a,encode as i}from"../encoding/hex.js";import{wait as c}from"../util.js";class d{constructor(t){this.nodeId=t.nodeId,this.transactionHash=t.transactionHash,this.transactionId=t.transactionId,this.transaction=t.transaction,this.logger=t.logger,this.transactionNodeAccountIds=t.transactionNodeAccountIds}static fromJSON(t){return new d({nodeId:o.fromString(t.nodeId),transactionHash:a(t.transactionHash),transactionId:s.fromString(t.transactionId)})}async getReceipt(n){let r;try{r=await this.getReceiptQuery(n).execute(n)}catch(r){if(r instanceof t&&r.status===e.ThrottledAtConsensus)return this.logger?.info("Transaction throttled at consensus"),this._retryTransaction(n);throw r}if(r.status!==e.Success&&r.status!==e.FeeScheduleFilePartUploaded)throw new t({transactionReceipt:r,status:r.status,transactionId:this.transactionId});return r}async getRecord(t){return await this.getReceipt(t),this.getRecordQuery(t).execute(t)}async getVerboseRecord(t){try{return await this.getReceiptQuery(t).execute(t),this.getRecordQuery(t).execute(t)}catch(e){return this.getRecordQuery(t).execute(t)}}async getReceiptWithSigner(n){const r=await this.getReceiptQuery().executeWithSigner(n);if(r.status!==e.Success)throw new t({transactionReceipt:r,status:r.status,transactionId:this.transactionId});return r}async getRecordWithSigner(t){return await this.getReceiptWithSigner(t),this.getRecordQuery().executeWithSigner(t)}getReceiptQuery(t){const e=(new n).setTransactionId(this.transactionId);if(null!=t&&t.allowReceiptNodeFailover){const n=null!=this.transactionNodeAccountIds&&this.transactionNodeAccountIds.length>0?this.transactionNodeAccountIds:t._network.getNodeAccountIdsForExecute(),r=[this.nodeId];for(const t of n)t.equals(this.nodeId)||r.push(t);e.setNodeAccountIds(r)}else e.setNodeAccountIds([this.nodeId]);return e}getRecordQuery(t){const e=(new r).setTransactionId(this.transactionId);if(null!=t&&t.allowReceiptNodeFailover){const n=null!=this.transactionNodeAccountIds&&this.transactionNodeAccountIds.length>0?this.transactionNodeAccountIds:t._network.getNodeAccountIdsForExecute(),r=[this.nodeId];for(const t of n)t.equals(this.nodeId)||r.push(t);e.setNodeAccountIds(r)}else e.setNodeAccountIds([this.nodeId]);return e}toJSON(){return{nodeId:this.nodeId.toString(),transactionHash:i(this.transactionHash),transactionId:this.transactionId.toString()}}async _retryTransaction(r){if(!this.transaction)throw new Error("If you retry transaction you should have the transaction set");if(r.operatorAccountId?.toString()!==this.transaction.transactionId?.accountId?.toString())throw new Error("Retry mechanism is not supported when tx id is not generated by the operator account");if(null===r.operatorAccountId)throw new Error("Operator account is not set");let o=250;for(let s=0;s<5;s++){if(this.logger?.trace(`Transaction throttled, retry attempt ${s}`),this.transaction?._resetTransaction(r),null==this.transaction||null==this.transaction.transactionId)throw new Error("Transaction or Transaction ID is null after reset");this.transactionId=this.transaction.transactionId,s>0&&(await c(Math.min(o,16e3)),o*=2);try{this.transaction._resetTransaction(r);const t=await this.transaction.execute(r),o=await(new n).setTransactionId(t.transactionId).setNodeAccountIds([t.nodeId]).execute(r);if(o.status!==e.ThrottledAtConsensus)return this.logger?.info(`Transaction throttle retry succeeded after attempt ${s}`),o}catch(n){if(n instanceof t&&n.status===e.ThrottledAtConsensus){this.logger?.info("Transaction throttled at consensus");continue}throw this.logger?.error(`An error occurred after throttle retry: ${n instanceof Error?n.message:String(n)}`),n}}throw this.logger?.error("Transaction throttle retry failed after maximum attempts"),new Error("Transaction retry failed after maximum attempts")}toString(){return JSON.stringify(this.toJSON())}}export{d as default};
2
2
  //# sourceMappingURL=TransactionResponse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransactionResponse.js","sources":["../../src/transaction/TransactionResponse.js"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nimport ReceiptStatusError from \"../ReceiptStatusError.js\";\nimport Status from \"../Status.js\";\nimport TransactionReceiptQuery from \"./TransactionReceiptQuery.js\";\nimport TransactionRecordQuery from \"./TransactionRecordQuery.js\";\nimport AccountId from \"../account/AccountId.js\";\nimport TransactionId from \"./TransactionId.js\";\nimport * as hex from \"../encoding/hex.js\";\nimport { wait } from \"../util.js\";\n\n/**\n * @typedef {import(\"../client/Client.js\").default<*, *>} Client\n * @typedef {import(\"./Transaction.js\").default} Transaction\n * @typedef {import(\"./TransactionReceipt.js\").default} TransactionReceipt\n * @typedef {import(\"./TransactionRecord.js\").default} TransactionRecord\n * @typedef {import(\"../Signer.js\").Signer} Signer\n * @typedef {import(\"../logger/Logger.js\").default} Logger\n */\n\n/**\n * @typedef {object} TransactionResponseJSON\n * @property {string} nodeId\n * @property {string} transactionHash\n * @property {string} transactionId\n */\n\n/**\n * When the client sends the node a transaction of any kind, the node\n * replies with this, which simply says that the transaction passed\n * the pre-check (so the node will submit it to the network) or it failed\n * (so it won't). To learn the consensus result, the client should later\n * obtain a receipt (free), or can buy a more detailed record (not free).\n * <br>\n * See <a href=\"https://docs.hedera.com/guides/docs/hedera-api/miscellaneous/transactionresponse\">Hedera Documentation</a>\n */\nexport default class TransactionResponse {\n /**\n * @internal\n * @param {object} props\n * @param {AccountId} props.nodeId\n * @param {Uint8Array} props.transactionHash\n * @param {TransactionId} props.transactionId\n * @param {Transaction} [props.transaction]\n * @param {Logger | null} [props.logger]\n */\n constructor(props) {\n /** @readonly */\n this.nodeId = props.nodeId;\n\n /** @readonly */\n this.transactionHash = props.transactionHash;\n\n this.transactionId = props.transactionId;\n\n this.transaction = props.transaction;\n\n this.logger = props.logger;\n }\n\n /**\n * @param {TransactionResponseJSON} json\n * @returns {TransactionResponse}\n */\n static fromJSON(json) {\n return new TransactionResponse({\n nodeId: AccountId.fromString(json.nodeId),\n transactionHash: hex.decode(json.transactionHash),\n transactionId: TransactionId.fromString(json.transactionId),\n });\n }\n\n /**\n * @param {Client} client\n * @returns {Promise<TransactionReceipt>}\n */\n async getReceipt(client) {\n let receipt;\n try {\n receipt = await this.getReceiptQuery().execute(client);\n } catch (err) {\n if (\n err instanceof ReceiptStatusError &&\n err.status === Status.ThrottledAtConsensus\n ) {\n this.logger?.info(\"Transaction throttled at consensus\");\n // need to reset the transaction to its initial state before retrying\n return this._retryTransaction(client);\n }\n throw err;\n }\n\n if (\n receipt.status !== Status.Success &&\n receipt.status !== Status.FeeScheduleFilePartUploaded\n ) {\n throw new ReceiptStatusError({\n transactionReceipt: receipt,\n status: receipt.status,\n transactionId: this.transactionId,\n });\n }\n\n return receipt;\n }\n\n /**\n * getRecord is calling getReceipt and in case the receipt status code is not OK, only the receipt is returned.\n *\n * @param {Client} client\n * @returns {Promise<TransactionRecord>}\n */\n async getRecord(client) {\n await this.getReceipt(client);\n\n return this.getRecordQuery().execute(client);\n }\n\n /**\n * getVerboseRecord is calling getReceipt and in case the receipt status code is not OK, the record is returned.\n *\n * @param {Client} client\n * @returns {Promise<TransactionRecord>}\n */\n async getVerboseRecord(client) {\n try {\n // The receipt needs to be called in order to wait for transaction to be included in the consensus. Otherwise we are going to get \"DUPLICATE_TRANSACTION\".\n await this.getReceiptQuery().execute(client);\n return this.getRecordQuery().execute(client);\n } catch (e) {\n return this.getRecordQuery().execute(client);\n }\n }\n\n /**\n * @param {Signer} signer\n * @returns {Promise<TransactionReceipt>}\n */\n async getReceiptWithSigner(signer) {\n const receipt = await this.getReceiptQuery().executeWithSigner(signer);\n\n if (receipt.status !== Status.Success) {\n throw new ReceiptStatusError({\n transactionReceipt: receipt,\n status: receipt.status,\n transactionId: this.transactionId,\n });\n }\n\n return receipt;\n }\n\n /**\n * @param {Signer} signer\n * @returns {Promise<TransactionRecord>}\n */\n async getRecordWithSigner(signer) {\n await this.getReceiptWithSigner(signer);\n\n return this.getRecordQuery().executeWithSigner(signer);\n }\n\n /**\n * @returns {TransactionReceiptQuery}\n */\n getReceiptQuery() {\n return new TransactionReceiptQuery()\n .setTransactionId(this.transactionId)\n .setNodeAccountIds([this.nodeId]);\n }\n\n /**\n * @returns {TransactionRecordQuery}\n */\n getRecordQuery() {\n return new TransactionRecordQuery()\n .setTransactionId(this.transactionId)\n .setNodeAccountIds([this.nodeId]);\n }\n\n /**\n * @returns {TransactionResponseJSON}\n */\n toJSON() {\n return {\n nodeId: this.nodeId.toString(),\n transactionHash: hex.encode(this.transactionHash),\n transactionId: this.transactionId.toString(),\n };\n }\n\n /**\n *\n * @param {Client} client\n * @returns {Promise<TransactionReceipt>}\n */\n async _retryTransaction(client) {\n if (!this.transaction) {\n throw new Error(\n \"If you retry transaction you should have the transaction set\",\n );\n }\n\n if (\n client.operatorAccountId?.toString() !==\n this.transaction.transactionId?.accountId?.toString()\n ) {\n throw new Error(\n \"Retry mechanism is not supported when tx id is not generated by the operator account\",\n );\n }\n\n if (client.operatorAccountId === null) {\n throw new Error(\"Operator account is not set\");\n }\n\n const MAX_RETRIES = 5;\n const MAX_BACKOFF = 16000;\n let BACKOFF = 250; // milliseconds\n\n for (let i = 0; i < MAX_RETRIES; i++) {\n this.logger?.trace(`Transaction throttled, retry attempt ${i}`);\n this.transaction?._resetTransaction(client);\n if (\n this.transaction == null ||\n this.transaction.transactionId == null\n ) {\n throw new Error(\n \"Transaction or Transaction ID is null after reset\",\n );\n }\n // need to set the transactionId again in case we are doing getRecord afterwards\n this.transactionId = this.transaction.transactionId;\n if (i > 0) {\n // Wait with exponential backoff before retrying\n await wait(Math.min(BACKOFF, MAX_BACKOFF));\n BACKOFF *= 2; // Double the backoff for next retry\n }\n\n try {\n this.transaction._resetTransaction(client);\n const resp = await this.transaction.execute(client);\n\n const receipt = await new TransactionReceiptQuery()\n .setTransactionId(resp.transactionId)\n .setNodeAccountIds([resp.nodeId])\n .execute(client);\n\n if (receipt.status !== Status.ThrottledAtConsensus) {\n this.logger?.info(\n `Transaction throttle retry succeeded after attempt ${i}`,\n );\n return receipt;\n }\n } catch (err) {\n if (\n err instanceof ReceiptStatusError &&\n err.status === Status.ThrottledAtConsensus\n ) {\n this.logger?.info(\"Transaction throttled at consensus\");\n // Continue to next retry on error\n continue;\n }\n this.logger?.error(\n `An error occurred after throttle retry: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n throw err;\n }\n }\n\n this.logger?.error(\n \"Transaction throttle retry failed after maximum attempts\",\n );\n throw new Error(\"Transaction retry failed after maximum attempts\");\n }\n\n /**\n * @returns {string}\n */\n toString() {\n return JSON.stringify(this.toJSON());\n }\n}\n"],"names":["TransactionResponse","constructor","props","this","nodeId","transactionHash","transactionId","transaction","logger","fromJSON","json","AccountId","fromString","hex.decode","TransactionId","getReceipt","client","receipt","getReceiptQuery","execute","err","ReceiptStatusError","status","Status","ThrottledAtConsensus","info","_retryTransaction","Success","FeeScheduleFilePartUploaded","transactionReceipt","getRecord","getRecordQuery","getVerboseRecord","e","getReceiptWithSigner","signer","executeWithSigner","getRecordWithSigner","TransactionReceiptQuery","setTransactionId","setNodeAccountIds","TransactionRecordQuery","toJSON","toString","hex.encode","Error","operatorAccountId","accountId","BACKOFF","i","trace","_resetTransaction","wait","Math","min","resp","error","message","String","JSON","stringify"],"mappings":"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"}
1
+ {"version":3,"file":"TransactionResponse.js","sources":["../../src/transaction/TransactionResponse.js"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nimport ReceiptStatusError from \"../ReceiptStatusError.js\";\nimport Status from \"../Status.js\";\nimport TransactionReceiptQuery from \"./TransactionReceiptQuery.js\";\nimport TransactionRecordQuery from \"./TransactionRecordQuery.js\";\nimport AccountId from \"../account/AccountId.js\";\nimport TransactionId from \"./TransactionId.js\";\nimport * as hex from \"../encoding/hex.js\";\nimport { wait } from \"../util.js\";\n\n/**\n * @typedef {import(\"../client/Client.js\").default<*, *>} Client\n * @typedef {import(\"./Transaction.js\").default} Transaction\n * @typedef {import(\"./TransactionReceipt.js\").default} TransactionReceipt\n * @typedef {import(\"./TransactionRecord.js\").default} TransactionRecord\n * @typedef {import(\"../Signer.js\").Signer} Signer\n * @typedef {import(\"../logger/Logger.js\").default} Logger\n */\n\n/**\n * @typedef {object} TransactionResponseJSON\n * @property {string} nodeId\n * @property {string} transactionHash\n * @property {string} transactionId\n */\n\n/**\n * When the client sends the node a transaction of any kind, the node\n * replies with this, which simply says that the transaction passed\n * the pre-check (so the node will submit it to the network) or it failed\n * (so it won't). To learn the consensus result, the client should later\n * obtain a receipt (free), or can buy a more detailed record (not free).\n * <br>\n * See <a href=\"https://docs.hedera.com/guides/docs/hedera-api/miscellaneous/transactionresponse\">Hedera Documentation</a>\n */\nexport default class TransactionResponse {\n /**\n * @internal\n * @param {object} props\n * @param {AccountId} props.nodeId\n * @param {Uint8Array} props.transactionHash\n * @param {TransactionId} props.transactionId\n * @param {Transaction} [props.transaction]\n * @param {Logger | null} [props.logger]\n * @param {AccountId[]} [props.transactionNodeAccountIds]\n */\n constructor(props) {\n /** @readonly */\n this.nodeId = props.nodeId;\n\n /** @readonly */\n this.transactionHash = props.transactionHash;\n\n this.transactionId = props.transactionId;\n\n this.transaction = props.transaction;\n\n this.logger = props.logger;\n\n /**\n * The node account IDs that were configured on the transaction.\n * Used for receipt query failover when allowReceiptNodeFailover is enabled.\n * @internal\n * @type {AccountId[] | undefined}\n */\n this.transactionNodeAccountIds = props.transactionNodeAccountIds;\n }\n\n /**\n * @param {TransactionResponseJSON} json\n * @returns {TransactionResponse}\n */\n static fromJSON(json) {\n return new TransactionResponse({\n nodeId: AccountId.fromString(json.nodeId),\n transactionHash: hex.decode(json.transactionHash),\n transactionId: TransactionId.fromString(json.transactionId),\n });\n }\n\n /**\n * @param {Client} client\n * @returns {Promise<TransactionReceipt>}\n */\n async getReceipt(client) {\n let receipt;\n try {\n receipt = await this.getReceiptQuery(client).execute(client);\n } catch (err) {\n if (\n err instanceof ReceiptStatusError &&\n err.status === Status.ThrottledAtConsensus\n ) {\n this.logger?.info(\"Transaction throttled at consensus\");\n // need to reset the transaction to its initial state before retrying\n return this._retryTransaction(client);\n }\n throw err;\n }\n\n if (\n receipt.status !== Status.Success &&\n receipt.status !== Status.FeeScheduleFilePartUploaded\n ) {\n throw new ReceiptStatusError({\n transactionReceipt: receipt,\n status: receipt.status,\n transactionId: this.transactionId,\n });\n }\n\n return receipt;\n }\n\n /**\n * getRecord is calling getReceipt and in case the receipt status code is not OK, only the receipt is returned.\n *\n * @param {Client} client\n * @returns {Promise<TransactionRecord>}\n */\n async getRecord(client) {\n await this.getReceipt(client);\n\n return this.getRecordQuery(client).execute(client);\n }\n\n /**\n * getVerboseRecord is calling getReceipt and in case the receipt status code is not OK, the record is returned.\n *\n * @param {Client} client\n * @returns {Promise<TransactionRecord>}\n */\n async getVerboseRecord(client) {\n try {\n // The receipt needs to be called in order to wait for transaction to be included in the consensus. Otherwise we are going to get \"DUPLICATE_TRANSACTION\".\n await this.getReceiptQuery(client).execute(client);\n return this.getRecordQuery(client).execute(client);\n } catch (e) {\n return this.getRecordQuery(client).execute(client);\n }\n }\n\n /**\n * @param {Signer} signer\n * @returns {Promise<TransactionReceipt>}\n */\n async getReceiptWithSigner(signer) {\n const receipt = await this.getReceiptQuery().executeWithSigner(signer);\n\n if (receipt.status !== Status.Success) {\n throw new ReceiptStatusError({\n transactionReceipt: receipt,\n status: receipt.status,\n transactionId: this.transactionId,\n });\n }\n\n return receipt;\n }\n\n /**\n * @param {Signer} signer\n * @returns {Promise<TransactionRecord>}\n */\n async getRecordWithSigner(signer) {\n await this.getReceiptWithSigner(signer);\n\n return this.getRecordQuery().executeWithSigner(signer);\n }\n\n /**\n * Create a receipt query for this transaction.\n *\n * By default, the query is pinned to the submitting node only. If the client has\n * `allowReceiptNodeFailover` enabled, the query can fail over to other nodes while\n * still starting with the submitting node first.\n *\n * When failover is enabled, the node list is determined by:\n * 1. Transaction's configured nodes (if transaction had specific nodes set), or\n * 2. Client's network nodes (as fallback)\n *\n * @param {Client} [client] - Optional client to enable failover behavior\n * @returns {TransactionReceiptQuery}\n */\n getReceiptQuery(client) {\n const query = new TransactionReceiptQuery().setTransactionId(\n this.transactionId,\n );\n\n // If client is provided and failover is enabled, construct a node list\n // that starts with the submitting node followed by other nodes\n if (client != null && client.allowReceiptNodeFailover) {\n // Use transaction's configured nodes if available, otherwise use client network\n const availableNodes =\n this.transactionNodeAccountIds != null &&\n this.transactionNodeAccountIds.length > 0\n ? this.transactionNodeAccountIds\n : client._network.getNodeAccountIdsForExecute();\n\n // Build node list: [submittedNode, ...otherNodes] without duplicates\n const nodeList = [this.nodeId];\n for (const node of availableNodes) {\n // Only add if it's not the submitting node (avoid duplicates)\n if (!node.equals(this.nodeId)) {\n nodeList.push(node);\n }\n }\n\n query.setNodeAccountIds(nodeList);\n } else {\n // Default behavior: pin to submitting node only\n query.setNodeAccountIds([this.nodeId]);\n }\n\n return query;\n }\n\n /**\n * Create a record query for this transaction.\n *\n * By default, the query is pinned to the submitting node only. If the client has\n * `allowReceiptNodeFailover` enabled, the query can fail over to other nodes while\n * still starting with the submitting node first.\n *\n * When failover is enabled, the node list is determined by:\n * 1. Transaction's configured nodes (if transaction had specific nodes set), or\n * 2. Client's network nodes (as fallback)\n *\n * @param {Client} [client] - Optional client to enable failover behavior\n * @returns {TransactionRecordQuery}\n */\n getRecordQuery(client) {\n const query = new TransactionRecordQuery().setTransactionId(\n this.transactionId,\n );\n\n // If client is provided and failover is enabled, construct a node list\n // that starts with the submitting node followed by other nodes\n if (client != null && client.allowReceiptNodeFailover) {\n // Use transaction's configured nodes if available, otherwise use client network\n const availableNodes =\n this.transactionNodeAccountIds != null &&\n this.transactionNodeAccountIds.length > 0\n ? this.transactionNodeAccountIds\n : client._network.getNodeAccountIdsForExecute();\n\n // Build node list: [submittedNode, ...otherNodes] without duplicates\n const nodeList = [this.nodeId];\n for (const node of availableNodes) {\n // Only add if it's not the submitting node (avoid duplicates)\n if (!node.equals(this.nodeId)) {\n nodeList.push(node);\n }\n }\n\n query.setNodeAccountIds(nodeList);\n } else {\n // Default behavior: pin to submitting node only\n query.setNodeAccountIds([this.nodeId]);\n }\n\n return query;\n }\n\n /**\n * @returns {TransactionResponseJSON}\n */\n toJSON() {\n return {\n nodeId: this.nodeId.toString(),\n transactionHash: hex.encode(this.transactionHash),\n transactionId: this.transactionId.toString(),\n };\n }\n\n /**\n *\n * @param {Client} client\n * @returns {Promise<TransactionReceipt>}\n */\n async _retryTransaction(client) {\n if (!this.transaction) {\n throw new Error(\n \"If you retry transaction you should have the transaction set\",\n );\n }\n\n if (\n client.operatorAccountId?.toString() !==\n this.transaction.transactionId?.accountId?.toString()\n ) {\n throw new Error(\n \"Retry mechanism is not supported when tx id is not generated by the operator account\",\n );\n }\n\n if (client.operatorAccountId === null) {\n throw new Error(\"Operator account is not set\");\n }\n\n const MAX_RETRIES = 5;\n const MAX_BACKOFF = 16000;\n let BACKOFF = 250; // milliseconds\n\n for (let i = 0; i < MAX_RETRIES; i++) {\n this.logger?.trace(`Transaction throttled, retry attempt ${i}`);\n this.transaction?._resetTransaction(client);\n if (\n this.transaction == null ||\n this.transaction.transactionId == null\n ) {\n throw new Error(\n \"Transaction or Transaction ID is null after reset\",\n );\n }\n // need to set the transactionId again in case we are doing getRecord afterwards\n this.transactionId = this.transaction.transactionId;\n if (i > 0) {\n // Wait with exponential backoff before retrying\n await wait(Math.min(BACKOFF, MAX_BACKOFF));\n BACKOFF *= 2; // Double the backoff for next retry\n }\n\n try {\n this.transaction._resetTransaction(client);\n const resp = await this.transaction.execute(client);\n\n const receipt = await new TransactionReceiptQuery()\n .setTransactionId(resp.transactionId)\n .setNodeAccountIds([resp.nodeId])\n .execute(client);\n\n if (receipt.status !== Status.ThrottledAtConsensus) {\n this.logger?.info(\n `Transaction throttle retry succeeded after attempt ${i}`,\n );\n return receipt;\n }\n } catch (err) {\n if (\n err instanceof ReceiptStatusError &&\n err.status === Status.ThrottledAtConsensus\n ) {\n this.logger?.info(\"Transaction throttled at consensus\");\n // Continue to next retry on error\n continue;\n }\n this.logger?.error(\n `An error occurred after throttle retry: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n throw err;\n }\n }\n\n this.logger?.error(\n \"Transaction throttle retry failed after maximum attempts\",\n );\n throw new Error(\"Transaction retry failed after maximum attempts\");\n }\n\n /**\n * @returns {string}\n */\n toString() {\n return JSON.stringify(this.toJSON());\n }\n}\n"],"names":["TransactionResponse","constructor","props","this","nodeId","transactionHash","transactionId","transaction","logger","transactionNodeAccountIds","fromJSON","json","AccountId","fromString","hex.decode","TransactionId","getReceipt","client","receipt","getReceiptQuery","execute","err","ReceiptStatusError","status","Status","ThrottledAtConsensus","info","_retryTransaction","Success","FeeScheduleFilePartUploaded","transactionReceipt","getRecord","getRecordQuery","getVerboseRecord","e","getReceiptWithSigner","signer","executeWithSigner","getRecordWithSigner","query","TransactionReceiptQuery","setTransactionId","allowReceiptNodeFailover","availableNodes","length","_network","getNodeAccountIdsForExecute","nodeList","node","equals","push","setNodeAccountIds","TransactionRecordQuery","toJSON","toString","hex.encode","Error","operatorAccountId","accountId","BACKOFF","i","trace","_resetTransaction","wait","Math","min","resp","error","message","String","JSON","stringify"],"mappings":"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"}
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
- const o="hiero-sdk-js",s="2.80.0";export{o as SDK_NAME,s as SDK_VERSION};
1
+ const e="hiero-sdk-js",o="2.81.0-beta.1";export{e as SDK_NAME,o as SDK_VERSION};
2
2
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hiero-ledger/sdk",
3
- "version": "2.80.0",
3
+ "version": "2.81.0-beta.1",
4
4
  "description": "Hiero SDK",
5
5
  "types": "./lib/index.d.ts",
6
6
  "main": "./lib/index.cjs",
@@ -75,12 +75,12 @@
75
75
  "long": "5.3.1",
76
76
  "pino": "10.1.0",
77
77
  "pino-pretty": "13.0.0",
78
- "protobufjs": "7.5.4",
78
+ "protobufjs": "8.0.0",
79
79
  "rfc4648": "1.5.3",
80
80
  "strip-ansi": "7.1.2",
81
81
  "utf8": "3.0.0",
82
- "@hiero-ledger/cryptography": "1.16.0-beta.3",
83
- "@hiero-ledger/proto": "2.26.0-beta.3"
82
+ "@hiero-ledger/proto": "2.26.0-beta.3",
83
+ "@hiero-ledger/cryptography": "1.16.0-beta.3"
84
84
  },
85
85
  "devDependencies": {
86
86
  "@babel/cli": "7.23.4",
@@ -106,25 +106,27 @@
106
106
  "@types/utf8": "3.0.1",
107
107
  "@typescript-eslint/eslint-plugin": "5.48.2",
108
108
  "@typescript-eslint/parser": "5.62.0",
109
- "@vitest/browser": "3.2.4",
110
- "@vitest/coverage-v8": "3.2.4",
109
+ "@vitest/browser": "4.0.18",
110
+ "@vitest/browser-playwright": "4.0.18",
111
+ "@vitest/coverage-istanbul": "4.0.18",
112
+ "@vitest/coverage-v8": "4.0.18",
111
113
  "babel-plugin-dynamic-import-node": "2.3.3",
112
114
  "babel-plugin-module-rewrite": "0.2.0",
113
115
  "c8": "10.1.3",
114
- "chromedriver": "143.0.3",
116
+ "chromedriver": "145.0.1",
115
117
  "codecov": "3.8.3",
116
- "dotenv": "17.0.1",
118
+ "dotenv": "17.2.3",
117
119
  "dpdm": "3.11.0",
118
120
  "eslint": "8.57.1",
119
- "eslint-plugin-compat": "6.0.2",
121
+ "eslint-plugin-compat": "6.1.0",
120
122
  "eslint-plugin-deprecation": "3.0.0",
121
123
  "eslint-plugin-ie11": "1.0.0",
122
124
  "eslint-plugin-import": "2.28.1",
123
- "eslint-plugin-jsdoc": "61.1.11",
125
+ "eslint-plugin-jsdoc": "62.5.5",
124
126
  "eslint-plugin-n": "17.16.1",
125
127
  "eslint-plugin-vitest": "0.3.25",
126
128
  "geckodriver": "6.0.1",
127
- "jsdom": "27.0.0",
129
+ "jsdom": "28.1.0",
128
130
  "msw": "2.10.2",
129
131
  "npm-run-all": "4.1.5",
130
132
  "npx": "10.2.2",
@@ -135,8 +137,8 @@
135
137
  "sinon": "21.0.0",
136
138
  "typedoc": "0.28.1",
137
139
  "typescript": "5.7.2",
138
- "vite": "6.4.1",
139
- "vitest": "3.2.4"
140
+ "vite": "7.3.1",
141
+ "vitest": "4.0.18"
140
142
  },
141
143
  "peerDependencies": {
142
144
  "bn.js": "5.2.1"
package/src/Executable.js CHANGED
@@ -665,13 +665,16 @@ export default class Executable {
665
665
  this._nodeAccountIds.index ===
666
666
  this._nodeAccountIds.list.length - 1;
667
667
 
668
- // Check if the request is a transaction receipt or record
669
- // request to retry 10 times, because getReceiptQuery/getRecordQuery
670
- // are single node requests
671
- if (
672
- isTransactionReceiptOrRecordRequest(request) ||
673
- isLocalNode
674
- ) {
668
+ // Check if the request is a transaction receipt or record request
669
+ // with a single node (traditional behavior), or if it's a local node.
670
+ // For single-node receipt queries, we retry the same node with backoff.
671
+ // For multi-node receipt queries (when failover is enabled), we allow
672
+ // advancing to the next node like other queries.
673
+ const isSingleNodeReceiptOrRecordRequest =
674
+ isTransactionReceiptOrRecordRequest(request) &&
675
+ this._nodeAccountIds.length <= 1;
676
+
677
+ if (isSingleNodeReceiptOrRecordRequest || isLocalNode) {
675
678
  await delayForAttempt(
676
679
  isLocalNode,
677
680
  attempt,
package/src/PublicKey.js CHANGED
@@ -114,48 +114,65 @@ export default class PublicKey extends Key {
114
114
  // before we execute the transaction (execute -> makeRequest -> buildTransaction -> signTransaction).
115
115
  // However, in JavaScript, we build the `_signedTransactions` list while signing the transaction.
116
116
  for (const signedTransaction of transaction._signedTransactions.list) {
117
- if (
118
- signedTransaction.sigMap != null &&
119
- signedTransaction.sigMap.sigPair != null
120
- ) {
121
- let found = false;
122
- for (const sigPair of signedTransaction.sigMap.sigPair) {
123
- const pubKeyPrefix = /** @type {Uint8Array} */ (
124
- sigPair.pubKeyPrefix
125
- );
126
- if (arrayEqual(pubKeyPrefix, this.toBytesRaw())) {
127
- found = true;
128
-
129
- const bodyBytes = /** @type {Uint8Array} */ (
130
- signedTransaction.bodyBytes
131
- );
132
-
133
- let signature = null;
134
- if (sigPair.ed25519 != null) {
135
- signature = sigPair.ed25519;
136
- } else if (sigPair.ECDSASecp256k1 != null) {
137
- signature = sigPair.ECDSASecp256k1;
138
- }
139
-
140
- if (signature == null) {
141
- continue;
142
- }
143
-
144
- if (!this.verify(bodyBytes, signature)) {
145
- return false;
146
- }
147
- }
148
- }
149
-
150
- if (!found) {
151
- return false;
152
- }
117
+ if (!this._verifySignedTransaction(signedTransaction)) {
118
+ return false;
153
119
  }
154
120
  }
155
121
 
156
122
  return true;
157
123
  }
158
124
 
125
+ /**
126
+ * @private
127
+ * @param {HieroProto.proto.ISignedTransaction} signedTransaction
128
+ * @returns {boolean}
129
+ */
130
+ _verifySignedTransaction(signedTransaction) {
131
+ const sigMap = signedTransaction.sigMap;
132
+ if (sigMap == null || sigMap.sigPair == null) {
133
+ return false;
134
+ }
135
+
136
+ const bodyBytes = /** @type {Uint8Array} */ (
137
+ signedTransaction.bodyBytes
138
+ );
139
+ const publicKeyBytes = this.toBytesRaw();
140
+
141
+ for (const sigPair of sigMap.sigPair) {
142
+ const pubKeyPrefix = /** @type {Uint8Array} */ (
143
+ sigPair.pubKeyPrefix
144
+ );
145
+
146
+ if (!arrayEqual(pubKeyPrefix, publicKeyBytes)) {
147
+ continue;
148
+ }
149
+
150
+ const signature = this._extractSignature(sigPair);
151
+ if (signature == null) {
152
+ return false;
153
+ }
154
+
155
+ return this.verify(bodyBytes, signature);
156
+ }
157
+
158
+ return false;
159
+ }
160
+
161
+ /**
162
+ * @private
163
+ * @param {HieroProto.proto.ISignaturePair} sigPair
164
+ * @returns {Uint8Array | null}
165
+ */
166
+ _extractSignature(sigPair) {
167
+ if (sigPair.ed25519 != null) {
168
+ return sigPair.ed25519;
169
+ }
170
+ if (sigPair.ECDSASecp256k1 != null) {
171
+ return sigPair.ECDSASecp256k1;
172
+ }
173
+ return null;
174
+ }
175
+
159
176
  /**
160
177
  * @returns {Uint8Array}
161
178
  */
@@ -217,6 +217,10 @@ export default class RequestType {
217
217
  return "LambdaSStore";
218
218
  case RequestType.HookDispatch:
219
219
  return "HookDispatch";
220
+ case RequestType.HookStore:
221
+ return "HookStore";
222
+ case RequestType.LedgerIdPublication:
223
+ return "LedgerIdPublication";
220
224
  default:
221
225
  return `UNKNOWN (${this._code})`;
222
226
  }
@@ -423,6 +427,10 @@ export default class RequestType {
423
427
  return RequestType.LambdaSStore;
424
428
  case 110:
425
429
  return RequestType.HookDispatch;
430
+ case 111:
431
+ return RequestType.HookStore;
432
+ case 112:
433
+ return RequestType.LedgerIdPublication;
426
434
  }
427
435
 
428
436
  throw new Error(
@@ -936,3 +944,13 @@ RequestType.LambdaSStore = new RequestType(109);
936
944
  * hook dispatch
937
945
  */
938
946
  RequestType.HookDispatch = new RequestType(110);
947
+
948
+ /**
949
+ * Update one or more storage slots in an EVM hook.
950
+ */
951
+ RequestType.HookStore = new RequestType(111);
952
+
953
+ /**
954
+ * (Internal-only) Publish a new ledger id and chain-of-trust key.
955
+ */
956
+ RequestType.LedgerIdPublication = new RequestType(112);