@anywalletkit/protocol-swap2-relay 0.1.1 → 0.1.3

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/dist/verify.cjs CHANGED
@@ -39,6 +39,7 @@ __export(verify_exports, {
39
39
  });
40
40
  module.exports = __toCommonJS(verify_exports);
41
41
  var import_viem2 = require("viem");
42
+ var import_errors2 = require("@anywalletkit/protocol-swap2-core/errors");
42
43
  var import_util = require("@anywalletkit/protocol-swap2-core/util");
43
44
 
44
45
  // src/config.ts
@@ -93,13 +94,15 @@ var RELAY_CLOCK_SKEW_S = 300;
93
94
 
94
95
  // src/order.ts
95
96
  var import_secp256k1 = require("@noble/curves/secp256k1.js");
97
+ var import_errors = require("@anywalletkit/protocol-swap2-core/errors");
96
98
  var import_viem = require("viem");
97
99
  var RelayRefusal = class extends Error {
98
100
  code;
99
- constructor(code, detail) {
101
+ constructor(code, detail, reason) {
100
102
  super(`relay: ${detail} [${code}]`);
101
103
  this.name = "RelayRefusal";
102
104
  this.code = code;
105
+ if (reason !== void 0) (0, import_errors.withReason)(this, reason);
103
106
  }
104
107
  };
105
108
  var RELAY_ORDER_TYPES = {
@@ -156,7 +159,7 @@ var MAX_BYTES_HEX = 2 + 2 * 1024;
156
159
  var MAX_TEXT = 64;
157
160
  var U256_MAX = (1n << 256n) - 1n;
158
161
  var bad = (what) => {
159
- throw new RelayRefusal("order-malformed", `the order's ${what}`);
162
+ throw new RelayRefusal("order-malformed", `the order's ${what}`, "upstream_unavailable");
160
163
  };
161
164
  function rec(v, what) {
162
165
  if (v === null || typeof v !== "object" || Array.isArray(v)) bad(`${what} is not an object`);
@@ -280,10 +283,10 @@ var clearedOrders = /* @__PURE__ */ new Map();
280
283
  function relayClearOrder(id, stage, nowMs = Date.now()) {
281
284
  const key = `${stage}:${id.toLowerCase()}`;
282
285
  const until = clearedOrders.get(key);
283
- if (until !== void 0 && until > nowMs) throw new RelayRefusal("order-reused", `order ${id} was already cleared for a deposit \u2014 quote again`);
286
+ if (until !== void 0 && until > nowMs) throw new RelayRefusal("order-reused", `order ${id} was already cleared for a deposit \u2014 quote again`, "policy_refused");
284
287
  if (clearedOrders.size >= CLEARED_MAX) {
285
288
  for (const [k, t] of clearedOrders) if (t <= nowMs) clearedOrders.delete(k);
286
- if (clearedOrders.size >= CLEARED_MAX) throw new RelayRefusal("order-reused", "too many deposits cleared in the last minutes \u2014 try again later");
289
+ if (clearedOrders.size >= CLEARED_MAX) throw new RelayRefusal("order-reused", "too many deposits cleared in the last minutes \u2014 try again later", "policy_refused");
287
290
  }
288
291
  clearedOrders.set(key, nowMs + CLEARED_TTL_MS);
289
292
  }
@@ -325,24 +328,24 @@ function buildRelayDeposit(source, depositor, token, amount, id) {
325
328
  };
326
329
  }
327
330
  function checkRequest(r) {
328
- const invalid = (what) => {
329
- throw new RelayRefusal("request-invalid", what);
331
+ const invalid = (what, reason) => {
332
+ throw new RelayRefusal("request-invalid", what, reason);
330
333
  };
331
334
  if (r === null || typeof r !== "object") invalid("no request to check the order against");
332
335
  const source = relayChain(r.sourceChain);
333
336
  const dest = relayChain(r.destChain);
334
- if (!source) throw new RelayRefusal("chain-unsupported", `source chain ${String(r.sourceChain)} is not a pinned Relay chain`);
335
- if (!dest) throw new RelayRefusal("chain-unsupported", `destination chain ${String(r.destChain)} is not a pinned Relay chain`);
336
- if (source === dest) throw new RelayRefusal("chain-unsupported", "source and destination are the same chain");
337
+ if (!source) throw new RelayRefusal("chain-unsupported", `source chain ${String(r.sourceChain)} is not a pinned Relay chain`, "unsupported_pair");
338
+ if (!dest) throw new RelayRefusal("chain-unsupported", `destination chain ${String(r.destChain)} is not a pinned Relay chain`, "unsupported_pair");
339
+ if (source === dest) throw new RelayRefusal("chain-unsupported", "source and destination are the same chain", "unsupported_pair");
337
340
  for (const [what, v] of [["input token", r.sourceToken], ["output token", r.destToken], ["depositor", r.depositor], ["recipient", r.recipient]]) {
338
341
  if (typeof v !== "string" || !ADDRESS.test(v)) invalid(`the ${what} is not an address`);
339
342
  }
340
- if (/^0x0{40}$/.test(r.depositor)) invalid("the depositor is the zero address");
341
- if (/^0x0{40}$/.test(r.recipient)) invalid("the recipient is the zero address");
343
+ if (/^0x0{40}$/.test(r.depositor)) invalid("the depositor is the zero address", "recipient_mismatch");
344
+ if (/^0x0{40}$/.test(r.recipient)) invalid("the recipient is the zero address", "recipient_mismatch");
342
345
  if (typeof r.amount !== "bigint" || r.amount <= 0n || r.amount > U256_MAX2) invalid("the amount is not a positive integer");
343
346
  if (r.minAmountOut !== void 0 && (typeof r.minAmountOut !== "bigint" || r.minAmountOut < 0n)) invalid("the output floor is not an unsigned integer");
344
347
  if (r.slippageBps !== void 0 && (!Number.isInteger(r.slippageBps) || r.slippageBps < 0 || r.slippageBps > RELAY_MAX_SLIPPAGE_BPS)) {
345
- invalid(`slippage must be a whole number of basis points up to ${RELAY_MAX_SLIPPAGE_BPS}`);
348
+ invalid(`slippage must be a whole number of basis points up to ${RELAY_MAX_SLIPPAGE_BPS}`, "policy_refused");
346
349
  }
347
350
  const nowMs = r.nowMs ?? Date.now();
348
351
  if (!Number.isFinite(nowMs) || nowMs <= 0) invalid("the clock is not a time");
@@ -352,143 +355,143 @@ var isAddr = (bytes2, addr) => bytes2.length === 42 && bytes2 === lower(addr);
352
355
  function checkDeadline(code, what, deadline, nowS) {
353
356
  const left = deadline - nowS;
354
357
  if (left > RELAY_ORDER_LIFETIME_S + RELAY_CLOCK_SKEW_S) {
355
- throw new RelayRefusal(code, `${what} is ${left} s away, past the ${RELAY_ORDER_LIFETIME_S} s an order lives`);
358
+ throw new RelayRefusal(code, `${what} is ${left} s away, past the ${RELAY_ORDER_LIFETIME_S} s an order lives`, "policy_refused");
356
359
  }
357
360
  if (left < RELAY_ORDER_LIFETIME_S - RELAY_MAX_ORDER_AGE_S) {
358
- throw new RelayRefusal(code, `${what} is ${left} s away: the order is older than ${RELAY_MAX_ORDER_AGE_S} s or already past it`);
361
+ throw new RelayRefusal(code, `${what} is ${left} s away: the order is older than ${RELAY_MAX_ORDER_AGE_S} s or already past it`, "quote_expired");
359
362
  }
360
363
  }
361
364
  function wordAddress(word) {
362
365
  return /^0{24}/.test(word) ? `0x${word.slice(24)}` : null;
363
366
  }
364
367
  function checkDepositTarget(tx, source) {
365
- if (tx === null || typeof tx !== "object") throw new RelayRefusal("tx-calldata", "there is no deposit transaction");
368
+ if (tx === null || typeof tx !== "object") throw new RelayRefusal("tx-calldata", "there is no deposit transaction", "policy_refused");
366
369
  if (tx.chainId !== source.chainId) {
367
- throw new RelayRefusal("tx-chain", `the deposit is for chain ${String(tx.chainId)}, not ${source.chainId}`);
370
+ throw new RelayRefusal("tx-chain", `the deposit is for chain ${String(tx.chainId)}, not ${source.chainId}`, "vault_mismatch");
368
371
  }
369
372
  if (typeof tx.to !== "string" || !ADDRESS.test(tx.to) || lower(tx.to) !== source.depository) {
370
- 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`);
373
+ 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`, "vault_mismatch");
371
374
  }
372
375
  }
373
376
  function checkDepositTx(tx, source, request, order, id) {
374
377
  checkDepositTarget(tx, source);
375
378
  if (typeof tx.data !== "string" || !/^0x(?:[0-9a-fA-F]{2})*$/.test(tx.data) || tx.data.length < 10) {
376
- throw new RelayRefusal("tx-calldata", "the deposit has no calldata");
379
+ throw new RelayRefusal("tx-calldata", "the deposit has no calldata", "policy_refused");
377
380
  }
378
381
  const data = lower(tx.data);
379
382
  const selector = data.slice(0, 10);
380
383
  const input = order.inputs[0].payment;
381
384
  const native = isNative(input.currency);
382
385
  if (selector === RELAY_DEPOSIT_ERC20_ALLOWANCE) {
383
- throw new RelayRefusal("tx-selector", "the deposit uses depositErc20 without an amount, which takes the whole allowance");
386
+ throw new RelayRefusal("tx-selector", "the deposit uses depositErc20 without an amount, which takes the whole allowance", "policy_refused");
384
387
  }
385
388
  if (selector !== RELAY_DEPOSIT_NATIVE && selector !== RELAY_DEPOSIT_ERC20) {
386
- throw new RelayRefusal("tx-selector", `the deposit calls ${selector}, not a known deposit function`);
389
+ throw new RelayRefusal("tx-selector", `the deposit calls ${selector}, not a known deposit function`, "policy_refused");
387
390
  }
388
391
  if (selector === RELAY_DEPOSIT_NATIVE !== native) {
389
- throw new RelayRefusal("tx-selector", `the deposit calls ${native ? "depositErc20" : "depositNative"} for an order whose input is ${native ? "the native coin" : "a token"}`);
392
+ throw new RelayRefusal("tx-selector", `the deposit calls ${native ? "depositErc20" : "depositNative"} for an order whose input is ${native ? "the native coin" : "a token"}`, "policy_refused");
390
393
  }
391
394
  const words = native ? 2 : 4;
392
395
  if (data.length !== 10 + 64 * words) {
393
- throw new RelayRefusal("tx-calldata", `the deposit calldata is ${(data.length - 2) / 2} bytes, not ${4 + 32 * words}`);
396
+ throw new RelayRefusal("tx-calldata", `the deposit calldata is ${(data.length - 2) / 2} bytes, not ${4 + 32 * words}`, "policy_refused");
394
397
  }
395
398
  const word = (i) => data.slice(10 + 64 * i, 74 + 64 * i);
396
399
  const depositor = wordAddress(word(0));
397
- if (depositor === null) throw new RelayRefusal("tx-calldata", "the depositor argument is not a padded address");
400
+ if (depositor === null) throw new RelayRefusal("tx-calldata", "the depositor argument is not a padded address", "policy_refused");
398
401
  if (depositor !== lower(request.depositor)) {
399
- throw new RelayRefusal("tx-depositor", `the deposit is credited to ${depositor}, not to the sender ${lower(request.depositor)}`);
402
+ throw new RelayRefusal("tx-depositor", `the deposit is credited to ${depositor}, not to the sender ${lower(request.depositor)}`, "recipient_mismatch");
400
403
  }
401
404
  if (!native) {
402
405
  const token = wordAddress(word(1));
403
- if (token === null) throw new RelayRefusal("tx-calldata", "the token argument is not a padded address");
404
- if (token !== input.currency) throw new RelayRefusal("tx-token", `the deposit moves ${token}, the order's input is ${input.currency}`);
406
+ if (token === null) throw new RelayRefusal("tx-calldata", "the token argument is not a padded address", "policy_refused");
407
+ if (token !== input.currency) throw new RelayRefusal("tx-token", `the deposit moves ${token}, the order's input is ${input.currency}`, "policy_refused");
405
408
  const amount = BigInt(`0x${word(2)}`);
406
- if (amount !== input.amount) throw new RelayRefusal("tx-amount", `the deposit moves ${amount}, the order's input is ${input.amount}`);
409
+ if (amount !== input.amount) throw new RelayRefusal("tx-amount", `the deposit moves ${amount}, the order's input is ${input.amount}`, "policy_refused");
407
410
  }
408
411
  const txId = `0x${word(native ? 1 : 3)}`;
409
- if (txId !== id) throw new RelayRefusal("tx-id", `the deposit names order ${txId}, the order received hashes to ${id}`);
412
+ if (txId !== id) throw new RelayRefusal("tx-id", `the deposit names order ${txId}, the order received hashes to ${id}`, "recipient_unverifiable");
410
413
  const value = typeof tx.value === "string" && /^(?:0|[1-9]\d{0,77})$/.test(tx.value) ? BigInt(tx.value) : null;
411
414
  const wantValue = native ? input.amount : 0n;
412
415
  if (value === null || value !== wantValue) {
413
- throw new RelayRefusal("tx-value", `the deposit sends ${String(tx.value)} wei, it must send ${wantValue}`);
416
+ throw new RelayRefusal("tx-value", `the deposit sends ${String(tx.value)} wei, it must send ${wantValue}`, "policy_refused");
414
417
  }
415
418
  }
416
419
  function verifyRelayOrder(request, protocol, deposit) {
417
420
  const { source, dest, nowS } = checkRequest(request);
418
421
  if (deposit !== void 0) checkDepositTarget(deposit, source);
419
422
  if (protocol === null || typeof protocol !== "object") {
420
- throw new RelayRefusal("protocol-data-missing", "the quote carries no order (protocol.v2) \u2014 nothing to check the deposit against");
423
+ throw new RelayRefusal("protocol-data-missing", "the quote carries no order (protocol.v2) \u2014 nothing to check the deposit against", "upstream_unavailable");
421
424
  }
422
425
  if (protocol.orderData === void 0 || protocol.orderData === null) {
423
- throw new RelayRefusal("protocol-data-missing", "the quote carries no order data \u2014 nothing to check the deposit against");
426
+ throw new RelayRefusal("protocol-data-missing", "the quote carries no order data \u2014 nothing to check the deposit against", "upstream_unavailable");
424
427
  }
425
428
  if (protocol.hubType !== "onchain") {
426
- throw new RelayRefusal("hub-type", `the order settles through a "${String(protocol.hubType)}" hub, only "onchain" is read`);
429
+ throw new RelayRefusal("hub-type", `the order settles through a "${String(protocol.hubType)}" hub, only "onchain" is read`, "unsupported_pair");
427
430
  }
428
431
  const order = parseRelayOrder(protocol.orderData);
429
- if (order.version !== RELAY_ORDER_VERSION) throw new RelayRefusal("order-version", `order version "${order.version}" is not ${RELAY_ORDER_VERSION}`);
430
- if (order.inputs.length !== 1) throw new RelayRefusal("order-inputs", `the order has ${order.inputs.length} inputs, exactly one is signed for`);
431
- if (order.output.payments.length !== 1) throw new RelayRefusal("order-payments", `the order pays ${order.output.payments.length} outputs, exactly one is accepted`);
432
- if (order.output.calls.length !== 0) throw new RelayRefusal("order-calls", "the order runs calls on the destination \u2014 only plain payments are accepted");
433
- 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");
432
+ if (order.version !== RELAY_ORDER_VERSION) throw new RelayRefusal("order-version", `order version "${order.version}" is not ${RELAY_ORDER_VERSION}`, "upstream_unavailable");
433
+ if (order.inputs.length !== 1) throw new RelayRefusal("order-inputs", `the order has ${order.inputs.length} inputs, exactly one is signed for`, "policy_refused");
434
+ if (order.output.payments.length !== 1) throw new RelayRefusal("order-payments", `the order pays ${order.output.payments.length} outputs, exactly one is accepted`, "policy_refused");
435
+ if (order.output.calls.length !== 0) throw new RelayRefusal("order-calls", "the order runs calls on the destination \u2014 only plain payments are accepted", "policy_refused");
436
+ 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", "policy_refused");
434
437
  const input = order.inputs[0];
435
438
  const pay = order.output.payments[0];
436
- if (input.payment.weight === 0n) throw new RelayRefusal("input-weight", "the order's input has zero weight");
439
+ if (input.payment.weight === 0n) throw new RelayRefusal("input-weight", "the order's input has zero weight", "policy_refused");
437
440
  if (!RELAY_SOLVERS.some((s) => s.address === order.solver && s.chainId === order.solverChainId)) {
438
- throw new RelayRefusal("solver-not-pinned", `solver ${order.solver} on "${order.solverChainId}" is not a pinned Relay solver`);
441
+ throw new RelayRefusal("solver-not-pinned", `solver ${order.solver} on "${order.solverChainId}" is not a pinned Relay solver`, "recipient_unverifiable");
439
442
  }
440
- 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}")`);
441
- if (!isAddr(pay.recipient, request.recipient)) throw new RelayRefusal("output-recipient", `the order pays ${pay.recipient}, not the recipient ${lower(request.recipient)}`);
442
- if (!isAddr(pay.currency, request.destToken)) throw new RelayRefusal("output-currency", `the order pays in ${pay.currency}, the request is for ${lower(request.destToken)}`);
443
- if (pay.minimumAmount <= 0n) throw new RelayRefusal("output-minimum", "the order's minimum output is zero");
443
+ 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}")`, "recipient_mismatch");
444
+ if (!isAddr(pay.recipient, request.recipient)) throw new RelayRefusal("output-recipient", `the order pays ${pay.recipient}, not the recipient ${lower(request.recipient)}`, "recipient_mismatch");
445
+ if (!isAddr(pay.currency, request.destToken)) throw new RelayRefusal("output-currency", `the order pays in ${pay.currency}, the request is for ${lower(request.destToken)}`, "price_check_failed");
446
+ if (pay.minimumAmount <= 0n) throw new RelayRefusal("output-minimum", "the order's minimum output is zero", "price_check_failed");
444
447
  if (request.minAmountOut !== void 0 && pay.minimumAmount < request.minAmountOut) {
445
- throw new RelayRefusal("output-minimum", `the order's minimum output ${pay.minimumAmount} is under the caller's floor ${request.minAmountOut}`);
448
+ throw new RelayRefusal("output-minimum", `the order's minimum output ${pay.minimumAmount} is under the caller's floor ${request.minAmountOut}`, "price_check_failed");
446
449
  }
447
- if (pay.expectedAmount < pay.minimumAmount) throw new RelayRefusal("output-expected", `the order expects ${pay.expectedAmount}, less than its own minimum ${pay.minimumAmount}`);
450
+ if (pay.expectedAmount < pay.minimumAmount) throw new RelayRefusal("output-expected", `the order expects ${pay.expectedAmount}, less than its own minimum ${pay.minimumAmount}`, "price_check_failed");
448
451
  const slippage = BigInt(request.slippageBps ?? RELAY_DEFAULT_SLIPPAGE_BPS);
449
452
  const floor = pay.expectedAmount * (10000n - slippage) / 10000n;
450
453
  if (pay.minimumAmount < floor) {
451
- throw new RelayRefusal("output-minimum", `the order's minimum output ${pay.minimumAmount} is more than ${slippage} bps under its expected ${pay.expectedAmount}`);
454
+ throw new RelayRefusal("output-minimum", `the order's minimum output ${pay.minimumAmount} is more than ${slippage} bps under its expected ${pay.expectedAmount}`, "price_check_failed");
452
455
  }
453
456
  checkDeadline("output-deadline", "the output deadline", order.output.deadline, nowS);
454
- 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}")`);
455
- 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)}`);
456
- if (input.payment.amount !== request.amount) throw new RelayRefusal("input-amount", `the order is funded with ${input.payment.amount}, the request sends ${request.amount}`);
457
+ 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}")`, "policy_refused");
458
+ 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)}`, "policy_refused");
459
+ if (input.payment.amount !== request.amount) throw new RelayRefusal("input-amount", `the order is funded with ${input.payment.amount}, the request sends ${request.amount}`, "policy_refused");
457
460
  let originRefund = false;
458
461
  for (const refund of input.refunds) {
459
462
  if (refund.chainId === source.slug) {
460
- 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)}`);
461
- if (refund.currency !== input.payment.currency) throw new RelayRefusal("refund-currency", `a source-chain refund is in ${refund.currency}, not the token sent`);
463
+ 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)}`, "recipient_mismatch");
464
+ if (refund.currency !== input.payment.currency) throw new RelayRefusal("refund-currency", `a source-chain refund is in ${refund.currency}, not the token sent`, "policy_refused");
462
465
  originRefund = true;
463
466
  } else if (refund.chainId === dest.slug) {
464
467
  if (!isAddr(refund.recipient, request.recipient) && !isAddr(refund.recipient, request.depositor)) {
465
- throw new RelayRefusal("refund-recipient", `a destination-chain refund goes to ${refund.recipient}, neither the recipient nor the sender`);
468
+ throw new RelayRefusal("refund-recipient", `a destination-chain refund goes to ${refund.recipient}, neither the recipient nor the sender`, "recipient_mismatch");
466
469
  }
467
- if (refund.currency.length !== 42) throw new RelayRefusal("refund-currency", "a destination-chain refund names no token");
470
+ if (refund.currency.length !== 42) throw new RelayRefusal("refund-currency", "a destination-chain refund names no token", "policy_refused");
468
471
  } else {
469
- throw new RelayRefusal("refund-chain", `a refund is payable on "${refund.chainId}", neither the source nor the destination chain`);
472
+ throw new RelayRefusal("refund-chain", `a refund is payable on "${refund.chainId}", neither the source nor the destination chain`, "recipient_mismatch");
470
473
  }
471
474
  checkDeadline("refund-deadline", "a refund deadline", refund.deadline, nowS);
472
475
  }
473
- if (!originRefund) throw new RelayRefusal("refund-missing", "the order has no refund to the sender on the source chain");
476
+ if (!originRefund) throw new RelayRefusal("refund-missing", "the order has no refund to the sender on the source chain", "policy_refused");
474
477
  const id = relayOrderId(order);
475
478
  if (typeof protocol.orderId !== "string" || lower(protocol.orderId) !== id) {
476
- throw new RelayRefusal("order-id-mismatch", `the quote names order ${String(protocol.orderId)}, the order data hashes to ${id}`);
479
+ throw new RelayRefusal("order-id-mismatch", `the quote names order ${String(protocol.orderId)}, the order data hashes to ${id}`, "recipient_unverifiable");
477
480
  }
478
481
  const signer = relayOrderSigner(id, protocol.orderSignature);
479
482
  if (signer === null || signer !== order.solver) {
480
- 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}`);
483
+ 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}`, "recipient_unverifiable");
481
484
  }
482
485
  const pd = protocol.paymentDetails;
483
- if (pd === null || typeof pd !== "object") throw new RelayRefusal("payment-details", "the quote has no payment details");
486
+ if (pd === null || typeof pd !== "object") throw new RelayRefusal("payment-details", "the quote has no payment details", "upstream_unavailable");
484
487
  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)) {
485
- throw new RelayRefusal("payment-details", "the quote's payment details do not describe the order's input on the pinned depository");
488
+ throw new RelayRefusal("payment-details", "the quote's payment details do not describe the order's input on the pinned depository", "vault_mismatch");
486
489
  }
487
490
  const built = buildRelayDeposit(source, request.depositor, input.payment.currency, input.payment.amount, id);
488
491
  if (deposit !== void 0) {
489
492
  checkDepositTx(deposit, source, request, order, id);
490
493
  if (lower(deposit.data) !== built.data || lower(deposit.to) !== built.to || deposit.value !== built.value) {
491
- throw new RelayRefusal("tx-calldata", "the deposit is not the call this module builds for the order");
494
+ throw new RelayRefusal("tx-calldata", "the deposit is not the call this module builds for the order", "policy_refused");
492
495
  }
493
496
  }
494
497
  return { order, id, deposit: built, expectedAmount: pay.expectedAmount, minimumAmount: pay.minimumAmount, source, dest };
@@ -498,22 +501,22 @@ function relayRefusalReason(err) {
498
501
  throw err;
499
502
  }
500
503
  function relayRequestOf(params, opts = {}) {
501
- const invalid = (what) => {
502
- throw new RelayRefusal("request-invalid", what);
504
+ const invalid = (what, reason) => {
505
+ throw new RelayRefusal("request-invalid", what, reason);
503
506
  };
504
- if (params.flex) invalid("the amount is sealed into the order (no flexible deposits)");
505
- if (!relayChain(params.sourceChain)) throw new RelayRefusal("chain-unsupported", `source chain ${params.sourceChain} is not a pinned Relay chain`);
506
- if (!relayChain(params.destChain)) throw new RelayRefusal("chain-unsupported", `destination chain ${params.destChain} is not a pinned Relay chain`);
507
- if (params.sourceChain === params.destChain) throw new RelayRefusal("chain-unsupported", "same-chain swaps are not served through the depository");
507
+ if (params.flex) invalid("the amount is sealed into the order (no flexible deposits)", "unsupported_pair");
508
+ if (!relayChain(params.sourceChain)) throw new RelayRefusal("chain-unsupported", `source chain ${params.sourceChain} is not a pinned Relay chain`, "unsupported_pair");
509
+ if (!relayChain(params.destChain)) throw new RelayRefusal("chain-unsupported", `destination chain ${params.destChain} is not a pinned Relay chain`, "unsupported_pair");
510
+ if (params.sourceChain === params.destChain) throw new RelayRefusal("chain-unsupported", "same-chain swaps are not served through the depository", "unsupported_pair");
508
511
  let sourceToken;
509
512
  if (typeof params.sourceToken === "string" && ADDRESS.test(params.sourceToken)) sourceToken = params.sourceToken;
510
513
  else {
511
514
  const asset = (0, import_util.sourceAssetOf)(params);
512
- if (!asset) invalid(`source token ${String(params.sourceToken)} is not known on ${params.sourceChain}`);
515
+ if (!asset) invalid(`source token ${String(params.sourceToken)} is not known on ${params.sourceChain}`, "unsupported_pair");
513
516
  sourceToken = asset.contract ?? RELAY_NATIVE;
514
- if (!ADDRESS.test(sourceToken)) invalid(`source token ${String(params.sourceToken)} has no EVM contract`);
517
+ if (!ADDRESS.test(sourceToken)) invalid(`source token ${String(params.sourceToken)} has no EVM contract`, "unsupported_pair");
515
518
  }
516
- if (typeof params.destToken !== "string" || !ADDRESS.test(params.destToken)) invalid("the destination token must be an EVM address (zero for the native coin)");
519
+ if (typeof params.destToken !== "string" || !ADDRESS.test(params.destToken)) invalid("the destination token must be an EVM address (zero for the native coin)", "unsupported_pair");
517
520
  if (typeof params.amountIn !== "string" || !/^[1-9]\d{0,77}$/.test(params.amountIn)) invalid("amount must be a positive base-unit integer");
518
521
  if (params.minAmountOut !== void 0 && !/^(?:0|[1-9]\d{0,77})$/.test(params.minAmountOut)) invalid("the output floor must be a base-unit integer");
519
522
  const recipient = params.destAddress || opts.placeholder || "";
@@ -549,57 +552,63 @@ function relayProtocolOf(quote) {
549
552
  return { orderId: pd.orderId, hubType: pd.hubType, orderData, orderSignature: pd.orderSignature, paymentDetails };
550
553
  }
551
554
  function checkRelayQuote(request, quote, tx) {
552
- if (quote === null || typeof quote !== "object" || quote.provider !== "relay") throw new RelayRefusal("quote-shape", "not a Relay quote");
555
+ if (quote === null || typeof quote !== "object" || quote.provider !== "relay") throw new RelayRefusal("quote-shape", "not a Relay quote", "policy_refused");
553
556
  const t = tx ?? quote.txRequest;
554
- if (!t) throw new RelayRefusal("quote-shape", "the quote has no transaction");
555
- if (quote.depositAddress) throw new RelayRefusal("quote-shape", "a Relay quote pays the depository through its calldata, never a deposit address");
557
+ if (!t) throw new RelayRefusal("quote-shape", "the quote has no transaction", "policy_refused");
558
+ if (quote.depositAddress) throw new RelayRefusal("quote-shape", "a Relay quote pays the depository through its calldata, never a deposit address", "vault_mismatch");
556
559
  if (quote.txRequest?.serializedTx !== void 0 || quote.txRequest?.nativeFee !== void 0) {
557
- throw new RelayRefusal("quote-shape", "a Relay deposit carries no extra native fee and no serialized transaction");
560
+ throw new RelayRefusal("quote-shape", "a Relay deposit carries no extra native fee and no serialized transaction", "policy_refused");
558
561
  }
559
562
  const v = verifyRelayOrder(request, relayProtocolOf(quote), t);
560
563
  const approval = t.approvalAddress;
561
564
  if (v.deposit.approvalAddress === void 0 ? approval !== void 0 && approval !== "" : typeof approval !== "string" || lower(approval) !== v.deposit.approvalAddress) {
562
- throw new RelayRefusal("quote-approval", `the quote approves ${String(approval)}, the order needs ${v.deposit.approvalAddress ?? "no approval"}`);
565
+ throw new RelayRefusal("quote-approval", `the quote approves ${String(approval)}, the order needs ${v.deposit.approvalAddress ?? "no approval"}`, "vault_mismatch");
563
566
  }
564
567
  if (quote.sourceAmount !== request.amount.toString(10) || quote.minDestAmount !== v.minimumAmount.toString(10) || quote.destAmount !== v.expectedAmount.toString(10)) {
565
- throw new RelayRefusal("quote-amounts", "the amounts the quote shows are not the order's");
568
+ throw new RelayRefusal("quote-amounts", "the amounts the quote shows are not the order's", "price_check_failed");
566
569
  }
567
570
  const gas = t.gasLimit;
568
571
  if (gas !== void 0) {
569
572
  const floor = v.deposit.approvalAddress === void 0 ? RELAY_GAS_FLOOR_NATIVE : RELAY_GAS_FLOOR_ERC20;
570
573
  if (typeof gas !== "string" || !/^[1-9]\d{0,10}$/.test(gas) || BigInt(gas) < floor || BigInt(gas) > RELAY_GAS_CAP) {
571
- throw new RelayRefusal("quote-gas", `the gas limit ${String(gas).slice(0, 40)} is outside ${floor}\u2013${RELAY_GAS_CAP}`);
574
+ throw new RelayRefusal("quote-gas", `the gas limit ${String(gas).slice(0, 40)} is outside ${floor}\u2013${RELAY_GAS_CAP}`, "policy_refused");
572
575
  }
573
576
  }
574
577
  const now = request.nowMs ?? Date.now();
575
578
  if (typeof quote.validUntilMs !== "number" || !Number.isFinite(quote.validUntilMs) || quote.validUntilMs > now + RELAY_MAX_QUOTE_LIFE_MS) {
576
- throw new RelayRefusal("quote-expiry", "the quote claims to live longer than a Relay quote may");
579
+ throw new RelayRefusal("quote-expiry", "the quote claims to live longer than a Relay quote may", "policy_refused");
577
580
  }
578
581
  if (typeof quote.intentId !== "string" || quote.intentId !== `relay:${String(quote.providerData?.requestId)}` || !/^relay:0x[0-9a-f]{64}$/.test(quote.intentId)) {
579
- throw new RelayRefusal("quote-shape", "the quote's id is not its Relay request id");
582
+ throw new RelayRefusal("quote-shape", "the quote's id is not its Relay request id", "policy_refused");
580
583
  }
581
584
  return v;
582
585
  }
586
+ var pinNotes = (0, import_errors2.refusalNotes)();
587
+ function notedReason(err) {
588
+ const text2 = relayRefusalReason(err);
589
+ const info = (0, import_errors2.refusalOf)(err);
590
+ return info ? pinNotes.note(text2, info) : text2;
591
+ }
583
592
  function relayVerifyQuote(params, quote) {
584
593
  try {
585
594
  checkRelayQuote(relayRequestOf(params), quote);
586
595
  return null;
587
596
  } catch (err) {
588
- return relayRefusalReason(err);
597
+ return notedReason(err);
589
598
  }
590
599
  }
591
600
  function relayVerifyBuild(quote, tx, params) {
592
601
  try {
593
- if (!params) throw new RelayRefusal("request-invalid", "the request this quote answered is not known on this side \u2014 quote again");
594
- if (tx.chain !== params.sourceChain) throw new RelayRefusal("tx-chain", `the build is for ${tx.chain}, not ${params.sourceChain}`);
602
+ if (!params) throw new RelayRefusal("request-invalid", "the request this quote answered is not known on this side \u2014 quote again", "policy_refused");
603
+ if (tx.chain !== params.sourceChain) throw new RelayRefusal("tx-chain", `the build is for ${tx.chain}, not ${params.sourceChain}`, "vault_mismatch");
595
604
  if (tx.serializedTx !== void 0 || tx.memo !== void 0 || tx.typedData !== void 0 || tx.bodyBoc !== void 0) {
596
- throw new RelayRefusal("quote-shape", "a Relay deposit is one EVM call");
605
+ throw new RelayRefusal("quote-shape", "a Relay deposit is one EVM call", "policy_refused");
597
606
  }
598
607
  const v = checkRelayQuote(relayRequestOf(params), quote, tx);
599
608
  relayClearOrder(v.id, "build");
600
609
  return null;
601
610
  } catch (err) {
602
- return relayRefusalReason(err);
611
+ return notedReason(err);
603
612
  }
604
613
  }
605
614
  var relayPins = Object.freeze({
@@ -612,6 +621,7 @@ var relayPins = Object.freeze({
612
621
  return c2 ? [c2.depository] : [];
613
622
  },
614
623
  verifyQuote: relayVerifyQuote,
615
- verifyBuild: relayVerifyBuild
624
+ verifyBuild: relayVerifyBuild,
625
+ reasonOf: pinNotes.reasonOf
616
626
  });
617
627
  //# sourceMappingURL=verify.cjs.map