@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.
- package/CHANGELOG.md +64 -0
- package/LICENSE +21 -0
- package/README.md +120 -2
- package/dist/cjs/claim.d.ts +33 -0
- package/dist/cjs/claim.js +44 -0
- package/dist/cjs/fee.d.ts +247 -0
- package/dist/cjs/fee.js +295 -0
- package/dist/cjs/index.d.ts +18 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/machine/claimInfo.d.ts +29 -0
- package/dist/cjs/machine/claimInfo.js +26 -0
- package/dist/cjs/machine/decisions.d.ts +452 -0
- package/dist/cjs/machine/decisions.js +665 -0
- package/dist/cjs/machine/deposit.d.ts +113 -0
- package/dist/cjs/machine/deposit.js +265 -0
- package/dist/cjs/machine/index.d.ts +23 -0
- package/dist/cjs/machine/index.js +53 -0
- package/dist/cjs/machine/machine.d.ts +411 -0
- package/dist/cjs/machine/machine.js +1627 -0
- package/dist/cjs/machine/phase.d.ts +24 -0
- package/dist/cjs/machine/phase.js +45 -0
- package/dist/cjs/machine/quoteChecks.d.ts +41 -0
- package/dist/cjs/machine/quoteChecks.js +82 -0
- package/dist/cjs/machine/receipt.d.ts +151 -0
- package/dist/cjs/machine/receipt.js +69 -0
- package/dist/cjs/machine/recipientEcho.d.ts +16 -0
- package/dist/cjs/machine/recipientEcho.js +27 -0
- package/dist/cjs/machine/solverPin.d.ts +110 -0
- package/dist/cjs/machine/solverPin.js +214 -0
- package/dist/cjs/machine/state.d.ts +167 -0
- package/dist/cjs/machine/state.js +31 -0
- package/dist/cjs/machine/transition.d.ts +15 -0
- package/dist/cjs/machine/transition.js +20 -0
- package/dist/cjs/machine/validateRequest.d.ts +15 -0
- package/dist/cjs/machine/validateRequest.js +127 -0
- package/dist/cjs/machine/view.d.ts +3 -0
- package/dist/cjs/machine/view.js +74 -0
- package/dist/cjs/machine/wire.d.ts +527 -0
- package/dist/cjs/machine/wire.js +280 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/shared/api.d.ts +9 -0
- package/dist/cjs/shared/api.js +5 -0
- package/dist/cjs/shared/chains.d.ts +243 -0
- package/dist/cjs/shared/chains.js +250 -0
- package/dist/cjs/shared/eip712.d.ts +44 -0
- package/dist/cjs/shared/eip712.js +64 -0
- package/dist/cjs/shared/index.d.ts +16 -0
- package/dist/cjs/shared/index.js +32 -0
- package/dist/cjs/shared/intentStream.d.ts +74 -0
- package/dist/cjs/shared/intentStream.js +59 -0
- package/dist/cjs/shared/intents.d.ts +88 -0
- package/dist/cjs/shared/intents.js +227 -0
- package/dist/cjs/shared/schemas.d.ts +928 -0
- package/dist/cjs/shared/schemas.js +524 -0
- package/dist/cjs/shared/shieldedPreview.d.ts +841 -0
- package/dist/cjs/shared/shieldedPreview.js +128 -0
- package/dist/cjs/shared/stealth.d.ts +53 -0
- package/dist/cjs/shared/stealth.js +68 -0
- package/dist/cjs/shared/trading.d.ts +153 -0
- package/dist/cjs/shared/trading.js +185 -0
- package/dist/cjs/shared/types.d.ts +37 -0
- package/dist/cjs/shared/types.js +7 -0
- package/dist/cjs/shared/validators.d.ts +30 -0
- package/dist/cjs/shared/validators.js +79 -0
- package/dist/cjs/transport/client.d.ts +234 -0
- package/dist/cjs/transport/client.js +1456 -0
- package/dist/esm/claim.d.ts +33 -0
- package/dist/esm/claim.js +41 -0
- package/dist/esm/fee.d.ts +247 -0
- package/dist/esm/fee.js +285 -0
- package/dist/esm/index.d.ts +18 -0
- package/dist/esm/index.js +17 -0
- package/dist/esm/machine/claimInfo.d.ts +29 -0
- package/dist/esm/machine/claimInfo.js +23 -0
- package/dist/esm/machine/decisions.d.ts +452 -0
- package/dist/esm/machine/decisions.js +640 -0
- package/dist/esm/machine/deposit.d.ts +113 -0
- package/dist/esm/machine/deposit.js +260 -0
- package/dist/esm/machine/index.d.ts +23 -0
- package/dist/esm/machine/index.js +23 -0
- package/dist/esm/machine/machine.d.ts +411 -0
- package/dist/esm/machine/machine.js +1621 -0
- package/dist/esm/machine/phase.d.ts +24 -0
- package/dist/esm/machine/phase.js +42 -0
- package/dist/esm/machine/quoteChecks.d.ts +41 -0
- package/dist/esm/machine/quoteChecks.js +78 -0
- package/dist/esm/machine/receipt.d.ts +151 -0
- package/dist/esm/machine/receipt.js +64 -0
- package/dist/esm/machine/recipientEcho.d.ts +16 -0
- package/dist/esm/machine/recipientEcho.js +24 -0
- package/dist/esm/machine/solverPin.d.ts +110 -0
- package/dist/esm/machine/solverPin.js +210 -0
- package/dist/esm/machine/state.d.ts +167 -0
- package/dist/esm/machine/state.js +28 -0
- package/dist/esm/machine/transition.d.ts +15 -0
- package/dist/esm/machine/transition.js +17 -0
- package/dist/esm/machine/validateRequest.d.ts +15 -0
- package/dist/esm/machine/validateRequest.js +123 -0
- package/dist/esm/machine/view.d.ts +3 -0
- package/dist/esm/machine/view.js +71 -0
- package/dist/esm/machine/wire.d.ts +527 -0
- package/dist/esm/machine/wire.js +266 -0
- package/dist/esm/shared/api.d.ts +9 -0
- package/dist/esm/shared/api.js +4 -0
- package/dist/esm/shared/chains.d.ts +243 -0
- package/dist/esm/shared/chains.js +236 -0
- package/dist/esm/shared/eip712.d.ts +44 -0
- package/dist/esm/shared/eip712.js +61 -0
- package/dist/esm/shared/index.d.ts +16 -0
- package/dist/esm/shared/index.js +16 -0
- package/dist/esm/shared/intentStream.d.ts +74 -0
- package/dist/esm/shared/intentStream.js +55 -0
- package/dist/esm/shared/intents.d.ts +88 -0
- package/dist/esm/shared/intents.js +213 -0
- package/dist/esm/shared/schemas.d.ts +928 -0
- package/dist/esm/shared/schemas.js +521 -0
- package/dist/esm/shared/shieldedPreview.d.ts +841 -0
- package/dist/esm/shared/shieldedPreview.js +124 -0
- package/dist/esm/shared/stealth.d.ts +53 -0
- package/dist/esm/shared/stealth.js +64 -0
- package/dist/esm/shared/trading.d.ts +153 -0
- package/dist/esm/shared/trading.js +182 -0
- package/dist/esm/shared/types.d.ts +37 -0
- package/dist/esm/shared/types.js +6 -0
- package/dist/esm/shared/validators.d.ts +30 -0
- package/dist/esm/shared/validators.js +74 -0
- package/dist/esm/transport/client.d.ts +234 -0
- package/dist/esm/transport/client.js +1447 -0
- package/package.json +61 -4
|
@@ -0,0 +1,236 @@
|
|
|
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
|
+
* The single source of truth for supported EVM chains.
|
|
15
|
+
*
|
|
16
|
+
* Keyed by slug rather than by id for two reasons: the slugs are themselves
|
|
17
|
+
* public API (`CHAIN_IDS.base`), and string keys preserve insertion order, so
|
|
18
|
+
* `SUPPORTED_CHAIN_IDS` keeps its declared order. Integer-like keys would be
|
|
19
|
+
* re-sorted ascending by the runtime, which would silently reorder the
|
|
20
|
+
* `/api/capabilities` fallback payload built from that array.
|
|
21
|
+
*
|
|
22
|
+
* Non-EVM and virtual chains are deliberately NOT here: Tron (base58 addresses,
|
|
23
|
+
* TronWeb signing, hash-route explorer) and the Aztec virtual source chain (0)
|
|
24
|
+
* are display-only, and join the extended maps below through their own
|
|
25
|
+
* constants. EVM-only code (viem/wagmi/RPC) must never receive those ids.
|
|
26
|
+
*
|
|
27
|
+
* Short names are the compact UI labels; explorers are the origins the link
|
|
28
|
+
* helpers below build on (one map, so per-component explorer maps cannot
|
|
29
|
+
* drift).
|
|
30
|
+
*/
|
|
31
|
+
export const CHAIN_REGISTRY = {
|
|
32
|
+
ethereum: { id: 1, name: "Ethereum", shortName: "ETH", explorer: "https://etherscan.io" },
|
|
33
|
+
optimism: {
|
|
34
|
+
id: 10,
|
|
35
|
+
name: "Optimism",
|
|
36
|
+
shortName: "OP",
|
|
37
|
+
explorer: "https://optimistic.etherscan.io",
|
|
38
|
+
},
|
|
39
|
+
polygon: {
|
|
40
|
+
id: 137,
|
|
41
|
+
name: "Polygon",
|
|
42
|
+
shortName: "POLY",
|
|
43
|
+
explorer: "https://polygonscan.com",
|
|
44
|
+
nativeCurrency: "POL",
|
|
45
|
+
},
|
|
46
|
+
arbitrum: { id: 42161, name: "Arbitrum", shortName: "ARB", explorer: "https://arbiscan.io" },
|
|
47
|
+
base: { id: 8453, name: "Base", shortName: "BASE", explorer: "https://basescan.org" },
|
|
48
|
+
robinhood: {
|
|
49
|
+
id: 4663,
|
|
50
|
+
name: "Robinhood",
|
|
51
|
+
shortName: "HOOD",
|
|
52
|
+
explorer: "https://robinhoodchain.blockscout.com",
|
|
53
|
+
},
|
|
54
|
+
arc: {
|
|
55
|
+
id: 5042,
|
|
56
|
+
name: "Arc",
|
|
57
|
+
shortName: "ARC",
|
|
58
|
+
explorer: "https://explorer.arc.io",
|
|
59
|
+
nativeCurrency: "USDC",
|
|
60
|
+
},
|
|
61
|
+
gnosis: {
|
|
62
|
+
id: 100,
|
|
63
|
+
name: "Gnosis",
|
|
64
|
+
shortName: "GNO",
|
|
65
|
+
explorer: "https://gnosisscan.io",
|
|
66
|
+
nativeCurrency: "xDAI",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
/** Registry entries in declaration order. */
|
|
70
|
+
const CHAIN_LIST = Object.values(CHAIN_REGISTRY);
|
|
71
|
+
/**
|
|
72
|
+
* Project the registry into a per-chain lookup.
|
|
73
|
+
*
|
|
74
|
+
* The assertion is confined to this helper: the loop writes exactly one entry
|
|
75
|
+
* per registry chain, so the result is exhaustive by construction, but TS cannot
|
|
76
|
+
* prove exhaustiveness of a runtime iteration. Call sites stay plain
|
|
77
|
+
* `Record<ChainId, T>` with no cast of their own.
|
|
78
|
+
*/
|
|
79
|
+
function byChainId(project) {
|
|
80
|
+
const lookup = {};
|
|
81
|
+
for (const chain of CHAIN_LIST)
|
|
82
|
+
lookup[chain.id] = project(chain);
|
|
83
|
+
return lookup;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Tron mainnet chain id. Tron is non-EVM (base58 addresses, TronWeb signing),
|
|
87
|
+
* so it is deliberately kept OUT of the EVM `ChainId` union -- EVM-only code
|
|
88
|
+
* (viem, wagmi, contract reads) must never receive it. UI-level chain selection
|
|
89
|
+
* uses `SelectableChainId` below.
|
|
90
|
+
*/
|
|
91
|
+
export const TRON_CHAIN_ID = 728_126_428;
|
|
92
|
+
/** Tron display names (Tron is outside CHAIN_REGISTRY, being non-EVM). */
|
|
93
|
+
export const TRON_CHAIN_NAME = "Tron";
|
|
94
|
+
export const TRON_SHORT_NAME = "TRON";
|
|
95
|
+
/** Type guard for the Tron mainnet chain id. */
|
|
96
|
+
export function isTronChainId(value) {
|
|
97
|
+
return value === TRON_CHAIN_ID;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Type guard for any chain the UI can render a link/name for (every EVM `ChainId`
|
|
101
|
+
* plus Tron). Guards raw `settlementChainId` values from Riddler -- which adds
|
|
102
|
+
* chains on its own cadence -- so an unknown id falls back to inference instead of
|
|
103
|
+
* producing a dead `href=""` or a `View undefined tx` label.
|
|
104
|
+
*/
|
|
105
|
+
export function isSelectableChainId(value) {
|
|
106
|
+
return isChainId(value) || isTronChainId(value);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Robinhood Chain (4663): an Arbitrum Orbit L2 whose native stablecoin is USDG
|
|
110
|
+
* (Global Dollar, Paxos). It has no USDC. The solver settles USDC<->USDG (and
|
|
111
|
+
* other stablecoin) cross-asset corridors to and from it. It is fully EVM (0x
|
|
112
|
+
* addresses, EIP-712 signing, Permit2 pull on USDG) and a first-class member
|
|
113
|
+
* of `ChainId`: the trade UI lists Robinhood + USDG, so the per-chain token
|
|
114
|
+
* maps carry it. USDG is a first-class token (see USDG_ADDRESSES in
|
|
115
|
+
* tokens.ts), never shoehorned into USDC_ADDRESSES (that map is Permit2-free
|
|
116
|
+
* ERC-3009 USDC only, and USDG supports neither ERC-3009 nor EIP-2612).
|
|
117
|
+
* `ROBINHOOD_CHAIN_ID` is kept for readable references and the settleable
|
|
118
|
+
* guards below.
|
|
119
|
+
*/
|
|
120
|
+
export const ROBINHOOD_CHAIN_ID = 4663;
|
|
121
|
+
/** Type guard for the Robinhood Chain id. */
|
|
122
|
+
export function isRobinhoodChainId(value) {
|
|
123
|
+
return value === ROBINHOOD_CHAIN_ID;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Arc chain id. Arc is Circle's EVM-compatible L1 where USDC is the native
|
|
127
|
+
* gas token (18 dec protocol-level, 6 dec ERC-20). No WETH, no ETH --
|
|
128
|
+
* stablecoin-only chain. Feature-flagged behind ARC_LIVE.
|
|
129
|
+
*/
|
|
130
|
+
export const ARC_CHAIN_ID = 5042;
|
|
131
|
+
/** Type guard for the Arc chain id. */
|
|
132
|
+
export function isArcChainId(value) {
|
|
133
|
+
return value === ARC_CHAIN_ID;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Gnosis Chain id. Native gas is xDAI. Xochi lists a single token here,
|
|
137
|
+
* Monerium EURe (18 dec, no ERC-3009, Permit2 pull); there is no WETH or USDC
|
|
138
|
+
* leg. Feature-flagged in the UI behind GNOSIS_LIVE.
|
|
139
|
+
*/
|
|
140
|
+
export const GNOSIS_CHAIN_ID = 100;
|
|
141
|
+
/** Type guard for the Gnosis Chain id. */
|
|
142
|
+
export function isGnosisChainId(value) {
|
|
143
|
+
return value === GNOSIS_CHAIN_ID;
|
|
144
|
+
}
|
|
145
|
+
/** Per-slug ids. Same assertion rationale as `byChainId`: `Object.fromEntries`
|
|
146
|
+
* erases the key/value correlation that the mapped type expresses. */
|
|
147
|
+
const CHAIN_IDS_BY_SLUG = Object.fromEntries(Object.entries(CHAIN_REGISTRY).map(([slug, chain]) => [slug, chain.id]));
|
|
148
|
+
/** All supported chain IDs */
|
|
149
|
+
export const CHAIN_IDS = {
|
|
150
|
+
...CHAIN_IDS_BY_SLUG,
|
|
151
|
+
aztec: 0,
|
|
152
|
+
};
|
|
153
|
+
/** Chain names for display */
|
|
154
|
+
export const CHAIN_NAMES = byChainId((chain) => chain.name);
|
|
155
|
+
/**
|
|
156
|
+
* Short chain names for compact display. Keyed by `SelectableChainId` so the
|
|
157
|
+
* non-EVM Tron destination (base58) has a short name too -- the tx-link/name
|
|
158
|
+
* helpers in the trade result surfaces index this with a destination chain id
|
|
159
|
+
* that can be Tron.
|
|
160
|
+
*/
|
|
161
|
+
export const CHAIN_SHORT_NAMES = {
|
|
162
|
+
...byChainId((chain) => chain.shortName),
|
|
163
|
+
[TRON_CHAIN_ID]: TRON_SHORT_NAME,
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Block explorer origins by chain (no trailing path). Single source of truth --
|
|
167
|
+
* build tx/address URLs through the helpers below so links always target the
|
|
168
|
+
* right chain (the old per-component maps drifted and one hardcoded Arbiscan).
|
|
169
|
+
*/
|
|
170
|
+
export const CHAIN_EXPLORERS = byChainId((chain) => chain.explorer);
|
|
171
|
+
/**
|
|
172
|
+
* Native currency symbol per chain. Used for gas display (QuoteDetails) and
|
|
173
|
+
* balance labels (usePublicBalances). Most chains use ETH; Polygon uses POL,
|
|
174
|
+
* Arc uses USDC (native gas token on Circle's stablecoin L1).
|
|
175
|
+
* Derived from `CHAIN_REGISTRY.nativeCurrency`, defaulting to "ETH".
|
|
176
|
+
*/
|
|
177
|
+
export const CHAIN_NATIVE_CURRENCY = byChainId((chain) => chain.nativeCurrency ?? "ETH");
|
|
178
|
+
/**
|
|
179
|
+
* Tronscan uses a `#/` hash route (not the `/tx/` path shape of the EVM
|
|
180
|
+
* explorers), so Tron links are built separately from `CHAIN_EXPLORERS`.
|
|
181
|
+
*/
|
|
182
|
+
export const TRON_EXPLORER = "https://tronscan.org";
|
|
183
|
+
/**
|
|
184
|
+
* Build a transaction URL on the given chain's explorer (empty if unknown).
|
|
185
|
+
* Accepts a `SelectableChainId` so a Tron destination fill can be linked; Tron
|
|
186
|
+
* routes to tronscan's hash-route form.
|
|
187
|
+
*/
|
|
188
|
+
export function getExplorerTxUrl(chainId, txHash) {
|
|
189
|
+
if (isTronChainId(chainId))
|
|
190
|
+
return `${TRON_EXPLORER}/#/transaction/${txHash}`;
|
|
191
|
+
const base = CHAIN_EXPLORERS[chainId];
|
|
192
|
+
return base ? `${base}/tx/${txHash}` : "";
|
|
193
|
+
}
|
|
194
|
+
/** Build an address URL on the given chain's explorer (empty if unknown). */
|
|
195
|
+
export function getExplorerAddressUrl(chainId, address) {
|
|
196
|
+
if (isTronChainId(chainId))
|
|
197
|
+
return `${TRON_EXPLORER}/#/address/${address}`;
|
|
198
|
+
const base = CHAIN_EXPLORERS[chainId];
|
|
199
|
+
return base ? `${base}/address/${address}` : "";
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Extended chain names including the Aztec source + non-EVM destinations. The
|
|
203
|
+
* Aztec virtual chain is branded "Xochi" in the UI, which is why its display
|
|
204
|
+
* name is not simply a chain name.
|
|
205
|
+
*/
|
|
206
|
+
export const EXTENDED_CHAIN_NAMES = {
|
|
207
|
+
...CHAIN_NAMES,
|
|
208
|
+
0: "Xochi",
|
|
209
|
+
[TRON_CHAIN_ID]: TRON_CHAIN_NAME,
|
|
210
|
+
};
|
|
211
|
+
/** Supported chain IDs as array */
|
|
212
|
+
export const SUPPORTED_CHAIN_IDS = CHAIN_LIST.map((chain) => chain.id);
|
|
213
|
+
/** Type guard for ChainId */
|
|
214
|
+
export function isChainId(value) {
|
|
215
|
+
return typeof value === "number" && SUPPORTED_CHAIN_IDS.includes(value);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Chain ids the solver can settle to or from; exactly `SUPPORTED_CHAIN_IDS`. The intent API
|
|
219
|
+
* (`/api/intent/quote` and `/api/intent/execute`) validates request chain ids against this set.
|
|
220
|
+
* Token addresses ride in the request body, so the API needs no per-chain token config to
|
|
221
|
+
* accept a corridor; the solver decides feasibility.
|
|
222
|
+
*/
|
|
223
|
+
export const SETTLEABLE_CHAIN_IDS = SUPPORTED_CHAIN_IDS;
|
|
224
|
+
/** Type guard for a settleable chain id (any supported chain, including Robinhood). */
|
|
225
|
+
export function isSettleableChainId(value) {
|
|
226
|
+
return typeof value === "number" && SETTLEABLE_CHAIN_IDS.includes(value);
|
|
227
|
+
}
|
|
228
|
+
/** Type guard for ExtendedChainId (EVM chains + Aztec source + Tron destination). */
|
|
229
|
+
export function isExtendedChainId(value) {
|
|
230
|
+
return (typeof value === "number" &&
|
|
231
|
+
(value === 0 || value === TRON_CHAIN_ID || SUPPORTED_CHAIN_IDS.includes(value)));
|
|
232
|
+
}
|
|
233
|
+
/** Check if route between chains is supported */
|
|
234
|
+
export function isRouteSupported(from, to) {
|
|
235
|
+
return isChainId(from) && isChainId(to);
|
|
236
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EIP-712 Types and Builders
|
|
3
|
+
*
|
|
4
|
+
* Typed data shapes served for signing, and the origin-pull amount reader.
|
|
5
|
+
*/
|
|
6
|
+
export interface Eip712Domain {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
chainId: number;
|
|
10
|
+
/**
|
|
11
|
+
* Present on Xochi-owned structs (Intent/LimitOrder/Mandate) and token-pull
|
|
12
|
+
* domains (ERC-3009/Permit2). The Riddler-served XochiIntent v3 domain omits
|
|
13
|
+
* it in favor of `salt`, so it is optional -- never assume it is set.
|
|
14
|
+
*/
|
|
15
|
+
verifyingContract?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Present on the Riddler-served XochiIntent v3 domain (keccak256(version));
|
|
18
|
+
* absent on verifyingContract-based domains. Part of the signed domain
|
|
19
|
+
* separator, so it must reach the signer verbatim.
|
|
20
|
+
*/
|
|
21
|
+
salt?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface Eip712TypeField {
|
|
24
|
+
name: string;
|
|
25
|
+
type: string;
|
|
26
|
+
}
|
|
27
|
+
export interface Eip712TypedData<T = Record<string, unknown>> {
|
|
28
|
+
domain: Eip712Domain;
|
|
29
|
+
types: Record<string, Eip712TypeField[]>;
|
|
30
|
+
primaryType: string;
|
|
31
|
+
message: T;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extract the origin-token amount (smallest units) a served origin-pull
|
|
35
|
+
* authorization would collect. ERC-3009 carries it as `value`; Permit2 as
|
|
36
|
+
* `permitted.amount`. Returns null for an unrecognized type or a
|
|
37
|
+
* missing/unparseable amount so callers fail closed.
|
|
38
|
+
*
|
|
39
|
+
* The pulled amount is what the user's signature authorizes on-chain (ERC-3009
|
|
40
|
+
* moves exactly `value`; Permit2 caps at `permitted.amount`), so binding it to
|
|
41
|
+
* the intended input amount is the origin leg's value guard (#170; see
|
|
42
|
+
* solverPin).
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractPullAmount(pull: Eip712TypedData): bigint | null;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EIP-712 Types and Builders
|
|
3
|
+
*
|
|
4
|
+
* Typed data shapes served for signing, and the origin-pull amount reader.
|
|
5
|
+
*/
|
|
6
|
+
// ============================================================
|
|
7
|
+
// Origin-pull amount extraction
|
|
8
|
+
// ============================================================
|
|
9
|
+
/**
|
|
10
|
+
* Origin-pull primaryTypes that carry the collected amount. ERC-3009
|
|
11
|
+
* (ReceiveWithAuthorization / TransferWithAuthorization) carries it top-level as
|
|
12
|
+
* `value`; Permit2 (PermitWitnessTransferFrom) as `permitted.amount`. Mirrors the
|
|
13
|
+
* set the solver pin recognizes.
|
|
14
|
+
*/
|
|
15
|
+
const ERC3009_PULL_TYPES = new Set([
|
|
16
|
+
"ReceiveWithAuthorization",
|
|
17
|
+
"TransferWithAuthorization",
|
|
18
|
+
]);
|
|
19
|
+
const PERMIT2_PULL_TYPE = "PermitWitnessTransferFrom";
|
|
20
|
+
/** Coerce a typed-data uint256 (decimal string / number / bigint) to bigint, or null. */
|
|
21
|
+
function coercePullAmount(value) {
|
|
22
|
+
if (typeof value === "bigint")
|
|
23
|
+
return value;
|
|
24
|
+
if (typeof value === "number" && Number.isInteger(value))
|
|
25
|
+
return BigInt(value);
|
|
26
|
+
if (typeof value === "string" && /^\d+$/.test(value.trim())) {
|
|
27
|
+
try {
|
|
28
|
+
return BigInt(value.trim());
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extract the origin-token amount (smallest units) a served origin-pull
|
|
38
|
+
* authorization would collect. ERC-3009 carries it as `value`; Permit2 as
|
|
39
|
+
* `permitted.amount`. Returns null for an unrecognized type or a
|
|
40
|
+
* missing/unparseable amount so callers fail closed.
|
|
41
|
+
*
|
|
42
|
+
* The pulled amount is what the user's signature authorizes on-chain (ERC-3009
|
|
43
|
+
* moves exactly `value`; Permit2 caps at `permitted.amount`), so binding it to
|
|
44
|
+
* the intended input amount is the origin leg's value guard (#170; see
|
|
45
|
+
* solverPin).
|
|
46
|
+
*/
|
|
47
|
+
export function extractPullAmount(pull) {
|
|
48
|
+
const message = pull.message;
|
|
49
|
+
if (!message)
|
|
50
|
+
return null;
|
|
51
|
+
if (ERC3009_PULL_TYPES.has(pull.primaryType)) {
|
|
52
|
+
return coercePullAmount(message.value);
|
|
53
|
+
}
|
|
54
|
+
if (pull.primaryType === PERMIT2_PULL_TYPE) {
|
|
55
|
+
const permitted = message.permitted;
|
|
56
|
+
return permitted ? coercePullAmount(permitted.amount) : null;
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
// ============================================================
|
|
61
|
+
// Intent EIP-712 (XochiIntent v3)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client-facing public subset of Xochi's shared vocabulary: chains, intent
|
|
3
|
+
* statuses, trading bounds, the served EIP-712 shapes, address validators,
|
|
4
|
+
* stealth factory trust, and the Worker's quote/execute response contract.
|
|
5
|
+
*/
|
|
6
|
+
export * from "./chains.js";
|
|
7
|
+
export * from "./intents.js";
|
|
8
|
+
export * from "./trading.js";
|
|
9
|
+
export * from "./types.js";
|
|
10
|
+
export * from "./stealth.js";
|
|
11
|
+
export * from "./eip712.js";
|
|
12
|
+
export * from "./validators.js";
|
|
13
|
+
export * from "./schemas.js";
|
|
14
|
+
export * from "./api.js";
|
|
15
|
+
export * from "./intentStream.js";
|
|
16
|
+
export * from "./shieldedPreview.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client-facing public subset of Xochi's shared vocabulary: chains, intent
|
|
3
|
+
* statuses, trading bounds, the served EIP-712 shapes, address validators,
|
|
4
|
+
* stealth factory trust, and the Worker's quote/execute response contract.
|
|
5
|
+
*/
|
|
6
|
+
export * from "./chains.js";
|
|
7
|
+
export * from "./intents.js";
|
|
8
|
+
export * from "./trading.js";
|
|
9
|
+
export * from "./types.js";
|
|
10
|
+
export * from "./stealth.js";
|
|
11
|
+
export * from "./eip712.js";
|
|
12
|
+
export * from "./validators.js";
|
|
13
|
+
export * from "./schemas.js";
|
|
14
|
+
export * from "./api.js";
|
|
15
|
+
export * from "./intentStream.js";
|
|
16
|
+
export * from "./shieldedPreview.js";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent lifecycle frame: the wire shape of a status transition published on an
|
|
3
|
+
* intent's stream topic (`GET /api/stream/:topicId`, settlement-protocol D5 5.9).
|
|
4
|
+
*
|
|
5
|
+
* The worker builds it (`broadcastStatusFrame`) and the browser parses it
|
|
6
|
+
* (`useIntentStream`); agents subscribed to the topic consume the same JSON.
|
|
7
|
+
* Defined here so the producer and the consumers cannot drift: the worker
|
|
8
|
+
* cannot publish a field the client schema does not know about without a type
|
|
9
|
+
* error, and the client tests feed this builder's output through the parser.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { type IntentStatus } from "./intents.js";
|
|
13
|
+
export declare const IntentStatusFrameSchema: z.ZodObject<{
|
|
14
|
+
type: z.ZodLiteral<"status">;
|
|
15
|
+
intent_id: z.ZodString;
|
|
16
|
+
from_status: z.ZodEffects<z.ZodString, IntentStatus, string>;
|
|
17
|
+
status: z.ZodEffects<z.ZodString, IntentStatus, string>;
|
|
18
|
+
/** The intent's settlement protocol (`intents.protocol`, e.g. `v1`). */
|
|
19
|
+
protocol: z.ZodString;
|
|
20
|
+
/**
|
|
21
|
+
* `intent_status_history` rowid: monotonic, so a subscriber can drop a frame
|
|
22
|
+
* older than one it already applied. Null only if D1 did not report it.
|
|
23
|
+
*/
|
|
24
|
+
revision: z.ZodNullable<z.ZodNumber>;
|
|
25
|
+
/** Unix ms at publish. */
|
|
26
|
+
ts: z.ZodNumber;
|
|
27
|
+
/** Present only for a PUBLIC settlement with a known hash. */
|
|
28
|
+
tx_hash: z.ZodOptional<z.ZodString>;
|
|
29
|
+
/**
|
|
30
|
+
* `NOT_EXECUTED_SUBSTATUS` on the `failed` transition of a row the worker
|
|
31
|
+
* finished itself knowing nothing moved; absent on every other frame.
|
|
32
|
+
*/
|
|
33
|
+
substatus: z.ZodOptional<z.ZodString>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
status: IntentStatus;
|
|
36
|
+
type: "status";
|
|
37
|
+
intent_id: string;
|
|
38
|
+
from_status: IntentStatus;
|
|
39
|
+
protocol: string;
|
|
40
|
+
revision: number | null;
|
|
41
|
+
ts: number;
|
|
42
|
+
tx_hash?: string | undefined;
|
|
43
|
+
substatus?: string | undefined;
|
|
44
|
+
}, {
|
|
45
|
+
status: string;
|
|
46
|
+
type: "status";
|
|
47
|
+
intent_id: string;
|
|
48
|
+
from_status: string;
|
|
49
|
+
protocol: string;
|
|
50
|
+
revision: number | null;
|
|
51
|
+
ts: number;
|
|
52
|
+
tx_hash?: string | undefined;
|
|
53
|
+
substatus?: string | undefined;
|
|
54
|
+
}>;
|
|
55
|
+
export type IntentStatusFrame = z.infer<typeof IntentStatusFrameSchema>;
|
|
56
|
+
/**
|
|
57
|
+
* Build the frame for one transition.
|
|
58
|
+
*
|
|
59
|
+
* `tx_hash` is omitted for any non-public settlement: a subscriber to a stealth
|
|
60
|
+
* or shielded intent holds the topic, but the hash is the one field that
|
|
61
|
+
* deanonymises the recipient on a public chain, and the relay replays its
|
|
62
|
+
* buffer for 10 minutes (D7 7.3).
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildIntentStatusFrame(input: {
|
|
65
|
+
intentId: string;
|
|
66
|
+
fromStatus: IntentStatus;
|
|
67
|
+
toStatus: IntentStatus;
|
|
68
|
+
protocol: string;
|
|
69
|
+
settlementType: string;
|
|
70
|
+
revision: number | null;
|
|
71
|
+
txHash?: string | null;
|
|
72
|
+
substatus?: string | null;
|
|
73
|
+
ts: number;
|
|
74
|
+
}): IntentStatusFrame;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent lifecycle frame: the wire shape of a status transition published on an
|
|
3
|
+
* intent's stream topic (`GET /api/stream/:topicId`, settlement-protocol D5 5.9).
|
|
4
|
+
*
|
|
5
|
+
* The worker builds it (`broadcastStatusFrame`) and the browser parses it
|
|
6
|
+
* (`useIntentStream`); agents subscribed to the topic consume the same JSON.
|
|
7
|
+
* Defined here so the producer and the consumers cannot drift: the worker
|
|
8
|
+
* cannot publish a field the client schema does not know about without a type
|
|
9
|
+
* error, and the client tests feed this builder's output through the parser.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { isIntentStatus } from "./intents.js";
|
|
13
|
+
export const IntentStatusFrameSchema = z.object({
|
|
14
|
+
type: z.literal("status"),
|
|
15
|
+
intent_id: z.string().min(1),
|
|
16
|
+
from_status: z.string().refine(isIntentStatus),
|
|
17
|
+
status: z.string().refine(isIntentStatus),
|
|
18
|
+
/** The intent's settlement protocol (`intents.protocol`, e.g. `v1`). */
|
|
19
|
+
protocol: z.string(),
|
|
20
|
+
/**
|
|
21
|
+
* `intent_status_history` rowid: monotonic, so a subscriber can drop a frame
|
|
22
|
+
* older than one it already applied. Null only if D1 did not report it.
|
|
23
|
+
*/
|
|
24
|
+
revision: z.number().int().nullable(),
|
|
25
|
+
/** Unix ms at publish. */
|
|
26
|
+
ts: z.number().int(),
|
|
27
|
+
/** Present only for a PUBLIC settlement with a known hash. */
|
|
28
|
+
tx_hash: z.string().optional(),
|
|
29
|
+
/**
|
|
30
|
+
* `NOT_EXECUTED_SUBSTATUS` on the `failed` transition of a row the worker
|
|
31
|
+
* finished itself knowing nothing moved; absent on every other frame.
|
|
32
|
+
*/
|
|
33
|
+
substatus: z.string().optional(),
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Build the frame for one transition.
|
|
37
|
+
*
|
|
38
|
+
* `tx_hash` is omitted for any non-public settlement: a subscriber to a stealth
|
|
39
|
+
* or shielded intent holds the topic, but the hash is the one field that
|
|
40
|
+
* deanonymises the recipient on a public chain, and the relay replays its
|
|
41
|
+
* buffer for 10 minutes (D7 7.3).
|
|
42
|
+
*/
|
|
43
|
+
export function buildIntentStatusFrame(input) {
|
|
44
|
+
return {
|
|
45
|
+
type: "status",
|
|
46
|
+
intent_id: input.intentId,
|
|
47
|
+
from_status: input.fromStatus,
|
|
48
|
+
status: input.toStatus,
|
|
49
|
+
protocol: input.protocol,
|
|
50
|
+
revision: input.revision,
|
|
51
|
+
ts: input.ts,
|
|
52
|
+
...(input.settlementType === "public" && input.txHash ? { tx_hash: input.txHash } : {}),
|
|
53
|
+
...(input.substatus ? { substatus: input.substatus } : {}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent Types
|
|
3
|
+
*
|
|
4
|
+
* Status types, order types, and state machine transitions
|
|
5
|
+
* for the cross-chain intent system.
|
|
6
|
+
*/
|
|
7
|
+
export type SettlementType = "public" | "shielded" | "stealth";
|
|
8
|
+
export declare function isSettlementType(value: unknown): value is SettlementType;
|
|
9
|
+
export type OrderType = "market" | "limit";
|
|
10
|
+
export declare function isOrderType(value: unknown): value is OrderType;
|
|
11
|
+
export type TriggerCondition = "gte" | "lte";
|
|
12
|
+
export declare function isTriggerCondition(value: unknown): value is TriggerCondition;
|
|
13
|
+
export type IntentStatus = "idle" | "pending" | "quoting" | "quoted" | "signing" | "awaiting_deposit" | "executing" | "bridging" | "settling" | "completed" | "refunded" | "failed" | "expired";
|
|
14
|
+
/** All valid intent statuses */
|
|
15
|
+
export declare const INTENT_STATUSES: readonly IntentStatus[];
|
|
16
|
+
export declare function isIntentStatus(value: unknown): value is IntentStatus;
|
|
17
|
+
/**
|
|
18
|
+
* The `substatus` the worker puts on a `failed` it wrote knowing nothing
|
|
19
|
+
* moved. The one list of its sources is docs/contracts/xochi-intent-api.md,
|
|
20
|
+
* "The worker's `not_executed` marker"; this mirrors it. Writers:
|
|
21
|
+
* 1. an intent read (`GET /api/intent/{id}`, the status poll) of an unsigned
|
|
22
|
+
* market `quoted` row (never a Tron deposit route or a limit order; never
|
|
23
|
+
* claimed, or every claim undone) past its signed deadline +
|
|
24
|
+
* `QUOTED_EXPIRY_GRACE_SECS`;
|
|
25
|
+
* 2. the quote sweep's finish of a touched `quoted` row past its 30 s quote
|
|
26
|
+
* expiry + 60 s;
|
|
27
|
+
* 3. the resend budget's finish after the solver's not-accepted refusals;
|
|
28
|
+
* 4. a not-accepted refusal finished because its un-claim's write failed
|
|
29
|
+
* (`NOT_ACCEPTED_FAULT_FINISH_ERROR`);
|
|
30
|
+
* 5. an execute refused because no solver is configured;
|
|
31
|
+
* 6. a solver refusal of the execute whose body says
|
|
32
|
+
* `details.funds_moved === false` (refused before this request's claim and
|
|
33
|
+
* before any pull).
|
|
34
|
+
* Served on every intent read, the history list, the stream frame of that
|
|
35
|
+
* transition, the execute 502 of writers 3-6, and echoed from the row by the
|
|
36
|
+
* execute's lost-race 502 and in-doubt 200. Any other solver-reported
|
|
37
|
+
* `failed` (which may follow an origin pull) never carries it, and neither
|
|
38
|
+
* does a `failed` nothing vouches for, such as a solver refusal without that
|
|
39
|
+
* body. A client that sent an execute may offer Retry on a `failed` with this
|
|
40
|
+
* marker; any other `failed` may follow moved funds (`@xochi/client` holds it
|
|
41
|
+
* as "may have moved"; the app and widget do not read the marker yet,
|
|
42
|
+
* xochi#691).
|
|
43
|
+
*
|
|
44
|
+
* Writers 1-4 and 6, and the sweep's deletion of an untouched `quoted` row
|
|
45
|
+
* (which a client holding the intent as not sent reads as nothing moved),
|
|
46
|
+
* rest on one premise: the worker is the only caller of the solver's execute
|
|
47
|
+
* for its quotes, which the solver enforces (its execute refuses a caller
|
|
48
|
+
* other than the one the quote was issued to, Riddler#1346).
|
|
49
|
+
*
|
|
50
|
+
* Mirrors `NOT_EXECUTED_SUBSTATUS` in xochi's `@xochi/shared` `intents.ts`
|
|
51
|
+
* verbatim (the doc path above is in xochi). In this package: README "Fund
|
|
52
|
+
* safety" (Retry only on this marker, or on a 404 while "not sent yet" past
|
|
53
|
+
* the Worker's finish).
|
|
54
|
+
*/
|
|
55
|
+
export declare const NOT_EXECUTED_SUBSTATUS = "not_executed";
|
|
56
|
+
/** Status transitions for the market order intent state machine */
|
|
57
|
+
export declare const INTENT_STATUS_TRANSITIONS: Record<IntentStatus, IntentStatus[]>;
|
|
58
|
+
/** Check if a status transition is valid */
|
|
59
|
+
export declare function canTransitionTo(from: IntentStatus, to: IntentStatus): boolean;
|
|
60
|
+
/** Get human-readable status label */
|
|
61
|
+
export declare function getStatusLabel(status: IntentStatus): string;
|
|
62
|
+
/**
|
|
63
|
+
* Plain-language copy for a deposit refund. Riddler returns a machine-readable
|
|
64
|
+
* `refundReason` code on a `refunded` status; map it to something a
|
|
65
|
+
* non-technical user understands. Every case reassures that funds are safe.
|
|
66
|
+
* Unknown codes fall back to the generic line rather than leaking the raw code.
|
|
67
|
+
*/
|
|
68
|
+
export declare function getRefundReasonLabel(code: string | null | undefined): string;
|
|
69
|
+
export type LimitOrderStatus = "idle" | "limit_quoting" | "limit_quoted" | "signing" | "waiting" | "triggered" | "executing" | "completed" | "cancelled" | "expired";
|
|
70
|
+
/** All valid limit order statuses */
|
|
71
|
+
export declare const LIMIT_ORDER_STATUSES: readonly LimitOrderStatus[];
|
|
72
|
+
export declare function isLimitOrderStatus(value: unknown): value is LimitOrderStatus;
|
|
73
|
+
/** Status transitions for limit order state machine */
|
|
74
|
+
export declare const LIMIT_ORDER_STATUS_TRANSITIONS: Record<LimitOrderStatus, LimitOrderStatus[]>;
|
|
75
|
+
/** Check if a limit order status transition is valid */
|
|
76
|
+
export declare function canLimitOrderTransitionTo(from: LimitOrderStatus, to: LimitOrderStatus): boolean;
|
|
77
|
+
/** Get human-readable status label for limit orders */
|
|
78
|
+
export declare function getLimitOrderStatusLabel(status: LimitOrderStatus): string;
|
|
79
|
+
/** Expiry presets for limit orders (in milliseconds) */
|
|
80
|
+
export declare const LIMIT_ORDER_EXPIRY_PRESETS: {
|
|
81
|
+
readonly "1h": number;
|
|
82
|
+
readonly "24h": number;
|
|
83
|
+
readonly "7d": number;
|
|
84
|
+
readonly "30d": number;
|
|
85
|
+
};
|
|
86
|
+
export type LimitOrderExpiryPreset = keyof typeof LIMIT_ORDER_EXPIRY_PRESETS;
|
|
87
|
+
export type DestinationType = "chain" | "aztec" | "stealth";
|
|
88
|
+
export declare function isDestinationType(value: unknown): value is DestinationType;
|