@stellar/typescript-wallet-sdk 3.0.0-beta.1779920488639 → 3.0.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.
@@ -44,11 +44,22 @@ export declare class Stellar {
44
44
  */
45
45
  makeFeeBump({ feeAddress, transaction, baseFee, }: FeeBumpTransactionParams): FeeBumpTransaction;
46
46
  /**
47
- * Submits a signed transaction to the server. If the submission fails with status
48
- * 504 indicating a timeout error, it will automatically retry.
47
+ * Submits a signed transaction to Horizon.
48
+ *
49
+ * On HTTP 504 (timeout), retries with exponential backoff up to
50
+ * {@link SUBMIT_504_MAX_RETRIES} times. Any non-504 error is rethrown
51
+ * immediately without retrying.
52
+ *
49
53
  * @param {Transaction|FeeBumpTransaction} signedTransaction - The signed transaction to submit.
50
- * @returns {boolean} `true` if the transaction was successfully submitted.
51
- * @throws {TransactionSubmitFailedError} If the transaction submission fails.
54
+ * @returns {boolean} `true` if Horizon confirmed the submission as successful.
55
+ * @throws {TransactionSubmitFailedError} If Horizon responded with a non-successful
56
+ * submission result (the transaction reached Horizon but was rejected).
57
+ * @throws The underlying 504 error if every retry attempt timed out. In this
58
+ * case the transaction's on-chain status is **indeterminate** — Horizon may
59
+ * have ingested it on the final attempt without responding in time. Callers
60
+ * should poll the transaction hash to determine the actual outcome rather
61
+ * than resubmit blindly; resubmitting a signed transaction with the same
62
+ * sequence number will fail with `tx_bad_seq` once the original lands.
52
63
  */
53
64
  submitTransaction(signedTransaction: Transaction | FeeBumpTransaction): Promise<boolean>;
54
65
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stellar/typescript-wallet-sdk",
3
- "version": "3.0.0-beta.1779920488639",
3
+ "version": "3.0.1",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },
@@ -75,4 +75,4 @@
75
75
  "example:sep24": "ts-node examples/sep24/sep24.ts",
76
76
  "example:sep12": "ts-node examples/sep12/sep12.ts"
77
77
  }
78
- }
78
+ }
@@ -125,11 +125,22 @@ export class Stellar {
125
125
  }
126
126
 
127
127
  /**
128
- * Submits a signed transaction to the server. If the submission fails with status
129
- * 504 indicating a timeout error, it will automatically retry.
128
+ * Submits a signed transaction to Horizon.
129
+ *
130
+ * On HTTP 504 (timeout), retries with exponential backoff up to
131
+ * {@link SUBMIT_504_MAX_RETRIES} times. Any non-504 error is rethrown
132
+ * immediately without retrying.
133
+ *
130
134
  * @param {Transaction|FeeBumpTransaction} signedTransaction - The signed transaction to submit.
131
- * @returns {boolean} `true` if the transaction was successfully submitted.
132
- * @throws {TransactionSubmitFailedError} If the transaction submission fails.
135
+ * @returns {boolean} `true` if Horizon confirmed the submission as successful.
136
+ * @throws {TransactionSubmitFailedError} If Horizon responded with a non-successful
137
+ * submission result (the transaction reached Horizon but was rejected).
138
+ * @throws The underlying 504 error if every retry attempt timed out. In this
139
+ * case the transaction's on-chain status is **indeterminate** — Horizon may
140
+ * have ingested it on the final attempt without responding in time. Callers
141
+ * should poll the transaction hash to determine the actual outcome rather
142
+ * than resubmit blindly; resubmitting a signed transaction with the same
143
+ * sequence number will fail with `tx_bad_seq` once the original lands.
133
144
  */
134
145
  async submitTransaction(
135
146
  signedTransaction: Transaction | FeeBumpTransaction,
@@ -152,12 +163,17 @@ export class Stellar {
152
163
  }
153
164
  // https://developers.stellar.org/api/errors/http-status-codes/horizon-specific/timeout
154
165
  // https://developers.stellar.org/docs/encyclopedia/error-handling#timeouts
166
+ // Equal-jitter backoff: each attempt waits at least half the capped
167
+ // exponential delay (a deterministic, progressive floor) plus a random
168
+ // amount up to the other half. Keeps the schedule predictable while
169
+ // smoothing correlated retries across many clients during a Horizon
170
+ // outage. Total sleep stays within SUBMIT_504_MAX_DELAY_MS.
155
171
  const cappedDelay = Math.min(
156
172
  SUBMIT_504_BASE_DELAY_MS * 2 ** attempt,
157
173
  SUBMIT_504_MAX_DELAY_MS,
158
174
  );
159
- const jitter = Math.random() * (cappedDelay / 2);
160
- await sleep(cappedDelay + jitter);
175
+ const half = cappedDelay / 2;
176
+ await sleep(half + Math.random() * half);
161
177
  }
162
178
  }
163
179
  throw lastError;
@@ -218,7 +234,7 @@ export class Stellar {
218
234
  if (resultCode === "tx_too_late") {
219
235
  const newFee = parseInt(transaction.fee) + baseFeeIncrease;
220
236
 
221
- if (maxFee !== undefined && newFee > maxFee) {
237
+ if (maxFee && newFee > maxFee) {
222
238
  throw new TransactionSubmitWithFeeIncreaseFailedError(maxFee, e);
223
239
  }
224
240
 
@@ -282,8 +282,9 @@ describe("Stellar", () => {
282
282
  const tx = {} as Transaction;
283
283
  const promise = stellar.submitTransaction(tx);
284
284
 
285
- // First retry waits SUBMIT_504_BASE_DELAY_MS = 1000ms (jitter stubbed to 0).
286
- await clock.tickAsync(1000);
285
+ // Equal-jitter sleep at attempt 0 with Math.random stubbed to 0 is
286
+ // cappedDelay/2 = 1000/2 = 500ms.
287
+ await clock.tickAsync(500);
287
288
 
288
289
  await expect(promise).resolves.toBe(true);
289
290
  expect(serverStub).toHaveBeenCalledTimes(2);
@@ -311,9 +312,9 @@ describe("Stellar", () => {
311
312
  // the test runner mid-tick.
312
313
  promise.catch(() => undefined);
313
314
 
314
- // Sum of capped exponential delays with zero jitter:
315
- // 1000 + 2000 + 4000 + 8000 + 16000 = 31000ms.
316
- await clock.tickAsync(31000);
315
+ // Sum of equal-jitter sleeps (cappedDelay/2) with Math.random stubbed
316
+ // to 0: 500 + 1000 + 2000 + 4000 + 8000 = 15500ms.
317
+ await clock.tickAsync(15500);
317
318
 
318
319
  await expect(promise).rejects.toMatchObject({
319
320
  response: { status: 504 },