@anywalletkit/protocol-swap2-relay 0.0.0-stage → 0.1.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 (58) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +116 -2
  3. package/dist/activity.cjs +82 -0
  4. package/dist/activity.cjs.map +1 -0
  5. package/dist/activity.d.cts +15 -0
  6. package/dist/activity.d.ts +15 -0
  7. package/dist/activity.js +10 -0
  8. package/dist/activity.js.map +1 -0
  9. package/dist/chunk-7LPLU3MB.js +27 -0
  10. package/dist/chunk-7LPLU3MB.js.map +1 -0
  11. package/dist/chunk-CCMNAZZB.js +307 -0
  12. package/dist/chunk-CCMNAZZB.js.map +1 -0
  13. package/dist/chunk-JQAN7HB5.js +80 -0
  14. package/dist/chunk-JQAN7HB5.js.map +1 -0
  15. package/dist/chunk-K5F3BEUO.js +22 -0
  16. package/dist/chunk-K5F3BEUO.js.map +1 -0
  17. package/dist/chunk-UVHDMGM5.js +190 -0
  18. package/dist/chunk-UVHDMGM5.js.map +1 -0
  19. package/dist/chunk-WRIKAUWI.js +384 -0
  20. package/dist/chunk-WRIKAUWI.js.map +1 -0
  21. package/dist/config.cjs +100 -0
  22. package/dist/config.cjs.map +1 -0
  23. package/dist/config.d.cts +58 -0
  24. package/dist/config.d.ts +58 -0
  25. package/dist/config.js +35 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/index.cjs +965 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +11 -0
  30. package/dist/index.d.ts +11 -0
  31. package/dist/index.js +98 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/order.cjs +210 -0
  34. package/dist/order.cjs.map +1 -0
  35. package/dist/order.d.cts +178 -0
  36. package/dist/order.d.ts +178 -0
  37. package/dist/order.js +15 -0
  38. package/dist/order.js.map +1 -0
  39. package/dist/protocol.cjs +922 -0
  40. package/dist/protocol.cjs.map +1 -0
  41. package/dist/protocol.d.cts +16 -0
  42. package/dist/protocol.d.ts +16 -0
  43. package/dist/protocol.js +12 -0
  44. package/dist/protocol.js.map +1 -0
  45. package/dist/provider.cjs +907 -0
  46. package/dist/provider.cjs.map +1 -0
  47. package/dist/provider.d.cts +31 -0
  48. package/dist/provider.d.ts +31 -0
  49. package/dist/provider.js +13 -0
  50. package/dist/provider.js.map +1 -0
  51. package/dist/verify.cjs +617 -0
  52. package/dist/verify.cjs.map +1 -0
  53. package/dist/verify.d.cts +151 -0
  54. package/dist/verify.d.ts +151 -0
  55. package/dist/verify.js +39 -0
  56. package/dist/verify.js.map +1 -0
  57. package/module.json +42 -0
  58. package/package.json +99 -3
@@ -0,0 +1,190 @@
1
+ // src/order.ts
2
+ import { secp256k1 } from "@noble/curves/secp256k1.js";
3
+ import { hashMessage, hashStruct, hexToBytes, keccak256 } from "viem";
4
+ var RelayRefusal = class extends Error {
5
+ code;
6
+ constructor(code, detail) {
7
+ super(`relay: ${detail} [${code}]`);
8
+ this.name = "RelayRefusal";
9
+ this.code = code;
10
+ }
11
+ };
12
+ var RELAY_ORDER_TYPES = {
13
+ Order: [
14
+ { name: "version", type: "string" },
15
+ { name: "solverChainId", type: "string" },
16
+ { name: "solver", type: "address" },
17
+ { name: "salt", type: "uint256" },
18
+ { name: "inputs", type: "Input[]" },
19
+ { name: "output", type: "Output" },
20
+ { name: "fees", type: "Fee[]" }
21
+ ],
22
+ Input: [
23
+ { name: "payment", type: "InputPayment" },
24
+ { name: "refunds", type: "InputRefund[]" }
25
+ ],
26
+ InputPayment: [
27
+ { name: "chainId", type: "string" },
28
+ { name: "currency", type: "bytes" },
29
+ { name: "amount", type: "uint256" },
30
+ { name: "weight", type: "uint256" }
31
+ ],
32
+ InputRefund: [
33
+ { name: "chainId", type: "string" },
34
+ { name: "recipient", type: "bytes" },
35
+ { name: "currency", type: "bytes" },
36
+ { name: "minimumAmount", type: "uint256" },
37
+ { name: "deadline", type: "uint32" },
38
+ { name: "extraData", type: "bytes" }
39
+ ],
40
+ Output: [
41
+ { name: "chainId", type: "string" },
42
+ { name: "payments", type: "OutputPayment[]" },
43
+ { name: "deadline", type: "uint32" },
44
+ { name: "calls", type: "bytes[]" },
45
+ { name: "extraData", type: "bytes" }
46
+ ],
47
+ OutputPayment: [
48
+ { name: "recipient", type: "bytes" },
49
+ { name: "currency", type: "bytes" },
50
+ { name: "minimumAmount", type: "uint256" },
51
+ { name: "expectedAmount", type: "uint256" }
52
+ ],
53
+ Fee: [
54
+ { name: "recipientChainId", type: "string" },
55
+ { name: "recipient", type: "bytes" },
56
+ { name: "currencyChainId", type: "string" },
57
+ { name: "currency", type: "bytes" },
58
+ { name: "amount", type: "uint256" }
59
+ ]
60
+ };
61
+ var MAX_LIST = 8;
62
+ var MAX_BYTES_HEX = 2 + 2 * 1024;
63
+ var MAX_TEXT = 64;
64
+ var U256_MAX = (1n << 256n) - 1n;
65
+ var bad = (what) => {
66
+ throw new RelayRefusal("order-malformed", `the order's ${what}`);
67
+ };
68
+ function rec(v, what) {
69
+ if (v === null || typeof v !== "object" || Array.isArray(v)) bad(`${what} is not an object`);
70
+ return v;
71
+ }
72
+ function list(v, what) {
73
+ if (!Array.isArray(v)) bad(`${what} is not a list`);
74
+ if (v.length > MAX_LIST) bad(`${what} has more than ${MAX_LIST} entries`);
75
+ return v;
76
+ }
77
+ function own(o, key) {
78
+ return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : void 0;
79
+ }
80
+ function text(v, what) {
81
+ if (typeof v !== "string" || v.length === 0 || v.length > MAX_TEXT) bad(`${what} is not a short string`);
82
+ return v;
83
+ }
84
+ function bytes(v, what) {
85
+ if (typeof v !== "string" || v.length > MAX_BYTES_HEX || !/^0x(?:[0-9a-fA-F]{2})*$/.test(v)) bad(`${what} is not hex bytes`);
86
+ return v.toLowerCase();
87
+ }
88
+ function uint(v, what, max = U256_MAX) {
89
+ let n = null;
90
+ if (typeof v === "string" && (/^(?:0|[1-9]\d{0,77})$/.test(v) || /^0x[0-9a-fA-F]{1,64}$/.test(v))) n = BigInt(v);
91
+ else if (typeof v === "number" && Number.isSafeInteger(v) && v >= 0) n = BigInt(v);
92
+ if (n === null || n > max) bad(`${what} is not an unsigned integer in range`);
93
+ return n;
94
+ }
95
+ function uint32(v, what) {
96
+ return parseInt(uint(v, what, 0xffffffffn).toString(10), 10);
97
+ }
98
+ function address(v, what) {
99
+ if (typeof v !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(v)) bad(`${what} is not an address`);
100
+ return v.toLowerCase();
101
+ }
102
+ function parseRelayOrder(raw) {
103
+ const o = rec(raw, "body");
104
+ const output = rec(own(o, "output"), "output");
105
+ return {
106
+ version: text(own(o, "version"), "version"),
107
+ solverChainId: text(own(o, "solverChainId"), "solver chain"),
108
+ solver: address(own(o, "solver"), "solver"),
109
+ salt: uint(own(o, "salt"), "salt"),
110
+ inputs: list(own(o, "inputs"), "inputs").map((x, i) => {
111
+ const input = rec(x, `input ${i}`);
112
+ const p = rec(own(input, "payment"), `input ${i} payment`);
113
+ return {
114
+ payment: {
115
+ chainId: text(own(p, "chainId"), `input ${i} chain`),
116
+ currency: bytes(own(p, "currency"), `input ${i} currency`),
117
+ amount: uint(own(p, "amount"), `input ${i} amount`),
118
+ weight: uint(own(p, "weight"), `input ${i} weight`)
119
+ },
120
+ refunds: list(own(input, "refunds"), `input ${i} refunds`).map((y, j) => {
121
+ const r = rec(y, `refund ${j}`);
122
+ return {
123
+ chainId: text(own(r, "chainId"), `refund ${j} chain`),
124
+ recipient: bytes(own(r, "recipient"), `refund ${j} recipient`),
125
+ currency: bytes(own(r, "currency"), `refund ${j} currency`),
126
+ minimumAmount: uint(own(r, "minimumAmount"), `refund ${j} minimum`),
127
+ deadline: uint32(own(r, "deadline"), `refund ${j} deadline`),
128
+ extraData: bytes(own(r, "extraData"), `refund ${j} extra data`)
129
+ };
130
+ })
131
+ };
132
+ }),
133
+ output: {
134
+ chainId: text(own(output, "chainId"), "output chain"),
135
+ payments: list(own(output, "payments"), "output payments").map((x, i) => {
136
+ const p = rec(x, `output payment ${i}`);
137
+ return {
138
+ recipient: bytes(own(p, "recipient"), `output payment ${i} recipient`),
139
+ currency: bytes(own(p, "currency"), `output payment ${i} currency`),
140
+ minimumAmount: uint(own(p, "minimumAmount"), `output payment ${i} minimum`),
141
+ expectedAmount: uint(own(p, "expectedAmount"), `output payment ${i} expected amount`)
142
+ };
143
+ }),
144
+ deadline: uint32(own(output, "deadline"), "output deadline"),
145
+ calls: list(own(output, "calls"), "output calls").map((x, i) => bytes(x, `output call ${i}`)),
146
+ extraData: bytes(own(output, "extraData"), "output extra data")
147
+ },
148
+ fees: list(own(o, "fees"), "fees").map((x, i) => {
149
+ const f = rec(x, `fee ${i}`);
150
+ return {
151
+ recipientChainId: text(own(f, "recipientChainId"), `fee ${i} recipient chain`),
152
+ recipient: bytes(own(f, "recipient"), `fee ${i} recipient`),
153
+ currencyChainId: text(own(f, "currencyChainId"), `fee ${i} currency chain`),
154
+ currency: bytes(own(f, "currency"), `fee ${i} currency`),
155
+ amount: uint(own(f, "amount"), `fee ${i} amount`)
156
+ };
157
+ })
158
+ };
159
+ }
160
+ function relayOrderId(order) {
161
+ return hashStruct({ types: RELAY_ORDER_TYPES, primaryType: "Order", data: order });
162
+ }
163
+ function relayOrderSigner(id, signature) {
164
+ if (typeof signature !== "string" || !/^0x[0-9a-fA-F]{130}$/.test(signature)) return null;
165
+ const sig = hexToBytes(signature);
166
+ const v = sig[64];
167
+ const recovery = v === 27 || v === 28 ? v - 27 : v === 0 || v === 1 ? v : -1;
168
+ if (recovery < 0) return null;
169
+ try {
170
+ const recoverable = new Uint8Array(65);
171
+ recoverable[0] = recovery;
172
+ recoverable.set(sig.subarray(0, 64), 1);
173
+ const digest = hexToBytes(hashMessage({ raw: id }));
174
+ const key = secp256k1.recoverPublicKey(recoverable, digest, { prehash: false });
175
+ if (!secp256k1.verify(sig.subarray(0, 64), digest, key, { prehash: false })) return null;
176
+ const uncompressed = secp256k1.Point.fromBytes(key).toBytes(false);
177
+ return `0x${keccak256(uncompressed.subarray(1)).slice(-40)}`.toLowerCase();
178
+ } catch {
179
+ return null;
180
+ }
181
+ }
182
+
183
+ export {
184
+ RelayRefusal,
185
+ RELAY_ORDER_TYPES,
186
+ parseRelayOrder,
187
+ relayOrderId,
188
+ relayOrderSigner
189
+ };
190
+ //# sourceMappingURL=chunk-UVHDMGM5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/order.ts"],"sourcesContent":["/**\n * A Relay order, read strictly, hashed and attributed here.\n *\n * - The order id is the EIP-712 `hashStruct` of the order under {@link RELAY_ORDER_TYPES} (no domain separator), as\n * github.com/relayprotocol/relay-protocol-sdk (src/order/index.ts) computes it. Chain ids are STRINGS (Relay's own\n * chain names), addresses and currencies are `bytes` (20 raw bytes on an EVM chain).\n * - `orderSignature` is the solver's EIP-191 `personal_sign` over the 32 raw bytes of that id.\n *\n * The id a deposit names is a commitment to everything in the order — recipient, chain, token, minimum, refunds — so\n * recomputing it from the order the API hands over, and reading that same parsed order, is what binds the deposit\n * to terms the device has seen.\n */\nimport {secp256k1} from \"@noble/curves/secp256k1.js\";\nimport {hashMessage, hashStruct, hexToBytes, keccak256, type Hex} from \"viem\";\n\n/** Why an order, a quote or a deposit was refused. One code per check; the message says what was found. */\nexport type RelayRefusalCode =\n | \"request-invalid\"\n | \"chain-unsupported\"\n | \"protocol-data-missing\"\n | \"hub-type\"\n | \"order-malformed\"\n | \"order-version\"\n | \"order-inputs\"\n | \"order-payments\"\n | \"order-calls\"\n | \"order-fees\"\n | \"solver-not-pinned\"\n | \"input-chain\"\n | \"input-currency\"\n | \"input-amount\"\n | \"input-weight\"\n | \"output-chain\"\n | \"output-recipient\"\n | \"output-currency\"\n | \"output-minimum\"\n | \"output-expected\"\n | \"output-deadline\"\n | \"refund-missing\"\n | \"refund-chain\"\n | \"refund-recipient\"\n | \"refund-currency\"\n | \"refund-deadline\"\n | \"order-id-mismatch\"\n | \"signature-invalid\"\n | \"payment-details\"\n | \"tx-chain\"\n | \"tx-target\"\n | \"tx-selector\"\n | \"tx-calldata\"\n | \"tx-depositor\"\n | \"tx-token\"\n | \"tx-amount\"\n | \"tx-id\"\n | \"tx-value\"\n | \"order-reused\"\n | \"app-fee\"\n | \"gas-topup\"\n | \"quote-gas\"\n | \"quote-expiry\"\n | \"quote-steps\"\n | \"quote-amounts\"\n | \"quote-approval\"\n | \"quote-shape\";\n\nexport class RelayRefusal extends Error {\n readonly code: RelayRefusalCode;\n constructor(code: RelayRefusalCode, detail: string) {\n super(`relay: ${detail} [${code}]`);\n this.name = \"RelayRefusal\";\n this.code = code;\n }\n}\n\nexport const RELAY_ORDER_TYPES = {\n Order: [\n {name: \"version\", type: \"string\"},\n {name: \"solverChainId\", type: \"string\"},\n {name: \"solver\", type: \"address\"},\n {name: \"salt\", type: \"uint256\"},\n {name: \"inputs\", type: \"Input[]\"},\n {name: \"output\", type: \"Output\"},\n {name: \"fees\", type: \"Fee[]\"},\n ],\n Input: [\n {name: \"payment\", type: \"InputPayment\"},\n {name: \"refunds\", type: \"InputRefund[]\"},\n ],\n InputPayment: [\n {name: \"chainId\", type: \"string\"},\n {name: \"currency\", type: \"bytes\"},\n {name: \"amount\", type: \"uint256\"},\n {name: \"weight\", type: \"uint256\"},\n ],\n InputRefund: [\n {name: \"chainId\", type: \"string\"},\n {name: \"recipient\", type: \"bytes\"},\n {name: \"currency\", type: \"bytes\"},\n {name: \"minimumAmount\", type: \"uint256\"},\n {name: \"deadline\", type: \"uint32\"},\n {name: \"extraData\", type: \"bytes\"},\n ],\n Output: [\n {name: \"chainId\", type: \"string\"},\n {name: \"payments\", type: \"OutputPayment[]\"},\n {name: \"deadline\", type: \"uint32\"},\n {name: \"calls\", type: \"bytes[]\"},\n {name: \"extraData\", type: \"bytes\"},\n ],\n OutputPayment: [\n {name: \"recipient\", type: \"bytes\"},\n {name: \"currency\", type: \"bytes\"},\n {name: \"minimumAmount\", type: \"uint256\"},\n {name: \"expectedAmount\", type: \"uint256\"},\n ],\n Fee: [\n {name: \"recipientChainId\", type: \"string\"},\n {name: \"recipient\", type: \"bytes\"},\n {name: \"currencyChainId\", type: \"string\"},\n {name: \"currency\", type: \"bytes\"},\n {name: \"amount\", type: \"uint256\"},\n ],\n} as const;\n\nexport interface RelayInputRefund {chainId: string; recipient: Hex; currency: Hex; minimumAmount: bigint; deadline: number; extraData: Hex}\nexport interface RelayInput {payment: {chainId: string; currency: Hex; amount: bigint; weight: bigint}; refunds: RelayInputRefund[]}\nexport interface RelayOutputPayment {recipient: Hex; currency: Hex; minimumAmount: bigint; expectedAmount: bigint}\nexport interface RelayFee {recipientChainId: string; recipient: Hex; currencyChainId: string; currency: Hex; amount: bigint}\n/** An order after {@link parseRelayOrder}: hex lowercased, integers exact. Every field below is hashed into the id. */\nexport interface RelayOrder {\n version: string;\n solverChainId: string;\n solver: Hex;\n salt: bigint;\n inputs: RelayInput[];\n output: {chainId: string; payments: RelayOutputPayment[]; deadline: number; calls: Hex[]; extraData: Hex};\n fees: RelayFee[];\n}\n\nconst MAX_LIST = 8;\nconst MAX_BYTES_HEX = 2 + 2 * 1024;\nconst MAX_TEXT = 64;\nconst U256_MAX = (1n << 256n) - 1n;\n\nconst bad = (what: string): never => { throw new RelayRefusal(\"order-malformed\", `the order's ${what}`); };\n\nfunction rec(v: unknown, what: string): Record<string, unknown> {\n if (v === null || typeof v !== \"object\" || Array.isArray(v)) bad(`${what} is not an object`);\n return v as Record<string, unknown>;\n}\nfunction list(v: unknown, what: string): unknown[] {\n if (!Array.isArray(v)) bad(`${what} is not a list`);\n if ((v as unknown[]).length > MAX_LIST) bad(`${what} has more than ${MAX_LIST} entries`);\n return v as unknown[];\n}\n/** Own property only: a field missing from the JSON is never read off a prototype. */\nfunction own(o: Record<string, unknown>, key: string): unknown {\n return Object.prototype.hasOwnProperty.call(o, key) ? o[key] : undefined;\n}\nfunction text(v: unknown, what: string): string {\n if (typeof v !== \"string\" || v.length === 0 || v.length > MAX_TEXT) bad(`${what} is not a short string`);\n return v as string;\n}\n/** `bytes`: 0x-hex of whole bytes, lowercased. */\nfunction bytes(v: unknown, what: string): Hex {\n if (typeof v !== \"string\" || v.length > MAX_BYTES_HEX || !/^0x(?:[0-9a-fA-F]{2})*$/.test(v)) bad(`${what} is not hex bytes`);\n return (v as string).toLowerCase() as Hex;\n}\n/** `uint256`: a decimal string, a 0x-hex string (Relay writes the salt that way) or a safe non-negative integer. */\nfunction uint(v: unknown, what: string, max: bigint = U256_MAX): bigint {\n let n: bigint | null = null;\n if (typeof v === \"string\" && (/^(?:0|[1-9]\\d{0,77})$/.test(v) || /^0x[0-9a-fA-F]{1,64}$/.test(v))) n = BigInt(v);\n else if (typeof v === \"number\" && Number.isSafeInteger(v) && v >= 0) n = BigInt(v);\n if (n === null || n > max) bad(`${what} is not an unsigned integer in range`);\n return n as bigint;\n}\nfunction uint32(v: unknown, what: string): number {\n // Below 2^32, so the conversion is exact.\n return parseInt(uint(v, what, 0xffff_ffffn).toString(10), 10);\n}\nfunction address(v: unknown, what: string): Hex {\n if (typeof v !== \"string\" || !/^0x[0-9a-fA-F]{40}$/.test(v)) bad(`${what} is not an address`);\n return (v as string).toLowerCase() as Hex;\n}\n\n/**\n * Read an order as the API gives it (`protocol.v2.orderData`, already JSON-parsed) into the one typed form the id,\n * the signature and every check are computed from. Anything that is not exactly the documented shape is refused\n * (`order-malformed`); keys the type does not have are ignored — they are outside the hash, and nothing reads them.\n */\nexport function parseRelayOrder(raw: unknown): RelayOrder {\n const o = rec(raw, \"body\");\n const output = rec(own(o, \"output\"), \"output\");\n return {\n version: text(own(o, \"version\"), \"version\"),\n solverChainId: text(own(o, \"solverChainId\"), \"solver chain\"),\n solver: address(own(o, \"solver\"), \"solver\"),\n salt: uint(own(o, \"salt\"), \"salt\"),\n inputs: list(own(o, \"inputs\"), \"inputs\").map((x, i) => {\n const input = rec(x, `input ${i}`);\n const p = rec(own(input, \"payment\"), `input ${i} payment`);\n return {\n payment: {\n chainId: text(own(p, \"chainId\"), `input ${i} chain`),\n currency: bytes(own(p, \"currency\"), `input ${i} currency`),\n amount: uint(own(p, \"amount\"), `input ${i} amount`),\n weight: uint(own(p, \"weight\"), `input ${i} weight`),\n },\n refunds: list(own(input, \"refunds\"), `input ${i} refunds`).map((y, j) => {\n const r = rec(y, `refund ${j}`);\n return {\n chainId: text(own(r, \"chainId\"), `refund ${j} chain`),\n recipient: bytes(own(r, \"recipient\"), `refund ${j} recipient`),\n currency: bytes(own(r, \"currency\"), `refund ${j} currency`),\n minimumAmount: uint(own(r, \"minimumAmount\"), `refund ${j} minimum`),\n deadline: uint32(own(r, \"deadline\"), `refund ${j} deadline`),\n extraData: bytes(own(r, \"extraData\"), `refund ${j} extra data`),\n };\n }),\n };\n }),\n output: {\n chainId: text(own(output, \"chainId\"), \"output chain\"),\n payments: list(own(output, \"payments\"), \"output payments\").map((x, i) => {\n const p = rec(x, `output payment ${i}`);\n return {\n recipient: bytes(own(p, \"recipient\"), `output payment ${i} recipient`),\n currency: bytes(own(p, \"currency\"), `output payment ${i} currency`),\n minimumAmount: uint(own(p, \"minimumAmount\"), `output payment ${i} minimum`),\n expectedAmount: uint(own(p, \"expectedAmount\"), `output payment ${i} expected amount`),\n };\n }),\n deadline: uint32(own(output, \"deadline\"), \"output deadline\"),\n calls: list(own(output, \"calls\"), \"output calls\").map((x, i) => bytes(x, `output call ${i}`)),\n extraData: bytes(own(output, \"extraData\"), \"output extra data\"),\n },\n fees: list(own(o, \"fees\"), \"fees\").map((x, i) => {\n const f = rec(x, `fee ${i}`);\n return {\n recipientChainId: text(own(f, \"recipientChainId\"), `fee ${i} recipient chain`),\n recipient: bytes(own(f, \"recipient\"), `fee ${i} recipient`),\n currencyChainId: text(own(f, \"currencyChainId\"), `fee ${i} currency chain`),\n currency: bytes(own(f, \"currency\"), `fee ${i} currency`),\n amount: uint(own(f, \"amount\"), `fee ${i} amount`),\n };\n }),\n };\n}\n\n/** The order id: `hashStruct(Order)`, no domain. */\nexport function relayOrderId(order: RelayOrder): Hex {\n return hashStruct({types: RELAY_ORDER_TYPES, primaryType: \"Order\", data: order as never});\n}\n\n/**\n * The address whose `personal_sign` over the id's 32 bytes this signature is (lowercase), or null when it is not a\n * 65-byte secp256k1 signature that recovers at all. Synchronous on purpose: the same check runs wherever the order\n * is read, with nothing left for a later asynchronous step.\n */\nexport function relayOrderSigner(id: Hex, signature: unknown): Hex | null {\n if (typeof signature !== \"string\" || !/^0x[0-9a-fA-F]{130}$/.test(signature)) return null;\n const sig = hexToBytes(signature as Hex);\n const v = sig[64]!;\n const recovery = v === 27 || v === 28 ? v - 27 : v === 0 || v === 1 ? v : -1;\n if (recovery < 0) return null;\n try {\n const recoverable = new Uint8Array(65);\n recoverable[0] = recovery;\n recoverable.set(sig.subarray(0, 64), 1);\n const digest = hexToBytes(hashMessage({raw: id}));\n const key = secp256k1.recoverPublicKey(recoverable, digest, {prehash: false});\n // The recovery must also verify: a malformed (r, s) never passes as a signer.\n if (!secp256k1.verify(sig.subarray(0, 64), digest, key, {prehash: false})) return null;\n const uncompressed = secp256k1.Point.fromBytes(key).toBytes(false);\n return `0x${keccak256(uncompressed.subarray(1)).slice(-40)}`.toLowerCase() as Hex;\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,384 @@
1
+ import {
2
+ RelayRefusal,
3
+ parseRelayOrder,
4
+ relayOrderId,
5
+ relayOrderSigner
6
+ } from "./chunk-UVHDMGM5.js";
7
+ import {
8
+ RELAY_CLOCK_SKEW_S,
9
+ RELAY_DEPOSIT_ERC20,
10
+ RELAY_DEPOSIT_ERC20_ALLOWANCE,
11
+ RELAY_DEPOSIT_NATIVE,
12
+ RELAY_MAX_ORDER_AGE_S,
13
+ RELAY_NATIVE,
14
+ RELAY_ORDER_LIFETIME_S,
15
+ RELAY_ORDER_VERSION,
16
+ RELAY_SOLVERS,
17
+ relayChain
18
+ } from "./chunk-JQAN7HB5.js";
19
+
20
+ // src/verify.ts
21
+ import { encodeFunctionData, parseAbi } from "viem";
22
+ import { sourceAssetOf } from "@anywalletkit/protocol-swap2-core/util";
23
+
24
+ // src/cleared.ts
25
+ var CLEARED_TTL_MS = (RELAY_MAX_ORDER_AGE_S + 2 * RELAY_CLOCK_SKEW_S) * 1e3;
26
+ var CLEARED_MAX = 4096;
27
+ var clearedOrders = /* @__PURE__ */ new Map();
28
+ function relayClearOrder(id, stage, nowMs = Date.now()) {
29
+ const key = `${stage}:${id.toLowerCase()}`;
30
+ const until = clearedOrders.get(key);
31
+ if (until !== void 0 && until > nowMs) throw new RelayRefusal("order-reused", `order ${id} was already cleared for a deposit \u2014 quote again`);
32
+ if (clearedOrders.size >= CLEARED_MAX) {
33
+ for (const [k, t] of clearedOrders) if (t <= nowMs) clearedOrders.delete(k);
34
+ if (clearedOrders.size >= CLEARED_MAX) throw new RelayRefusal("order-reused", "too many deposits cleared in the last minutes \u2014 try again later");
35
+ }
36
+ clearedOrders.set(key, nowMs + CLEARED_TTL_MS);
37
+ }
38
+
39
+ // src/verify.ts
40
+ var DEPOSITORY_ABI = parseAbi([
41
+ "function depositNative(address depositor, bytes32 id) payable",
42
+ "function depositErc20(address depositor, address token, uint256 amount, bytes32 id)"
43
+ ]);
44
+ var RELAY_MAX_SLIPPAGE_BPS = 5e3;
45
+ var RELAY_DEFAULT_SLIPPAGE_BPS = 200;
46
+ var RELAY_GAS_FLOOR_NATIVE = 90000n;
47
+ var RELAY_GAS_FLOOR_ERC20 = 180000n;
48
+ var RELAY_GAS_CAP = 60000000n;
49
+ var RELAY_MAX_QUOTE_LIFE_MS = 3e5 + RELAY_CLOCK_SKEW_S * 1e3;
50
+ var ADDRESS = /^0x[0-9a-fA-F]{40}$/;
51
+ var U256_MAX = (1n << 256n) - 1n;
52
+ var lower = (s) => s.toLowerCase();
53
+ var isNative = (token) => lower(token) === RELAY_NATIVE;
54
+ function buildRelayDeposit(source, depositor, token, amount, id) {
55
+ if (!ADDRESS.test(depositor) || /^0x0{40}$/.test(depositor)) throw new RelayRefusal("request-invalid", "the depositor is not an address");
56
+ if (!ADDRESS.test(token)) throw new RelayRefusal("request-invalid", "the input token is not an address");
57
+ if (amount <= 0n || amount > U256_MAX) throw new RelayRefusal("request-invalid", "the amount is not a positive integer");
58
+ if (!/^0x[0-9a-f]{64}$/.test(id)) throw new RelayRefusal("order-id-mismatch", "the order id is not 32 bytes");
59
+ if (isNative(token)) {
60
+ return {
61
+ to: source.depository,
62
+ data: encodeFunctionData({ abi: DEPOSITORY_ABI, functionName: "depositNative", args: [lower(depositor), id] }),
63
+ value: amount.toString(10),
64
+ chainId: source.chainId
65
+ };
66
+ }
67
+ return {
68
+ to: source.depository,
69
+ data: encodeFunctionData({ abi: DEPOSITORY_ABI, functionName: "depositErc20", args: [lower(depositor), lower(token), amount, id] }),
70
+ value: "0",
71
+ chainId: source.chainId,
72
+ approvalAddress: source.depository
73
+ };
74
+ }
75
+ function checkRequest(r) {
76
+ const invalid = (what) => {
77
+ throw new RelayRefusal("request-invalid", what);
78
+ };
79
+ if (r === null || typeof r !== "object") invalid("no request to check the order against");
80
+ const source = relayChain(r.sourceChain);
81
+ const dest = relayChain(r.destChain);
82
+ if (!source) throw new RelayRefusal("chain-unsupported", `source chain ${String(r.sourceChain)} is not a pinned Relay chain`);
83
+ if (!dest) throw new RelayRefusal("chain-unsupported", `destination chain ${String(r.destChain)} is not a pinned Relay chain`);
84
+ if (source === dest) throw new RelayRefusal("chain-unsupported", "source and destination are the same chain");
85
+ for (const [what, v] of [["input token", r.sourceToken], ["output token", r.destToken], ["depositor", r.depositor], ["recipient", r.recipient]]) {
86
+ if (typeof v !== "string" || !ADDRESS.test(v)) invalid(`the ${what} is not an address`);
87
+ }
88
+ if (/^0x0{40}$/.test(r.depositor)) invalid("the depositor is the zero address");
89
+ if (/^0x0{40}$/.test(r.recipient)) invalid("the recipient is the zero address");
90
+ if (typeof r.amount !== "bigint" || r.amount <= 0n || r.amount > U256_MAX) invalid("the amount is not a positive integer");
91
+ if (r.minAmountOut !== void 0 && (typeof r.minAmountOut !== "bigint" || r.minAmountOut < 0n)) invalid("the output floor is not an unsigned integer");
92
+ if (r.slippageBps !== void 0 && (!Number.isInteger(r.slippageBps) || r.slippageBps < 0 || r.slippageBps > RELAY_MAX_SLIPPAGE_BPS)) {
93
+ invalid(`slippage must be a whole number of basis points up to ${RELAY_MAX_SLIPPAGE_BPS}`);
94
+ }
95
+ const nowMs = r.nowMs ?? Date.now();
96
+ if (!Number.isFinite(nowMs) || nowMs <= 0) invalid("the clock is not a time");
97
+ return { source, dest, nowS: Math.floor(nowMs / 1e3) };
98
+ }
99
+ var isAddr = (bytes, addr) => bytes.length === 42 && bytes === lower(addr);
100
+ function checkDeadline(code, what, deadline, nowS) {
101
+ const left = deadline - nowS;
102
+ if (left > RELAY_ORDER_LIFETIME_S + RELAY_CLOCK_SKEW_S) {
103
+ throw new RelayRefusal(code, `${what} is ${left} s away, past the ${RELAY_ORDER_LIFETIME_S} s an order lives`);
104
+ }
105
+ if (left < RELAY_ORDER_LIFETIME_S - RELAY_MAX_ORDER_AGE_S) {
106
+ throw new RelayRefusal(code, `${what} is ${left} s away: the order is older than ${RELAY_MAX_ORDER_AGE_S} s or already past it`);
107
+ }
108
+ }
109
+ function wordAddress(word) {
110
+ return /^0{24}/.test(word) ? `0x${word.slice(24)}` : null;
111
+ }
112
+ function checkDepositTarget(tx, source) {
113
+ if (tx === null || typeof tx !== "object") throw new RelayRefusal("tx-calldata", "there is no deposit transaction");
114
+ if (tx.chainId !== source.chainId) {
115
+ throw new RelayRefusal("tx-chain", `the deposit is for chain ${String(tx.chainId)}, not ${source.chainId}`);
116
+ }
117
+ if (typeof tx.to !== "string" || !ADDRESS.test(tx.to) || lower(tx.to) !== source.depository) {
118
+ throw new RelayRefusal("tx-target", `the deposit calls ${String(tx.to)}, not the ${source.name} depository ${source.depository} \u2014 routes that first swap on the source chain go through a router and are not signed by this module`);
119
+ }
120
+ }
121
+ function checkDepositTx(tx, source, request, order, id) {
122
+ checkDepositTarget(tx, source);
123
+ if (typeof tx.data !== "string" || !/^0x(?:[0-9a-fA-F]{2})*$/.test(tx.data) || tx.data.length < 10) {
124
+ throw new RelayRefusal("tx-calldata", "the deposit has no calldata");
125
+ }
126
+ const data = lower(tx.data);
127
+ const selector = data.slice(0, 10);
128
+ const input = order.inputs[0].payment;
129
+ const native = isNative(input.currency);
130
+ if (selector === RELAY_DEPOSIT_ERC20_ALLOWANCE) {
131
+ throw new RelayRefusal("tx-selector", "the deposit uses depositErc20 without an amount, which takes the whole allowance");
132
+ }
133
+ if (selector !== RELAY_DEPOSIT_NATIVE && selector !== RELAY_DEPOSIT_ERC20) {
134
+ throw new RelayRefusal("tx-selector", `the deposit calls ${selector}, not a known deposit function`);
135
+ }
136
+ if (selector === RELAY_DEPOSIT_NATIVE !== native) {
137
+ throw new RelayRefusal("tx-selector", `the deposit calls ${native ? "depositErc20" : "depositNative"} for an order whose input is ${native ? "the native coin" : "a token"}`);
138
+ }
139
+ const words = native ? 2 : 4;
140
+ if (data.length !== 10 + 64 * words) {
141
+ throw new RelayRefusal("tx-calldata", `the deposit calldata is ${(data.length - 2) / 2} bytes, not ${4 + 32 * words}`);
142
+ }
143
+ const word = (i) => data.slice(10 + 64 * i, 74 + 64 * i);
144
+ const depositor = wordAddress(word(0));
145
+ if (depositor === null) throw new RelayRefusal("tx-calldata", "the depositor argument is not a padded address");
146
+ if (depositor !== lower(request.depositor)) {
147
+ throw new RelayRefusal("tx-depositor", `the deposit is credited to ${depositor}, not to the sender ${lower(request.depositor)}`);
148
+ }
149
+ if (!native) {
150
+ const token = wordAddress(word(1));
151
+ if (token === null) throw new RelayRefusal("tx-calldata", "the token argument is not a padded address");
152
+ if (token !== input.currency) throw new RelayRefusal("tx-token", `the deposit moves ${token}, the order's input is ${input.currency}`);
153
+ const amount = BigInt(`0x${word(2)}`);
154
+ if (amount !== input.amount) throw new RelayRefusal("tx-amount", `the deposit moves ${amount}, the order's input is ${input.amount}`);
155
+ }
156
+ const txId = `0x${word(native ? 1 : 3)}`;
157
+ if (txId !== id) throw new RelayRefusal("tx-id", `the deposit names order ${txId}, the order received hashes to ${id}`);
158
+ const value = typeof tx.value === "string" && /^(?:0|[1-9]\d{0,77})$/.test(tx.value) ? BigInt(tx.value) : null;
159
+ const wantValue = native ? input.amount : 0n;
160
+ if (value === null || value !== wantValue) {
161
+ throw new RelayRefusal("tx-value", `the deposit sends ${String(tx.value)} wei, it must send ${wantValue}`);
162
+ }
163
+ }
164
+ function verifyRelayOrder(request, protocol, deposit) {
165
+ const { source, dest, nowS } = checkRequest(request);
166
+ if (deposit !== void 0) checkDepositTarget(deposit, source);
167
+ if (protocol === null || typeof protocol !== "object") {
168
+ throw new RelayRefusal("protocol-data-missing", "the quote carries no order (protocol.v2) \u2014 nothing to check the deposit against");
169
+ }
170
+ if (protocol.orderData === void 0 || protocol.orderData === null) {
171
+ throw new RelayRefusal("protocol-data-missing", "the quote carries no order data \u2014 nothing to check the deposit against");
172
+ }
173
+ if (protocol.hubType !== "onchain") {
174
+ throw new RelayRefusal("hub-type", `the order settles through a "${String(protocol.hubType)}" hub, only "onchain" is read`);
175
+ }
176
+ const order = parseRelayOrder(protocol.orderData);
177
+ if (order.version !== RELAY_ORDER_VERSION) throw new RelayRefusal("order-version", `order version "${order.version}" is not ${RELAY_ORDER_VERSION}`);
178
+ if (order.inputs.length !== 1) throw new RelayRefusal("order-inputs", `the order has ${order.inputs.length} inputs, exactly one is signed for`);
179
+ if (order.output.payments.length !== 1) throw new RelayRefusal("order-payments", `the order pays ${order.output.payments.length} outputs, exactly one is accepted`);
180
+ if (order.output.calls.length !== 0) throw new RelayRefusal("order-calls", "the order runs calls on the destination \u2014 only plain payments are accepted");
181
+ if (order.fees.length !== 0) throw new RelayRefusal("order-fees", "the order carries order-level fees, which this module does not show and does not accept");
182
+ const input = order.inputs[0];
183
+ const pay = order.output.payments[0];
184
+ if (input.payment.weight === 0n) throw new RelayRefusal("input-weight", "the order's input has zero weight");
185
+ if (!RELAY_SOLVERS.some((s) => s.address === order.solver && s.chainId === order.solverChainId)) {
186
+ throw new RelayRefusal("solver-not-pinned", `solver ${order.solver} on "${order.solverChainId}" is not a pinned Relay solver`);
187
+ }
188
+ if (order.output.chainId !== dest.slug) throw new RelayRefusal("output-chain", `the order pays on "${order.output.chainId}", the request is for ${dest.name} ("${dest.slug}")`);
189
+ if (!isAddr(pay.recipient, request.recipient)) throw new RelayRefusal("output-recipient", `the order pays ${pay.recipient}, not the recipient ${lower(request.recipient)}`);
190
+ if (!isAddr(pay.currency, request.destToken)) throw new RelayRefusal("output-currency", `the order pays in ${pay.currency}, the request is for ${lower(request.destToken)}`);
191
+ if (pay.minimumAmount <= 0n) throw new RelayRefusal("output-minimum", "the order's minimum output is zero");
192
+ if (request.minAmountOut !== void 0 && pay.minimumAmount < request.minAmountOut) {
193
+ throw new RelayRefusal("output-minimum", `the order's minimum output ${pay.minimumAmount} is under the caller's floor ${request.minAmountOut}`);
194
+ }
195
+ if (pay.expectedAmount < pay.minimumAmount) throw new RelayRefusal("output-expected", `the order expects ${pay.expectedAmount}, less than its own minimum ${pay.minimumAmount}`);
196
+ const slippage = BigInt(request.slippageBps ?? RELAY_DEFAULT_SLIPPAGE_BPS);
197
+ const floor = pay.expectedAmount * (10000n - slippage) / 10000n;
198
+ if (pay.minimumAmount < floor) {
199
+ throw new RelayRefusal("output-minimum", `the order's minimum output ${pay.minimumAmount} is more than ${slippage} bps under its expected ${pay.expectedAmount}`);
200
+ }
201
+ checkDeadline("output-deadline", "the output deadline", order.output.deadline, nowS);
202
+ if (input.payment.chainId !== source.slug) throw new RelayRefusal("input-chain", `the order is funded on "${input.payment.chainId}", the request sends on ${source.name} ("${source.slug}")`);
203
+ if (!isAddr(input.payment.currency, request.sourceToken)) throw new RelayRefusal("input-currency", `the order is funded in ${input.payment.currency}, the request sends ${lower(request.sourceToken)}`);
204
+ if (input.payment.amount !== request.amount) throw new RelayRefusal("input-amount", `the order is funded with ${input.payment.amount}, the request sends ${request.amount}`);
205
+ let originRefund = false;
206
+ for (const refund of input.refunds) {
207
+ if (refund.chainId === source.slug) {
208
+ if (!isAddr(refund.recipient, request.depositor)) throw new RelayRefusal("refund-recipient", `a source-chain refund goes to ${refund.recipient}, not the sender ${lower(request.depositor)}`);
209
+ if (refund.currency !== input.payment.currency) throw new RelayRefusal("refund-currency", `a source-chain refund is in ${refund.currency}, not the token sent`);
210
+ originRefund = true;
211
+ } else if (refund.chainId === dest.slug) {
212
+ if (!isAddr(refund.recipient, request.recipient) && !isAddr(refund.recipient, request.depositor)) {
213
+ throw new RelayRefusal("refund-recipient", `a destination-chain refund goes to ${refund.recipient}, neither the recipient nor the sender`);
214
+ }
215
+ if (refund.currency.length !== 42) throw new RelayRefusal("refund-currency", "a destination-chain refund names no token");
216
+ } else {
217
+ throw new RelayRefusal("refund-chain", `a refund is payable on "${refund.chainId}", neither the source nor the destination chain`);
218
+ }
219
+ checkDeadline("refund-deadline", "a refund deadline", refund.deadline, nowS);
220
+ }
221
+ if (!originRefund) throw new RelayRefusal("refund-missing", "the order has no refund to the sender on the source chain");
222
+ const id = relayOrderId(order);
223
+ if (typeof protocol.orderId !== "string" || lower(protocol.orderId) !== id) {
224
+ throw new RelayRefusal("order-id-mismatch", `the quote names order ${String(protocol.orderId)}, the order data hashes to ${id}`);
225
+ }
226
+ const signer = relayOrderSigner(id, protocol.orderSignature);
227
+ if (signer === null || signer !== order.solver) {
228
+ throw new RelayRefusal("signature-invalid", signer === null ? "the order signature is not a valid signature" : `the order is signed by ${signer}, not by its solver ${order.solver}`);
229
+ }
230
+ const pd = protocol.paymentDetails;
231
+ if (pd === null || typeof pd !== "object") throw new RelayRefusal("payment-details", "the quote has no payment details");
232
+ if (pd.chainId !== source.slug || typeof pd.depository !== "string" || lower(pd.depository) !== source.depository || typeof pd.currency !== "string" || lower(pd.currency) !== input.payment.currency || typeof pd.amount !== "string" || pd.amount !== input.payment.amount.toString(10)) {
233
+ throw new RelayRefusal("payment-details", "the quote's payment details do not describe the order's input on the pinned depository");
234
+ }
235
+ const built = buildRelayDeposit(source, request.depositor, input.payment.currency, input.payment.amount, id);
236
+ if (deposit !== void 0) {
237
+ checkDepositTx(deposit, source, request, order, id);
238
+ if (lower(deposit.data) !== built.data || lower(deposit.to) !== built.to || deposit.value !== built.value) {
239
+ throw new RelayRefusal("tx-calldata", "the deposit is not the call this module builds for the order");
240
+ }
241
+ }
242
+ return { order, id, deposit: built, expectedAmount: pay.expectedAmount, minimumAmount: pay.minimumAmount, source, dest };
243
+ }
244
+ function relayRefusalReason(err) {
245
+ if (err instanceof RelayRefusal) return err.message;
246
+ throw err;
247
+ }
248
+ function relayRequestOf(params, opts = {}) {
249
+ const invalid = (what) => {
250
+ throw new RelayRefusal("request-invalid", what);
251
+ };
252
+ if (params.flex) invalid("the amount is sealed into the order (no flexible deposits)");
253
+ if (!relayChain(params.sourceChain)) throw new RelayRefusal("chain-unsupported", `source chain ${params.sourceChain} is not a pinned Relay chain`);
254
+ if (!relayChain(params.destChain)) throw new RelayRefusal("chain-unsupported", `destination chain ${params.destChain} is not a pinned Relay chain`);
255
+ if (params.sourceChain === params.destChain) throw new RelayRefusal("chain-unsupported", "same-chain swaps are not served through the depository");
256
+ let sourceToken;
257
+ if (typeof params.sourceToken === "string" && ADDRESS.test(params.sourceToken)) sourceToken = params.sourceToken;
258
+ else {
259
+ const asset = sourceAssetOf(params);
260
+ if (!asset) invalid(`source token ${String(params.sourceToken)} is not known on ${params.sourceChain}`);
261
+ sourceToken = asset.contract ?? RELAY_NATIVE;
262
+ if (!ADDRESS.test(sourceToken)) invalid(`source token ${String(params.sourceToken)} has no EVM contract`);
263
+ }
264
+ if (typeof params.destToken !== "string" || !ADDRESS.test(params.destToken)) invalid("the destination token must be an EVM address (zero for the native coin)");
265
+ if (typeof params.amountIn !== "string" || !/^[1-9]\d{0,77}$/.test(params.amountIn)) invalid("amount must be a positive base-unit integer");
266
+ if (params.minAmountOut !== void 0 && !/^(?:0|[1-9]\d{0,77})$/.test(params.minAmountOut)) invalid("the output floor must be a base-unit integer");
267
+ const recipient = params.destAddress || opts.placeholder || "";
268
+ if (!recipient) invalid("a live quote needs a recipient");
269
+ if (!ADDRESS.test(recipient)) invalid("the recipient must be an EVM address");
270
+ const depositor = params.refundAddress || opts.placeholder || "";
271
+ if (!depositor) invalid("a live quote needs the sender's address (refundAddress)");
272
+ if (!ADDRESS.test(depositor)) invalid("the sender's address must be an EVM address");
273
+ return {
274
+ sourceChain: params.sourceChain,
275
+ destChain: params.destChain,
276
+ sourceToken,
277
+ destToken: params.destToken,
278
+ amount: BigInt(params.amountIn),
279
+ depositor,
280
+ recipient,
281
+ ...params.minAmountOut !== void 0 ? { minAmountOut: BigInt(params.minAmountOut) } : {},
282
+ ...params.slippageBps !== void 0 ? { slippageBps: params.slippageBps } : {},
283
+ ...opts.nowMs !== void 0 ? { nowMs: opts.nowMs } : {}
284
+ };
285
+ }
286
+ function relayProtocolOf(quote) {
287
+ const pd = quote.providerData;
288
+ if (!pd || typeof pd.orderData !== "string") return null;
289
+ let orderData;
290
+ let paymentDetails;
291
+ try {
292
+ orderData = JSON.parse(pd.orderData);
293
+ paymentDetails = typeof pd.paymentDetails === "string" ? JSON.parse(pd.paymentDetails) : void 0;
294
+ } catch {
295
+ return null;
296
+ }
297
+ return { orderId: pd.orderId, hubType: pd.hubType, orderData, orderSignature: pd.orderSignature, paymentDetails };
298
+ }
299
+ function checkRelayQuote(request, quote, tx) {
300
+ if (quote === null || typeof quote !== "object" || quote.provider !== "relay") throw new RelayRefusal("quote-shape", "not a Relay quote");
301
+ const t = tx ?? quote.txRequest;
302
+ if (!t) throw new RelayRefusal("quote-shape", "the quote has no transaction");
303
+ if (quote.depositAddress) throw new RelayRefusal("quote-shape", "a Relay quote pays the depository through its calldata, never a deposit address");
304
+ if (quote.txRequest?.serializedTx !== void 0 || quote.txRequest?.nativeFee !== void 0) {
305
+ throw new RelayRefusal("quote-shape", "a Relay deposit carries no extra native fee and no serialized transaction");
306
+ }
307
+ const v = verifyRelayOrder(request, relayProtocolOf(quote), t);
308
+ const approval = t.approvalAddress;
309
+ if (v.deposit.approvalAddress === void 0 ? approval !== void 0 && approval !== "" : typeof approval !== "string" || lower(approval) !== v.deposit.approvalAddress) {
310
+ throw new RelayRefusal("quote-approval", `the quote approves ${String(approval)}, the order needs ${v.deposit.approvalAddress ?? "no approval"}`);
311
+ }
312
+ if (quote.sourceAmount !== request.amount.toString(10) || quote.minDestAmount !== v.minimumAmount.toString(10) || quote.destAmount !== v.expectedAmount.toString(10)) {
313
+ throw new RelayRefusal("quote-amounts", "the amounts the quote shows are not the order's");
314
+ }
315
+ const gas = t.gasLimit;
316
+ if (gas !== void 0) {
317
+ const floor = v.deposit.approvalAddress === void 0 ? RELAY_GAS_FLOOR_NATIVE : RELAY_GAS_FLOOR_ERC20;
318
+ if (typeof gas !== "string" || !/^[1-9]\d{0,10}$/.test(gas) || BigInt(gas) < floor || BigInt(gas) > RELAY_GAS_CAP) {
319
+ throw new RelayRefusal("quote-gas", `the gas limit ${String(gas).slice(0, 40)} is outside ${floor}\u2013${RELAY_GAS_CAP}`);
320
+ }
321
+ }
322
+ const now = request.nowMs ?? Date.now();
323
+ if (typeof quote.validUntilMs !== "number" || !Number.isFinite(quote.validUntilMs) || quote.validUntilMs > now + RELAY_MAX_QUOTE_LIFE_MS) {
324
+ throw new RelayRefusal("quote-expiry", "the quote claims to live longer than a Relay quote may");
325
+ }
326
+ if (typeof quote.intentId !== "string" || quote.intentId !== `relay:${String(quote.providerData?.requestId)}` || !/^relay:0x[0-9a-f]{64}$/.test(quote.intentId)) {
327
+ throw new RelayRefusal("quote-shape", "the quote's id is not its Relay request id");
328
+ }
329
+ return v;
330
+ }
331
+ function relayVerifyQuote(params, quote) {
332
+ try {
333
+ checkRelayQuote(relayRequestOf(params), quote);
334
+ return null;
335
+ } catch (err) {
336
+ return relayRefusalReason(err);
337
+ }
338
+ }
339
+ function relayVerifyBuild(quote, tx, params) {
340
+ try {
341
+ if (!params) throw new RelayRefusal("request-invalid", "the request this quote answered is not known on this side \u2014 quote again");
342
+ if (tx.chain !== params.sourceChain) throw new RelayRefusal("tx-chain", `the build is for ${tx.chain}, not ${params.sourceChain}`);
343
+ if (tx.serializedTx !== void 0 || tx.memo !== void 0 || tx.typedData !== void 0 || tx.bodyBoc !== void 0) {
344
+ throw new RelayRefusal("quote-shape", "a Relay deposit is one EVM call");
345
+ }
346
+ const v = checkRelayQuote(relayRequestOf(params), quote, tx);
347
+ relayClearOrder(v.id, "build");
348
+ return null;
349
+ } catch (err) {
350
+ return relayRefusalReason(err);
351
+ }
352
+ }
353
+ var relayPins = Object.freeze({
354
+ callTargets: (chain) => {
355
+ const c = relayChain(chain);
356
+ return c ? [c.depository] : [];
357
+ },
358
+ spenders: (chain) => {
359
+ const c = relayChain(chain);
360
+ return c ? [c.depository] : [];
361
+ },
362
+ verifyQuote: relayVerifyQuote,
363
+ verifyBuild: relayVerifyBuild
364
+ });
365
+
366
+ export {
367
+ relayClearOrder,
368
+ RELAY_MAX_SLIPPAGE_BPS,
369
+ RELAY_DEFAULT_SLIPPAGE_BPS,
370
+ RELAY_GAS_FLOOR_NATIVE,
371
+ RELAY_GAS_FLOOR_ERC20,
372
+ RELAY_GAS_CAP,
373
+ RELAY_MAX_QUOTE_LIFE_MS,
374
+ buildRelayDeposit,
375
+ verifyRelayOrder,
376
+ relayRefusalReason,
377
+ relayRequestOf,
378
+ relayProtocolOf,
379
+ checkRelayQuote,
380
+ relayVerifyQuote,
381
+ relayVerifyBuild,
382
+ relayPins
383
+ };
384
+ //# sourceMappingURL=chunk-WRIKAUWI.js.map