@eco-foundation/api-schemas 0.4.1 → 0.7.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 (47) hide show
  1. package/README.md +393 -10
  2. package/dist/fixtures/index.js +2 -2
  3. package/dist/fixtures/index.js.map +1 -1
  4. package/dist/fixtures/v1/intents-submit-permit2.request.quote-target.json +4 -3
  5. package/dist/fixtures/v1/intents-submit-permit3.request.quote-target.json +8 -3
  6. package/dist/fixtures/v1/quotes-create.response.all-quotes.json +6 -3
  7. package/dist/fixtures/v1/quotes-create.response.private-swap.json +2 -1
  8. package/dist/fixtures/v1/quotes-create.response.public-swap.json +2 -1
  9. package/dist/fixtures/v1/tokens-list.response.default.json +1 -1
  10. package/dist/generated/build-digest.json +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/v1/endpoints/chains.d.ts +7 -0
  13. package/dist/v1/endpoints/chains.js +5 -1
  14. package/dist/v1/endpoints/chains.js.map +1 -1
  15. package/dist/v1/endpoints/deposit-addresses.js +1 -1
  16. package/dist/v1/endpoints/deposit-addresses.js.map +1 -1
  17. package/dist/v1/endpoints/quotes.d.ts +7 -1
  18. package/dist/v1/endpoints/quotes.js +42 -6
  19. package/dist/v1/endpoints/quotes.js.map +1 -1
  20. package/dist/v1/endpoints/registry.d.ts +114 -21
  21. package/dist/v1/endpoints/registry.js +4 -2
  22. package/dist/v1/endpoints/registry.js.map +1 -1
  23. package/dist/v1/endpoints/status.d.ts +211 -26
  24. package/dist/v1/endpoints/status.js +39 -7
  25. package/dist/v1/endpoints/status.js.map +1 -1
  26. package/dist/v1/endpoints/submit.d.ts +43 -24
  27. package/dist/v1/endpoints/submit.js +16 -9
  28. package/dist/v1/endpoints/submit.js.map +1 -1
  29. package/dist/v1/endpoints/tokens.d.ts +7 -0
  30. package/dist/v1/endpoints/tokens.js +5 -1
  31. package/dist/v1/endpoints/tokens.js.map +1 -1
  32. package/dist/v1/enums.d.ts +2 -1
  33. package/dist/v1/enums.js +1 -1
  34. package/dist/v1/enums.js.map +1 -1
  35. package/dist/v1/errors/catalog.d.ts +14 -0
  36. package/dist/v1/errors/catalog.js +3 -1
  37. package/dist/v1/errors/catalog.js.map +1 -1
  38. package/dist/v1/errors/problem.d.ts +10 -0
  39. package/dist/v1/errors/problem.js +20 -10
  40. package/dist/v1/errors/problem.js.map +1 -1
  41. package/dist/v1/primitives.d.ts +10 -1
  42. package/dist/v1/primitives.js +16 -1
  43. package/dist/v1/primitives.js.map +1 -1
  44. package/dist/v1/types.d.ts +36 -1
  45. package/errors/catalog.lock.json +10 -0
  46. package/openapi/v1.json +672 -127
  47. package/package.json +19 -16
package/README.md CHANGED
@@ -4,7 +4,7 @@ Zod-first schemas, error catalog, golden fixtures, and generated OpenAPI 3.1 for
4
4
  API. The Zod schemas are the source of truth; everything else (OpenAPI, fixtures, plain types)
5
5
  is generated from or gated against them.
6
6
 
7
- Today the package covers **13 endpoints across 12 paths**, **37 error codes** (51 namespaced
7
+ Today the package covers **13 endpoints across 12 paths**, **39 error codes** (51 namespaced
8
8
  legacy references), and **19 golden fixtures**.
9
9
 
10
10
  ## Install
@@ -14,13 +14,13 @@ While the package is 0.x, pin the patch range or the exact version:
14
14
  ```json
15
15
  {
16
16
  "dependencies": {
17
- "@eco-foundation/api-schemas": "~0.4.1"
17
+ "@eco-foundation/api-schemas": "~0.7.0"
18
18
  }
19
19
  }
20
20
  ```
21
21
 
22
22
  **Never write `^0`.** npm resolves `^0.x` as `>=0.0.0 <1.0.0`, so it silently accepts every
23
- future breaking `0.y` — it is not a pin at all. Use `~0.4.1` or the exact `0.4.1`.
23
+ future breaking `0.y` — it is not a pin at all. Use `~0.7.0` or the exact `0.7.0`.
24
24
 
25
25
  A matching version string is not evidence of a matching artifact: also compare
26
26
  `V1_SCHEMA_DIGEST` (see [Invariants](#invariants-enforced-in-ci)). Two builds both called
@@ -30,6 +30,365 @@ A matching version string is not evidence of a matching artifact: also compare
30
30
  zod-bearing entry point. Which case you are in is decided entirely by your imports; see
31
31
  [Consumers](#consumers).
32
32
 
33
+ ## Migrating 0.6.0 -> 0.7.0
34
+
35
+ **BREAKING under 0.x semver** (breaking bumps the minor while the major is 0). Nothing on the
36
+ wire that `0.6.0` accepted is rejected, and nothing `0.6.0` published is removed: two operations
37
+ RETURN, one response field and one error code are ADDED. Three things still break, and one of
38
+ them is a live-behaviour change rather than a compile error — read all three before bumping.
39
+
40
+ **`V1_SCHEMA_DIGEST` MOVES.** Both digest inputs changed (`errors/catalog.lock.json` gained one
41
+ code; `openapi/v1.json` gained two operations, two request schemas and one response field), so the
42
+ value is now `3e13c5eeb8b054f3a48a22c7694de16b0fc11e1dbf6bc3c27e8c575100225b2a` — was
43
+ `a6724fa4dd585e77aebe680655ac10fe5a2f4b70537930a0b4dee2612afb7c8e` on `0.6.0`. Every consumer
44
+ running `assertNoSkew` must move to the new value **in the same rollout**; a mixed fleet fails
45
+ the check by design.
46
+
47
+ **THE THREE BREAKING ITEMS FIRST.**
48
+
49
+ **1. `LaneStandard` widens back to all four standards — a compile break for anyone keying on
50
+ it.** `STANDARDS_BY_TARGET.quote` is `['erc-3009', 'permit2', 'permit3']` (`depositAddress` is
51
+ unchanged), and `LaneStandard` is derived from the matrix, so it is now
52
+ `'erc-3009' | 'permit2' | 'permit3' | 'erc-2612'` — the exact mirror of `0.6.0`'s narrowing.
53
+ `V1_SUBMIT_SCHEMAS: Record<LaneStandard, …>` regains its `permit2`/`permit3` entries, and
54
+ `V1_SUBMIT_SCHEMAS_BY_SERVICE.intents` has three lanes. **Your own `Record<LaneStandard, X>`,
55
+ and every exhaustive `switch` over a `LaneStandard`, stops compiling until it gains two arms.**
56
+ That is the intended signal: the alternative is a dispatcher that meets `undefined` at runtime.
57
+ A consumer that only indexes `V1_SUBMIT_SCHEMAS_BY_SERVICE['deposit-addresses']` is untouched.
58
+
59
+ **2. A bare dependency bump WIDENS what a server ADVERTISES.** A router that derives its
60
+ `/v1/tokens` `supports.quote` from `STANDARDS_BY_TARGET` advertises `permit2` and `permit3` the
61
+ moment this version is installed — before it can necessarily execute them. That is exactly the
62
+ false promise `0.6.0` closed. Ship the bump in the same release as the lane implementation
63
+ (quoted-salt dispatch, `execution.vault` publication, and the vault binding described under the
64
+ additive items), or gate discovery separately. This is the one item here that changes live
65
+ behaviour with no code change on your side.
66
+
67
+ **3. Consumer-side, but read it: the lock gained a 400.** `V1ProblemSchema` cross-checks a KNOWN
68
+ code's `status`/`type` against the catalog. `vault-mismatch` (below) is now known, so a body
69
+ carrying that spelling with a contradicting status or type stops parsing where `0.6.0` tolerated
70
+ it as "a newer server". An exhaustive `switch` over `V1ErrorCode` will not compile until it
71
+ handles it.
72
+
73
+ **THE ADDITIVE ITEMS.**
74
+
75
+ **Returned — `POST /v1/intents/submit/permit2` and `/permit3`.** This supersedes `0.6.0`'s
76
+ breaking item 4. The lanes can complete now because the two things that item named as missing
77
+ exist: the router dispatches the QUOTED `route.salt` unchanged (so the intent it funds is the
78
+ intent it quoted), and the quote response publishes the intent vault that salt produces
79
+ (`execution.vault`, below), so a signer can name the vault-bound counterparty before signing.
80
+ Both operations, both `V1_ENDPOINTS` entries (`intents.submit.permit2`, `intents.submit.permit3`),
81
+ both golden fixtures, and the five schema exports `Permit2PermitSingleSchema`,
82
+ `Permit2SubmitSchema`, `Permit3AllowanceSchema`, `Permit3PayloadSchema`, `Permit3SubmitSchema` are
83
+ back. Path order in the document is `erc-3009`, `permit2`, `permit3` — the matrix order — and
84
+ the tokens fixture advertises the same three under `supports.quote`.
85
+
86
+ **The bodies are NOT the `0.5.0` bodies.** A consumer skipping `0.6.0` (`0.5.0 -> 0.7.0`) sees
87
+ SIX newly-required fields, and a `0.5.0` body is a 400 at these paths. This is the material the
88
+ solver's DTOs require and verify, which the `0.5.0` shapes omitted:
89
+
90
+ ```diff
91
+ // POST /v1/intents/submit/permit2
92
+ {
93
+ + "chainId": 8453,
94
+ "target": { "quoteId": "quote:…" },
95
+ "permit2": {
96
+ "details": { "token": "0x…", "amount": "1043221", "expiration": 1767225600, "nonce": 0 },
97
+ - "spender": "<anything>",
98
+ + "spender": "<execution.vault of the quote>",
99
+ - "sigDeadline": 1767225600
100
+ + "sigDeadline": "1767225600"
101
+ },
102
+ "signature": "0x…"
103
+ }
104
+ ```
105
+
106
+ ```diff
107
+ // POST /v1/intents/submit/permit3
108
+ {
109
+ "target": { "quoteId": "quote:…" },
110
+ "permit3": {
111
+ "owner": "0x…",
112
+ + "permitContract": "0x…",
113
+ "salt": "0x…",
114
+ "deadline": 1767225600,
115
+ + "timestamp": 1767222000,
116
+ + "merkleRoot": "0x…",
117
+ "permits": [
118
+ - { "chainId": 8453, "token": "0x…", "amount": "1043221" }
119
+ + { "chainId": 8453, "token": "0x…", "amount": "1043221",
120
+ + "account": "<execution.vault of the quote>", "modeOrExpiration": 0 }
121
+ ]
122
+ },
123
+ "signature": "0x…"
124
+ }
125
+ ```
126
+
127
+ - **permit2 `chainId` (top-level, required)** is the EIP-712 domain chainId the signature was
128
+ produced under and the chain the permit executes on; the solver verifies the two agree. It
129
+ follows the C4 convention `erc-3009` and `erc-2612` already use.
130
+ - **permit3 has NO top-level `chainId`**, deliberately: its EIP-712 domain is not the source
131
+ chain, and each leg names its own chain. A consumer that needs one chain id for the body takes
132
+ `permits[0].chainId`. It also carries no `leaves` and no `tokenKey` — the solver recomputes the
133
+ merkle tree from the legs, and `tokenKey` is `pad(token, 32)` (ERC-20 only) by definition.
134
+ - **permit3 `permitContract`, `timestamp`, `merkleRoot`** are the signer's values, never
135
+ synthesized: the solver recomputes the root from the legs and rejects a mismatch.
136
+ - **permit3 leg `account` and `modeOrExpiration`**: `account` is where the leg pushes funds
137
+ (mode `0`, immediate transfer) or grants the allowance (any other value, read as the allowance
138
+ expiration in Unix seconds). On a quote target it is always the vault.
139
+ - **`nonce`, `expiration`, `timestamp` and `modeOrExpiration` are `Uint48`**, a new primitive
140
+ (with `UINT48_MAX`, `2^48 - 1`): the fields are uint48 on-chain and the ABI encoder truncates
141
+ rather than rejects, so the edge does. Expressed as bounds so the ceiling reaches the OpenAPI
142
+ document.
143
+ - **permit2 `sigDeadline` is a decimal STRING (`UintString`), and `details.expiration` a
144
+ `Uint48`** — both carry their on-chain width instead of `UnixSeconds`. The Permit2 SDK's
145
+ `MaxAllowanceExpiration` (`2^48-1`) and `MaxSigDeadline` (`2^256-1`) are the standard "no
146
+ expiry" idiom many wallets sign, and a `<=2100` bound rejected a valid signature that would
147
+ have funded. Same narrow exception erc-3009's `validAfter`/`validBefore` carry; a NUMBER
148
+ `sigDeadline` is a 400 at `permit2.sigDeadline`. Every other deadline in the module
149
+ (`permit3.deadline`, erc-2612's) is still `UnixSeconds` and still rejects a milliseconds value.
150
+ - **`Permit3PayloadSchema` stays a plain stripping `z.object`.** A `permit3.signature` sent in
151
+ the wrong place is dropped, so a reader has exactly one place to find the signature.
152
+
153
+ **What the schema does NOT check, and the router does.** The body carries no vault, so the vault
154
+ binding cannot be a refinement here (`refineDepositAddressBinding` is a no-op on quote targets by
155
+ construction). Before the signature pin the router asserts, per lane: the signed counterparty
156
+ (`permit2.spender`, every `permits[].account`) equals the quote's `execution.vault` — compared
157
+ CASE-INSENSITIVELY (`isSameEvmAddress`, exported here), since neither side is checksum-normalized
158
+ and a naive `===` turns a checksummed vault against a lowercase signature into a spurious 400 —
159
+ else `vault-mismatch` (400); every permit3 leg `chainId` and the permit2 `chainId` equal the quote's
160
+ source chain; the token equals the quote's source token and the amount is at least the reward
161
+ amount for it; `permit2.details.expiration`, `permit2.sigDeadline`, `permit3.deadline` and a
162
+ non-zero `modeOrExpiration` are all more than 60 seconds in the future (a stale authorisation is a
163
+ 400, not a reverting funding batch). A green parse is not a green submit.
164
+
165
+ **Added — `execution.vault` on every quote object (optional, nullable, `AnyAddress`).** The
166
+ intent vault for THIS quote: the CREATE2 address the source-chain Portal funds the intent
167
+ through, derived from the quoted intent (route.salt included), so it changes whenever the salt
168
+ does. It is the value to sign as erc-3009 `authorization.to`, permit2 `spender` and every permit3
169
+ leg `account`. **Absent means the producer predates the field; `null` means the producer could
170
+ not derive it** — today that is any non-EVM source (an SVM vault is a PDA and is not published).
171
+ `AnyAddress` rather than `EvmAddress` because the same envelope carries SVM funding transactions
172
+ and a future SVM producer must be able to publish the PDA here without a shape break; as always,
173
+ never infer a VM from the branch that matched. Each ranked `quotes[]` entry carries its own. The
174
+ zod-free `V1Execution` alias gains `vault?: string | null`, and the parity spec pins the optional
175
+ member explicitly (an optional key is the one drift the mutual-assignability gate cannot see
176
+ through a `looseObject`'s index signature).
177
+
178
+ **Added — `vault-mismatch` (400): the signed counterparty is not the quote's intent vault.** The
179
+ quote-target twin of `deposit-address-mismatch`, which is the wrong NAME on a quote target (there
180
+ is no deposit address) — and `invalid-parameter` says nothing a caller can act on. `audience:
181
+ 'write'` — like the twin it needs a signed counterparty, so only a submit can emit it — and
182
+ `legacyCodes: []` (no legacy service ever compared against a vault). A router's
183
+ `detail` names the field (`permit2.spender`, `permit3.permits[1].account`, `authorization.to`),
184
+ never the signed address. Branch on `code`: it shares 400 with `invalid-request`.
185
+
186
+ ## Migrating 0.5.0 -> 0.6.0
187
+
188
+ **BREAKING under 0.x semver** (breaking bumps the minor while the major is 0). Five items REJECT
189
+ a request `0.5.0` accepted or remove something `0.5.0` published; four are additive. Every
190
+ breaking item is listed here — if you send anything named below, read its entry before bumping.
191
+
192
+ **`V1_SCHEMA_DIGEST` MOVES.** Both digest inputs changed (`errors/catalog.lock.json` gained one
193
+ code; `openapi/v1.json` lost two operations, gained two parameters and several descriptions), so
194
+ the value is now `a6724fa4dd585e77aebe680655ac10fe5a2f4b70537930a0b4dee2612afb7c8e` — was
195
+ `1d8e88e957795b23e1317dc1e3783fd64bf79b756e3f28bd40e02b047542d790` on `0.4.0`, `0.4.1` and
196
+ `0.5.0`. Every consumer running `assertNoSkew` must move to the new value **in the same
197
+ rollout**. Unlike `0.5.0`, this time the skew check DOES see the difference, so a mixed fleet
198
+ fails it by design rather than silently validating two ways.
199
+
200
+ **THE FIVE BREAKING ITEMS FIRST.**
201
+
202
+ **1. `slippage` now rejects `0` and anything below `0.0001`, and the rejection is named.**
203
+
204
+ ```ts
205
+ // 0.5.0: parses (and then fails downstream). 0.6.0: 400, code slippage-out-of-bounds, path ['slippage'].
206
+ { ..., slippage: 0 }
207
+ { ..., slippage: 0.00005 }
208
+ ```
209
+
210
+ The range is `0.0001`-`1` (`SLIPPAGE_MIN`/`SLIPPAGE_MAX`, both exported), a DECIMAL FRACTION of
211
+ the destination amount: `0.005` is 0.5%. No solver can express a tolerance below one basis
212
+ point, so a `0` could only ever be rejected downstream, silently clamped, or silently replaced
213
+ by a default; refusing it at the edge with a named code is the honest one. Zero tolerance is
214
+ meaningless on a swap route and ignored on a non-swap route, so nothing is lost.
215
+
216
+ **The code changes for EVERY out-of-range value, not only the new floor.** `0.5.0` enforced the
217
+ bound with a built-in `.min()/.max()`, which zod reports as `too_small`/`too_big` — and
218
+ `v1ErrorCodeFromIssues` maps only a `custom` issue carrying `v1IssueParams`, so the catalog's
219
+ `slippage-out-of-bounds` was promised and unreachable: `50` rendered as the generic
220
+ `invalid-request` with `legacyCode: eco-quotes:1003`. It now renders as
221
+ `slippage-out-of-bounds` (status 400 unchanged, `detail` text unchanged, no `legacyCode`
222
+ because that code has none). An integrator branching on `code === 'invalid-request'` for a
223
+ bad slippage, or reading `legacyCode` there, sees the change. The catalog TITLE names the
224
+ floor now; code, status and `legacyCodes` are untouched.
225
+
226
+ The published document also carries the units for the first time: both `slippage` fields have a
227
+ `description`, and the request field keeps `minimum`/`maximum` (via `.meta()`, since the bound
228
+ itself lives in a refinement that `z.toJSONSchema` drops). The response `slippage` is documented
229
+ as the tolerance ACTUALLY bound into `destination.minAmountOut` — when a request omits
230
+ `slippage`, that is the default the solver applied, not the omission.
231
+
232
+ **2. A zero `amount` is rejected on the quote request.**
233
+
234
+ ```ts
235
+ // 0.5.0: parses, reaches a solver, comes back as a 502. 0.6.0: 400, path ['source','amount'].
236
+ { ..., source: { chainId: 8453, token: '0x…', amount: '0' } }
237
+ ```
238
+
239
+ `source.amount` and `destination.amount` are `PositiveUintString` (new primitive: `UintString`
240
+ with `'0'` excluded, message `must be greater than 0`). Every other `UintString` field is
241
+ unchanged — a zero `value` on a destination call or a zero fee is still legal. The bound reaches
242
+ the OpenAPI document as a `description` only; a string has no `minimum`.
243
+
244
+ **3. `options.maxCallDataSize` is gone.**
245
+
246
+ ```ts
247
+ // 0.5.0: parses. 0.6.0: 400, unrecognized_keys at path ['options'].
248
+ { ..., options: { maxCallDataSize: 1000 } }
249
+ ```
250
+
251
+ It was published with no description and read by no service, so a caller sending it was handed
252
+ a 200 for a bound nobody enforced. The strict `options` object now names the key in a 400, the
253
+ same disposition `allowHighSlippage` has had since `0.3.0`. The zod-free `V1QuoteRequest` alias
254
+ drops the member too. A caller that needs a calldata cap needs one that is defined and enforced,
255
+ which is a different change.
256
+
257
+ **4. `POST /v1/intents/submit/permit2` and `/permit3` are WITHDRAWN.** (Superseded by `0.7.0`,
258
+ which returns both lanes with the fields named below — see that section.)
259
+
260
+ Neither lane can complete, and this is why. The signed Permit2 `spender` and every Permit3 leg
261
+ `account` must be the intent VAULT (`Portal.fundFor` pulls the funds through
262
+ `IPermit.transferFrom(funder, vault)`), and the vault is derived from the route salt the router
263
+ dispatches — a value the signer cannot know before signing until quoted-salt dispatch and vault
264
+ binding exist. On top of that the published bodies omitted material the solver requires (permit2
265
+ `chainId`; permit3 `permitContract`, `timestamp`, `merkleRoot`, per-leg `account` /
266
+ `modeOrExpiration`), so the first refusal was a 401 on every request. Advertising a lane whose
267
+ every body ends in a 4xx is a false promise. The lanes return as a follow-on once quoted-salt
268
+ dispatch and vault binding land; `erc-3009` is the quote-target intents standard until then.
269
+
270
+ What moved, concretely:
271
+
272
+ - `STANDARDS_BY_TARGET.quote` is `['erc-3009']`. `depositAddress` is unchanged.
273
+ - The two registry entries, the two operations in `openapi/v1.json`, and the two golden fixtures
274
+ are gone (11 endpoints over 10 paths; 17 fixtures). A router that dispatches from
275
+ `V1_SUBMIT_SCHEMAS_BY_SERVICE.intents` answers `invalid-parameter` on those routes by
276
+ construction.
277
+ - **Five exports are deleted:** `Permit3AllowanceSchema`, `Permit3PayloadSchema`,
278
+ `Permit3SubmitSchema`, `Permit2PermitSingleSchema`, `Permit2SubmitSchema`. No endpoint accepts
279
+ those bodies, so there is nothing for them to validate.
280
+ - **`V1_SUBMIT_SCHEMAS` is keyed by the new `LaneStandard` type** (`'erc-3009' | 'erc-2612'` —
281
+ the standards that have a lane), not by `SubmitStandard`. `V1_SUBMIT_SCHEMAS[standard]` with
282
+ a `SubmitStandard`-typed index no longer compiles; narrow to `LaneStandard` first. That is the
283
+ intended signal — the alternative was an `undefined` a dispatcher trips over at runtime.
284
+ - **`SUBMIT_STANDARDS` and `SubmitStandard` KEEP all four spellings.** That enum is also the
285
+ discovery vocabulary a token advertises under `supports`, and narrowing it would make a
286
+ consumer hard-fail on a token list from a server still spelling `permit3`. The vocabulary is
287
+ what a token MAY advertise; the matrix is what has a lane. The tokens fixture advertises
288
+ `quote: ['erc-3009']`.
289
+
290
+ **5. Consumer-side only, but read it: the lock gained a 502.** `V1ProblemSchema` cross-checks a
291
+ KNOWN code's `status`/`type` against the catalog. `solver-error` (below) is now known, so a body
292
+ carrying that spelling with a contradicting status or type stops parsing where `0.5.0` tolerated
293
+ it as "a newer server". An exhaustive `switch` over `V1ErrorCode` will not compile until it
294
+ handles it.
295
+
296
+ **THE FOUR ADDITIVE ITEMS.**
297
+
298
+ **Added — `solver-error` (502): an upstream solver rejected or failed the quote request.**
299
+ `solver-timeout` was the only 502, so a router had to label a solver answering 400 in six
300
+ milliseconds with a title that says "timed out". `solver-error` is the code for every upstream
301
+ failure that is NOT a deadline expiry — a solver 4xx/5xx, a network error, an unparseable body.
302
+ It is 502 rather than 4xx/422 on purpose: the gateway built the RFQ, so a solver rejection is a
303
+ gateway/contract fault, never the caller's, and a 422 mapping would hide a contract bug as "no
304
+ route". `legacyCodes` is EMPTY by construction: `eco-quotes:1025` (Failed) is the ref that would
305
+ belong here, but it was published on `solver-timeout` and the lock is append-only, so it stays
306
+ there. Branch on `code`, not on `status`, to tell the two 502s apart.
307
+
308
+ **Added — `?chainId=` on `GET /v1/chains` and `GET /v1/tokens`.** OPTIONAL on both (the
309
+ unfiltered document is unchanged and stays legal), a single value only. A malformed value —
310
+ `abc`, `0`, `-1`, `1.5`, or a repeated `?chainId=1&chainId=8453` — is a 400 at the field; a
311
+ syntactically valid chain id that matches nothing is a 200 with `chains: []` /
312
+ `tokens: [], nextCursor: null`, never a 404. New exports: `CHAINS_LIST_QUERY_SHAPE` /
313
+ `ChainsListQuerySchema`, `TOKENS_LIST_QUERY_SHAPE` / `TokensListQuerySchema`, and `ChainIdParam`
314
+ (the coercing query-string twin of the body `ChainId`, which all three `chainId` query params —
315
+ these two and the deposit-address lookup's — now wrap, so the accepted set cannot differ between
316
+ endpoints publishing the same parameter name). Query-side only: never coerce a chain id in a
317
+ JSON body.
318
+
319
+ **Added — `renderIssuesAsProblemParts(issues, opts?) -> { code, detail?, errors? }`, THE one
320
+ sanctioned path from a `ZodError` to a problem body.** Two services rendered the same validation
321
+ failure with a cap of 4 and a cap of 10, a `(+N more issues)` suffix and an `N issues, first M:`
322
+ prefix, a bare root message and a `(root)` placeholder, and only one of them emitted `errors[]`.
323
+ This function is the single set of conventions: cap `MAX_DETAIL_ISSUES` (8, now exported) for
324
+ both `detail` and `errors`; overflow is ONE trailing `(+N more issues)`; a root-level issue is
325
+ its bare message; `errors` carries bare dotted fields and is omitted when nothing survives.
326
+ Absent keys are absent, so the result spreads straight into `problem(code, rest)` or your own
327
+ builder. `problemFromZodError` is built on it and a test pins that the two produce byte-identical
328
+ bodies. A service with its own problem type should route every `ZodError` through here and
329
+ delete its local cap and overflow constants.
330
+
331
+ **Added — execution detail on a status entry.** `StatusEntrySchema` and `statusEntrySchemaFor`
332
+ gain three OPTIONAL members: `sourceTx` and `destinationTx` as
333
+ `{ chainId, txHash, token, amount }`, and `steps[]` as
334
+ `{ type: 'SWAP' | 'BRIDGE', status, from, to, transactions: { created?, fulfilled?, refunded? } }`
335
+ with `{ token, amount, chainId }` legs and `{ chainId, txHash }` transaction refs. The shape
336
+ mirrors the solver's step facts verbatim; the step `type` is the producer's vocabulary (not the
337
+ quote-response `StepKind`) and the step `status` is the producer's raw per-step state beneath the
338
+ C1 entry-level vocabulary, deliberately unmapped. **Absent means unknown; `null` is rejected** —
339
+ a null would read as "known to be none" on a lane whose upstream simply has no token/amount.
340
+ Today the quote-status lane can populate them; the general intent-status lane omits them.
341
+ `chainId` is a JSON number (the solver spells it as a string; the producer converts), amounts
342
+ are uint strings, `token` is a bare string because the native asset may be a sentinel. New
343
+ schema exports `StatusTxRefSchema`, `StatusTokenAmountSchema`, `StatusTxDetailSchema`,
344
+ `StatusStepSchema`, `StatusStepType` / `STATUS_STEP_TYPES`; new zod-free aliases `V1StatusTxRef`,
345
+ `V1StatusTokenAmount`, `V1StatusTxDetail`, `V1StatusStep`, `V1StatusStepType`.
346
+
347
+ ## Migrating 0.4.1 -> 0.5.0
348
+
349
+ **BREAKING under 0.x semver** (breaking bumps the minor while the major is 0): this release
350
+ REJECTS a request body `0.4.1` accepted. Nothing else moved — no code, status, `legacyCodes`
351
+ mapping, or response shape changed.
352
+
353
+ **`V1_SCHEMA_DIGEST` DOES NOT MOVE, and that is the caveat to read before rolling out.** The new
354
+ rule is a `superRefine`, and `z.toJSONSchema` drops refinements, so neither digest input changed:
355
+ `openapi/v1.json` is byte-identical and `assertNoSkew` cannot see the difference. A fleet running
356
+ `0.4.1` and `0.5.0` side by side therefore passes the skew check while VALIDATING DIFFERENTLY —
357
+ the same body is a 400 on one instance and a 200 on another. Roll every consumer together, or
358
+ accept that inconsistency knowingly.
359
+
360
+ **Rejected — a `funder` that cannot share a chain with `source.token`.**
361
+
362
+ ```ts
363
+ // 0.4.1: parses. 0.5.0: 400, path ['funder'].
364
+ { source: { chainId: 1399811149, token: '<a Solana mint>' }, funder: '0x3333…3333' }
365
+ ```
366
+
367
+ Both fields live on the SOURCE chain, so an EVM funder beside a Solana source token describes no
368
+ chain that exists. It used to parse, get quoted, and then fail wherever a service classified the
369
+ funder against the source VM — and a service that read a malformed funder as ITS OWN material
370
+ answered `500 internal-error` for a field the caller sent.
371
+
372
+ **What this rule deliberately does NOT do: bind `funder` to `source.chainId`.** That needs a
373
+ chain-ID-to-VM table, and this package holds none by design — `ChainId` is any positive integer,
374
+ and `ADDRESS_BY_CHAIN_TYPE` exists for the caller that already knows the chain type. A table here
375
+ would make every published version an allow-list of chains: a newly launched SVM chain would be
376
+ misclassified by every consumer still on an older pin, and its valid base58 funder rejected, so
377
+ this package would have to be re-released and rolled out before a chain could launch. Comparing
378
+ two addresses from the same request needs no table and cannot go stale.
379
+
380
+ So the check is a NECESSARY condition, not a sufficient one, in two specific ways:
381
+
382
+ - **Two EVM addresses agree with each other whatever `chainId` says**, including a Solana chain id.
383
+ A green parse is not evidence the funder is right for the chain.
384
+ - **SVM and TVM are not separated.** A Tron base58check address also satisfies `SvmAddress`'s
385
+ 32-44 character range (see the `AnyAddress` docblock), so shape cannot decide between them and
386
+ the rule lets that pair through rather than guessing.
387
+
388
+ A service that knows the chain's VM must still check each address against it. Two new exports help:
389
+ `addressFamilies(value)` returns every family a value is consistent with, and
390
+ `addressFamiliesCanAgree(a, b)` is the pairwise predicate the refinement uses.
391
+
33
392
  ## Migrating 0.4.0 -> 0.4.1
34
393
 
35
394
  Purely additive; no schema, wire, or digest change. `V1_SCHEMA_DIGEST` is UNCHANGED, so this is
@@ -550,10 +909,10 @@ which needs no server.
550
909
  build → lint:check → test → catalog:check → openapi:check → digest:check
551
910
  ```
552
911
 
553
- Both `.github/workflows/ci.yml` (every PR) and `.github/workflows/publish-api-schemas.yml`
912
+ Both `.github/workflows/ci.yml` (every PR) and `.github/workflows/publish.yml`
554
913
  (every release tag) run exactly that one command.
555
914
 
556
- **The `verify`-before-`publish` step in the publish workflow is load-bearing — do not
915
+ **The `verify`-before-`stage` step in the release workflow is load-bearing — do not
557
916
  streamline it away.** `build` uses `tsconfig.build.json`, which excludes `src/**/*.spec.ts`, so
558
917
  the compile-time gates that live in spec files — most importantly the `v1/types` parity gate —
559
918
  cannot fail `build`. They fail `test`. Publishing without running `verify` would therefore ship
@@ -577,13 +936,37 @@ Two `catalog:check` outcomes are NOT failures and must not be confused with each
577
936
 
578
937
  ## Publishing
579
938
 
580
- Tag `v<version>` (must equal `package.json` version) — the `publish` workflow verifies and
581
- publishes. It needs the `NPM_TOKEN` repo secret (an npm automation token with publish rights on
582
- `@eco-foundation`). It fails with `::error::tag version <x> != package version <y>`
583
- if the two drift, so a stale tag can never publish a mismatched artifact.
939
+ Publishing is **two steps, and CI only does the first one.**
940
+
941
+ **1. Tag `v<version>`** (must equal `package.json` version). The `Stage release` workflow
942
+ verifies and then runs `npm stage publish`, which uploads the tarball to npm in a pending state.
943
+ It fails with `::error::tag version <x> != package version <y>` if the two drift, so a stale tag
944
+ can never stage a mismatched artifact. It needs the `NPM_TOKEN` repo secret: a granular token
945
+ scoped to `@eco-foundation` with **"Read and write (stage only)"** rights.
946
+
947
+ **A green run means the version is QUEUED, not released.** Nobody can install it yet.
948
+
949
+ **2. A maintainer promotes it**, which costs a 2FA challenge:
950
+
951
+ ```
952
+ npm stage list @eco-foundation/api-schemas
953
+ npm stage approve <stage-id> # or: npm stage reject <stage-id>
954
+ ```
955
+
956
+ The queue is also visible on npmjs.com, and the workflow's run summary repeats these commands.
957
+
958
+ Why the split: npm removes direct publish from granular access tokens in **January 2027**, and
959
+ an approval cannot be satisfied by any CI credential — token or OIDC — by design. A stolen
960
+ runner token can queue a release; it can never ship one. `npm stage approve` needs npm ≥
961
+ `11.15.0` locally, same as CI.
962
+
963
+ Two staging rules worth knowing before you tag. The dist-tag is **immutable once staged** — it
964
+ cannot be changed on the way to approval, only rejected and re-staged — and a version that is
965
+ already staged cannot be staged again, so a re-tag of a queued version fails until the queued
966
+ one is approved or rejected.
584
967
 
585
968
  Semver: breaking schema change = major, additive = minor; consumers pin minor. **While the
586
- package is 0.x, "pin minor" means `~0.4.1` or the exact `0.4.1` — never `^0`** (see
969
+ package is 0.x, "pin minor" means `~0.7.0` or the exact `0.7.0` — never `^0`** (see
587
970
  [Install](#install)). Consumers additionally compare `V1_SCHEMA_DIGEST`: a matching version
588
971
  string is not evidence of a matching artifact. `/v1/routes` is draft-tagged and exempt until its
589
972
  stability flips.
@@ -29,9 +29,9 @@ const FIXTURE_BINDINGS = [
29
29
  bind('quotes.create', 'response', 'public-swap', quotes_create_response_public_swap_json_1.default),
30
30
  bind('quotes.create', 'response', 'private-swap', quotes_create_response_private_swap_json_1.default),
31
31
  bind('quotes.create', 'response', 'all-quotes', quotes_create_response_all_quotes_json_1.default),
32
- bind('intents.submit.permit3', 'request', 'quote-target', intents_submit_permit3_request_quote_target_json_1.default),
33
- bind('intents.submit.permit2', 'request', 'quote-target', intents_submit_permit2_request_quote_target_json_1.default),
34
32
  bind('intents.submit.erc-3009', 'response', 'job', intents_submit_erc_3009_response_job_json_1.default),
33
+ bind('intents.submit.permit2', 'request', 'quote-target', intents_submit_permit2_request_quote_target_json_1.default),
34
+ bind('intents.submit.permit3', 'request', 'quote-target', intents_submit_permit3_request_quote_target_json_1.default),
35
35
  bind('deposit-addresses.submit.erc-3009', 'request', 'deposit-address-target', deposit_addresses_submit_erc_3009_request_deposit_address_target_json_1.default),
36
36
  bind('deposit-addresses.submit.erc-2612', 'request', 'deposit-address-target', deposit_addresses_submit_erc_2612_request_deposit_address_target_json_1.default),
37
37
  bind('intents.status', 'response', 'intent-filled', intents_status_response_intent_filled_json_1.default),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"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"}
@@ -7,18 +7,19 @@
7
7
  "expectedStatus": 202,
8
8
  "sideEffect": true,
9
9
  "payload": {
10
+ "chainId": 8453,
10
11
  "target": {
11
12
  "quoteId": "quote:8f14e45f-ea3c-4c2d-9b6e-1a2b3c4d5e6f"
12
13
  },
13
14
  "permit2": {
14
15
  "details": {
15
- "token": "0x2222222222222222222222222222222222222222",
16
+ "token": "0x1111111111111111111111111111111111111111",
16
17
  "amount": "1043221",
17
18
  "expiration": 1767225600,
18
19
  "nonce": 0
19
20
  },
20
- "spender": "0x1111111111111111111111111111111111111111",
21
- "sigDeadline": 1767225600
21
+ "spender": "0x5555555555555555555555555555555555555555",
22
+ "sigDeadline": "1767225600"
22
23
  },
23
24
  "signature": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
24
25
  }
@@ -11,14 +11,19 @@
11
11
  "quoteId": "quote:8f14e45f-ea3c-4c2d-9b6e-1a2b3c4d5e6f"
12
12
  },
13
13
  "permit3": {
14
- "owner": "0x1111111111111111111111111111111111111111",
14
+ "owner": "0x3333333333333333333333333333333333333333",
15
+ "permitContract": "0x6666666666666666666666666666666666666666",
15
16
  "salt": "0xabababababababababababababababababababababababababababababababab",
16
17
  "deadline": 1767225600,
18
+ "timestamp": 1767222000,
19
+ "merkleRoot": "0x7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a",
17
20
  "permits": [
18
21
  {
19
22
  "chainId": 8453,
20
- "token": "0x2222222222222222222222222222222222222222",
21
- "amount": "1043221"
23
+ "token": "0x1111111111111111111111111111111111111111",
24
+ "amount": "1043221",
25
+ "account": "0x5555555555555555555555555555555555555555",
26
+ "modeOrExpiration": 0
22
27
  }
23
28
  ]
24
29
  },
@@ -149,7 +149,8 @@
149
149
  }
150
150
  },
151
151
  "encodedRoute": "0xdead",
152
- "encodedReward": "0xbeef"
152
+ "encodedReward": "0xbeef",
153
+ "vault": "0x5555555555555555555555555555555555555555"
153
154
  },
154
155
  "expiresAt": 1767225600,
155
156
  "signature": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
@@ -297,7 +298,8 @@
297
298
  }
298
299
  },
299
300
  "encodedRoute": "0xdead",
300
- "encodedReward": "0xbeef"
301
+ "encodedReward": "0xbeef",
302
+ "vault": "0x5555555555555555555555555555555555555555"
301
303
  },
302
304
  "expiresAt": 1767225600,
303
305
  "signature": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
@@ -445,7 +447,8 @@
445
447
  }
446
448
  },
447
449
  "encodedRoute": "0xdead",
448
- "encodedReward": "0xbeef"
450
+ "encodedReward": "0xbeef",
451
+ "vault": "0x7777777777777777777777777777777777777777"
449
452
  },
450
453
  "expiresAt": 1767225600,
451
454
  "signature": "0x9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a9a"
@@ -143,7 +143,8 @@
143
143
  }
144
144
  },
145
145
  "encodedRoute": null,
146
- "encodedReward": null
146
+ "encodedReward": null,
147
+ "vault": "0x5555555555555555555555555555555555555555"
147
148
  },
148
149
  "expiresAt": 1767225600,
149
150
  "signature": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
@@ -149,7 +149,8 @@
149
149
  }
150
150
  },
151
151
  "encodedRoute": "0xdead",
152
- "encodedReward": "0xbeef"
152
+ "encodedReward": "0xbeef",
153
+ "vault": "0x5555555555555555555555555555555555555555"
153
154
  },
154
155
  "expiresAt": 1767225600,
155
156
  "signature": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
@@ -14,7 +14,7 @@
14
14
  "symbol": "USDC",
15
15
  "decimals": 6,
16
16
  "supports": {
17
- "quote": ["permit3", "permit2", "erc-3009"],
17
+ "quote": ["erc-3009", "permit2", "permit3"],
18
18
  "depositAddress": ["erc-2612", "erc-3009"]
19
19
  }
20
20
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "digest": "1d8e88e957795b23e1317dc1e3783fd64bf79b756e3f28bd40e02b047542d790",
2
+ "digest": "3e13c5eeb8b054f3a48a22c7694de16b0fc11e1dbf6bc3c27e8c575100225b2a",
3
3
  "inputs": [
4
4
  "errors/catalog.lock.json",
5
5
  "openapi/v1.json"
package/dist/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export { generateOpenApiDocument, STABLE_TAG } from './openapi';
3
3
  export type { V1Fixture } from './testing';
4
4
  export { assertMatchesV1Schema, loadV1Fixtures } from './testing';
5
5
  export * as v1 from './v1';
6
- export type { LegacyCodeRef, V1Chain, V1ChainType, V1DepositAddress, V1DepositAddressChainStatus, V1DepositAddressCreateRequest, V1DepositAddressCreateResponse, V1DepositAddressKind, V1DestinationCall, V1ErrorCode, V1ErrorDefinition, V1Execution, V1Fee, V1FeeKind, V1FeeToken, V1FundingTransaction, V1GaslessJob, V1GaslessJobStatus, V1GaslessSubState, V1GaslessSubStatus, V1Guarantee, V1IntentCall, V1IntentReward, V1IntentRoute, V1IntentTokenAmount, V1ProblemBody, V1QuoteCore, V1QuoteRequest, V1QuoteResponse, V1RankedQuoteEntry, V1RelatedIntent, V1RelatedIntentRole, V1SolverIdentity, V1StatusEntry, V1StatusType, V1Step, V1StepKind, V1StepLeg, V1SvmAccountMeta, V1SvmInstruction, V1SwapType, V1TokenEntry, V1Visibility, } from './v1/types';
6
+ export type { LegacyCodeRef, V1Chain, V1ChainType, V1DepositAddress, V1DepositAddressChainStatus, V1DepositAddressCreateRequest, V1DepositAddressCreateResponse, V1DepositAddressKind, V1DestinationCall, V1ErrorCode, V1ErrorDefinition, V1Execution, V1Fee, V1FeeKind, V1FeeToken, V1FundingTransaction, V1GaslessJob, V1GaslessJobStatus, V1GaslessSubState, V1GaslessSubStatus, V1Guarantee, V1IntentCall, V1IntentReward, V1IntentRoute, V1IntentTokenAmount, V1ProblemBody, V1QuoteCore, V1QuoteRequest, V1QuoteResponse, V1RankedQuoteEntry, V1RelatedIntent, V1RelatedIntentRole, V1SolverIdentity, V1StatusEntry, V1StatusStep, V1StatusStepType, V1StatusTokenAmount, V1StatusTxDetail, V1StatusTxRef, V1StatusType, V1Step, V1StepKind, V1StepLeg, V1SvmAccountMeta, V1SvmInstruction, V1SwapType, V1TokenEntry, V1Visibility, } from './v1/types';
@@ -1,4 +1,11 @@
1
1
  import { z } from 'zod';
2
+ export declare const CHAINS_LIST_QUERY_SHAPE: {
3
+ chainId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
4
+ };
5
+ export declare const ChainsListQuerySchema: z.ZodObject<{
6
+ chainId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
7
+ }, z.core.$strip>;
8
+ export type ChainsListQuery = z.infer<typeof ChainsListQuerySchema>;
2
9
  export declare const ChainContractsSchema: z.ZodObject<{
3
10
  portal: z.ZodUnion<readonly [z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodString]>, z.ZodString]>;
4
11
  executor: z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodString]>, z.ZodString]>>;
@@ -1,10 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ChainsResponseSchema = exports.V1LimitsSchema = exports.ChainSchema = exports.ChainContractsSchema = void 0;
3
+ exports.ChainsResponseSchema = exports.V1LimitsSchema = exports.ChainSchema = exports.ChainContractsSchema = exports.ChainsListQuerySchema = exports.CHAINS_LIST_QUERY_SHAPE = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const enums_1 = require("../enums");
6
6
  const primitives_1 = require("../primitives");
7
7
  const status_1 = require("./status");
8
+ exports.CHAINS_LIST_QUERY_SHAPE = {
9
+ chainId: primitives_1.ChainIdParam.optional(),
10
+ };
11
+ exports.ChainsListQuerySchema = zod_1.z.object(exports.CHAINS_LIST_QUERY_SHAPE);
8
12
  exports.ChainContractsSchema = zod_1.z.looseObject({
9
13
  portal: primitives_1.AnyAddress,
10
14
  executor: primitives_1.AnyAddress.nullable(),