@injectivelabs/sdk-ts 1.19.25 → 1.19.27

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.
@@ -257,6 +257,377 @@ const getTxRawFromTxRawOrDirectSignResponse = (txRawOrDirectSignResponse) => {
257
257
  return txRawOrDirectSignResponse.signed === void 0 ? txRawOrDirectSignResponse : createTxRawFromSigResponse(txRawOrDirectSignResponse);
258
258
  };
259
259
 
260
+ //#endregion
261
+ //#region src/core/tx/types/tx.ts
262
+ const TxInclusionStrategy = {
263
+ Poll: "poll",
264
+ TendermintEvent: "tendermint-event",
265
+ TendermintEventAndPoll: "tendermint-event-and-poll"
266
+ };
267
+ const TxClientMode = {
268
+ gRpc: "grpc",
269
+ rest: "rest"
270
+ };
271
+
272
+ //#endregion
273
+ //#region src/core/tx/api/TxEventInclusion.ts
274
+ function normalizeTendermintWebSocketEndpoint(endpoint) {
275
+ let normalized = endpoint;
276
+ if (normalized.startsWith("http://")) normalized = `ws://${normalized.slice(7)}`;
277
+ else if (normalized.startsWith("https://")) normalized = `wss://${normalized.slice(8)}`;
278
+ return normalized.endsWith("/websocket") ? normalized : `${normalized.replace(/\/$/, "")}/websocket`;
279
+ }
280
+ async function subscribeToTendermintTxEvent({ txHash, timeout, endpoint, webSocketFactory }) {
281
+ const normalizedTxHash = normalizeTendermintTxHash(txHash);
282
+ const socket = createTendermintSocket(normalizeTendermintWebSocketEndpoint(endpoint), webSocketFactory);
283
+ const query = `tm.event='Tx' AND tx.hash='${normalizedTxHash}'`;
284
+ const requestId = `tx-event-${Date.now()}-${Math.random()}`;
285
+ return new Promise((resolve, reject) => {
286
+ let ready = false;
287
+ let waitSettled = false;
288
+ let closedIntentionally = false;
289
+ let timeoutId;
290
+ let waitResolve;
291
+ let waitReject;
292
+ const waitPromise = new Promise((resolveWait$1, rejectWait$1) => {
293
+ waitResolve = resolveWait$1;
294
+ waitReject = rejectWait$1;
295
+ });
296
+ const resolveSubscription = () => {
297
+ if (ready) return;
298
+ ready = true;
299
+ resolve({
300
+ close: cleanup,
301
+ wait: () => waitPromise
302
+ });
303
+ };
304
+ const cleanup = () => {
305
+ closedIntentionally = true;
306
+ clearTimeout(timeoutId);
307
+ socket.removeEventListener("open", onOpen);
308
+ socket.removeEventListener("message", onMessage);
309
+ socket.removeEventListener("error", onError);
310
+ socket.removeEventListener("close", onClose);
311
+ if (socket.readyState === 1 || socket.readyState === 0) socket.close();
312
+ };
313
+ const rejectWait = (error) => {
314
+ if (waitSettled) return;
315
+ waitSettled = true;
316
+ waitReject(error);
317
+ cleanup();
318
+ };
319
+ timeoutId = setTimeout(() => {
320
+ const error = /* @__PURE__ */ new Error(`Timed out waiting for Tendermint tx event after ${timeout}ms`);
321
+ if (ready) {
322
+ rejectWait(error);
323
+ return;
324
+ }
325
+ cleanup();
326
+ reject(error);
327
+ }, timeout);
328
+ const resolveWait = (response) => {
329
+ if (waitSettled) return;
330
+ waitSettled = true;
331
+ waitResolve(response);
332
+ cleanup();
333
+ };
334
+ const rejectForMessageError = (error) => {
335
+ if (ready) {
336
+ rejectWait(error);
337
+ return;
338
+ }
339
+ cleanup();
340
+ reject(error);
341
+ };
342
+ const onOpen = () => {
343
+ socket.send(JSON.stringify({
344
+ id: requestId,
345
+ jsonrpc: "2.0",
346
+ method: "subscribe",
347
+ params: { query }
348
+ }));
349
+ };
350
+ const onMessage = (event) => {
351
+ readMessageEventData(event).then((messageData) => {
352
+ const message = JSON.parse(messageData);
353
+ const eventResponse = parseTxEventResponse(message, normalizedTxHash);
354
+ if (eventResponse) {
355
+ resolveSubscription();
356
+ resolveWait(eventResponse);
357
+ return;
358
+ }
359
+ if (message.id !== requestId) return;
360
+ if (message.error) {
361
+ rejectForMessageError(/* @__PURE__ */ new Error(`Tendermint subscribe failed: ${JSON.stringify(message.error)}`));
362
+ return;
363
+ }
364
+ resolveSubscription();
365
+ }).catch((error) => {
366
+ rejectForMessageError(error instanceof Error ? error : /* @__PURE__ */ new Error(`Invalid Tendermint WebSocket JSON: ${String(error)}`));
367
+ });
368
+ };
369
+ const onError = () => {
370
+ const error = /* @__PURE__ */ new Error("Tendermint WebSocket error");
371
+ if (ready) {
372
+ rejectWait(error);
373
+ return;
374
+ }
375
+ cleanup();
376
+ reject(error);
377
+ };
378
+ const onClose = () => {
379
+ if (closedIntentionally) return;
380
+ const error = /* @__PURE__ */ new Error("Tendermint WebSocket closed");
381
+ if (ready) {
382
+ rejectWait(error);
383
+ return;
384
+ }
385
+ cleanup();
386
+ reject(error);
387
+ };
388
+ socket.addEventListener("open", onOpen);
389
+ socket.addEventListener("message", onMessage);
390
+ socket.addEventListener("error", onError);
391
+ socket.addEventListener("close", onClose);
392
+ });
393
+ }
394
+ function normalizeTendermintTxHash(txHash) {
395
+ if (!/^[0-9a-fA-F]{64}$/.test(txHash)) throw new Error("Invalid Tendermint tx hash");
396
+ return txHash.toUpperCase();
397
+ }
398
+ function createTendermintSocket(endpoint, webSocketFactory) {
399
+ if (webSocketFactory) return webSocketFactory(endpoint);
400
+ if (!globalThis.WebSocket) throw new Error("WebSocket is not available in this environment");
401
+ return new globalThis.WebSocket(endpoint);
402
+ }
403
+ async function readMessageEventData(event) {
404
+ const { data } = event;
405
+ if (typeof data === "string") return data;
406
+ if (typeof Blob !== "undefined" && data instanceof Blob) return data.text();
407
+ if (typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) return new TextDecoder().decode(data);
408
+ if (ArrayBuffer.isView(data)) return new TextDecoder().decode(data);
409
+ return String(data);
410
+ }
411
+ function parseTxEventResponse(message, txHash) {
412
+ var _message$params$resul, _message$params, _message$result, _data$value, _ref, _value$TxResult, _txResult$result;
413
+ const data = (_message$params$resul = message === null || message === void 0 || (_message$params = message.params) === null || _message$params === void 0 || (_message$params = _message$params.result) === null || _message$params === void 0 ? void 0 : _message$params.data) !== null && _message$params$resul !== void 0 ? _message$params$resul : message === null || message === void 0 || (_message$result = message.result) === null || _message$result === void 0 ? void 0 : _message$result.data;
414
+ const eventTxHashes = readTxEventHashes(data);
415
+ if (eventTxHashes.length > 0 && !eventTxHashes.some((eventTxHash) => eventTxHash.toUpperCase() === txHash.toUpperCase())) return;
416
+ const value = (_data$value = data === null || data === void 0 ? void 0 : data.value) !== null && _data$value !== void 0 ? _data$value : data;
417
+ const txResult = (_ref = (_value$TxResult = value === null || value === void 0 ? void 0 : value.TxResult) !== null && _value$TxResult !== void 0 ? _value$TxResult : value === null || value === void 0 ? void 0 : value.tx_result) !== null && _ref !== void 0 ? _ref : value;
418
+ const result = (_txResult$result = txResult === null || txResult === void 0 ? void 0 : txResult.result) !== null && _txResult$result !== void 0 ? _txResult$result : txResult === null || txResult === void 0 ? void 0 : txResult.Result;
419
+ if (!txResult || !result) return;
420
+ return {
421
+ txHash,
422
+ logs: [],
423
+ timestamp: "",
424
+ data: result.data || "",
425
+ info: result.info || "",
426
+ events: result.events || [],
427
+ code: Number(result.code || 0),
428
+ codespace: result.codespace || "",
429
+ rawLog: result.log || result.raw_log || "",
430
+ height: Number(txResult.height || (value === null || value === void 0 ? void 0 : value.height) || 0),
431
+ gasUsed: Number(result.gas_used || result.gasUsed || 0),
432
+ gasWanted: Number(result.gas_wanted || result.gasWanted || 0)
433
+ };
434
+ }
435
+ function readTxEventHashes(data) {
436
+ var _data$events$txHash, _data$events, _data$events2;
437
+ const txHashEvent = (_data$events$txHash = data === null || data === void 0 || (_data$events = data.events) === null || _data$events === void 0 ? void 0 : _data$events["tx.hash"]) !== null && _data$events$txHash !== void 0 ? _data$events$txHash : data === null || data === void 0 || (_data$events2 = data.events) === null || _data$events2 === void 0 ? void 0 : _data$events2.tx_hash;
438
+ if (Array.isArray(txHashEvent)) return txHashEvent.map(String);
439
+ if (txHashEvent) return [String(txHashEvent)];
440
+ return [];
441
+ }
442
+
443
+ //#endregion
444
+ //#region src/core/tx/api/TxInclusion.ts
445
+ function isTendermintEventStrategy(inclusionStrategy) {
446
+ return inclusionStrategy === TxInclusionStrategy.TendermintEvent || inclusionStrategy === TxInclusionStrategy.TendermintEventAndPoll;
447
+ }
448
+ async function prepareTxInclusionWaiter({ txHash, timeout, options, fetchTx, fetchTxPoll, createRequestException }) {
449
+ const inclusionStrategy = options === null || options === void 0 ? void 0 : options.inclusionStrategy;
450
+ if (!isTendermintEventStrategy(inclusionStrategy)) return createPollingInclusionWaiter({
451
+ txHash,
452
+ timeout,
453
+ fetchTxPoll
454
+ });
455
+ const eventOptions = options === null || options === void 0 ? void 0 : options.eventInclusion;
456
+ const rpcEndpoint = eventOptions === null || eventOptions === void 0 ? void 0 : eventOptions.rpcEndpoint;
457
+ const fallbackToPolling = (eventOptions === null || eventOptions === void 0 ? void 0 : eventOptions.fallbackToPolling) !== false;
458
+ if (!rpcEndpoint) {
459
+ var _eventOptions$onFallb;
460
+ const error = new GeneralException(/* @__PURE__ */ new Error("Tendermint RPC endpoint is required for event inclusion"));
461
+ if (!fallbackToPolling) throw createRequestException(error, "event-inclusion");
462
+ eventOptions === null || eventOptions === void 0 || (_eventOptions$onFallb = eventOptions.onFallback) === null || _eventOptions$onFallb === void 0 || _eventOptions$onFallb.call(eventOptions, error);
463
+ return createPollingInclusionWaiter({
464
+ txHash,
465
+ timeout,
466
+ fetchTxPoll
467
+ });
468
+ }
469
+ try {
470
+ const subscription = await subscribeToTendermintTxEvent({
471
+ txHash,
472
+ endpoint: rpcEndpoint,
473
+ timeout: (eventOptions === null || eventOptions === void 0 ? void 0 : eventOptions.timeout) || timeout,
474
+ webSocketFactory: eventOptions === null || eventOptions === void 0 ? void 0 : eventOptions.webSocketFactory
475
+ });
476
+ const hashMismatchPollAbortController = new AbortController();
477
+ const close = () => {
478
+ hashMismatchPollAbortController.abort();
479
+ subscription.close();
480
+ };
481
+ return {
482
+ txHash,
483
+ inclusionStrategy,
484
+ close,
485
+ wait: async (includedTxHash = txHash) => {
486
+ if (includedTxHash.toUpperCase() !== txHash.toUpperCase()) {
487
+ var _eventOptions$onFallb2;
488
+ subscription.close();
489
+ eventOptions === null || eventOptions === void 0 || (_eventOptions$onFallb2 = eventOptions.onFallback) === null || _eventOptions$onFallb2 === void 0 || _eventOptions$onFallb2.call(eventOptions, new GeneralException(/* @__PURE__ */ new Error(`Broadcast tx hash ${includedTxHash} did not match subscribed tx hash ${txHash}`)));
490
+ return fetchTxPoll({
491
+ txHash: includedTxHash,
492
+ timeout,
493
+ abortSignal: hashMismatchPollAbortController.signal
494
+ });
495
+ }
496
+ if (inclusionStrategy === TxInclusionStrategy.TendermintEventAndPoll) return waitForSubscribedTxInclusionAndPoll({
497
+ txHash,
498
+ timeout,
499
+ fetchTx,
500
+ options,
501
+ fetchTxPoll,
502
+ subscription
503
+ });
504
+ return waitForSubscribedTxInclusion({
505
+ txHash,
506
+ timeout,
507
+ options,
508
+ fetchTx,
509
+ subscription,
510
+ fetchTxPoll,
511
+ createRequestException
512
+ });
513
+ }
514
+ };
515
+ } catch (e) {
516
+ var _eventOptions$onFallb3;
517
+ if (e instanceof TransactionException) throw e;
518
+ const error = e instanceof Error ? e : new Error(String(e));
519
+ if (!fallbackToPolling) throw createRequestException(error, "event-inclusion");
520
+ eventOptions === null || eventOptions === void 0 || (_eventOptions$onFallb3 = eventOptions.onFallback) === null || _eventOptions$onFallb3 === void 0 || _eventOptions$onFallb3.call(eventOptions, error);
521
+ return createPollingInclusionWaiter({
522
+ txHash,
523
+ timeout,
524
+ fetchTxPoll
525
+ });
526
+ }
527
+ }
528
+ function createPollingInclusionWaiter({ txHash, timeout, fetchTxPoll }) {
529
+ const pollAbortController = new AbortController();
530
+ return {
531
+ txHash,
532
+ inclusionStrategy: TxInclusionStrategy.Poll,
533
+ close: () => {
534
+ pollAbortController.abort();
535
+ },
536
+ wait: (includedTxHash = txHash) => fetchTxPoll({
537
+ txHash: includedTxHash,
538
+ timeout,
539
+ abortSignal: pollAbortController.signal
540
+ })
541
+ };
542
+ }
543
+ async function waitForSubscribedTxInclusion({ txHash, timeout, options, fetchTx, fetchTxPoll, subscription, createRequestException }) {
544
+ var _options$eventInclusi;
545
+ const fallbackToPolling = (options === null || options === void 0 || (_options$eventInclusi = options.eventInclusion) === null || _options$eventInclusi === void 0 ? void 0 : _options$eventInclusi.fallbackToPolling) !== false;
546
+ try {
547
+ return await waitForSubscribedTxEvent({
548
+ txHash,
549
+ subscription,
550
+ fetchTx
551
+ });
552
+ } catch (e) {
553
+ var _options$eventInclusi2, _options$eventInclusi3;
554
+ if (e instanceof TransactionException) throw e;
555
+ const error = e instanceof GeneralException ? e : new GeneralException(new Error(String(e)));
556
+ if (!fallbackToPolling) throw createRequestException(error, "event-inclusion");
557
+ options === null || options === void 0 || (_options$eventInclusi2 = options.eventInclusion) === null || _options$eventInclusi2 === void 0 || (_options$eventInclusi3 = _options$eventInclusi2.onFallback) === null || _options$eventInclusi3 === void 0 || _options$eventInclusi3.call(_options$eventInclusi2, error);
558
+ return fetchTxPoll({
559
+ txHash,
560
+ timeout
561
+ });
562
+ }
563
+ }
564
+ async function waitForSubscribedTxInclusionAndPoll({ txHash, timeout, options, fetchTx, fetchTxPoll, subscription }) {
565
+ const pollAbortController = new AbortController();
566
+ return new Promise((resolve, reject) => {
567
+ let settled = false;
568
+ let finishedCount = 0;
569
+ let eventError;
570
+ let pollError;
571
+ const rejectIfBothFailed = () => {
572
+ if (finishedCount < 2 || settled) return;
573
+ reject(pollError || eventError || new GeneralException(/* @__PURE__ */ new Error("Tx inclusion failed")));
574
+ };
575
+ const resolveOnce = (txResponse, source) => {
576
+ if (settled) return;
577
+ settled = true;
578
+ if (source === "poll") {
579
+ subscription.close();
580
+ resolve(txResponse);
581
+ return;
582
+ }
583
+ pollAbortController.abort();
584
+ resolve(txResponse);
585
+ };
586
+ const rejectTerminal = (error) => {
587
+ if (settled) return true;
588
+ if (error instanceof TransactionException) {
589
+ settled = true;
590
+ subscription.close();
591
+ pollAbortController.abort();
592
+ reject(error);
593
+ return true;
594
+ }
595
+ return false;
596
+ };
597
+ waitForSubscribedTxEvent({
598
+ txHash,
599
+ subscription,
600
+ fetchTx
601
+ }).then((txResponse) => resolveOnce(txResponse, "event")).catch((error) => {
602
+ var _options$eventInclusi4, _options$eventInclusi5;
603
+ if (rejectTerminal(error)) return;
604
+ const fallbackError = error instanceof Error ? error : new Error(String(error));
605
+ eventError = fallbackError;
606
+ finishedCount += 1;
607
+ options === null || options === void 0 || (_options$eventInclusi4 = options.eventInclusion) === null || _options$eventInclusi4 === void 0 || (_options$eventInclusi5 = _options$eventInclusi4.onFallback) === null || _options$eventInclusi5 === void 0 || _options$eventInclusi5.call(_options$eventInclusi4, fallbackError);
608
+ rejectIfBothFailed();
609
+ });
610
+ fetchTxPoll({
611
+ txHash,
612
+ timeout,
613
+ abortSignal: pollAbortController.signal
614
+ }).then((txResponse) => resolveOnce(txResponse, "poll")).catch((error) => {
615
+ if (rejectTerminal(error)) return;
616
+ pollError = error instanceof Error ? error : new Error(String(error));
617
+ finishedCount += 1;
618
+ rejectIfBothFailed();
619
+ });
620
+ });
621
+ }
622
+ async function waitForSubscribedTxEvent({ txHash, fetchTx, subscription }) {
623
+ const eventTx = await subscription.wait();
624
+ if (eventTx.code !== 0) throw new TransactionException(new Error(eventTx.rawLog), {
625
+ contextCode: eventTx.code,
626
+ contextModule: eventTx.codespace
627
+ });
628
+ return fetchTx(txHash);
629
+ }
630
+
260
631
  //#endregion
261
632
  //#region src/core/tx/api/TxGrpcApi.ts
262
633
  var TxGrpcApi = class extends BaseGrpcConsumer {
@@ -296,15 +667,19 @@ var TxGrpcApi = class extends BaseGrpcConsumer {
296
667
  });
297
668
  }
298
669
  }
299
- async fetchTxPoll(txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS) {
670
+ async fetchTxPoll({ txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS, abortSignal }) {
300
671
  const deadline = Date.now() + timeout;
301
672
  for (let start = Date.now(); start < deadline; start = Date.now()) {
673
+ this.throwIfTxPollingCancelled(abortSignal);
302
674
  try {
303
- const tx = await this.fetchTxDual(txHash, deadline);
675
+ const tx = await this.fetchTxDual(txHash, deadline, abortSignal);
676
+ this.throwIfTxPollingCancelled(abortSignal);
304
677
  if (tx) return tx;
305
678
  } catch (e) {
679
+ this.throwIfTxPollingCancelled(abortSignal);
306
680
  if (e instanceof TransactionException) throw e;
307
681
  }
682
+ this.throwIfTxPollingCancelled(abortSignal);
308
683
  const gap = DEFAULT_TX_POLL_INTERVAL_MS - (Date.now() - start);
309
684
  if (gap > 0) await sleep(gap);
310
685
  }
@@ -313,20 +688,46 @@ var TxGrpcApi = class extends BaseGrpcConsumer {
313
688
  contextModule: "fetch-tx-poll"
314
689
  });
315
690
  }
316
- async safeFetchTx(txHash, delay) {
691
+ async waitForTxInclusion(txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS, options) {
692
+ const txResponse = await (await this.prepareTxInclusionWait(txHash, timeout, options)).wait();
693
+ if (!txResponse) throw new GrpcUnaryRequestException(/* @__PURE__ */ new Error(`The transaction with ${txHash} is not found`), {
694
+ context: "TxGrpcApi",
695
+ contextModule: "wait-for-tx-inclusion"
696
+ });
697
+ return txResponse;
698
+ }
699
+ async prepareTxInclusionWait(txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS, options) {
700
+ return prepareTxInclusionWaiter({
701
+ txHash,
702
+ timeout,
703
+ options,
704
+ fetchTx: (includedTxHash) => this.fetchTx(includedTxHash),
705
+ fetchTxPoll: (args) => this.fetchTxPoll(args),
706
+ createRequestException: (error, contextModule) => new GrpcUnaryRequestException(error, {
707
+ context: "TxGrpcApi",
708
+ contextModule
709
+ })
710
+ });
711
+ }
712
+ async safeFetchTx(txHash, delay, abortSignal) {
317
713
  if (delay) await sleep(delay);
714
+ this.throwIfTxPollingCancelled(abortSignal);
318
715
  return this.fetchTx(txHash).catch((e) => {
319
716
  if (e instanceof TransactionException) throw e;
320
717
  return null;
321
718
  });
322
719
  }
323
- fetchTxDual(txHash, deadline) {
720
+ fetchTxDual(txHash, deadline, abortSignal) {
324
721
  const STAGGER = 300;
325
722
  const timeout = Math.max(0, Math.min(DEFAULT_TX_POLL_CALL_TIMEOUT_MS, deadline - Date.now()));
326
- const fetches = Promise.all([this.safeFetchTx(txHash), this.safeFetchTx(txHash, STAGGER)]).then(([a, b]) => a !== null && a !== void 0 ? a : b);
723
+ const fetches = Promise.all([this.safeFetchTx(txHash, void 0, abortSignal), this.safeFetchTx(txHash, STAGGER, abortSignal)]).then(([a, b]) => a !== null && a !== void 0 ? a : b);
327
724
  fetches.catch(() => {});
328
725
  return Promise.race([fetches, sleep(timeout).then(() => null)]);
329
726
  }
727
+ throwIfTxPollingCancelled(abortSignal) {
728
+ if (!(abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted)) return;
729
+ throw new Error("Transaction inclusion polling was cancelled");
730
+ }
330
731
  async simulate(txRaw) {
331
732
  const txRawClone = CosmosTxV1Beta1TxPb.TxRaw.create({ ...txRaw });
332
733
  const simulateRequest = CosmosTxV1Beta1ServicePb.SimulateRequest.create();
@@ -356,12 +757,15 @@ var TxGrpcApi = class extends BaseGrpcConsumer {
356
757
  }
357
758
  }
358
759
  async broadcast(txRaw, options) {
359
- const mode = (options === null || options === void 0 ? void 0 : options.mode) || CosmosTxV1Beta1ServicePb.BroadcastMode.SYNC;
360
760
  const timeout = (options === null || options === void 0 ? void 0 : options.timeout) || toBigNumber((options === null || options === void 0 ? void 0 : options.txTimeout) || DEFAULT_BLOCK_TIMEOUT_HEIGHT).times(DEFAULT_BLOCK_TIME_IN_SECONDS * 1e3).toNumber();
361
- const broadcastTxRequest = CosmosTxV1Beta1ServicePb.BroadcastTxRequest.create();
362
- broadcastTxRequest.txBytes = CosmosTxV1Beta1TxPb.TxRaw.toBinary(txRaw);
363
- broadcastTxRequest.mode = mode;
761
+ const txHash = TxClient.hash(txRaw);
762
+ let inclusionWaiter;
364
763
  try {
764
+ inclusionWaiter = await this.prepareTxInclusionWait(txHash, timeout, options);
765
+ const mode = (options === null || options === void 0 ? void 0 : options.mode) || (inclusionWaiter.inclusionStrategy !== TxInclusionStrategy.Poll ? CosmosTxV1Beta1ServicePb.BroadcastMode.ASYNC : CosmosTxV1Beta1ServicePb.BroadcastMode.SYNC);
766
+ const broadcastTxRequest = CosmosTxV1Beta1ServicePb.BroadcastTxRequest.create();
767
+ broadcastTxRequest.txBytes = CosmosTxV1Beta1TxPb.TxRaw.toBinary(txRaw);
768
+ broadcastTxRequest.mode = mode;
365
769
  const txResponse = (await this.executeGrpcCall(broadcastTxRequest, this.client.broadcastTx.bind(this.client))).txResponse;
366
770
  if (!txResponse) throw new GrpcUnaryRequestException(/* @__PURE__ */ new Error(`The transaction has failed to be broadcasted`), {
367
771
  context: "TxGrpcApi.broadcast",
@@ -372,8 +776,14 @@ var TxGrpcApi = class extends BaseGrpcConsumer {
372
776
  contextModule: txResponse.codespace
373
777
  });
374
778
  if (options === null || options === void 0 ? void 0 : options.onBroadcast) options.onBroadcast(txResponse.txhash);
375
- return await this.fetchTxPoll(txResponse.txhash, timeout);
779
+ const result = await inclusionWaiter.wait(txResponse.txhash);
780
+ if (!result) throw new GrpcUnaryRequestException(/* @__PURE__ */ new Error(`The transaction with ${txResponse.txhash} is not found`), {
781
+ context: "TxGrpcApi.broadcast",
782
+ contextModule: "wait-for-tx-inclusion"
783
+ });
784
+ return result;
376
785
  } catch (e) {
786
+ inclusionWaiter === null || inclusionWaiter === void 0 || inclusionWaiter.close();
377
787
  if (e instanceof TransactionException) throw e;
378
788
  if (e instanceof GrpcUnaryRequestException) throw e;
379
789
  throw new TransactionException(new Error(e));
@@ -460,16 +870,19 @@ var TxRestApi = class {
460
870
  });
461
871
  }
462
872
  }
463
- async fetchTxPoll(txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS) {
873
+ async fetchTxPoll({ txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS, abortSignal }) {
464
874
  const deadline = Date.now() + timeout;
465
875
  for (let start = Date.now(); start < deadline; start = Date.now()) {
876
+ this.throwIfTxPollingCancelled(abortSignal);
466
877
  const callTimeout = Math.max(0, Math.min(DEFAULT_TX_POLL_CALL_TIMEOUT_MS, deadline - Date.now()));
467
878
  try {
468
879
  const txResponse = await Promise.race([this.fetchTx(txHash), sleep(callTimeout).then(() => null)]);
469
880
  if (txResponse) return txResponse;
470
881
  } catch (e) {
882
+ this.throwIfTxPollingCancelled(abortSignal);
471
883
  if (e instanceof TransactionException) throw e;
472
884
  }
885
+ this.throwIfTxPollingCancelled(abortSignal);
473
886
  const remaining = DEFAULT_TX_POLL_INTERVAL_MS - (Date.now() - start);
474
887
  if (remaining > 0) await sleep(remaining);
475
888
  }
@@ -478,6 +891,31 @@ var TxRestApi = class {
478
891
  contextModule: "TxRestApi.fetch-tx-poll"
479
892
  });
480
893
  }
894
+ throwIfTxPollingCancelled(abortSignal) {
895
+ if (!(abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted)) return;
896
+ throw new Error("Transaction inclusion polling was cancelled");
897
+ }
898
+ async waitForTxInclusion(txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS, options) {
899
+ const txResponse = await (await this.prepareTxInclusionWait(txHash, timeout, options)).wait();
900
+ if (!txResponse) throw new HttpRequestException(/* @__PURE__ */ new Error(`The transaction with ${txHash} is not found`), {
901
+ context: "TxRestApi",
902
+ contextModule: "wait-for-tx-inclusion"
903
+ });
904
+ return txResponse;
905
+ }
906
+ async prepareTxInclusionWait(txHash, timeout = DEFAULT_TX_BLOCK_INCLUSION_TIMEOUT_IN_MS, options) {
907
+ return prepareTxInclusionWaiter({
908
+ txHash,
909
+ timeout,
910
+ options,
911
+ fetchTx: (includedTxHash) => this.fetchTx(includedTxHash),
912
+ fetchTxPoll: (args) => this.fetchTxPoll(args),
913
+ createRequestException: (error, contextModule) => new HttpRequestException(error, {
914
+ context: "TxRestApi",
915
+ contextModule
916
+ })
917
+ });
918
+ }
481
919
  async simulate(txRaw) {
482
920
  const txRawClone = CosmosTxV1Beta1TxPb.TxRaw.create({ ...txRaw });
483
921
  if (txRawClone.signatures.length === 0) txRawClone.signatures = [new Uint8Array(0)];
@@ -500,8 +938,11 @@ var TxRestApi = class {
500
938
  }
501
939
  async broadcast(txRaw, options) {
502
940
  const timeout = (options === null || options === void 0 ? void 0 : options.timeout) || toBigNumber((options === null || options === void 0 ? void 0 : options.txTimeout) || DEFAULT_BLOCK_TIMEOUT_HEIGHT).times(DEFAULT_BLOCK_TIME_IN_SECONDS * 1e3).toNumber();
941
+ const txHash = TxClient.hash(txRaw);
942
+ let inclusionWaiter;
503
943
  try {
504
- const { tx_response: txResponse } = await this.broadcastTx(txRaw, BroadcastMode.Sync);
944
+ inclusionWaiter = await this.prepareTxInclusionWait(txHash, timeout, options);
945
+ const { tx_response: txResponse } = await this.broadcastTx(txRaw, inclusionWaiter.inclusionStrategy !== TxInclusionStrategy.Poll ? BroadcastMode.Async : BroadcastMode.Sync);
505
946
  if (!txResponse) throw new HttpRequestException(/* @__PURE__ */ new Error("The transaction has failed to be broadcasted"), {
506
947
  context: "TxRestApi.broadcast",
507
948
  contextModule: "broadcast"
@@ -511,8 +952,14 @@ var TxRestApi = class {
511
952
  contextModule: txResponse.codespace
512
953
  });
513
954
  if (options === null || options === void 0 ? void 0 : options.onBroadcast) options.onBroadcast(txResponse.txhash);
514
- return await this.fetchTxPoll(txResponse.txhash, timeout);
955
+ const result = await inclusionWaiter.wait(txResponse.txhash);
956
+ if (!result) throw new HttpRequestException(/* @__PURE__ */ new Error(`The transaction with ${txResponse.txhash} is not found`), {
957
+ context: "TxRestApi.broadcast",
958
+ contextModule: "wait-for-tx-inclusion"
959
+ });
960
+ return result;
515
961
  } catch (e) {
962
+ inclusionWaiter === null || inclusionWaiter === void 0 || inclusionWaiter.close();
516
963
  if (e instanceof HttpRequestException) {
517
964
  if (e.code !== StatusCodes.OK) throw e;
518
965
  }
@@ -605,7 +1052,13 @@ var TxRestApi = class {
605
1052
  //#region src/core/tx/api/utils.ts
606
1053
  const waitTxBroadcasted = (txHash, options) => {
607
1054
  const timeout = toBigNumber((options === null || options === void 0 ? void 0 : options.txTimeout) || DEFAULT_BLOCK_TIMEOUT_HEIGHT).times(DEFAULT_BLOCK_TIME_IN_SECONDS * 1e3).toNumber();
608
- return options.endpoints.grpc ? new TxGrpcApi(options.endpoints.grpc).fetchTxPoll(txHash, timeout) : new TxRestApi(options.endpoints.rest).fetchTxPoll(txHash, timeout);
1055
+ return options.endpoints.grpc ? new TxGrpcApi(options.endpoints.grpc).fetchTxPoll({
1056
+ txHash,
1057
+ timeout
1058
+ }) : new TxRestApi(options.endpoints.rest).fetchTxPoll({
1059
+ txHash,
1060
+ timeout
1061
+ });
609
1062
  };
610
1063
 
611
1064
  //#endregion
@@ -636,13 +1089,6 @@ const generateArbitrarySignDoc = (message, signer) => {
636
1089
  };
637
1090
  };
638
1091
 
639
- //#endregion
640
- //#region src/core/tx/types/tx.ts
641
- const TxClientMode = {
642
- gRpc: "grpc",
643
- rest: "rest"
644
- };
645
-
646
1092
  //#endregion
647
1093
  //#region src/core/tx/broadcaster/MsgBroadcasterWithPk.ts
648
1094
  /**
@@ -732,7 +1178,11 @@ var MsgBroadcasterWithPk = class {
732
1178
  chainId: evmChainId,
733
1179
  signature: `0x${uint8ArrayToHex(signature)}`
734
1180
  });
735
- return await new TxGrpcApi(endpoints.grpc).fetchTxPoll(response.txHash);
1181
+ const timeoutInMs = toBigNumber(txTimeout).times(DEFAULT_BLOCK_TIME_IN_SECONDS).times(1e3).toNumber();
1182
+ return await new TxGrpcApi(endpoints.grpc).fetchTxPoll({
1183
+ txHash: response.txHash,
1184
+ timeout: timeoutInMs
1185
+ });
736
1186
  }
737
1187
  /**
738
1188
  * Broadcasting the transaction using the client
@@ -887,4 +1337,4 @@ var MsgBroadcasterWithPk = class {
887
1337
  };
888
1338
 
889
1339
  //#endregion
890
- export { errorToErrorMessage as C, SIGN_EIP712_V2 as S, CosmosTxV1Beta1TxPb as _, TxRestApi as a, SIGN_DIRECT as b, TxGrpcApi as c, createTransactionAndCosmosSignDocForAddressAndMsg as d, createTransactionForAddressAndMsg as f, getTxRawFromTxRawOrDirectSignResponse as g, createTxRawFromSigResponse as h, waitTxBroadcasted as i, createTransaction as l, createTransactionWithSigners as m, TxClientMode as n, BroadcastMode as o, createTransactionFromMsg as p, generateArbitrarySignDoc as r, BroadcastModeKeplr as s, MsgBroadcasterWithPk as t, createTransactionAndCosmosSignDoc as u, TxClient as v, isTxNotFoundError as w, SIGN_EIP712 as x, SIGN_AMINO as y };
1340
+ export { SIGN_DIRECT as C, isTxNotFoundError as D, errorToErrorMessage as E, SIGN_AMINO as S, SIGN_EIP712_V2 as T, createTransactionWithSigners as _, BroadcastMode as a, CosmosTxV1Beta1TxPb as b, normalizeTendermintWebSocketEndpoint as c, TxInclusionStrategy as d, createTransaction as f, createTransactionFromMsg as g, createTransactionForAddressAndMsg as h, TxRestApi as i, subscribeToTendermintTxEvent as l, createTransactionAndCosmosSignDocForAddressAndMsg as m, generateArbitrarySignDoc as n, BroadcastModeKeplr as o, createTransactionAndCosmosSignDoc as p, waitTxBroadcasted as r, TxGrpcApi as s, MsgBroadcasterWithPk as t, TxClientMode as u, createTxRawFromSigResponse as v, SIGN_EIP712 as w, TxClient as x, getTxRawFromTxRawOrDirectSignResponse as y };
@@ -1,6 +1,6 @@
1
1
  import "./tx_pb-DG9OU_HE.js";
2
2
  import "./index-DJtcTm1W.js";
3
- import { $d as denomAmountFromGrpcChainDenomAmount, $f as TypedMessageV4, Ad as toBase64, Af as spotQuantityFromChainQuantity, Bd as getInjectiveAddress, Bf as isBrowser, Cd as concatUint8Arrays, Cf as getTensMultiplier, Dd as hexToBuff, Df as spotPriceFromChainPriceToFixed, Ed as hexToBase64, Ef as spotPriceFromChainPrice, Fd as addHexPrefix, Ff as bigIntToNumber, Gd as getDerivativeMarketDecimals, Gf as objectToJson, Hd as getSubaccountId, Hf as isNode, Id as getAddressFromInjectiveAddress, If as bigIntToString, Jd as getSpotMarketTensMultiplier, Jf as sortObjectByKeys, Kd as getDerivativeMarketTensMultiplier, Kf as protoObjectToJson, Ld as getChecksumAddress, Lf as getErrorMessage, Md as uint8ArrayToBase64, Mf as spotQuantityToChainQuantity, Mx as GrpcWebFetchTransport, Nd as uint8ArrayToHex, Nf as spotQuantityToChainQuantityToFixed, Od as hexToUint8Array, Of as spotPriceToChainPrice, Pd as uint8ArrayToString, Pf as bigIntReplacer, Qd as denomAmountFromChainDenomAmountToFixed, Qf as TypedDataUtilsSanitizeData, Rd as getDefaultSubaccountId, Rf as grpcCoinToUiCoin, Sd as binaryToBase64, Sf as getSignificantDecimalsFromNumber, Td as fromUtf8, Tf as numberToCosmosSdkDecString, Ud as isCw20ContractAddress, Uf as isReactNative, Vd as getInjectiveAddressFromSubaccountId, Vf as isJsonString, Wd as removeHexPrefix, Wf as isServerSide, Xd as cosmosSdkDecToBigNumber, Xf as SignTypedDataVersionV4, Yd as amountToCosmosSdkDecAmount, Yf as sortObjectByKeysWithReduce, Zd as denomAmountFromChainDenomAmount, Zf as TypedDataUtilsHashStruct, _d as BECH32_PUBKEY_CONS_PREFIX, _f as formatNumberToAllowableDecimals, _p as makeTimeoutTimestampInNs, ad as recoverTypedSignaturePubKey, af as derivativeMarginToChainMargin, ap as privateKeyHashToPublicKeyBase64, bd as base64ToUint8Array, bf as formatPriceToAllowablePrice, bp as protobufTimestampToUnixSeconds, cd as grpcPagingToPaging, cf as derivativePriceFromChainPriceToFixed, cp as publicKeyToAddress, dd as paginationRequestFromPagination, df as derivativeQuantityFromChainQuantity, dp as sha256, ef as denomAmountToChainDenomAmount, ep as decompressPubKey, fd as paginationUint8ArrayToString, ff as derivativeQuantityFromChainQuantityToFixed, fp as parseCoins, gd as BECH32_PUBKEY_ACC_PREFIX, gf as formatAmountToAllowableDecimals, gp as makeTimeoutTimestamp, hd as BECH32_ADDR_VAL_PREFIX, hf as formatAmountToAllowableAmount, hp as getGasPriceBasedOnMessage, if as derivativeMarginFromChainMarginToFixed, ip as privateKeyHashToPublicKey, jd as toUtf8, jf as spotQuantityFromChainQuantityToFixed, kd as stringToUint8Array, kf as spotPriceToChainPriceToFixed, ld as grpcPagingToPagingV2, lf as derivativePriceToChainPrice, lp as ripemd160, md as BECH32_ADDR_CONS_PREFIX, mf as derivativeQuantityToChainQuantityToFixed, mp as getGrpcWebTransport, nf as denomAmountToGrpcChainDenomAmount, np as hashToHex, od as fetchAllWithPagination, of as derivativeMarginToChainMarginToFixed, op as privateKeyToPublicKey, pd as BECH32_ADDR_ACC_PREFIX, pf as derivativeQuantityToChainQuantity, pp as ofacList, qd as getSpotMarketDecimals, qf as safeBigIntStringify, rf as derivativeMarginFromChainMargin, rp as messageHash, sd as grpcPaginationToPagination, sf as derivativePriceFromChainPrice, sp as privateKeyToPublicKeyBase64, tf as denomAmountToChainDenomAmountToFixed, tp as domainHash, ud as pageRequestToGrpcPageRequestV2, uf as derivativePriceToChainPriceToFixed, up as sanitizeTypedData, vd as BECH32_PUBKEY_VAL_PREFIX, vf as formatNumberToAllowableTensMultiplier, vp as protobufTimestampToDate, wd as fromBase64, wf as isNumber, xd as base64ToUtf8, xf as getExactDecimalsFromNumber, yd as DEFAULT_DERIVATION_PATH, yf as formatPriceToAllowableDecimals, yp as protobufTimestampToUnixMs, zd as getEthereumAddress, zf as hexToNumber } from "./index-65Emc5ml.js";
3
+ import { $d as cosmosSdkDecToBigNumber, $f as SignTypedDataVersionV4, Ad as hexToBuff, Af as spotPriceFromChainPriceToFixed, Bd as getChecksumAddress, Bf as getErrorMessage, Cd as base64ToUint8Array, Cf as formatPriceToAllowablePrice, Cp as protobufTimestampToUnixSeconds, Dd as fromBase64, Df as isNumber, Ed as concatUint8Arrays, Ef as getTensMultiplier, Fd as uint8ArrayToBase64, Ff as spotQuantityToChainQuantity, Gd as getSubaccountId, Gf as isNode, Hd as getEthereumAddress, Hf as hexToNumber, Id as uint8ArrayToHex, If as spotQuantityToChainQuantityToFixed, Jd as getDerivativeMarketDecimals, Jf as objectToJson, Kd as isCw20ContractAddress, Kf as isReactNative, Ld as uint8ArrayToString, Lf as bigIntReplacer, Md as stringToUint8Array, Mf as spotPriceToChainPriceToFixed, Nd as toBase64, Nf as spotQuantityFromChainQuantity, Od as fromUtf8, Of as numberToCosmosSdkDecString, Pd as toUtf8, Pf as spotQuantityFromChainQuantityToFixed, Qd as amountToCosmosSdkDecAmount, Qf as sortObjectByKeysWithReduce, Rd as addHexPrefix, Rf as bigIntToNumber, Sd as DEFAULT_DERIVATION_PATH, Sf as formatPriceToAllowableDecimals, Sp as protobufTimestampToUnixMs, Td as binaryToBase64, Tf as getSignificantDecimalsFromNumber, Ud as getInjectiveAddress, Uf as isBrowser, Ux as GrpcWebFetchTransport, Vd as getDefaultSubaccountId, Vf as grpcCoinToUiCoin, Wd as getInjectiveAddressFromSubaccountId, Wf as isJsonString, Xd as getSpotMarketDecimals, Xf as safeBigIntStringify, Yd as getDerivativeMarketTensMultiplier, Yf as protoObjectToJson, Zd as getSpotMarketTensMultiplier, Zf as sortObjectByKeys, _d as BECH32_ADDR_CONS_PREFIX, _f as derivativeQuantityToChainQuantityToFixed, _p as getGrpcWebTransport, af as denomAmountToGrpcChainDenomAmount, ap as hashToHex, bd as BECH32_PUBKEY_CONS_PREFIX, bf as formatNumberToAllowableDecimals, bp as makeTimeoutTimestampInNs, cd as recoverTypedSignaturePubKey, cf as derivativeMarginToChainMargin, cp as privateKeyHashToPublicKeyBase64, dd as grpcPagingToPaging, df as derivativePriceFromChainPriceToFixed, dp as publicKeyToAddress, ef as denomAmountFromChainDenomAmount, ep as TypedDataUtilsHashStruct, fd as grpcPagingToPagingV2, ff as derivativePriceToChainPrice, fp as ripemd160, gd as BECH32_ADDR_ACC_PREFIX, gf as derivativeQuantityToChainQuantity, gp as ofacList, hd as paginationUint8ArrayToString, hf as derivativeQuantityFromChainQuantityToFixed, hp as parseCoins, if as denomAmountToChainDenomAmountToFixed, ip as domainHash, jd as hexToUint8Array, jf as spotPriceToChainPrice, kd as hexToBase64, kf as spotPriceFromChainPrice, ld as fetchAllWithPagination, lf as derivativeMarginToChainMarginToFixed, lp as privateKeyToPublicKey, md as paginationRequestFromPagination, mf as derivativeQuantityFromChainQuantity, mp as sha256, nf as denomAmountFromGrpcChainDenomAmount, np as TypedMessageV4, of as derivativeMarginFromChainMargin, op as messageHash, pd as pageRequestToGrpcPageRequestV2, pf as derivativePriceToChainPriceToFixed, pp as sanitizeTypedData, qd as removeHexPrefix, qf as isServerSide, rf as denomAmountToChainDenomAmount, rp as decompressPubKey, sf as derivativeMarginFromChainMarginToFixed, sp as privateKeyHashToPublicKey, tf as denomAmountFromChainDenomAmountToFixed, tp as TypedDataUtilsSanitizeData, ud as grpcPaginationToPagination, uf as derivativePriceFromChainPrice, up as privateKeyToPublicKeyBase64, vd as BECH32_ADDR_VAL_PREFIX, vf as formatAmountToAllowableAmount, vp as getGasPriceBasedOnMessage, wd as base64ToUtf8, wf as getExactDecimalsFromNumber, xd as BECH32_PUBKEY_VAL_PREFIX, xf as formatNumberToAllowableTensMultiplier, xp as protobufTimestampToDate, yd as BECH32_PUBKEY_ACC_PREFIX, yf as formatAmountToAllowableDecimals, yp as makeTimeoutTimestamp, zd as getAddressFromInjectiveAddress, zf as bigIntToString } from "./index-C4ebvHUB.js";
4
4
  import "./BaseGrpcConsumer-BptQBj1l.js";
5
5
  import "./index-BSAdUyzU.js";
6
6
  import "./index-sT17wTBx.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@injectivelabs/sdk-ts",
3
- "version": "1.19.25",
3
+ "version": "1.19.27",
4
4
  "description": "SDK in TypeScript for building Injective applications in a browser, node, and react native environment.",
5
5
  "license": "Apache-2.0",
6
6
  "author": {
@@ -351,10 +351,10 @@
351
351
  "rxjs": "7.8.2",
352
352
  "snakecase-keys": "^5.4.1",
353
353
  "viem": "^2.41.2",
354
- "@injectivelabs/exceptions": "1.19.25",
355
- "@injectivelabs/ts-types": "1.19.25",
356
- "@injectivelabs/networks": "1.19.25",
357
- "@injectivelabs/utils": "1.19.25"
354
+ "@injectivelabs/exceptions": "1.19.27",
355
+ "@injectivelabs/networks": "1.19.27",
356
+ "@injectivelabs/ts-types": "1.19.27",
357
+ "@injectivelabs/utils": "1.19.27"
358
358
  },
359
359
  "publishConfig": {
360
360
  "access": "public"