@anywalletkit/protocol-swap2-chainflip 0.4.6 → 0.4.7
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/activity.cjs +36 -14
- package/dist/activity.cjs.map +1 -1
- package/dist/activity.js +2 -2
- package/dist/{chunk-ZH5XKSCP.js → chunk-C2OITXU4.js} +2 -2
- package/dist/{chunk-RRCQYT67.js → chunk-G5FZLGMT.js} +3 -3
- package/dist/{chunk-DGLXKJQ7.js → chunk-IQSAPDND.js} +35 -15
- package/dist/chunk-IQSAPDND.js.map +1 -0
- package/dist/{chunk-RU2NXJTL.js → chunk-XUMGQNH4.js} +66 -40
- package/dist/chunk-XUMGQNH4.js.map +1 -0
- package/dist/config.cjs +34 -14
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +2 -12
- package/dist/config.d.ts +2 -12
- package/dist/config.js +1 -1
- package/dist/index.cjs +99 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -4
- package/dist/protocol.cjs +99 -51
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.js +4 -4
- package/dist/provider.cjs +99 -51
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.js +3 -3
- package/package.json +3 -3
- package/dist/chunk-DGLXKJQ7.js.map +0 -1
- package/dist/chunk-RU2NXJTL.js.map +0 -1
- /package/dist/{chunk-ZH5XKSCP.js.map → chunk-C2OITXU4.js.map} +0 -0
- /package/dist/{chunk-RRCQYT67.js.map → chunk-G5FZLGMT.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ChainflipSwap2Protocol
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-G5FZLGMT.js";
|
|
4
4
|
import {
|
|
5
5
|
chainflipProvider
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XUMGQNH4.js";
|
|
7
7
|
import {
|
|
8
8
|
CHAINFLIP_MODULE,
|
|
9
9
|
describeChainflipActivity
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-C2OITXU4.js";
|
|
11
11
|
import {
|
|
12
12
|
CF_API_DEFAULT,
|
|
13
13
|
CF_ASSETS,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
chainflip,
|
|
19
19
|
chainflipPins,
|
|
20
20
|
chainflipVerifyQuote
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-IQSAPDND.js";
|
|
22
22
|
import {
|
|
23
23
|
decodeCfParameters,
|
|
24
24
|
decodeEvmVaultCall,
|
package/dist/protocol.cjs
CHANGED
|
@@ -25,6 +25,9 @@ __export(protocol_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(protocol_exports);
|
|
26
26
|
var import_single = require("@anywalletkit/protocol-swap2-core/swap2/single");
|
|
27
27
|
|
|
28
|
+
// src/config.ts
|
|
29
|
+
var import_errors = require("@anywalletkit/protocol-swap2-core/errors");
|
|
30
|
+
|
|
28
31
|
// src/codec.ts
|
|
29
32
|
var import_base = require("@scure/base");
|
|
30
33
|
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
@@ -205,50 +208,69 @@ var chainflip = {
|
|
|
205
208
|
supportsChain: (chain) => !!CF_CHAINS[chain],
|
|
206
209
|
supports: (from, to) => CF_SOURCE_CHAINS.has(from) && !!CF_CHAINS[to] && from !== to
|
|
207
210
|
};
|
|
211
|
+
var notes = (0, import_errors.refusalNotes)();
|
|
212
|
+
var unparsed = /* @__PURE__ */ new Set();
|
|
213
|
+
function decodeFailure(text, requestParsed) {
|
|
214
|
+
unparsed.delete(text);
|
|
215
|
+
if (requestParsed) return notes.note(text, "upstream_unavailable");
|
|
216
|
+
unparsed.add(text);
|
|
217
|
+
if (unparsed.size > 64) unparsed.delete(unparsed.values().next().value);
|
|
218
|
+
return text;
|
|
219
|
+
}
|
|
220
|
+
var reasonOf = (text) => unparsed.has(text) ? void 0 : notes.reasonOf(text);
|
|
208
221
|
function chainflipVerifyQuote(params, quote) {
|
|
222
|
+
let readingRequest = false;
|
|
209
223
|
try {
|
|
210
224
|
const src = cfAsset(params.sourceChain, params.sourceToken);
|
|
211
225
|
const dst = cfAsset(params.destChain, params.destToken);
|
|
212
226
|
const dstChain = CF_CHAINS[params.destChain];
|
|
213
227
|
const vault = Object.prototype.hasOwnProperty.call(CF_VAULTS, params.sourceChain) ? CF_VAULTS[params.sourceChain] : void 0;
|
|
214
|
-
if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return "not a vault swap this release signs";
|
|
228
|
+
if (!src || !dst || !dstChain || !vault || !CF_SOURCE_CHAINS.has(params.sourceChain)) return notes.note("not a vault swap this release signs", "unsupported_pair");
|
|
215
229
|
if (!quote.txRequest && !quote.depositAddress) return null;
|
|
216
|
-
if (!params.refundAddress) return "a live quote needs the refund address";
|
|
230
|
+
if (!params.refundAddress) return notes.note("a live quote needs the refund address", "policy_refused");
|
|
231
|
+
readingRequest = true;
|
|
217
232
|
const amountIn = BigInt(params.amountIn);
|
|
218
233
|
const dest = destAddressBytes(params.destChain, params.destAddress);
|
|
219
234
|
const refund = destAddressBytes(params.sourceChain, params.refundAddress);
|
|
235
|
+
readingRequest = false;
|
|
220
236
|
const checkParams = (p) => {
|
|
221
|
-
if (!sameBytes(fromHex(p.refundAddress), refund)) return "the refund address is not the sender";
|
|
222
|
-
if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return "the minimum price does not guarantee the quoted minimum";
|
|
223
|
-
if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return "DCA, boost, a broker fee or affiliates";
|
|
237
|
+
if (!sameBytes(fromHex(p.refundAddress), refund)) return notes.note("the refund address is not the sender", "recipient_mismatch");
|
|
238
|
+
if (minOutOf(amountIn, p.minPriceX128) < BigInt(quote.minDestAmount)) return notes.note("the minimum price does not guarantee the quoted minimum", "price_check_failed");
|
|
239
|
+
if (p.dca !== null || p.boostFeeBps !== 0 || p.broker.feeBps !== 0 || p.affiliates.length) return notes.note("DCA, boost, a broker fee or affiliates", "policy_refused");
|
|
224
240
|
return null;
|
|
225
241
|
};
|
|
226
242
|
if (params.sourceChain.startsWith("eip155:")) {
|
|
227
243
|
const tx = quote.txRequest;
|
|
228
|
-
if (quote.depositAddress || !tx?.data || tx.serializedTx !== void 0) return "an EVM vault swap is a vault call, not a deposit";
|
|
229
|
-
if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return `the call targets ${tx.to}, not the Vault
|
|
244
|
+
if (quote.depositAddress || !tx?.data || tx.serializedTx !== void 0) return notes.note("an EVM vault swap is a vault call, not a deposit", "policy_refused");
|
|
245
|
+
if (!tx.to || tx.to.toLowerCase() !== vault.toLowerCase()) return notes.note(`the call targets ${tx.to}, not the Vault`, "vault_mismatch");
|
|
230
246
|
const v = decodeEvmVaultCall(tx.data);
|
|
231
|
-
if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return "the vault call names another destination";
|
|
247
|
+
if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, dest)) return notes.note("the vault call names another destination", "recipient_mismatch");
|
|
232
248
|
if (src.token === null) {
|
|
233
|
-
if (!v.native || BigInt(tx.value ?? "0") !== amountIn || tx.approvalAddress) return "the native vault call moves another amount";
|
|
249
|
+
if (!v.native || BigInt(tx.value ?? "0") !== amountIn || tx.approvalAddress) return notes.note("the native vault call moves another amount", "policy_refused");
|
|
234
250
|
} else if (v.native || v.srcToken?.toLowerCase() !== src.token.toLowerCase() || v.amount !== amountIn || BigInt(tx.value ?? "0") !== 0n || tx.approvalAddress?.toLowerCase() !== vault.toLowerCase()) {
|
|
235
|
-
return "the token vault call moves another token or amount";
|
|
251
|
+
return notes.note("the token vault call moves another token or amount", "policy_refused");
|
|
236
252
|
}
|
|
237
253
|
return checkParams(v.params);
|
|
238
254
|
}
|
|
239
|
-
if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo)
|
|
255
|
+
if (quote.txRequest || quote.depositAddress !== vault || !quote.depositMemo) {
|
|
256
|
+
return notes.note(
|
|
257
|
+
"a Tron vault swap is a send to the Tron Vault with its note",
|
|
258
|
+
quote.txRequest ? "policy_refused" : quote.depositAddress !== vault ? "vault_mismatch" : "recipient_unverifiable"
|
|
259
|
+
);
|
|
260
|
+
}
|
|
240
261
|
const n = decodeTronNote(quote.depositMemo);
|
|
241
|
-
if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return "the note names another destination";
|
|
262
|
+
if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, dest)) return notes.note("the note names another destination", "recipient_mismatch");
|
|
242
263
|
return checkParams(n.params);
|
|
243
264
|
} catch (e) {
|
|
244
|
-
return `the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})
|
|
265
|
+
return decodeFailure(`the vault swap does not decode (${(e instanceof Error ? e.message : String(e)).slice(0, 120)})`, !readingRequest);
|
|
245
266
|
}
|
|
246
267
|
}
|
|
247
268
|
var chainflipPins = Object.freeze({
|
|
248
269
|
callTargets: (chain) => chainflipVaultFor(chain),
|
|
249
270
|
spenders: (chain) => chainflipVaultFor(chain),
|
|
250
271
|
verifyQuote: chainflipVerifyQuote,
|
|
251
|
-
verifyBuild: (quote, tx) => quote.depositMemo && tx.memoEncoding !== "hex" ? "the Tron note is not sent as hex bytes" : null,
|
|
272
|
+
verifyBuild: (quote, tx) => quote.depositMemo && tx.memoEncoding !== "hex" ? notes.note("the Tron note is not sent as hex bytes", "policy_refused") : null,
|
|
273
|
+
reasonOf,
|
|
252
274
|
depositAddressRoutes: true
|
|
253
275
|
});
|
|
254
276
|
function chainflipVaultFor(chain) {
|
|
@@ -270,6 +292,7 @@ function describeChainflipActivity(tx, ctx) {
|
|
|
270
292
|
}
|
|
271
293
|
|
|
272
294
|
// src/provider.ts
|
|
295
|
+
var import_errors2 = require("@anywalletkit/protocol-swap2-core/errors");
|
|
273
296
|
var import_util = require("@anywalletkit/protocol-swap2-core/util");
|
|
274
297
|
var import_viem2 = require("viem");
|
|
275
298
|
var QUOTE_TTL_MS = 6e4;
|
|
@@ -277,6 +300,25 @@ var RETRY_BLOCKS = 50;
|
|
|
277
300
|
var MAX_RETRY_BLOCKS = 600;
|
|
278
301
|
var ERC20 = (0, import_viem2.parseAbi)(["function transfer(address to, uint256 amount) returns (bool)"]);
|
|
279
302
|
var INTENT_PREFIX = "cfvault:";
|
|
303
|
+
var notes2 = (0, import_errors2.refusalNotes)();
|
|
304
|
+
function backendRefusal(status, body, retryAfter) {
|
|
305
|
+
const http = (0, import_errors2.httpRefusal)(status, retryAfter);
|
|
306
|
+
const byStatus = http?.reason === "key_rejected" ? { reason: "upstream_unavailable", httpStatus: status } : http;
|
|
307
|
+
if (byStatus?.reason === "rate_limited") return byStatus;
|
|
308
|
+
const m = body?.message;
|
|
309
|
+
const said = typeof m === "string" ? backendReason(m) : void 0;
|
|
310
|
+
return said && said !== byStatus?.reason ? { reason: said } : byStatus;
|
|
311
|
+
}
|
|
312
|
+
function backendReason(message) {
|
|
313
|
+
if (/liquidity/i.test(message)) return "insufficient_liquidity";
|
|
314
|
+
if (/maximum (?:swap )?amount|above (?:the )?max|too (?:large|big|high)|exceeds? (?:the )?max/i.test(message)) return "amount_too_large";
|
|
315
|
+
if (/minimum (?:swap |deposit )?amount|below (?:the )?minimum|lower than (?:the )?(?:estimated|minimum)|too (?:small|low)/i.test(message)) return "amount_too_small";
|
|
316
|
+
if (/halt|paus|maintenance|disabled|suspend|not enabled/i.test(message)) return "chain_halted";
|
|
317
|
+
if (/rate.?limit|too many requests/i.test(message)) return "rate_limited";
|
|
318
|
+
if (/not supported|unsupported|unknown asset|invalid asset/i.test(message)) return "unsupported_pair";
|
|
319
|
+
if (/no (?:route|quote)|could not find/i.test(message)) return "no_route";
|
|
320
|
+
return void 0;
|
|
321
|
+
}
|
|
280
322
|
function chainflipProvider(config = {}) {
|
|
281
323
|
config = Object.freeze({ ...config });
|
|
282
324
|
const base = new URL(config.apiUrl ?? CF_API_DEFAULT).toString().replace(/\/$/, "");
|
|
@@ -288,18 +330,18 @@ function chainflipProvider(config = {}) {
|
|
|
288
330
|
await new Promise((r) => setTimeout(r, 1200));
|
|
289
331
|
continue;
|
|
290
332
|
}
|
|
291
|
-
return { ok: res.ok, status: res.status, body };
|
|
333
|
+
return { ok: res.ok, status: res.status, body, retryAfter: res.headers?.get?.("retry-after") ?? null };
|
|
292
334
|
}
|
|
293
335
|
};
|
|
294
336
|
const checkParams = (p, want) => {
|
|
295
|
-
if (!sameBytes(fromHex(p.refundAddress), want.refund)) return `refund address ${p.refundAddress} is not the sender
|
|
296
|
-
if (p.minPriceX128 < want.minPriceX128) return "minimum price is below the one requested";
|
|
297
|
-
if (p.retryDurationBlocks > MAX_RETRY_BLOCKS) return `retry window ${p.retryDurationBlocks} blocks is too long
|
|
298
|
-
if (p.maxOraclePriceSlippageBps !== want.oracle) return "oracle slippage guard differs from the request";
|
|
299
|
-
if (p.dca !== null) return "unexpected DCA parameters";
|
|
300
|
-
if (p.boostFeeBps !== 0) return "unexpected boost fee";
|
|
301
|
-
if (p.broker.feeBps !== 0) return `broker takes ${p.broker.feeBps} bps
|
|
302
|
-
if (p.affiliates.length) return "unexpected affiliates";
|
|
337
|
+
if (!sameBytes(fromHex(p.refundAddress), want.refund)) return notes2.note(`refund address ${p.refundAddress} is not the sender`, "recipient_mismatch");
|
|
338
|
+
if (p.minPriceX128 < want.minPriceX128) return notes2.note("minimum price is below the one requested", "price_check_failed");
|
|
339
|
+
if (p.retryDurationBlocks > MAX_RETRY_BLOCKS) return notes2.note(`retry window ${p.retryDurationBlocks} blocks is too long`, "policy_refused");
|
|
340
|
+
if (p.maxOraclePriceSlippageBps !== want.oracle) return notes2.note("oracle slippage guard differs from the request", "price_check_failed");
|
|
341
|
+
if (p.dca !== null) return notes2.note("unexpected DCA parameters", "policy_refused");
|
|
342
|
+
if (p.boostFeeBps !== 0) return notes2.note("unexpected boost fee", "policy_refused");
|
|
343
|
+
if (p.broker.feeBps !== 0) return notes2.note(`broker takes ${p.broker.feeBps} bps`, "policy_refused");
|
|
344
|
+
if (p.affiliates.length) return notes2.note("unexpected affiliates", "policy_refused");
|
|
303
345
|
return null;
|
|
304
346
|
};
|
|
305
347
|
return {
|
|
@@ -315,16 +357,19 @@ function chainflipProvider(config = {}) {
|
|
|
315
357
|
},
|
|
316
358
|
async getQuote(params, signal) {
|
|
317
359
|
const dry = params.dry !== false;
|
|
318
|
-
const refuse = (reason) => {
|
|
319
|
-
|
|
360
|
+
const refuse = (reason, why) => {
|
|
361
|
+
const info = typeof why === "string" ? { reason: why } : why;
|
|
362
|
+
if (info) params.onRefusal?.(`chainflip: ${reason}`, info);
|
|
363
|
+
else params.onRefusal?.(`chainflip: ${reason}`);
|
|
320
364
|
return null;
|
|
321
365
|
};
|
|
322
|
-
|
|
366
|
+
const unreachable = () => signal?.aborted ? void 0 : "upstream_unavailable";
|
|
367
|
+
if (!chainflip.supports(params.sourceChain, params.destChain)) return refuse(`no vault swap ${params.sourceChain} \u2192 ${params.destChain}`, "unsupported_pair");
|
|
323
368
|
const src = cfAsset(params.sourceChain, params.sourceToken);
|
|
324
369
|
const dst = cfAsset(params.destChain, params.destToken);
|
|
325
|
-
if (!src || !dst) return refuse(`asset not listed (${params.sourceToken} on ${params.sourceChain} \u2192 ${params.destToken} on ${params.destChain})
|
|
370
|
+
if (!src || !dst) return refuse(`asset not listed (${params.sourceToken} on ${params.sourceChain} \u2192 ${params.destToken} on ${params.destChain})`, "unsupported_pair");
|
|
326
371
|
const amountIn = BigInt(params.amountIn);
|
|
327
|
-
if (amountIn < src.minDeposit) return refuse(`below the minimum deposit (${src.minDeposit} ${src.asset})
|
|
372
|
+
if (amountIn < src.minDeposit) return refuse(`below the minimum deposit (${src.minDeposit} ${src.asset})`, "amount_too_small");
|
|
328
373
|
let destBytes;
|
|
329
374
|
try {
|
|
330
375
|
destBytes = destAddressBytes(params.destChain, params.destAddress);
|
|
@@ -333,21 +378,23 @@ function chainflipProvider(config = {}) {
|
|
|
333
378
|
}
|
|
334
379
|
const qs = new URLSearchParams({ amount: params.amountIn, srcChain: src.chain, srcAsset: src.asset, destChain: dst.chain, destAsset: dst.asset, isVaultSwap: "true", isOnChain: "false", dcaV2Enabled: "false" });
|
|
335
380
|
let q;
|
|
381
|
+
let answered;
|
|
336
382
|
try {
|
|
337
383
|
const r = await call(`/v2/quote?${qs.toString()}`, {}, signal);
|
|
338
|
-
if (!r.ok) return refuse(`quote ${r.status}: ${String(r.body?.message ?? "").slice(0, 160)}
|
|
384
|
+
if (!r.ok) return refuse(`quote ${r.status}: ${String(r.body?.message ?? "").slice(0, 160)}`, backendRefusal(r.status, r.body, r.retryAfter));
|
|
385
|
+
answered = r.body;
|
|
339
386
|
q = r.body?.find((x) => x.type === "REGULAR") ?? r.body?.[0];
|
|
340
387
|
} catch (e) {
|
|
341
|
-
return refuse(`quote failed: ${e.message.slice(0, 160)}
|
|
388
|
+
return refuse(`quote failed: ${e.message.slice(0, 160)}`, unreachable());
|
|
342
389
|
}
|
|
343
|
-
if (!q?.egressAmount || !/^\d+$/.test(q.egressAmount)) return refuse("quote without an egress amount");
|
|
344
|
-
if (q.type && q.type !== "REGULAR") return refuse(`${q.type} quotes are not supported
|
|
390
|
+
if (!q?.egressAmount || !/^\d+$/.test(q.egressAmount)) return refuse("quote without an egress amount", Array.isArray(answered) && answered.length === 0 ? "no_route" : unreachable());
|
|
391
|
+
if (q.type && q.type !== "REGULAR") return refuse(`${q.type} quotes are not supported`, "unsupported_pair");
|
|
345
392
|
const expected = BigInt(q.egressAmount);
|
|
346
393
|
const slipBps = params.slippageBps ?? Math.round((q.recommendedSlippageTolerancePercent ?? 1) * 100);
|
|
347
394
|
const byTolerance = expected * BigInt(1e4 - Math.min(9999, Math.max(0, slipBps))) / 10000n;
|
|
348
395
|
const callerFloor = params.minAmountOut !== void 0 ? BigInt(params.minAmountOut) : void 0;
|
|
349
396
|
const minOut = callerFloor === void 0 ? byTolerance : params.slippageBps !== void 0 && byTolerance > callerFloor ? byTolerance : callerFloor;
|
|
350
|
-
if (minOut > expected) return refuse(`floor ${minOut} above the expected output ${expected}
|
|
397
|
+
if (minOut > expected) return refuse(`floor ${minOut} above the expected output ${expected}`, "price_check_failed");
|
|
351
398
|
const minPriceX128 = minPriceX128For(amountIn, minOut);
|
|
352
399
|
const guaranteed = minOutOf(amountIn, minPriceX128);
|
|
353
400
|
const oracle = config.maxOraclePriceSlippageBps !== void 0 ? config.maxOraclePriceSlippageBps : q.recommendedLivePriceSlippageTolerancePercent !== void 0 ? Math.round(q.recommendedLivePriceSlippageTolerancePercent * 100) : null;
|
|
@@ -365,7 +412,7 @@ function chainflipProvider(config = {}) {
|
|
|
365
412
|
validUntilMs: Date.now() + QUOTE_TTL_MS
|
|
366
413
|
};
|
|
367
414
|
if (dry) return { ...common, intentId: `dry:${crypto.randomUUID()}`, depositAddress: "", depositMemo: null };
|
|
368
|
-
if (!params.refundAddress) return refuse("live quote without a refund address");
|
|
415
|
+
if (!params.refundAddress) return refuse("live quote without a refund address", "policy_refused");
|
|
369
416
|
let refund;
|
|
370
417
|
try {
|
|
371
418
|
refund = destAddressBytes(params.sourceChain, params.refundAddress);
|
|
@@ -384,26 +431,26 @@ function chainflipProvider(config = {}) {
|
|
|
384
431
|
let enc;
|
|
385
432
|
try {
|
|
386
433
|
const r = await call("/api/encodeVaultSwapData", { method: "POST", body: JSON.stringify(body) }, signal);
|
|
387
|
-
if (!r.ok) return refuse(`encode ${r.status}: ${String(r.body?.message ?? "").slice(0, 160)}
|
|
434
|
+
if (!r.ok) return refuse(`encode ${r.status}: ${String(r.body?.message ?? "").slice(0, 160)}`, backendRefusal(r.status, r.body, r.retryAfter));
|
|
388
435
|
enc = r.body ?? {};
|
|
389
436
|
} catch (e) {
|
|
390
|
-
return refuse(`encode failed: ${e.message.slice(0, 160)}
|
|
437
|
+
return refuse(`encode failed: ${e.message.slice(0, 160)}`, unreachable());
|
|
391
438
|
}
|
|
392
439
|
const want = { refund, minPriceX128, oracle };
|
|
393
440
|
const vault = CF_VAULTS[params.sourceChain];
|
|
394
441
|
const dstChain = CF_CHAINS[params.destChain];
|
|
395
442
|
try {
|
|
396
443
|
if (params.sourceChain.startsWith("eip155:")) {
|
|
397
|
-
if (!enc.to || enc.to.toLowerCase() !== vault.toLowerCase()) return refuse(`encoder targets ${enc.to}, not the ${src.chain} Vault
|
|
444
|
+
if (!enc.to || enc.to.toLowerCase() !== vault.toLowerCase()) return refuse(`encoder targets ${enc.to}, not the ${src.chain} Vault`, !enc.to ? unreachable() : "vault_mismatch");
|
|
398
445
|
const v = decodeEvmVaultCall(enc.calldata ?? "0x");
|
|
399
|
-
if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, destBytes)) return refuse("encoded destination differs from the request");
|
|
446
|
+
if (v.dstChain !== dstChain.id || v.dstToken !== dst.id || !sameBytes(v.dstAddress, destBytes)) return refuse("encoded destination differs from the request", "recipient_mismatch");
|
|
400
447
|
if (src.token === null) {
|
|
401
|
-
if (!v.native || BigInt(enc.value ?? "0") !== amountIn) return refuse("native vault call with a different amount");
|
|
448
|
+
if (!v.native || BigInt(enc.value ?? "0") !== amountIn) return refuse("native vault call with a different amount", "policy_refused");
|
|
402
449
|
} else if (v.native || v.srcToken?.toLowerCase() !== src.token.toLowerCase() || v.amount !== amountIn || BigInt(enc.value ?? "0") !== 0n) {
|
|
403
|
-
return refuse("token vault call with a different token or amount");
|
|
450
|
+
return refuse("token vault call with a different token or amount", "policy_refused");
|
|
404
451
|
}
|
|
405
452
|
const bad2 = checkParams(v.params, want);
|
|
406
|
-
if (bad2) return refuse(bad2);
|
|
453
|
+
if (bad2) return refuse(bad2, notes2.reasonOf(bad2));
|
|
407
454
|
return {
|
|
408
455
|
...common,
|
|
409
456
|
intentId: `${INTENT_PREFIX}${params.sourceChain}`,
|
|
@@ -413,17 +460,18 @@ function chainflipProvider(config = {}) {
|
|
|
413
460
|
providerData: { kind: "evm", srcAsset: String(src.id), dstAsset: String(dst.id) }
|
|
414
461
|
};
|
|
415
462
|
}
|
|
416
|
-
if (enc.to !== vault) return refuse(`encoder targets ${enc.to}, not the Tron Vault
|
|
417
|
-
if (!enc.note) return refuse("Tron vault swap without a note");
|
|
463
|
+
if (enc.to !== vault) return refuse(`encoder targets ${enc.to}, not the Tron Vault`, !enc.to ? unreachable() : "vault_mismatch");
|
|
464
|
+
if (!enc.note) return refuse("Tron vault swap without a note", "recipient_unverifiable");
|
|
418
465
|
if (src.token !== null) {
|
|
419
|
-
if (enc.sourceTokenAddress !== src.token) return refuse(`source token ${enc.sourceTokenAddress} is not ${src.asset}
|
|
466
|
+
if (enc.sourceTokenAddress !== src.token) return refuse(`source token ${enc.sourceTokenAddress} is not ${src.asset}`, "policy_refused");
|
|
420
467
|
const t = (0, import_viem2.decodeFunctionData)({ abi: ERC20, data: enc.calldata ?? "0x" });
|
|
421
|
-
|
|
468
|
+
const toVault = sameBytes(fromHex(String(t.args[0])), tronToBytes(vault));
|
|
469
|
+
if (!toVault || t.args[1] !== amountIn) return refuse("TRC-20 transfer is not the amount to the Vault", toVault ? "policy_refused" : "vault_mismatch");
|
|
422
470
|
}
|
|
423
471
|
const n = decodeTronNote(enc.note);
|
|
424
|
-
if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, destBytes)) return refuse("note names another destination");
|
|
472
|
+
if (n.outputAsset !== dst.id || n.destTag !== dstChain.addrTag || !sameBytes(n.destAddress, destBytes)) return refuse("note names another destination", "recipient_mismatch");
|
|
425
473
|
const bad = checkParams(n.params, want);
|
|
426
|
-
if (bad) return refuse(bad);
|
|
474
|
+
if (bad) return refuse(bad, notes2.reasonOf(bad));
|
|
427
475
|
return {
|
|
428
476
|
...common,
|
|
429
477
|
intentId: `${INTENT_PREFIX}${params.sourceChain}`,
|
|
@@ -432,20 +480,20 @@ function chainflipProvider(config = {}) {
|
|
|
432
480
|
providerData: { kind: "tron", memoEncoding: "hex", srcAsset: String(src.id), dstAsset: String(dst.id) }
|
|
433
481
|
};
|
|
434
482
|
} catch (e) {
|
|
435
|
-
return refuse(`encoder output does not decode: ${e.message.slice(0, 160)}
|
|
483
|
+
return refuse(`encoder output does not decode: ${e.message.slice(0, 160)}`, "upstream_unavailable");
|
|
436
484
|
}
|
|
437
485
|
},
|
|
438
486
|
async buildDeposit(quote) {
|
|
439
487
|
if (quote.providerData?.kind === "evm") {
|
|
440
488
|
const tx = quote.txRequest;
|
|
441
|
-
if (!tx?.to || !tx.data) throw
|
|
489
|
+
if (!tx?.to || !tx.data) throw (0, import_errors2.refusal)("policy_refused", "chainflip: quote has no vault call");
|
|
442
490
|
return { chain: "", to: tx.to, value: tx.value ?? "0", data: tx.data, ...tx.chainId !== void 0 ? { chainId: tx.chainId } : {}, ...tx.approvalAddress ? { approvalAddress: tx.approvalAddress } : {} };
|
|
443
491
|
}
|
|
444
492
|
if (quote.providerData?.kind === "tron") {
|
|
445
|
-
if (!quote.depositAddress || !quote.depositMemo) throw
|
|
493
|
+
if (!quote.depositAddress || !quote.depositMemo) throw (0, import_errors2.refusal)("policy_refused", "chainflip: Tron quote without vault or note");
|
|
446
494
|
return { chain: "", to: quote.depositAddress, value: quote.sourceAmount, memo: quote.depositMemo, memoEncoding: "hex" };
|
|
447
495
|
}
|
|
448
|
-
throw
|
|
496
|
+
throw (0, import_errors2.refusal)("policy_refused", "chainflip: not a live vault-swap quote");
|
|
449
497
|
},
|
|
450
498
|
async trackIntent(ref) {
|
|
451
499
|
if (!ref.sourceTxHash) return { state: "pending" };
|