aboutsummaryrefslogtreecommitdiffstats
path: root/src/api.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-15 13:17:26 -0700
committerAdam Soltys <[email protected]>2026-06-15 13:17:26 -0700
commit3dd7f8425ecf339332cc44b6f9734b51472d22c1 (patch)
treee7eadb18256f0436c9aab671ded66acd0da7d713 /src/api.js
parent3ecb137cc4300e60f00fbb575441f34e01839a8e (diff)
downloadcoinosv3-3dd7f8425ecf339332cc44b6f9734b51472d22c1.tar.gz
coinosv3-3dd7f8425ecf339332cc44b6f9734b51472d22c1.zip
Broadcast sends to all explorers in parallel
Post the signed tx to both mempool.space and Blockstream at once (outside the throttle, since a send is urgent) so it's visible regardless of which explorer the recipient watches. Succeeds if any accept; only fails if all do. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src/api.js')
-rw-r--r--src/api.js30
1 files changed, 15 insertions, 15 deletions
diff --git a/src/api.js b/src/api.js
index 8ceb870..1c70640 100644
--- a/src/api.js
+++ b/src/api.js
@@ -147,22 +147,22 @@ export class Api {
return { fastestFee: 20, halfHourFee: 10, hourFee: 5, economyFee: 2, minimumFee: 1 };
}
+ // Broadcast to ALL explorers in parallel (not via the throttle — a send is
+ // urgent) so the tx is visible regardless of which explorer the recipient
+ // watches. Resolves with the txid if any accept it; rejects only if all fail.
async broadcast(hexTx) {
- let lastErr;
- for (const base of this._hosts) {
- try {
- const res = await this.#run(base + '/tx', { method: 'POST', body: hexTx });
- const body = await res.text();
- if (!res.ok) {
- lastErr = new Error(body || `${res.status} broadcast failed`);
- continue;
- }
- return body.trim(); // txid
- } catch (e) {
- lastErr = e;
- }
- }
- throw lastErr;
+ if (this.offline) throw new Error('offline');
+ const attempts = this._hosts.map(async (base) => {
+ const res = await fetch(base + '/tx', { method: 'POST', body: hexTx });
+ const body = await res.text();
+ if (res.status === 429) this.#penalize();
+ if (!res.ok) throw new Error(body || `${res.status} broadcast failed`);
+ return body.trim(); // txid
+ });
+ const results = await Promise.allSettled(attempts);
+ const ok = results.find((r) => r.status === 'fulfilled');
+ if (ok) return ok.value;
+ throw (results.find((r) => r.status === 'rejected') || {}).reason || new Error('broadcast failed');
}
}