@xochi/client 0.0.0-stage → 0.1.2

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 (129) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +21 -0
  3. package/README.md +120 -2
  4. package/dist/cjs/claim.d.ts +33 -0
  5. package/dist/cjs/claim.js +44 -0
  6. package/dist/cjs/fee.d.ts +247 -0
  7. package/dist/cjs/fee.js +295 -0
  8. package/dist/cjs/index.d.ts +18 -0
  9. package/dist/cjs/index.js +33 -0
  10. package/dist/cjs/machine/claimInfo.d.ts +29 -0
  11. package/dist/cjs/machine/claimInfo.js +26 -0
  12. package/dist/cjs/machine/decisions.d.ts +452 -0
  13. package/dist/cjs/machine/decisions.js +665 -0
  14. package/dist/cjs/machine/deposit.d.ts +113 -0
  15. package/dist/cjs/machine/deposit.js +265 -0
  16. package/dist/cjs/machine/index.d.ts +23 -0
  17. package/dist/cjs/machine/index.js +53 -0
  18. package/dist/cjs/machine/machine.d.ts +411 -0
  19. package/dist/cjs/machine/machine.js +1627 -0
  20. package/dist/cjs/machine/phase.d.ts +24 -0
  21. package/dist/cjs/machine/phase.js +45 -0
  22. package/dist/cjs/machine/quoteChecks.d.ts +41 -0
  23. package/dist/cjs/machine/quoteChecks.js +82 -0
  24. package/dist/cjs/machine/receipt.d.ts +151 -0
  25. package/dist/cjs/machine/receipt.js +69 -0
  26. package/dist/cjs/machine/recipientEcho.d.ts +16 -0
  27. package/dist/cjs/machine/recipientEcho.js +27 -0
  28. package/dist/cjs/machine/solverPin.d.ts +110 -0
  29. package/dist/cjs/machine/solverPin.js +214 -0
  30. package/dist/cjs/machine/state.d.ts +167 -0
  31. package/dist/cjs/machine/state.js +31 -0
  32. package/dist/cjs/machine/transition.d.ts +15 -0
  33. package/dist/cjs/machine/transition.js +20 -0
  34. package/dist/cjs/machine/validateRequest.d.ts +15 -0
  35. package/dist/cjs/machine/validateRequest.js +127 -0
  36. package/dist/cjs/machine/view.d.ts +3 -0
  37. package/dist/cjs/machine/view.js +74 -0
  38. package/dist/cjs/machine/wire.d.ts +527 -0
  39. package/dist/cjs/machine/wire.js +280 -0
  40. package/dist/cjs/package.json +1 -0
  41. package/dist/cjs/shared/api.d.ts +9 -0
  42. package/dist/cjs/shared/api.js +5 -0
  43. package/dist/cjs/shared/chains.d.ts +243 -0
  44. package/dist/cjs/shared/chains.js +250 -0
  45. package/dist/cjs/shared/eip712.d.ts +44 -0
  46. package/dist/cjs/shared/eip712.js +64 -0
  47. package/dist/cjs/shared/index.d.ts +16 -0
  48. package/dist/cjs/shared/index.js +32 -0
  49. package/dist/cjs/shared/intentStream.d.ts +74 -0
  50. package/dist/cjs/shared/intentStream.js +59 -0
  51. package/dist/cjs/shared/intents.d.ts +88 -0
  52. package/dist/cjs/shared/intents.js +227 -0
  53. package/dist/cjs/shared/schemas.d.ts +928 -0
  54. package/dist/cjs/shared/schemas.js +524 -0
  55. package/dist/cjs/shared/shieldedPreview.d.ts +841 -0
  56. package/dist/cjs/shared/shieldedPreview.js +128 -0
  57. package/dist/cjs/shared/stealth.d.ts +53 -0
  58. package/dist/cjs/shared/stealth.js +68 -0
  59. package/dist/cjs/shared/trading.d.ts +153 -0
  60. package/dist/cjs/shared/trading.js +185 -0
  61. package/dist/cjs/shared/types.d.ts +37 -0
  62. package/dist/cjs/shared/types.js +7 -0
  63. package/dist/cjs/shared/validators.d.ts +30 -0
  64. package/dist/cjs/shared/validators.js +79 -0
  65. package/dist/cjs/transport/client.d.ts +234 -0
  66. package/dist/cjs/transport/client.js +1456 -0
  67. package/dist/esm/claim.d.ts +33 -0
  68. package/dist/esm/claim.js +41 -0
  69. package/dist/esm/fee.d.ts +247 -0
  70. package/dist/esm/fee.js +285 -0
  71. package/dist/esm/index.d.ts +18 -0
  72. package/dist/esm/index.js +17 -0
  73. package/dist/esm/machine/claimInfo.d.ts +29 -0
  74. package/dist/esm/machine/claimInfo.js +23 -0
  75. package/dist/esm/machine/decisions.d.ts +452 -0
  76. package/dist/esm/machine/decisions.js +640 -0
  77. package/dist/esm/machine/deposit.d.ts +113 -0
  78. package/dist/esm/machine/deposit.js +260 -0
  79. package/dist/esm/machine/index.d.ts +23 -0
  80. package/dist/esm/machine/index.js +23 -0
  81. package/dist/esm/machine/machine.d.ts +411 -0
  82. package/dist/esm/machine/machine.js +1621 -0
  83. package/dist/esm/machine/phase.d.ts +24 -0
  84. package/dist/esm/machine/phase.js +42 -0
  85. package/dist/esm/machine/quoteChecks.d.ts +41 -0
  86. package/dist/esm/machine/quoteChecks.js +78 -0
  87. package/dist/esm/machine/receipt.d.ts +151 -0
  88. package/dist/esm/machine/receipt.js +64 -0
  89. package/dist/esm/machine/recipientEcho.d.ts +16 -0
  90. package/dist/esm/machine/recipientEcho.js +24 -0
  91. package/dist/esm/machine/solverPin.d.ts +110 -0
  92. package/dist/esm/machine/solverPin.js +210 -0
  93. package/dist/esm/machine/state.d.ts +167 -0
  94. package/dist/esm/machine/state.js +28 -0
  95. package/dist/esm/machine/transition.d.ts +15 -0
  96. package/dist/esm/machine/transition.js +17 -0
  97. package/dist/esm/machine/validateRequest.d.ts +15 -0
  98. package/dist/esm/machine/validateRequest.js +123 -0
  99. package/dist/esm/machine/view.d.ts +3 -0
  100. package/dist/esm/machine/view.js +71 -0
  101. package/dist/esm/machine/wire.d.ts +527 -0
  102. package/dist/esm/machine/wire.js +266 -0
  103. package/dist/esm/shared/api.d.ts +9 -0
  104. package/dist/esm/shared/api.js +4 -0
  105. package/dist/esm/shared/chains.d.ts +243 -0
  106. package/dist/esm/shared/chains.js +236 -0
  107. package/dist/esm/shared/eip712.d.ts +44 -0
  108. package/dist/esm/shared/eip712.js +61 -0
  109. package/dist/esm/shared/index.d.ts +16 -0
  110. package/dist/esm/shared/index.js +16 -0
  111. package/dist/esm/shared/intentStream.d.ts +74 -0
  112. package/dist/esm/shared/intentStream.js +55 -0
  113. package/dist/esm/shared/intents.d.ts +88 -0
  114. package/dist/esm/shared/intents.js +213 -0
  115. package/dist/esm/shared/schemas.d.ts +928 -0
  116. package/dist/esm/shared/schemas.js +521 -0
  117. package/dist/esm/shared/shieldedPreview.d.ts +841 -0
  118. package/dist/esm/shared/shieldedPreview.js +124 -0
  119. package/dist/esm/shared/stealth.d.ts +53 -0
  120. package/dist/esm/shared/stealth.js +64 -0
  121. package/dist/esm/shared/trading.d.ts +153 -0
  122. package/dist/esm/shared/trading.js +182 -0
  123. package/dist/esm/shared/types.d.ts +37 -0
  124. package/dist/esm/shared/types.js +6 -0
  125. package/dist/esm/shared/validators.d.ts +30 -0
  126. package/dist/esm/shared/validators.js +74 -0
  127. package/dist/esm/transport/client.d.ts +234 -0
  128. package/dist/esm/transport/client.js +1447 -0
  129. package/package.json +61 -4
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Wire shapes and decoders.
3
+ *
4
+ * The worker speaks the canonical snake_case contract (`QuoteResponseSchema` in
5
+ * `@xochi/shared`, `public/openapi.yaml`); everything past this module is
6
+ * camelCase. Decoding happens HERE, once, so the trade widget and `@xochi/sdk`
7
+ * read a quote, an execute result and an intent status through the same code
8
+ * rather than through two mappers that drift.
9
+ */
10
+ import { ExecuteResponseSchema, QuoteResponseSchema, READ_TOKEN_PATTERN, isSettlementType, isIntentStatus, } from "../shared/index.js";
11
+ // ============================================================
12
+ // Wire adapters: snake_case wire (worker/openapi) -> camelCase app types
13
+ //
14
+ // The worker emits the canonical snake_case contract (see QuoteResponseSchema
15
+ // in @xochi/shared and public/openapi.yaml). The React app stays camelCase;
16
+ // intentAPI.ts maps at the client boundary via these helpers. The `eip712`
17
+ // value is verbatim EIP-712 typed data -- its internal keys are already the
18
+ // standard camelCase and pass through unchanged.
19
+ // ============================================================
20
+ /**
21
+ * The response contracts as the client applies them: every declared field is
22
+ * held to its schema (a `fee_breakdown` without `gas_floor`, a non-string
23
+ * `eip712`, a numeric `claim_info.factory_address` all fail), but an
24
+ * undeclared top-level key is let through rather than failing the whole
25
+ * quote, so an additive server field does not take every client down. The
26
+ * decoders read the original object, never the parse output, so the EIP-712
27
+ * payloads reach the wallet byte-for-byte as served.
28
+ */
29
+ const QUOTE_RESPONSE = QuoteResponseSchema.passthrough();
30
+ const EXECUTE_RESPONSE = ExecuteResponseSchema.passthrough();
31
+ export function isQuoteResponseWire(value) {
32
+ return QUOTE_RESPONSE.safeParse(value).success;
33
+ }
34
+ export function isExecuteResponseWire(value) {
35
+ return EXECUTE_RESPONSE.safeParse(value).success;
36
+ }
37
+ /**
38
+ * Read the resolved settlement type out of the solver's opaque `route` bag.
39
+ *
40
+ * `route` is `z.record(z.string(), z.unknown())` in the contract: a passthrough
41
+ * the worker does not model, so it arrives untyped. Narrow it to the closed
42
+ * settlement vocabulary here rather than casting, and return undefined for
43
+ * anything unrecognised. Callers that need it (the v2 deposit attestation) must
44
+ * treat undefined as a refusal: a wrong guess produces a message that fails to
45
+ * recover, which reads as a solver outage rather than as our bug.
46
+ */
47
+ export function readResolvedSettlementType(route) {
48
+ const value = route?.settlement_type;
49
+ // Reuses the shared predicate rather than re-listing the vocabulary. A second
50
+ // copy of the closed set compiles fine and silently refuses every deposit
51
+ // quote on whichever settlement type it forgot.
52
+ return typeof value === "string" && isSettlementType(value) ? value : undefined;
53
+ }
54
+ export function mapQuoteResponse(w) {
55
+ return {
56
+ success: w.success,
57
+ intentId: w.intent_id,
58
+ quoteId: w.quote_id,
59
+ canSolve: w.can_solve,
60
+ preview: w.preview,
61
+ toAmount: w.to_amount ?? "0",
62
+ minToAmount: w.min_to_amount ?? "0",
63
+ xochiFee: w.xochi_fee ?? "0",
64
+ xochiFeeRate: w.xochi_fee_rate ?? "",
65
+ costBps: w.cost_bps,
66
+ feeBreakdown: w.fee_breakdown
67
+ ? {
68
+ tier: w.fee_breakdown.tier,
69
+ assetClass: w.fee_breakdown.asset_class,
70
+ gasFloor: {
71
+ amount: w.fee_breakdown.gas_floor.amount,
72
+ usd: w.fee_breakdown.gas_floor.usd,
73
+ },
74
+ solverFeeBps: w.fee_breakdown.solver_fee_bps,
75
+ solverFee: w.fee_breakdown.solver_fee,
76
+ priceImpactBps: w.fee_breakdown.price_impact_bps,
77
+ priceImpact: w.fee_breakdown.price_impact,
78
+ venueFeeBps: w.fee_breakdown.venue_fee_bps,
79
+ venueFee: w.fee_breakdown.venue_fee,
80
+ routingFeeBps: w.fee_breakdown.routing_fee_bps,
81
+ routingFee: w.fee_breakdown.routing_fee,
82
+ totalBps: w.fee_breakdown.total_bps,
83
+ totalFee: w.fee_breakdown.total_fee,
84
+ totalUsd: w.fee_breakdown.total_usd,
85
+ surplusSharePct: w.fee_breakdown.surplus_share_pct,
86
+ }
87
+ : undefined,
88
+ // Passed through, never defaulted. An absent field means the server did not
89
+ // state the denomination, which the renderer has to be able to tell apart
90
+ // from a server that said "origin".
91
+ feeDenomination: w.fee_denomination,
92
+ estimatedGasCost: w.estimated_gas_cost ?? "",
93
+ // Passed through, never defaulted and never backfilled from intent_id.
94
+ streamTopic: w.stream_topic,
95
+ expiry: w.expiry,
96
+ gasless: w.gasless ?? false,
97
+ gaslessFee: w.gasless_fee,
98
+ paymentMethod: w.payment_method,
99
+ eip712Data: w.eip712,
100
+ pullAuthorization: w.pull_authorization,
101
+ depositAddress: w.deposit_address,
102
+ depositAttestation: w.deposit_attestation,
103
+ depositDeadline: w.deposit_deadline,
104
+ settlementType: readResolvedSettlementType(w.route),
105
+ recipientAddress: w.recipient_address,
106
+ settlementOptions: w.settlement_options ?? [],
107
+ claimInfo: w.claim_info
108
+ ? { factoryAddress: w.claim_info.factory_address, salt: w.claim_info.salt }
109
+ : undefined,
110
+ error: w.error,
111
+ errorCategory: w.error_category,
112
+ minimumAmountUsd: w.minimum_amount_usd,
113
+ minFillableUsd: w.min_fillable_usd,
114
+ // Passed through untouched, never interpreted: the signer refuses it.
115
+ ...("escrow" in w ? { escrow: w.escrow } : {}),
116
+ };
117
+ }
118
+ export function mapExecuteResponse(w) {
119
+ return {
120
+ success: w.success,
121
+ intentId: w.intent_id,
122
+ status: w.status,
123
+ txHash: w.tx_hash,
124
+ receivingTxHash: w.receiving_tx_hash,
125
+ settlementTxHash: w.settlement_tx_hash,
126
+ settlementChainId: w.settlement_chain_id,
127
+ bridgeTxHash: w.bridge_tx_hash,
128
+ reconciling: w.reconciling,
129
+ error: w.error,
130
+ ...(typeof w.substatus === "string" ? { substatus: w.substatus } : {}),
131
+ noteCommitment: w.note_commitment,
132
+ stealthAddress: w.stealth_address,
133
+ ephemeralPubKey: w.ephemeral_pub_key,
134
+ viewTag: w.view_tag,
135
+ // The decoders read the raw body, not the parse output, so the schema's
136
+ // drop of a malformed token does not reach here: check it again.
137
+ readToken: typeof w.read_token === "string" && READ_TOKEN_PATTERN.test(w.read_token)
138
+ ? w.read_token
139
+ : undefined,
140
+ };
141
+ }
142
+ // ============================================================
143
+ // Race Stream Messages
144
+ // ============================================================
145
+ export const RACE_MESSAGE_TYPES = ["race_started", "solver_bid", "race_won"];
146
+ export function isRaceWebSocketMessage(value) {
147
+ if (typeof value !== "object" || value === null)
148
+ return false;
149
+ const obj = value;
150
+ return (typeof obj.type === "string" &&
151
+ RACE_MESSAGE_TYPES.includes(obj.type) &&
152
+ typeof obj.intentId === "string");
153
+ }
154
+ // ============================================================
155
+ // Intent status (GET /api/intent/:id/status)
156
+ // ============================================================
157
+ /**
158
+ * Granular origin-pull states the solver may emit that the `IntentStatus`
159
+ * union doesn't model, bucketed into the nearest known state. Unknown/granular
160
+ * strings otherwise reach `phaseFromStatus` (which drops them to the confirm
161
+ * screen) and fall outside the poll's in-flight set (freezing the row mid-flight
162
+ * -- the dead-spinner bug).
163
+ */
164
+ export const GRANULAR_WIRE_STATUS = {
165
+ pulling: "executing",
166
+ pulled: "executing",
167
+ filling: "settling",
168
+ filled: "completed",
169
+ refunding: "settling",
170
+ pull_failed: "failed",
171
+ fill_failed: "failed",
172
+ refund_failed: "failed",
173
+ };
174
+ export function decodeWireStatus(raw) {
175
+ if (typeof raw !== "string")
176
+ return { kind: "absent", status: "executing" };
177
+ if (isIntentStatus(raw))
178
+ return { kind: "mapped", status: raw };
179
+ const bucket = GRANULAR_WIRE_STATUS[raw];
180
+ if (bucket)
181
+ return { kind: "mapped", status: bucket };
182
+ return { kind: "unmapped", status: "executing", raw };
183
+ }
184
+ /**
185
+ * Statuses that are settled: no further status polling is needed. Xochi's own
186
+ * lifecycle vocabulary (`IntentStatus`), and the fallback the status decoder
187
+ * uses when the worker omits `terminal`.
188
+ */
189
+ export const TERMINAL_INTENT_STATUSES = {
190
+ completed: true,
191
+ failed: true,
192
+ expired: true,
193
+ refunded: true,
194
+ };
195
+ export function isTerminalIntentStatus(status) {
196
+ return TERMINAL_INTENT_STATUSES[status] === true;
197
+ }
198
+ /**
199
+ * Whether an anonymous read's `settlement_confirmed` (xochi#563) counts as a
200
+ * delivered fill. Only on a read that withheld the legs (the marker stands in
201
+ * for the withheld receipt), and only when `status` decodes (`decodeWireStatus`)
202
+ * to a status this build models that is not a terminal failure and not part of
203
+ * a refund: never on `refunded` / `failed` / `expired`, on a granular status
204
+ * bucketed to one (`fill_failed`, `refund_failed`), on any `refund*` status
205
+ * (`refunding`, `refund_pending`), or on an unmapped or absent status.
206
+ */
207
+ export function withheldSettlementConfirmed(read) {
208
+ if (read.legsWithheld !== true || read.settlementConfirmed !== true)
209
+ return false;
210
+ const decoded = decodeWireStatus(read.status);
211
+ if (decoded.kind !== "mapped")
212
+ return false;
213
+ if (typeof read.status === "string" && read.status.startsWith("refund"))
214
+ return false;
215
+ return !(isTerminalIntentStatus(decoded.status) && decoded.status !== "completed");
216
+ }
217
+ /**
218
+ * One `GET /api/intent/:id` body: the status-only `WithheldIntentRecord` when
219
+ * the server says it withheld the legs, else the full record.
220
+ */
221
+ export function mapIntentRead(w) {
222
+ if (w.legs_withheld !== true)
223
+ return mapIntentRecord(w);
224
+ const decoded = decodeWireStatus(w.status);
225
+ return {
226
+ legsWithheld: true,
227
+ id: w.id,
228
+ status: decoded.status,
229
+ ...(decoded.kind === "unmapped" ? { unmapped: true } : {}),
230
+ fromChainId: w.from_chain_id,
231
+ toChainId: w.to_chain_id,
232
+ settlementType: w.settlement_type,
233
+ error: w.error,
234
+ ...(typeof w.substatus === "string" ? { substatus: w.substatus } : {}),
235
+ settlementConfirmed: withheldSettlementConfirmed({
236
+ status: w.status,
237
+ legsWithheld: w.legs_withheld,
238
+ settlementConfirmed: w.settlement_confirmed,
239
+ }),
240
+ };
241
+ }
242
+ export function mapIntentRecord(w) {
243
+ return {
244
+ id: w.id,
245
+ walletAddress: w.wallet_address ?? "",
246
+ status: w.status,
247
+ fromChainId: w.from_chain_id,
248
+ toChainId: w.to_chain_id,
249
+ fromToken: w.from_token ?? "",
250
+ toToken: w.to_token ?? "",
251
+ fromAmount: w.from_amount,
252
+ toAmount: w.to_amount,
253
+ quoteId: w.quote_id ?? "",
254
+ tier: w.tier ?? "",
255
+ feeRate: w.fee_rate ?? 0,
256
+ settlementType: w.settlement_type ?? "public",
257
+ aztecNoteHash: w.aztec_note_hash,
258
+ txHash: w.tx_hash,
259
+ settlementTxHash: w.settlement_tx_hash ?? undefined,
260
+ settlementChainId: w.settlement_chain_id ?? undefined,
261
+ createdAt: w.created_at,
262
+ updatedAt: w.updated_at,
263
+ error: w.error,
264
+ ...(typeof w.substatus === "string" ? { substatus: w.substatus } : {}),
265
+ };
266
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * API types shared by the client and the Worker.
3
+ */
4
+ import type { SettlementType } from "./intents.js";
5
+ export interface SettlementOption {
6
+ type: SettlementType;
7
+ available: boolean;
8
+ reason?: string;
9
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * API types shared by the client and the Worker.
3
+ */
4
+ export {};
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Chain Definitions
3
+ *
4
+ * Supported chains and their configuration.
5
+ *
6
+ * `CHAIN_REGISTRY` is the ONE literal in this file: the `ChainId` union, every
7
+ * display/lookup map and `SUPPORTED_CHAIN_IDS` are derived from it. `SUPPORTED_CHAIN_IDS`
8
+ * is typed `readonly ChainId[]`, so a hand-maintained copy that omitted a chain compiled
9
+ * cleanly and silently excluded it from `isChainId`, `SETTLEABLE_CHAIN_IDS` and the
10
+ * capabilities fallback; the per-chain maps outside this file (`tokens.ts`) fail to
11
+ * compile until they carry a new registry entry.
12
+ */
13
+ /**
14
+ * One supported EVM chain. `explorer` is an origin with no trailing path.
15
+ * `nativeCurrency` is the gas token symbol (defaults to "ETH" if omitted).
16
+ */
17
+ export interface ChainDefinition {
18
+ readonly id: number;
19
+ readonly name: string;
20
+ readonly shortName: string;
21
+ readonly explorer: string;
22
+ readonly nativeCurrency?: string;
23
+ }
24
+ /**
25
+ * The single source of truth for supported EVM chains.
26
+ *
27
+ * Keyed by slug rather than by id for two reasons: the slugs are themselves
28
+ * public API (`CHAIN_IDS.base`), and string keys preserve insertion order, so
29
+ * `SUPPORTED_CHAIN_IDS` keeps its declared order. Integer-like keys would be
30
+ * re-sorted ascending by the runtime, which would silently reorder the
31
+ * `/api/capabilities` fallback payload built from that array.
32
+ *
33
+ * Non-EVM and virtual chains are deliberately NOT here: Tron (base58 addresses,
34
+ * TronWeb signing, hash-route explorer) and the Aztec virtual source chain (0)
35
+ * are display-only, and join the extended maps below through their own
36
+ * constants. EVM-only code (viem/wagmi/RPC) must never receive those ids.
37
+ *
38
+ * Short names are the compact UI labels; explorers are the origins the link
39
+ * helpers below build on (one map, so per-component explorer maps cannot
40
+ * drift).
41
+ */
42
+ export declare const CHAIN_REGISTRY: {
43
+ readonly ethereum: {
44
+ readonly id: 1;
45
+ readonly name: "Ethereum";
46
+ readonly shortName: "ETH";
47
+ readonly explorer: "https://etherscan.io";
48
+ };
49
+ readonly optimism: {
50
+ readonly id: 10;
51
+ readonly name: "Optimism";
52
+ readonly shortName: "OP";
53
+ readonly explorer: "https://optimistic.etherscan.io";
54
+ };
55
+ readonly polygon: {
56
+ readonly id: 137;
57
+ readonly name: "Polygon";
58
+ readonly shortName: "POLY";
59
+ readonly explorer: "https://polygonscan.com";
60
+ readonly nativeCurrency: "POL";
61
+ };
62
+ readonly arbitrum: {
63
+ readonly id: 42161;
64
+ readonly name: "Arbitrum";
65
+ readonly shortName: "ARB";
66
+ readonly explorer: "https://arbiscan.io";
67
+ };
68
+ readonly base: {
69
+ readonly id: 8453;
70
+ readonly name: "Base";
71
+ readonly shortName: "BASE";
72
+ readonly explorer: "https://basescan.org";
73
+ };
74
+ readonly robinhood: {
75
+ readonly id: 4663;
76
+ readonly name: "Robinhood";
77
+ readonly shortName: "HOOD";
78
+ readonly explorer: "https://robinhoodchain.blockscout.com";
79
+ };
80
+ readonly arc: {
81
+ readonly id: 5042;
82
+ readonly name: "Arc";
83
+ readonly shortName: "ARC";
84
+ readonly explorer: "https://explorer.arc.io";
85
+ readonly nativeCurrency: "USDC";
86
+ };
87
+ readonly gnosis: {
88
+ readonly id: 100;
89
+ readonly name: "Gnosis";
90
+ readonly shortName: "GNO";
91
+ readonly explorer: "https://gnosisscan.io";
92
+ readonly nativeCurrency: "xDAI";
93
+ };
94
+ };
95
+ /** Slug of a supported chain: the `CHAIN_REGISTRY` keys. */
96
+ export type ChainSlug = keyof typeof CHAIN_REGISTRY;
97
+ /** Supported L1/L2 chain IDs, derived from `CHAIN_REGISTRY`. */
98
+ export type ChainId = (typeof CHAIN_REGISTRY)[ChainSlug]["id"];
99
+ /** Aztec virtual chain ID for shielded operations */
100
+ export type AztecChainId = 0;
101
+ /**
102
+ * Extended chain ID: every UI-renderable chain beyond the core EVM `ChainId`.
103
+ * Includes the Aztec virtual source chain (0) and non-EVM destinations (Tron).
104
+ * Used for `Token.chainId` and the display maps (`EXTENDED_CHAIN_NAMES`,
105
+ * `CHAIN_ICONS`). EVM-only code (viem/wagmi/RPC) must never receive these.
106
+ */
107
+ export type ExtendedChainId = ChainId | AztecChainId | TronChainId;
108
+ /**
109
+ * Tron mainnet chain id. Tron is non-EVM (base58 addresses, TronWeb signing),
110
+ * so it is deliberately kept OUT of the EVM `ChainId` union -- EVM-only code
111
+ * (viem, wagmi, contract reads) must never receive it. UI-level chain selection
112
+ * uses `SelectableChainId` below.
113
+ */
114
+ export declare const TRON_CHAIN_ID = 728126428;
115
+ export type TronChainId = typeof TRON_CHAIN_ID;
116
+ /** Tron display names (Tron is outside CHAIN_REGISTRY, being non-EVM). */
117
+ export declare const TRON_CHAIN_NAME = "Tron";
118
+ export declare const TRON_SHORT_NAME = "TRON";
119
+ /**
120
+ * Chains a user can pick in the trade UI: every EVM chain plus Tron. Components
121
+ * that only do chain *selection* (selectors, route display) accept this wider
122
+ * union; anything that touches an EVM RPC stays on `ChainId`.
123
+ */
124
+ export type SelectableChainId = ChainId | TronChainId;
125
+ /** Type guard for the Tron mainnet chain id. */
126
+ export declare function isTronChainId(value: unknown): value is TronChainId;
127
+ /**
128
+ * Type guard for any chain the UI can render a link/name for (every EVM `ChainId`
129
+ * plus Tron). Guards raw `settlementChainId` values from Riddler -- which adds
130
+ * chains on its own cadence -- so an unknown id falls back to inference instead of
131
+ * producing a dead `href=""` or a `View undefined tx` label.
132
+ */
133
+ export declare function isSelectableChainId(value: unknown): value is SelectableChainId;
134
+ /**
135
+ * Robinhood Chain (4663): an Arbitrum Orbit L2 whose native stablecoin is USDG
136
+ * (Global Dollar, Paxos). It has no USDC. The solver settles USDC<->USDG (and
137
+ * other stablecoin) cross-asset corridors to and from it. It is fully EVM (0x
138
+ * addresses, EIP-712 signing, Permit2 pull on USDG) and a first-class member
139
+ * of `ChainId`: the trade UI lists Robinhood + USDG, so the per-chain token
140
+ * maps carry it. USDG is a first-class token (see USDG_ADDRESSES in
141
+ * tokens.ts), never shoehorned into USDC_ADDRESSES (that map is Permit2-free
142
+ * ERC-3009 USDC only, and USDG supports neither ERC-3009 nor EIP-2612).
143
+ * `ROBINHOOD_CHAIN_ID` is kept for readable references and the settleable
144
+ * guards below.
145
+ */
146
+ export declare const ROBINHOOD_CHAIN_ID = 4663;
147
+ export type RobinhoodChainId = typeof ROBINHOOD_CHAIN_ID;
148
+ /** Type guard for the Robinhood Chain id. */
149
+ export declare function isRobinhoodChainId(value: unknown): value is RobinhoodChainId;
150
+ /**
151
+ * Arc chain id. Arc is Circle's EVM-compatible L1 where USDC is the native
152
+ * gas token (18 dec protocol-level, 6 dec ERC-20). No WETH, no ETH --
153
+ * stablecoin-only chain. Feature-flagged behind ARC_LIVE.
154
+ */
155
+ export declare const ARC_CHAIN_ID = 5042;
156
+ export type ArcChainId = typeof ARC_CHAIN_ID;
157
+ /** Type guard for the Arc chain id. */
158
+ export declare function isArcChainId(value: unknown): value is ArcChainId;
159
+ /**
160
+ * Gnosis Chain id. Native gas is xDAI. Xochi lists a single token here,
161
+ * Monerium EURe (18 dec, no ERC-3009, Permit2 pull); there is no WETH or USDC
162
+ * leg. Feature-flagged in the UI behind GNOSIS_LIVE.
163
+ */
164
+ export declare const GNOSIS_CHAIN_ID = 100;
165
+ export type GnosisChainId = typeof GNOSIS_CHAIN_ID;
166
+ /** Type guard for the Gnosis Chain id. */
167
+ export declare function isGnosisChainId(value: unknown): value is GnosisChainId;
168
+ /**
169
+ * Slug -> chain id, derived from the registry, plus the Aztec virtual chain
170
+ * (0), which has no registry entry because it is not an EVM chain.
171
+ */
172
+ type ChainIdsBySlug = {
173
+ readonly [K in ChainSlug]: (typeof CHAIN_REGISTRY)[K]["id"];
174
+ } & {
175
+ readonly aztec: AztecChainId;
176
+ };
177
+ /** All supported chain IDs */
178
+ export declare const CHAIN_IDS: ChainIdsBySlug;
179
+ /** Chain names for display */
180
+ export declare const CHAIN_NAMES: Record<ChainId, string>;
181
+ /**
182
+ * Short chain names for compact display. Keyed by `SelectableChainId` so the
183
+ * non-EVM Tron destination (base58) has a short name too -- the tx-link/name
184
+ * helpers in the trade result surfaces index this with a destination chain id
185
+ * that can be Tron.
186
+ */
187
+ export declare const CHAIN_SHORT_NAMES: Record<SelectableChainId, string>;
188
+ /**
189
+ * Block explorer origins by chain (no trailing path). Single source of truth --
190
+ * build tx/address URLs through the helpers below so links always target the
191
+ * right chain (the old per-component maps drifted and one hardcoded Arbiscan).
192
+ */
193
+ export declare const CHAIN_EXPLORERS: Record<ChainId, string>;
194
+ /**
195
+ * Native currency symbol per chain. Used for gas display (QuoteDetails) and
196
+ * balance labels (usePublicBalances). Most chains use ETH; Polygon uses POL,
197
+ * Arc uses USDC (native gas token on Circle's stablecoin L1).
198
+ * Derived from `CHAIN_REGISTRY.nativeCurrency`, defaulting to "ETH".
199
+ */
200
+ export declare const CHAIN_NATIVE_CURRENCY: Record<ChainId, string>;
201
+ /**
202
+ * Tronscan uses a `#/` hash route (not the `/tx/` path shape of the EVM
203
+ * explorers), so Tron links are built separately from `CHAIN_EXPLORERS`.
204
+ */
205
+ export declare const TRON_EXPLORER = "https://tronscan.org";
206
+ /**
207
+ * Build a transaction URL on the given chain's explorer (empty if unknown).
208
+ * Accepts a `SelectableChainId` so a Tron destination fill can be linked; Tron
209
+ * routes to tronscan's hash-route form.
210
+ */
211
+ export declare function getExplorerTxUrl(chainId: SelectableChainId, txHash: string): string;
212
+ /** Build an address URL on the given chain's explorer (empty if unknown). */
213
+ export declare function getExplorerAddressUrl(chainId: SelectableChainId, address: string): string;
214
+ /**
215
+ * Extended chain names including the Aztec source + non-EVM destinations. The
216
+ * Aztec virtual chain is branded "Xochi" in the UI, which is why its display
217
+ * name is not simply a chain name.
218
+ */
219
+ export declare const EXTENDED_CHAIN_NAMES: Record<ExtendedChainId, string>;
220
+ /** Supported chain IDs as array */
221
+ export declare const SUPPORTED_CHAIN_IDS: readonly ChainId[];
222
+ /** Type guard for ChainId */
223
+ export declare function isChainId(value: unknown): value is ChainId;
224
+ /**
225
+ * A chain id the solver can settle; equals `ChainId` (Robinhood is a first-class chain). The
226
+ * name is kept for the intent-API call sites (schema validation) that document the settleable
227
+ * surface explicitly, mirroring xochi's `@xochi/shared`.
228
+ */
229
+ export type SettleableChainId = ChainId | RobinhoodChainId;
230
+ /**
231
+ * Chain ids the solver can settle to or from; exactly `SUPPORTED_CHAIN_IDS`. The intent API
232
+ * (`/api/intent/quote` and `/api/intent/execute`) validates request chain ids against this set.
233
+ * Token addresses ride in the request body, so the API needs no per-chain token config to
234
+ * accept a corridor; the solver decides feasibility.
235
+ */
236
+ export declare const SETTLEABLE_CHAIN_IDS: readonly SettleableChainId[];
237
+ /** Type guard for a settleable chain id (any supported chain, including Robinhood). */
238
+ export declare function isSettleableChainId(value: unknown): value is SettleableChainId;
239
+ /** Type guard for ExtendedChainId (EVM chains + Aztec source + Tron destination). */
240
+ export declare function isExtendedChainId(value: unknown): value is ExtendedChainId;
241
+ /** Check if route between chains is supported */
242
+ export declare function isRouteSupported(from: ChainId, to: ChainId): boolean;
243
+ export {};