@ironwallet/mcp-server 1.0.0-preprod.0

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 (110) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/assets/knight.png +0 -0
  4. package/assets/wordmark.svg +20 -0
  5. package/dist/api/auth.d.ts +20 -0
  6. package/dist/api/auth.js +92 -0
  7. package/dist/api/auth.js.map +1 -0
  8. package/dist/api/balances.d.ts +25 -0
  9. package/dist/api/balances.js +565 -0
  10. package/dist/api/balances.js.map +1 -0
  11. package/dist/api/http.d.ts +34 -0
  12. package/dist/api/http.js +277 -0
  13. package/dist/api/http.js.map +1 -0
  14. package/dist/api/relay.d.ts +49 -0
  15. package/dist/api/relay.js +194 -0
  16. package/dist/api/relay.js.map +1 -0
  17. package/dist/api/rpc.d.ts +10 -0
  18. package/dist/api/rpc.js +26 -0
  19. package/dist/api/rpc.js.map +1 -0
  20. package/dist/api/swap.d.ts +134 -0
  21. package/dist/api/swap.js +554 -0
  22. package/dist/api/swap.js.map +1 -0
  23. package/dist/cli.d.ts +6 -0
  24. package/dist/cli.js +20 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/config.d.ts +91 -0
  27. package/dist/config.js +175 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/generated/env-config.d.ts +5 -0
  30. package/dist/generated/env-config.js +23 -0
  31. package/dist/generated/env-config.js.map +1 -0
  32. package/dist/generated/env-profile.d.ts +15 -0
  33. package/dist/generated/env-profile.js +2 -0
  34. package/dist/generated/env-profile.js.map +1 -0
  35. package/dist/keystore/crypto.d.ts +17 -0
  36. package/dist/keystore/crypto.js +57 -0
  37. package/dist/keystore/crypto.js.map +1 -0
  38. package/dist/keystore/store.d.ts +45 -0
  39. package/dist/keystore/store.js +224 -0
  40. package/dist/keystore/store.js.map +1 -0
  41. package/dist/keystore/types.d.ts +31 -0
  42. package/dist/keystore/types.js +2 -0
  43. package/dist/keystore/types.js.map +1 -0
  44. package/dist/local-secrets.d.ts +16 -0
  45. package/dist/local-secrets.js +73 -0
  46. package/dist/local-secrets.js.map +1 -0
  47. package/dist/log.d.ts +30 -0
  48. package/dist/log.js +323 -0
  49. package/dist/log.js.map +1 -0
  50. package/dist/passphrase.d.ts +6 -0
  51. package/dist/passphrase.js +10 -0
  52. package/dist/passphrase.js.map +1 -0
  53. package/dist/policy.d.ts +22 -0
  54. package/dist/policy.js +108 -0
  55. package/dist/policy.js.map +1 -0
  56. package/dist/server.d.ts +6 -0
  57. package/dist/server.js +38 -0
  58. package/dist/server.js.map +1 -0
  59. package/dist/signing/bitcoin.d.ts +18 -0
  60. package/dist/signing/bitcoin.js +84 -0
  61. package/dist/signing/bitcoin.js.map +1 -0
  62. package/dist/signing/dispatch.d.ts +7 -0
  63. package/dist/signing/dispatch.js +35 -0
  64. package/dist/signing/dispatch.js.map +1 -0
  65. package/dist/signing/evm.d.ts +16 -0
  66. package/dist/signing/evm.js +59 -0
  67. package/dist/signing/evm.js.map +1 -0
  68. package/dist/signing/index.d.ts +10 -0
  69. package/dist/signing/index.js +57 -0
  70. package/dist/signing/index.js.map +1 -0
  71. package/dist/signing/solana.d.ts +18 -0
  72. package/dist/signing/solana.js +106 -0
  73. package/dist/signing/solana.js.map +1 -0
  74. package/dist/signing/swap.d.ts +10 -0
  75. package/dist/signing/swap.js +114 -0
  76. package/dist/signing/swap.js.map +1 -0
  77. package/dist/signing/ton.d.ts +33 -0
  78. package/dist/signing/ton.js +166 -0
  79. package/dist/signing/ton.js.map +1 -0
  80. package/dist/signing/tron.d.ts +11 -0
  81. package/dist/signing/tron.js +39 -0
  82. package/dist/signing/tron.js.map +1 -0
  83. package/dist/signing/types.d.ts +23 -0
  84. package/dist/signing/types.js +2 -0
  85. package/dist/signing/types.js.map +1 -0
  86. package/dist/signing/xrp.d.ts +11 -0
  87. package/dist/signing/xrp.js +122 -0
  88. package/dist/signing/xrp.js.map +1 -0
  89. package/dist/tools/helpers.d.ts +42 -0
  90. package/dist/tools/helpers.js +80 -0
  91. package/dist/tools/helpers.js.map +1 -0
  92. package/dist/tools/index.d.ts +7 -0
  93. package/dist/tools/index.js +16 -0
  94. package/dist/tools/index.js.map +1 -0
  95. package/dist/tools/swap.d.ts +6 -0
  96. package/dist/tools/swap.js +343 -0
  97. package/dist/tools/swap.js.map +1 -0
  98. package/dist/tools/transfer.d.ts +6 -0
  99. package/dist/tools/transfer.js +284 -0
  100. package/dist/tools/transfer.js.map +1 -0
  101. package/dist/tools/wallets.d.ts +6 -0
  102. package/dist/tools/wallets.js +79 -0
  103. package/dist/tools/wallets.js.map +1 -0
  104. package/dist/wallet/derive.d.ts +53 -0
  105. package/dist/wallet/derive.js +233 -0
  106. package/dist/wallet/derive.js.map +1 -0
  107. package/dist/web/manager.d.ts +15 -0
  108. package/dist/web/manager.js +444 -0
  109. package/dist/web/manager.js.map +1 -0
  110. package/package.json +54 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Fetch helper with JSON handling, per-attempt timeouts and bounded retries.
3
+ *
4
+ * Timeouts: every attempt is aborted after `timeoutMs` (default from config).
5
+ * Retries: transient failures (network errors, timeouts, and retryable HTTP
6
+ * statuses like 429/5xx) are retried with exponential backoff + jitter, honoring
7
+ * a `Retry-After` header when present.
8
+ *
9
+ * Safety: retries default ON for idempotent methods (GET/HEAD) and OFF for others
10
+ * (a broadcast POST must never be silently resent). Callers can override this per
11
+ * request with `retry: true` for read-only POSTs (e.g. auth, Tron node reads).
12
+ *
13
+ * Every attempt is written to the JSONL file logger (see src/log.ts) with
14
+ * timings, status, retry decisions and undici cause chains — without secrets.
15
+ */
16
+ import { getConfig } from "../config.js";
17
+ import { errorDetails, logDebug, logError, logInfo, logWarn, newCorrelationId, redactHeaders, summarizeBody, truncate, } from "../log.js";
18
+ const RETRYABLE_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]);
19
+ function isIdempotent(method) {
20
+ return method === "GET" || method === "HEAD" || method === "OPTIONS";
21
+ }
22
+ function delay(ms) {
23
+ return new Promise((resolve) => setTimeout(resolve, ms));
24
+ }
25
+ /** Backoff for attempt N (0-based): ~0.3s, 0.6s, 1.2s … capped, plus jitter. */
26
+ function backoffMs(attempt, retryAfter) {
27
+ if (retryAfter) {
28
+ const secs = Number(retryAfter);
29
+ if (Number.isFinite(secs))
30
+ return Math.min(30000, Math.max(0, secs * 1000));
31
+ const date = Date.parse(retryAfter);
32
+ if (!Number.isNaN(date))
33
+ return Math.min(30000, Math.max(0, date - Date.now()));
34
+ }
35
+ const base = Math.min(4000, 300 * 2 ** attempt);
36
+ return base + Math.floor(Math.random() * 250);
37
+ }
38
+ function pickResponseHeaders(res) {
39
+ const interesting = [
40
+ "content-type",
41
+ "content-length",
42
+ "retry-after",
43
+ "x-request-id",
44
+ "x-correlation-id",
45
+ "x-amzn-trace-id",
46
+ "cf-ray",
47
+ "date",
48
+ "server",
49
+ ];
50
+ const out = {};
51
+ for (const h of interesting) {
52
+ const v = res.headers.get(h);
53
+ if (v)
54
+ out[h] = v;
55
+ }
56
+ return out;
57
+ }
58
+ export async function httpJson(url, init, opts = {}) {
59
+ const cfg = getConfig();
60
+ const method = (init.method ?? "GET").toUpperCase();
61
+ const timeoutMs = opts.timeoutMs ?? cfg.httpTimeoutMs;
62
+ const retriesEnabled = opts.retry ?? isIdempotent(method);
63
+ const maxRetries = retriesEnabled ? opts.retries ?? cfg.httpRetries : 0;
64
+ const correlationId = opts.correlationId ?? newCorrelationId("http");
65
+ const label = opts.label ?? "http";
66
+ const startedAt = Date.now();
67
+ const bodyText = typeof init.body === "string"
68
+ ? init.body
69
+ : init.body != null
70
+ ? String(init.body)
71
+ : undefined;
72
+ logInfo("http.request.start", {
73
+ correlationId,
74
+ label,
75
+ method,
76
+ url,
77
+ timeoutMs,
78
+ retriesEnabled,
79
+ maxRetries,
80
+ headers: redactHeaders(init.headers),
81
+ body: summarizeBody(bodyText),
82
+ });
83
+ let attempt = 0;
84
+ for (;;) {
85
+ const attemptStarted = Date.now();
86
+ const controller = new AbortController();
87
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
88
+ let timedOut = false;
89
+ controller.signal.addEventListener("abort", () => {
90
+ timedOut = true;
91
+ });
92
+ logDebug("http.attempt.start", {
93
+ correlationId,
94
+ label,
95
+ method,
96
+ url,
97
+ attempt,
98
+ maxRetries,
99
+ timeoutMs,
100
+ elapsedMs: Date.now() - startedAt,
101
+ });
102
+ try {
103
+ const res = await fetch(url, { ...init, signal: controller.signal });
104
+ const headersMs = Date.now() - attemptStarted;
105
+ const text = await res.text();
106
+ const totalAttemptMs = Date.now() - attemptStarted;
107
+ if (!res.ok) {
108
+ const willRetry = attempt < maxRetries && RETRYABLE_STATUS.has(res.status);
109
+ logWarn("http.attempt.http_error", {
110
+ correlationId,
111
+ label,
112
+ method,
113
+ url,
114
+ attempt,
115
+ status: res.status,
116
+ statusText: res.statusText,
117
+ headersMs,
118
+ totalAttemptMs,
119
+ responseHeaders: pickResponseHeaders(res),
120
+ bodyPreview: truncate(text, 800),
121
+ willRetry,
122
+ retryableStatus: RETRYABLE_STATUS.has(res.status),
123
+ });
124
+ if (willRetry) {
125
+ clearTimeout(timer);
126
+ const wait = backoffMs(attempt, res.headers.get("retry-after"));
127
+ logInfo("http.retry", {
128
+ correlationId,
129
+ label,
130
+ attempt,
131
+ nextAttempt: attempt + 1,
132
+ waitMs: wait,
133
+ reason: `HTTP ${res.status}`,
134
+ });
135
+ await delay(wait);
136
+ attempt++;
137
+ continue;
138
+ }
139
+ const err = new Error(`HTTP ${res.status} for ${method} ${url}: ${text.slice(0, 500)}`);
140
+ err.status = res.status;
141
+ err.body = text;
142
+ logError("http.request.fail", err, {
143
+ correlationId,
144
+ label,
145
+ method,
146
+ url,
147
+ attempts: attempt + 1,
148
+ elapsedMs: Date.now() - startedAt,
149
+ kind: "http_status",
150
+ });
151
+ throw err;
152
+ }
153
+ logInfo("http.attempt.ok", {
154
+ correlationId,
155
+ label,
156
+ method,
157
+ url,
158
+ attempt,
159
+ status: res.status,
160
+ headersMs,
161
+ bodyMs: totalAttemptMs - headersMs,
162
+ totalAttemptMs,
163
+ elapsedMs: Date.now() - startedAt,
164
+ responseHeaders: pickResponseHeaders(res),
165
+ body: summarizeBody(text),
166
+ });
167
+ logInfo("http.request.ok", {
168
+ correlationId,
169
+ label,
170
+ method,
171
+ url,
172
+ attempts: attempt + 1,
173
+ elapsedMs: Date.now() - startedAt,
174
+ status: res.status,
175
+ });
176
+ if (!text)
177
+ return undefined;
178
+ try {
179
+ return JSON.parse(text);
180
+ }
181
+ catch {
182
+ return text;
183
+ }
184
+ }
185
+ catch (e) {
186
+ // HttpError (non-retryable status) bubbles straight up (already logged).
187
+ if (e instanceof Error && "status" in e)
188
+ throw e;
189
+ const attemptMs = Date.now() - attemptStarted;
190
+ const transient = timedOut || isTransport(e);
191
+ const willRetry = attempt < maxRetries && transient;
192
+ logWarn("http.attempt.transport_error", {
193
+ correlationId,
194
+ label,
195
+ method,
196
+ url,
197
+ attempt,
198
+ timedOut,
199
+ timeoutMs,
200
+ attemptMs,
201
+ elapsedMs: Date.now() - startedAt,
202
+ isTransport: isTransport(e),
203
+ willRetry,
204
+ error: errorDetails(e),
205
+ });
206
+ if (willRetry) {
207
+ const wait = backoffMs(attempt);
208
+ logInfo("http.retry", {
209
+ correlationId,
210
+ label,
211
+ attempt,
212
+ nextAttempt: attempt + 1,
213
+ waitMs: wait,
214
+ reason: timedOut ? "timeout" : "transport",
215
+ });
216
+ await delay(wait);
217
+ attempt++;
218
+ continue;
219
+ }
220
+ if (timedOut) {
221
+ const err = new Error(`Request timed out after ${timeoutMs}ms for ${method} ${url}` +
222
+ (attempt > 0 ? ` (after ${attempt + 1} attempts)` : ""));
223
+ logError("http.request.fail", err, {
224
+ correlationId,
225
+ label,
226
+ method,
227
+ url,
228
+ attempts: attempt + 1,
229
+ elapsedMs: Date.now() - startedAt,
230
+ kind: "timeout",
231
+ timeoutMs,
232
+ note: method === "POST" && /\/forward$/.test(url)
233
+ ? "Broadcast may still have been accepted by the relay — check balances before retrying."
234
+ : undefined,
235
+ });
236
+ throw err;
237
+ }
238
+ const msg = e instanceof Error ? e.message : String(e);
239
+ const err = new Error(`Network error for ${method} ${url}: ${msg}`);
240
+ logError("http.request.fail", err, {
241
+ correlationId,
242
+ label,
243
+ method,
244
+ url,
245
+ attempts: attempt + 1,
246
+ elapsedMs: Date.now() - startedAt,
247
+ kind: "transport",
248
+ cause: errorDetails(e),
249
+ note: method === "POST" && /\/forward$/.test(url)
250
+ ? "Connection dropped after send; relay may still have processed the request — check balances before retrying."
251
+ : undefined,
252
+ });
253
+ throw err;
254
+ }
255
+ finally {
256
+ clearTimeout(timer);
257
+ }
258
+ }
259
+ }
260
+ /** Transport-level failures worth retrying (DNS/connection resets, fetch failed). */
261
+ function isTransport(e) {
262
+ if (!(e instanceof Error))
263
+ return false;
264
+ // undici surfaces network issues as TypeError('fetch failed') with a cause.
265
+ if (e.name === "TypeError")
266
+ return true;
267
+ const code = e.code;
268
+ if (code && ["ECONNRESET", "ECONNREFUSED", "ETIMEDOUT", "EAI_AGAIN", "ENOTFOUND", "EPIPE"].includes(code)) {
269
+ return true;
270
+ }
271
+ const cause = e.cause;
272
+ if (cause?.code && ["ECONNRESET", "ECONNREFUSED", "ETIMEDOUT", "EAI_AGAIN", "ENOTFOUND", "EPIPE", "UND_ERR_CONNECT_TIMEOUT", "UND_ERR_SOCKET"].includes(cause.code)) {
273
+ return true;
274
+ }
275
+ return false;
276
+ }
277
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/api/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Relay (forward) API client, mirroring the mobile RelayApiV2Client:
3
+ * GET {relayUrl}{ver}/{Network}/forward/estimate?fromAddress&toAddress&...
4
+ * POST {relayUrl}{ver}/{Network}/forward
5
+ * GET {relayUrl}{ver}/{Network}/forward/operation/{id}/state
6
+ *
7
+ * `ver` defaults to `/v1` (gasless v1). Set IW_RELAY_VERSION= (empty) or
8
+ * IW_RELAY_VERSION=v0 to fall back to the legacy path without a version segment.
9
+ */
10
+ import { type NetworkId } from "../config.js";
11
+ import type { SignedTransaction, TransactionToSign } from "../signing/types.js";
12
+ export interface EstimateResult {
13
+ amount?: string;
14
+ coinFee?: string;
15
+ tokenFee?: string;
16
+ transactionsToSign: TransactionToSign[];
17
+ additionalEstimates?: unknown[];
18
+ timeout?: number;
19
+ }
20
+ export interface SignedEstimate {
21
+ signature?: string;
22
+ estimateResult?: EstimateResult;
23
+ traceId?: string;
24
+ }
25
+ export interface ForwardResult {
26
+ txHash?: string;
27
+ operationId?: string;
28
+ chainId?: string;
29
+ [k: string]: unknown;
30
+ }
31
+ export interface EstimateParams {
32
+ fromAddress: string;
33
+ toAddress: string;
34
+ tokenAddress?: string;
35
+ amount: string;
36
+ memo?: string;
37
+ /** Required for TON (mobile IR-673): 32-byte ed25519 pubkey hex. */
38
+ fromPublicKey?: string;
39
+ }
40
+ export interface RelayCallOpts {
41
+ correlationId?: string;
42
+ }
43
+ export declare function estimate(network: NetworkId, token: string, params: EstimateParams, callOpts?: RelayCallOpts): Promise<SignedEstimate>;
44
+ export declare function forward(network: NetworkId, token: string, params: EstimateParams, signedEstimateResult: SignedEstimate, signedTransactions: SignedTransaction[], callOpts?: RelayCallOpts): Promise<ForwardResult>;
45
+ export declare function operationState(network: NetworkId, token: string, operationId: string, callOpts?: RelayCallOpts): Promise<{
46
+ state?: string;
47
+ reasonCode?: string;
48
+ [k: string]: unknown;
49
+ }>;
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Relay (forward) API client, mirroring the mobile RelayApiV2Client:
3
+ * GET {relayUrl}{ver}/{Network}/forward/estimate?fromAddress&toAddress&...
4
+ * POST {relayUrl}{ver}/{Network}/forward
5
+ * GET {relayUrl}{ver}/{Network}/forward/operation/{id}/state
6
+ *
7
+ * `ver` defaults to `/v1` (gasless v1). Set IW_RELAY_VERSION= (empty) or
8
+ * IW_RELAY_VERSION=v0 to fall back to the legacy path without a version segment.
9
+ */
10
+ import { getConfig, relaySegment } from "../config.js";
11
+ import { authHeaders } from "./auth.js";
12
+ import { httpJson } from "./http.js";
13
+ import { logError, logInfo, newCorrelationId } from "../log.js";
14
+ function versionSegment() {
15
+ // Default to v1 (matches the mobile gaslessV1 path). Explicit empty / "v0"
16
+ // selects the legacy unversioned URL.
17
+ const raw = process.env.IW_RELAY_VERSION;
18
+ const v = (raw === undefined ? "v1" : raw).trim();
19
+ if (!v || v === "v0")
20
+ return "";
21
+ return v.startsWith("/") ? v : `/${v}`;
22
+ }
23
+ function baseUrl(network) {
24
+ const cfg = getConfig();
25
+ return `${cfg.relayUrl}${versionSegment()}/${relaySegment(network)}`;
26
+ }
27
+ export async function estimate(network, token, params, callOpts = {}) {
28
+ const correlationId = callOpts.correlationId ?? newCorrelationId("est");
29
+ const query = new URLSearchParams();
30
+ query.set("fromAddress", params.fromAddress);
31
+ query.set("toAddress", params.toAddress);
32
+ if (params.tokenAddress)
33
+ query.set("tokenAddress", params.tokenAddress);
34
+ query.set("amount", params.amount);
35
+ if (params.memo)
36
+ query.set("memo", params.memo);
37
+ if (params.fromPublicKey)
38
+ query.set("fromPublicKey", params.fromPublicKey);
39
+ const url = `${baseUrl(network)}/forward/estimate?${query.toString()}`;
40
+ logInfo("relay.estimate.start", {
41
+ correlationId,
42
+ network,
43
+ fromAddress: params.fromAddress,
44
+ toAddress: params.toAddress,
45
+ amount: params.amount,
46
+ tokenAddress: params.tokenAddress,
47
+ hasMemo: Boolean(params.memo),
48
+ hasFromPublicKey: Boolean(params.fromPublicKey),
49
+ url,
50
+ });
51
+ const started = Date.now();
52
+ try {
53
+ const result = await httpJson(url, {
54
+ method: "GET",
55
+ headers: authHeaders(token),
56
+ }, { correlationId, label: "relay.estimate" });
57
+ const er = result.estimateResult;
58
+ logInfo("relay.estimate.ok", {
59
+ correlationId,
60
+ network,
61
+ elapsedMs: Date.now() - started,
62
+ traceId: result.traceId,
63
+ amount: er?.amount,
64
+ coinFee: er?.coinFee,
65
+ tokenFee: er?.tokenFee,
66
+ transactionsToSign: er?.transactionsToSign?.length ?? 0,
67
+ timeout: er?.timeout,
68
+ hasSignature: typeof result.signature === "string",
69
+ });
70
+ return result;
71
+ }
72
+ catch (e) {
73
+ logError("relay.estimate.fail", e, {
74
+ correlationId,
75
+ network,
76
+ elapsedMs: Date.now() - started,
77
+ });
78
+ throw e;
79
+ }
80
+ }
81
+ export async function forward(network, token, params, signedEstimateResult, signedTransactions, callOpts = {}) {
82
+ const correlationId = callOpts.correlationId ?? newCorrelationId("fwd");
83
+ const body = {
84
+ fromAddress: params.fromAddress,
85
+ toAddress: params.toAddress,
86
+ amount: params.amount,
87
+ signedEstimateResult,
88
+ signedTransactions,
89
+ };
90
+ if (params.tokenAddress)
91
+ body.tokenAddress = params.tokenAddress;
92
+ const cfg = getConfig();
93
+ const url = `${baseUrl(network)}/forward`;
94
+ logInfo("relay.forward.start", {
95
+ correlationId,
96
+ network,
97
+ fromAddress: params.fromAddress,
98
+ toAddress: params.toAddress,
99
+ amount: params.amount,
100
+ tokenAddress: params.tokenAddress,
101
+ url,
102
+ timeoutMs: cfg.httpForwardTimeoutMs,
103
+ retries: false,
104
+ signedTxCount: signedTransactions.length,
105
+ signedTxs: signedTransactions.map((t, i) => ({
106
+ i,
107
+ transactionId: t.transactionId,
108
+ txID: t.txID,
109
+ signatureLen: t.signature?.length,
110
+ txDataLen: t.txData?.length,
111
+ })),
112
+ estimateTraceId: signedEstimateResult.traceId,
113
+ estimateAmount: signedEstimateResult.estimateResult?.amount,
114
+ estimateCoinFee: signedEstimateResult.estimateResult?.coinFee,
115
+ estimateTokenFee: signedEstimateResult.estimateResult?.tokenFee,
116
+ });
117
+ const started = Date.now();
118
+ try {
119
+ const result = await httpJson(url, {
120
+ method: "POST",
121
+ headers: { ...authHeaders(token), "Content-Type": "application/json" },
122
+ body: JSON.stringify(body),
123
+ },
124
+ // Never retry a broadcast. Use the longer forward timeout — the relay may
125
+ // still submit the tx even if the client would otherwise give up at 15s.
126
+ {
127
+ retry: false,
128
+ timeoutMs: cfg.httpForwardTimeoutMs,
129
+ correlationId,
130
+ label: "relay.forward",
131
+ });
132
+ logInfo("relay.forward.ok", {
133
+ correlationId,
134
+ network,
135
+ elapsedMs: Date.now() - started,
136
+ txHash: result.txHash,
137
+ operationId: result.operationId,
138
+ chainId: result.chainId,
139
+ resultKeys: Object.keys(result),
140
+ });
141
+ return result;
142
+ }
143
+ catch (e) {
144
+ const msg = e instanceof Error ? e.message : String(e);
145
+ const timedOut = /timed out/i.test(msg);
146
+ logError("relay.forward.fail", e, {
147
+ correlationId,
148
+ network,
149
+ elapsedMs: Date.now() - started,
150
+ timedOut,
151
+ timeoutMs: cfg.httpForwardTimeoutMs,
152
+ warning: "Relay may still have broadcast the transaction. Check sender/receiver balances and explorer before retrying — do not resend blindly.",
153
+ });
154
+ if (timedOut) {
155
+ throw new Error(`${msg}. The relay may still have broadcast the transaction — ` +
156
+ `check the wallet balance / explorer before retrying (do not resend blindly). ` +
157
+ `[correlationId=${correlationId}]`);
158
+ }
159
+ throw new Error(`${msg} [correlationId=${correlationId}]` +
160
+ (/fetch failed|Network error/i.test(msg)
161
+ ? ". Connection may have dropped after the relay accepted the request — check balances before retrying."
162
+ : ""));
163
+ }
164
+ }
165
+ export async function operationState(network, token, operationId, callOpts = {}) {
166
+ const correlationId = callOpts.correlationId ?? newCorrelationId("ops");
167
+ const url = `${baseUrl(network)}/forward/operation/${operationId}/state`;
168
+ logInfo("relay.operation_state.start", {
169
+ correlationId,
170
+ network,
171
+ operationId,
172
+ url,
173
+ });
174
+ try {
175
+ const result = await httpJson(url, { method: "GET", headers: authHeaders(token) }, { correlationId, label: "relay.operation_state" });
176
+ logInfo("relay.operation_state.ok", {
177
+ correlationId,
178
+ network,
179
+ operationId,
180
+ state: result.state,
181
+ reasonCode: result.reasonCode,
182
+ });
183
+ return result;
184
+ }
185
+ catch (e) {
186
+ logError("relay.operation_state.fail", e, {
187
+ correlationId,
188
+ network,
189
+ operationId,
190
+ });
191
+ throw e;
192
+ }
193
+ }
194
+ //# sourceMappingURL=relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../src/api/relay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Shared ethers JsonRpcProvider factory with a bounded per-request timeout.
3
+ *
4
+ * ethers' default FetchRequest timeout is 5 minutes, which would let a stuck RPC
5
+ * node hang balance reads and the signing nonce/chainId lookups indefinitely. We
6
+ * cap it at the configured HTTP timeout and cache one provider per URL.
7
+ */
8
+ import { JsonRpcProvider } from "ethers";
9
+ import { type NetworkId } from "../config.js";
10
+ export declare function providerFor(network: NetworkId): JsonRpcProvider;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared ethers JsonRpcProvider factory with a bounded per-request timeout.
3
+ *
4
+ * ethers' default FetchRequest timeout is 5 minutes, which would let a stuck RPC
5
+ * node hang balance reads and the signing nonce/chainId lookups indefinitely. We
6
+ * cap it at the configured HTTP timeout and cache one provider per URL.
7
+ */
8
+ import { FetchRequest, JsonRpcProvider } from "ethers";
9
+ import { getConfig } from "../config.js";
10
+ const providerCache = new Map();
11
+ export function providerFor(network) {
12
+ const cfg = getConfig();
13
+ const url = cfg.evmRpcUrls[network];
14
+ if (!url)
15
+ throw new Error(`No RPC endpoint configured for ${network}.`);
16
+ let provider = providerCache.get(url);
17
+ if (!provider) {
18
+ const req = new FetchRequest(url);
19
+ req.timeout = cfg.httpTimeoutMs;
20
+ // Assume a stable chain id so ethers doesn't re-detect the network on every call.
21
+ provider = new JsonRpcProvider(req, undefined, { staticNetwork: true });
22
+ providerCache.set(url, provider);
23
+ }
24
+ return provider;
25
+ }
26
+ //# sourceMappingURL=rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../src/api/rpc.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACvD,OAAO,EAAE,SAAS,EAAkB,MAAM,cAAc,CAAC;AAEzD,MAAM,aAAa,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEzD,MAAM,UAAU,WAAW,CAAC,OAAkB;IAC5C,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,OAAO,GAAG,CAAC,CAAC;IAExE,IAAI,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;QAClC,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC;QAChC,kFAAkF;QAClF,QAAQ,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACxE,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}