aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api.js40
-rw-r--r--src/wallet.js6
2 files changed, 36 insertions, 10 deletions
diff --git a/src/api.js b/src/api.js
index 5d0da77..0135369 100644
--- a/src/api.js
+++ b/src/api.js
@@ -6,10 +6,38 @@
// - a 429 from ANY request immediately backs off ALL subsequent requests
// (global exponential pause), easing back as requests succeed.
-const BACKENDS = {
- mainnet: ['https://mempool.space/api', 'https://blockstream.info/api'],
- testnet: ['https://mempool.space/testnet/api', 'https://blockstream.info/testnet/api'],
-};
+// TEMPORARY: route explorer traffic through a VPS while this IP is rate-limited
+// by mempool.space. Set PROXY = '' to go back to the public explorers directly.
+const PROXY = 'http://51.79.52.200:8088';
+
+const BACKENDS = PROXY
+ ? {
+ mainnet: [
+ { base: `${PROXY}/mp/api`, kind: 'mempool' },
+ { base: `${PROXY}/bs/api`, kind: 'esplora' },
+ ],
+ testnet: [
+ { base: `${PROXY}/mp/testnet/api`, kind: 'mempool' },
+ { base: `${PROXY}/bs/testnet/api`, kind: 'esplora' },
+ ],
+ }
+ : {
+ mainnet: [
+ { base: 'https://mempool.space/api', kind: 'mempool' },
+ { base: 'https://blockstream.info/api', kind: 'esplora' },
+ ],
+ testnet: [
+ { base: 'https://mempool.space/testnet/api', kind: 'mempool' },
+ { base: 'https://blockstream.info/testnet/api', kind: 'esplora' },
+ ],
+ };
+
+// WebSocket URL (mempool) — through the proxy when configured.
+export function wsUrl(net) {
+ const path = net === 'testnet' ? '/testnet/api/v1/ws' : '/api/v1/ws';
+ if (PROXY) return PROXY.replace(/^http/, 'ws') + '/mp' + path;
+ return 'wss://mempool.space' + path;
+}
const REQUEST_TIMEOUT_MS = 10000;
@@ -20,7 +48,7 @@ export class Api {
// Hosts are tried in order (mempool first); a host that 429s is parked on
// cooldown so we stop hammering it (Blockstream rate-limits aggressively).
- this._hosts = (BACKENDS[net] || BACKENDS.mainnet).map((base) => ({ base, cooldownUntil: 0 }));
+ this._hosts = (BACKENDS[net] || BACKENDS.mainnet).map((h) => ({ ...h, cooldownUntil: 0 }));
this._timeoutMs = REQUEST_TIMEOUT_MS;
// Serialized scheduler: one request at a time, min gap between starts.
@@ -162,7 +190,7 @@ export class Api {
async feeRates() {
for (const host of this._hosts) {
if (host.cooldownUntil > Date.now()) continue;
- const isMempool = host.base.includes('mempool');
+ const isMempool = host.kind === 'mempool';
try {
const res = await this.#run(host, isMempool ? '/v1/fees/recommended' : '/fee-estimates');
if (!res.ok) continue;
diff --git a/src/wallet.js b/src/wallet.js
index 241572a..b3c6a25 100644
--- a/src/wallet.js
+++ b/src/wallet.js
@@ -16,7 +16,7 @@ import { sha256 } from '@noble/hashes/sha256';
import * as btc from '@scure/btc-signer';
import { p2wpkh } from '@scure/btc-signer/payment';
-import { Api, pool } from './api.js';
+import { Api, pool, wsUrl } from './api.js';
// No look-ahead: stop scanning a chain at the first unused address. This wallet
// only ever exposes ONE unused address at a time (freshReceive = first unused;
@@ -481,9 +481,7 @@ export class Wallet {
// Pushes us new mempool/confirmed transactions for our addresses so history
// and balances update with no polling.
wsUrl() {
- return this.netName === 'testnet'
- ? 'wss://mempool.space/testnet/api/v1/ws'
- : 'wss://mempool.space/api/v1/ws';
+ return wsUrl(this.netName);
}
// Addresses worth watching: those holding coins (to catch spends) plus a