@anywalletkit/protocol-swap2-core 0.6.1 → 0.8.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.
- package/README.md +1 -1
- package/dist/chunk-2KC734UX.js +117 -0
- package/dist/chunk-2KC734UX.js.map +1 -0
- package/dist/{chunk-KIAQXIBG.js → chunk-5FPDKWBG.js} +21 -2
- package/dist/chunk-5FPDKWBG.js.map +1 -0
- package/dist/{chunk-ZMWK3RQ4.js → chunk-6MTZNYKM.js} +40 -5
- package/dist/chunk-6MTZNYKM.js.map +1 -0
- package/dist/{chunk-IGTMUTNJ.js → chunk-CRCDWV3L.js} +130 -7
- package/dist/chunk-CRCDWV3L.js.map +1 -0
- package/dist/{chunk-JFGMF6FO.js → chunk-FHEU7E5A.js} +9 -3
- package/dist/chunk-FHEU7E5A.js.map +1 -0
- package/dist/index.cjs +256 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +10 -6
- package/dist/remote.cjs +38 -3
- package/dist/remote.cjs.map +1 -1
- package/dist/remote.d.cts +33 -1
- package/dist/remote.d.ts +33 -1
- package/dist/remote.js +2 -2
- package/dist/server.cjs +23 -4
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +6 -5
- package/dist/server.js.map +1 -1
- package/dist/swap2/base.cjs +187 -16
- package/dist/swap2/base.cjs.map +1 -1
- package/dist/swap2/base.d.cts +19 -1
- package/dist/swap2/base.d.ts +19 -1
- package/dist/swap2/base.js +2 -1
- package/dist/swap2/single.cjs +210 -16
- package/dist/swap2/single.cjs.map +1 -1
- package/dist/swap2/single.js +4 -3
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +49 -1
- package/dist/types.d.ts +49 -1
- package/dist/util.cjs +70 -2
- package/dist/util.cjs.map +1 -1
- package/dist/util.d.cts +13 -2
- package/dist/util.d.ts +13 -2
- package/dist/util.js +7 -3
- package/dist/validate.cjs +19 -0
- package/dist/validate.cjs.map +1 -1
- package/dist/validate.d.cts +12 -2
- package/dist/validate.d.ts +12 -2
- package/dist/validate.js +3 -1
- package/package.json +5 -5
- package/dist/chunk-IGTMUTNJ.js.map +0 -1
- package/dist/chunk-JFGMF6FO.js.map +0 -1
- package/dist/chunk-KIAQXIBG.js.map +0 -1
- package/dist/chunk-MNJTMSFN.js +0 -49
- package/dist/chunk-MNJTMSFN.js.map +0 -1
- package/dist/chunk-ZMWK3RQ4.js.map +0 -1
package/dist/swap2/base.cjs
CHANGED
|
@@ -33,7 +33,58 @@ module.exports = __toCommonJS(base_exports);
|
|
|
33
33
|
var import_core = require("@anywalletkit/core");
|
|
34
34
|
var import_viem = require("viem");
|
|
35
35
|
var import_tx_preview_evm = require("@anywalletkit/tx-preview-evm");
|
|
36
|
+
var import_swap2_assets2 = require("@anywalletkit/swap2-assets");
|
|
37
|
+
|
|
38
|
+
// src/util.ts
|
|
36
39
|
var import_swap2_assets = require("@anywalletkit/swap2-assets");
|
|
40
|
+
var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
41
|
+
function base64Bytes(text) {
|
|
42
|
+
const s = text.replace(/-/g, "+").replace(/_/g, "/").replace(/=+$/, "");
|
|
43
|
+
if (!/^[A-Za-z0-9+/]*$/.test(s) || s.length % 4 === 1) return null;
|
|
44
|
+
const out = new Uint8Array(Math.floor(s.length * 3 / 4));
|
|
45
|
+
let bits = 0, acc = 0, n = 0;
|
|
46
|
+
for (const ch of s) {
|
|
47
|
+
acc = acc << 6 | B64.indexOf(ch);
|
|
48
|
+
bits += 6;
|
|
49
|
+
if (bits >= 8) {
|
|
50
|
+
bits -= 8;
|
|
51
|
+
out[n++] = acc >> bits & 255;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return out.subarray(0, n);
|
|
55
|
+
}
|
|
56
|
+
function crc16(bytes) {
|
|
57
|
+
let crc = 0;
|
|
58
|
+
for (const b of bytes) {
|
|
59
|
+
crc ^= b << 8;
|
|
60
|
+
for (let i = 0; i < 8; i++) crc = crc & 32768 ? (crc << 1 ^ 4129) & 65535 : crc << 1 & 65535;
|
|
61
|
+
}
|
|
62
|
+
return crc;
|
|
63
|
+
}
|
|
64
|
+
function tonRawAddress(address) {
|
|
65
|
+
if (address && typeof address === "object") {
|
|
66
|
+
const o = address;
|
|
67
|
+
if (typeof o.toRawString === "function") {
|
|
68
|
+
try {
|
|
69
|
+
return tonRawAddress(o.toRawString());
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (typeof o.workChain === "number" && o.hash instanceof Uint8Array && o.hash.length === 32) {
|
|
75
|
+
return `${o.workChain}:${Array.from(o.hash, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
if (typeof address !== "string") return null;
|
|
80
|
+
const raw = /^(-?[0-9]{1,3}):([0-9a-fA-F]{64})$/.exec(address.trim());
|
|
81
|
+
if (raw) return `${Number(raw[1])}:${raw[2].toLowerCase()}`;
|
|
82
|
+
if (!/^[A-Za-z0-9+/_-]{48}$/.test(address.trim())) return null;
|
|
83
|
+
const bytes = base64Bytes(address.trim());
|
|
84
|
+
if (!bytes || bytes.length !== 36 || crc16(bytes.subarray(0, 34)) !== (bytes[34] << 8 | bytes[35])) return null;
|
|
85
|
+
const wc = bytes[1] === 255 ? -1 : bytes[1];
|
|
86
|
+
return `${wc}:${Array.from(bytes.subarray(2, 34), (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
87
|
+
}
|
|
37
88
|
|
|
38
89
|
// src/errors.ts
|
|
39
90
|
var Swap2Error = class extends Error {
|
|
@@ -201,7 +252,64 @@ function normalizeTypedDomain(domain) {
|
|
|
201
252
|
else if (typeof raw === "string" && /^0x[0-9a-fA-F]+$/.test(raw)) chainId = safeChainId(BigInt(raw));
|
|
202
253
|
return chainId === void 0 || !Number.isSafeInteger(chainId) ? domain : { ...domain, chainId };
|
|
203
254
|
}
|
|
255
|
+
function assertTypedOrder(typedData, approvalAddress, e) {
|
|
256
|
+
const fail = (why) => new Swap2ValidationError(`swap2: typed order refused \u2014 ${why}`);
|
|
257
|
+
let parsed;
|
|
258
|
+
try {
|
|
259
|
+
parsed = JSON.parse(typedData);
|
|
260
|
+
} catch {
|
|
261
|
+
throw fail("the typed data is not JSON");
|
|
262
|
+
}
|
|
263
|
+
if (!parsed || typeof parsed !== "object") throw fail("the typed data is not an object");
|
|
264
|
+
const td = parsed;
|
|
265
|
+
const primary = td.primaryType;
|
|
266
|
+
if (typeof primary !== "string" || !primary) throw fail("it names no primaryType");
|
|
267
|
+
if (/^permit/i.test(primary)) throw fail(`${primary} is a token approval, not an order`);
|
|
268
|
+
if (primary !== "Order") throw fail(`primaryType ${primary} is not an order this engine signs`);
|
|
269
|
+
const fields = td.types?.Order;
|
|
270
|
+
const has = (name, type) => Array.isArray(fields) && fields.some((f) => f?.name === name && f?.type === type);
|
|
271
|
+
if (!has("maker", "address") || !has("makerAsset", "address") || !has("makingAmount", "uint256")) throw fail("the Order type has no maker / makerAsset / makingAmount");
|
|
272
|
+
const verifying = td.domain?.verifyingContract;
|
|
273
|
+
if (!approvalAddress || typeof verifying !== "string" || verifying.toLowerCase() !== approvalAddress.toLowerCase()) {
|
|
274
|
+
throw fail(`verifyingContract ${String(verifying)} is not the settlement contract the swap approves`);
|
|
275
|
+
}
|
|
276
|
+
if (e.chainId !== null && normalizeTypedDomain(td.domain)?.chainId !== e.chainId) throw fail("the domain chainId is not the source chain");
|
|
277
|
+
const m = td.message ?? {};
|
|
278
|
+
if (String(m.maker ?? "").toLowerCase() !== e.self.toLowerCase()) throw fail("the maker is not this account");
|
|
279
|
+
if (!e.token || String(m.makerAsset ?? "").toLowerCase() !== e.token.toLowerCase()) throw fail("the makerAsset is not the source token");
|
|
280
|
+
const raw = m.makingAmount;
|
|
281
|
+
const making = typeof raw === "string" && /^(?:0x[0-9a-fA-F]{1,64}|[0-9]{1,78})$/.test(raw) ? BigInt(raw) : typeof raw === "number" && Number.isSafeInteger(raw) ? BigInt(raw) : null;
|
|
282
|
+
if (making === null || making !== BigInt(e.amount)) throw fail(`makingAmount ${String(raw)} is not the swap's ${e.amount}`);
|
|
283
|
+
}
|
|
204
284
|
var DEFAULT_SERIALIZED_NATIVE_ALLOWANCE = 20000000n;
|
|
285
|
+
var DEFAULT_TON_GAS_CEILING = 1000000000n;
|
|
286
|
+
var JETTON_TRANSFER_OP = 260734629;
|
|
287
|
+
function readTonBody(cell) {
|
|
288
|
+
let s;
|
|
289
|
+
try {
|
|
290
|
+
s = cell.beginParse();
|
|
291
|
+
} catch {
|
|
292
|
+
return { op: null };
|
|
293
|
+
}
|
|
294
|
+
let op;
|
|
295
|
+
try {
|
|
296
|
+
op = s.loadUint(32);
|
|
297
|
+
} catch {
|
|
298
|
+
return { op: null };
|
|
299
|
+
}
|
|
300
|
+
if (op !== JETTON_TRANSFER_OP) return { op };
|
|
301
|
+
try {
|
|
302
|
+
s.loadUintBig(64);
|
|
303
|
+
const amount = s.loadCoins();
|
|
304
|
+
const destination = tonRawAddress(s.loadAddress());
|
|
305
|
+
const response = s.loadMaybeAddress();
|
|
306
|
+
s.loadMaybeRef();
|
|
307
|
+
const forwardTon = s.loadCoins();
|
|
308
|
+
return { op, jettonTransfer: { amount, destination, responseDestination: response == null ? null : tonRawAddress(response), forwardTon } };
|
|
309
|
+
} catch {
|
|
310
|
+
return { op };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
205
313
|
function reviewedIdentity(plan) {
|
|
206
314
|
const { feeUsd: _fee, etaSeconds: _eta, validUntilMs: _valid, approvals: _approvals, destAmount: _dest, requoted: _requoted, ...pinned } = plan;
|
|
207
315
|
return JSON.stringify(pinned, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
@@ -282,17 +390,17 @@ function nonEmptyRef(ref, side) {
|
|
|
282
390
|
}
|
|
283
391
|
function toSymbol(caip2, ref) {
|
|
284
392
|
nonEmptyRef(ref, "source");
|
|
285
|
-
const byToken = ref.startsWith("0x") || ref.length > 20 ? (0,
|
|
393
|
+
const byToken = ref.startsWith("0x") || ref.length > 20 ? (0, import_swap2_assets2.ccAssetByToken)(caip2, ref) : void 0;
|
|
286
394
|
if (byToken) return byToken.symbol;
|
|
287
|
-
if ((0,
|
|
395
|
+
if ((0, import_swap2_assets2.ccAsset)(caip2, ref)) return ref;
|
|
288
396
|
return ref;
|
|
289
397
|
}
|
|
290
398
|
function toDestAddress(caip2, ref, allowUnlisted = false) {
|
|
291
399
|
nonEmptyRef(ref, "destination");
|
|
292
400
|
if (ref.startsWith("0x")) return ref;
|
|
293
|
-
const asset = (0,
|
|
401
|
+
const asset = (0, import_swap2_assets2.ccAssetByToken)(caip2, ref) ?? (0, import_swap2_assets2.ccAsset)(caip2, ref);
|
|
294
402
|
if (!asset) {
|
|
295
|
-
if (allowUnlisted && (0,
|
|
403
|
+
if (allowUnlisted && (0, import_swap2_assets2.isTokenAddress)(caip2, ref)) return ref;
|
|
296
404
|
throw new Error(`swap2: unknown destination token '${ref}' on ${caip2}`);
|
|
297
405
|
}
|
|
298
406
|
return asset.contract ?? ZERO;
|
|
@@ -421,7 +529,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
421
529
|
/** The source asset the options name: the catalog's, or (allowUnlistedTokens) an unlisted one with its decimals. */
|
|
422
530
|
sourceAsset(options) {
|
|
423
531
|
const decimals = options.fromTokenDecimals;
|
|
424
|
-
return (0,
|
|
532
|
+
return (0, import_swap2_assets2.resolveAsset)(this.fromChain, toSymbol(this.fromChain, options.fromToken), {
|
|
425
533
|
allowUnlisted: this.unlistedAllowed(),
|
|
426
534
|
...decimals !== void 0 ? { decimals } : {}
|
|
427
535
|
});
|
|
@@ -435,7 +543,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
435
543
|
async prepareOptions(options) {
|
|
436
544
|
if (!this.unlistedAllowed()) return options;
|
|
437
545
|
const ref = toSymbol(this.fromChain, options.fromToken);
|
|
438
|
-
if ((0,
|
|
546
|
+
if ((0, import_swap2_assets2.resolveAsset)(this.fromChain, ref) || !(0, import_swap2_assets2.isTokenAddress)(this.fromChain, ref)) return options;
|
|
439
547
|
const key = ref.startsWith("0x") ? ref.toLowerCase() : ref;
|
|
440
548
|
let decimals = this.unlistedDecimals.get(key);
|
|
441
549
|
if (decimals === void 0) {
|
|
@@ -466,8 +574,8 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
466
574
|
const source = this.sourceAsset(options);
|
|
467
575
|
const params = {
|
|
468
576
|
sourceChain: this.fromChain,
|
|
469
|
-
sourceToken: (0,
|
|
470
|
-
...(0,
|
|
577
|
+
sourceToken: (0, import_swap2_assets2.isUnlisted)(source) ? source.contract : toSymbol(this.fromChain, options.fromToken),
|
|
578
|
+
...(0, import_swap2_assets2.isUnlisted)(source) ? { sourceDecimals: source.decimals } : {},
|
|
471
579
|
destChain,
|
|
472
580
|
destToken: toDestAddress(destChain, options.toToken, this.unlistedAllowed()),
|
|
473
581
|
amountIn: amountIn.toString(),
|
|
@@ -661,12 +769,15 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
661
769
|
}
|
|
662
770
|
}
|
|
663
771
|
const executionModels = [unsigned.data !== void 0, unsigned.bodyBoc !== void 0, unsigned.typedData !== void 0].filter(Boolean).length;
|
|
664
|
-
if (executionModels > 1 || unsigned.memo !== void 0 && (unsigned.bodyBoc !== void 0 || unsigned.typedData !== void 0)) {
|
|
772
|
+
if (executionModels > 1 || unsigned.memo !== void 0 && (unsigned.bodyBoc !== void 0 || unsigned.typedData !== void 0) || unsigned.orderExtension !== void 0 && unsigned.typedData === void 0) {
|
|
665
773
|
throw new Error("swap2: provider returned ambiguous execution payloads");
|
|
666
774
|
}
|
|
667
775
|
if (unsigned.approvalAddress && !unsigned.data && !unsigned.typedData) {
|
|
668
776
|
throw new Error("swap2: approval is only valid for calldata or typed-order execution");
|
|
669
777
|
}
|
|
778
|
+
if (provider.remote === true && provider.depositAddressRoutes !== true && unsigned.data === void 0 && unsigned.bodyBoc === void 0 && unsigned.typedData === void 0 && !serialized) {
|
|
779
|
+
throw new Swap2ValidationError(`swap2: remote provider '${q.provider}' sends the input to ${unsigned.to}, an address its backend named, and the app did not allow deposit-address routes for it (remoteProvider depositAddressRoutes) \u2014 refused`);
|
|
780
|
+
}
|
|
670
781
|
const tronSource = this.fromChain.startsWith("tron:");
|
|
671
782
|
const nearSource = this.fromChain.startsWith("near:");
|
|
672
783
|
if (unsigned.memo && !this.fromChain.startsWith("ton:") && !tronSource && !nearSource) {
|
|
@@ -694,10 +805,12 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
694
805
|
throw new Error(`swap2: provider transaction chain ${unsigned.chainId} does not match ${this.fromChain}`);
|
|
695
806
|
}
|
|
696
807
|
let tokenId;
|
|
808
|
+
let engineTransfer = false;
|
|
697
809
|
if (!unsigned.data && !unsigned.bodyBoc && !unsigned.typedData && !serialized) {
|
|
698
810
|
const src = this.sourceAsset(executionOptions);
|
|
699
811
|
if (src?.contract) {
|
|
700
812
|
if (this.fromChain.startsWith("eip155:")) {
|
|
813
|
+
engineTransfer = true;
|
|
701
814
|
unsigned = {
|
|
702
815
|
...unsigned,
|
|
703
816
|
to: src.contract,
|
|
@@ -736,12 +849,69 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
736
849
|
} else if (!unsigned.typedData && !unsigned.bodyBoc && executionValue !== BigInt(q.sourceAmount) + declaredNativeFee(q, this.fromChain)) {
|
|
737
850
|
throw new Error("swap2: provider execution amount does not match the validated quote");
|
|
738
851
|
}
|
|
852
|
+
let tonBody;
|
|
853
|
+
if (cellBody !== void 0) {
|
|
854
|
+
const refuse = (why) => {
|
|
855
|
+
throw new Swap2ValidationError(`swap2: TON cell-body build refused \u2014 ${why}`);
|
|
856
|
+
};
|
|
857
|
+
const raw = this._config.tonGasCeiling;
|
|
858
|
+
const ceiling = raw === void 0 ? DEFAULT_TON_GAS_CEILING : BigInt(raw);
|
|
859
|
+
if (ceiling < 0n) throw new Swap2ConfigurationError("swap2: tonGasCeiling must be non-negative");
|
|
860
|
+
if (provider.remote === true && provider.verifiesBuilds !== true) refuse("a remote provider's cell body needs the app's own validator (remoteProvider verifyBuild)");
|
|
861
|
+
tonBody = readTonBody(cellBody);
|
|
862
|
+
const input = BigInt(q.sourceAmount);
|
|
863
|
+
if (source.contract) {
|
|
864
|
+
if (executionValue > ceiling) refuse(`it attaches ${executionValue} nanoTON to a jetton transfer, more than the ${ceiling} gas ceiling`);
|
|
865
|
+
const t = tonBody.jettonTransfer;
|
|
866
|
+
if (!t) refuse("a jetton-source body must be a jetton transfer");
|
|
867
|
+
if (t.amount !== input) refuse(`the jetton transfer moves ${t.amount}, not the swap's ${input}`);
|
|
868
|
+
if (!t.responseDestination || t.responseDestination !== tonRawAddress(selfAddress)) refuse("the jetton transfer returns its excess to another wallet");
|
|
869
|
+
if (t.forwardTon >= executionValue) refuse("the jetton transfer forwards more TON than the message carries");
|
|
870
|
+
const own = typeof signer.getJettonWalletAddress === "function" ? tonRawAddress(await signer.getJettonWalletAddress(source.contract)) : null;
|
|
871
|
+
if (!own) refuse("the account cannot name its own jetton wallet (getJettonWalletAddress), so the target cannot be checked");
|
|
872
|
+
if (tonRawAddress(unsigned.to) !== own) refuse(`it is sent to ${unsigned.to}, not this account's ${source.symbol ?? "source"} jetton wallet`);
|
|
873
|
+
} else {
|
|
874
|
+
if (executionValue < input || executionValue - input > ceiling) refuse(`it attaches ${executionValue} nanoTON for a ${input} input, more than the ${ceiling} gas ceiling on top`);
|
|
875
|
+
const pinned = provider.remote === true ? [...provider.callTargets?.(this.fromChain) ?? [], ...q.depositAddress ? [q.depositAddress] : []].map(tonRawAddress).filter((a) => !!a) : [];
|
|
876
|
+
if (pinned.length && !pinned.includes(tonRawAddress(unsigned.to) ?? "")) refuse(`remote provider '${q.provider}' sends it to ${unsigned.to}, which the app did not pin (remoteProvider callTargets)`);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
const remote = provider.remote === true;
|
|
880
|
+
const pins = (list) => (list ?? []).filter((a) => typeof a === "string" && /^0x[0-9a-fA-F]{40}$/.test(a)).map((a) => a.toLowerCase());
|
|
881
|
+
const pinnedTargets = remote ? pins(provider.callTargets?.(this.fromChain)) : [];
|
|
882
|
+
const pinnedSpenders = remote ? pins(provider.spenders?.(this.fromChain)) : [];
|
|
883
|
+
if (remote && unsigned.approvalAddress && !pinnedSpenders.includes(unsigned.approvalAddress.toLowerCase())) {
|
|
884
|
+
throw new Swap2ValidationError(`swap2: remote provider '${q.provider}' asks to approve ${unsigned.approvalAddress} on ${this.fromChain}, which the app did not pin as a spender (remoteProvider spenders) \u2014 refused`);
|
|
885
|
+
}
|
|
886
|
+
if (unsigned.typedData !== void 0) {
|
|
887
|
+
if (remote && provider.verifiesBuilds !== true) {
|
|
888
|
+
throw new Swap2ValidationError(`swap2: remote provider '${q.provider}' asks to sign a typed order, which needs the app's own validator (remoteProvider verifyBuild) \u2014 refused`);
|
|
889
|
+
}
|
|
890
|
+
const chainId = this.fromChain.startsWith("eip155:") ? Number(this.fromChain.slice("eip155:".length)) : null;
|
|
891
|
+
assertTypedOrder(unsigned.typedData, unsigned.approvalAddress, { self: selfAddress, token: source.contract ?? void 0, amount: q.sourceAmount, chainId });
|
|
892
|
+
}
|
|
739
893
|
if (unsigned.data !== void 0 && this.fromChain.startsWith("eip155:")) {
|
|
740
894
|
const call = (0, import_tx_preview_evm.decodeCall)({ to: unsigned.to, data: unsigned.data, value: executionValue });
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
895
|
+
if (call.undecodable) throw new Swap2ValidationError("swap2: quote calldata is not hex bytes \u2014 refused");
|
|
896
|
+
if (call.approval && call.approval.kind !== "erc20") {
|
|
897
|
+
throw new Swap2ValidationError(`swap2: quote calldata is ${call.approval.kind === "operator" ? "an operator approval (setApprovalForAll)" : "a Permit2 approval"} \u2014 never a swap's main call; refused`);
|
|
898
|
+
}
|
|
899
|
+
if (call.transfer || call.approval) {
|
|
900
|
+
if (!source.contract || unsigned.to.toLowerCase() !== source.contract.toLowerCase()) {
|
|
901
|
+
throw new Swap2ValidationError(`swap2: quote calldata (${call.method}) moves ${(0, import_viem.getAddress)(unsigned.to)}, not the source token \u2014 refused`);
|
|
902
|
+
}
|
|
903
|
+
if (call.method === "transferFrom") throw new Swap2ValidationError("swap2: quote calldata pulls the source token with transferFrom \u2014 refused");
|
|
904
|
+
const amount = call.transfer?.amount ?? call.approval?.amount ?? null;
|
|
905
|
+
if (amount === null || amount > BigInt(q.sourceAmount)) {
|
|
906
|
+
throw new Swap2ValidationError(`swap2: quote calldata (${call.method}) covers ${amount === null ? "an unlimited amount" : amount} of the source token, more than the swap's ${q.sourceAmount} \u2014 refused`);
|
|
907
|
+
}
|
|
908
|
+
const named = (call.transfer?.to ?? call.approval.spender).toLowerCase();
|
|
909
|
+
const allowed = engineTransfer ? [q.depositAddress] : remote ? [selfAddress, ...pinnedTargets, ...pinnedSpenders] : [selfAddress, q.depositAddress, unsigned.approvalAddress];
|
|
910
|
+
if (!allowed.filter((a) => !!a).map((a) => a.toLowerCase()).includes(named)) {
|
|
911
|
+
throw new Swap2ValidationError(`swap2: quote calldata (${call.method}) names ${(0, import_viem.getAddress)(named)}, which is not this account, the deposit address or ${remote ? "a spender the app pinned" : "the declared spender"} \u2014 refused`);
|
|
912
|
+
}
|
|
913
|
+
} else if (remote && !pinnedTargets.includes(unsigned.to.toLowerCase())) {
|
|
914
|
+
throw new Swap2ValidationError(`swap2: remote provider '${q.provider}' calls ${(0, import_viem.getAddress)(unsigned.to)} on ${this.fromChain}, which the app did not pin as a call target (remoteProvider callTargets) \u2014 refused`);
|
|
745
915
|
}
|
|
746
916
|
}
|
|
747
917
|
const needsApproval = !!unsigned.approvalAddress && !!source.contract;
|
|
@@ -803,7 +973,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
803
973
|
...unsigned.chainId !== void 0 ? { chainId: unsigned.chainId } : {},
|
|
804
974
|
...unsigned.gasLimit ? { gasLimit: BigInt(unsigned.gasLimit) } : {},
|
|
805
975
|
...unsigned.memo ? { memo: unsigned.memo, ...unsigned.memoEncoding ? { memoEncoding: unsigned.memoEncoding } : {} } : {},
|
|
806
|
-
...cellBody !== void 0 ? { cellBody: true } : {}
|
|
976
|
+
...cellBody !== void 0 ? { cellBody: true, ...tonBody ? { cellBodyDecoded: tonBody } : {} } : {}
|
|
807
977
|
}
|
|
808
978
|
};
|
|
809
979
|
const previous = carried?.reviewed;
|
|
@@ -1068,6 +1238,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1068
1238
|
throw new Swap2ValidationError(`swap2: claim target ${unsigned.to} is not a contract '${name}' declares for ${unsigned.chain} \u2014 refused`);
|
|
1069
1239
|
}
|
|
1070
1240
|
const claimCall = (0, import_tx_preview_evm.decodeCall)({ to: unsigned.to, data: unsigned.data, value: 0n });
|
|
1241
|
+
if (claimCall.undecodable) throw new Swap2ValidationError("swap2: claim calldata is not hex bytes \u2014 refused");
|
|
1071
1242
|
if (claimCall.transfer || claimCall.approval) {
|
|
1072
1243
|
throw new Swap2ValidationError(`swap2: claim calldata (${claimCall.method}) moves tokens or grants an allowance \u2014 refused`);
|
|
1073
1244
|
}
|
|
@@ -1128,7 +1299,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1128
1299
|
/** Source chains this protocol can swap from. */
|
|
1129
1300
|
async getSupportedChains() {
|
|
1130
1301
|
if (!this.protocolEnabled()) return [];
|
|
1131
|
-
return
|
|
1302
|
+
return import_swap2_assets2.CC_SOURCE_CHAINS.filter((c) => this.chainSupported(c.caip2)).map((c) => ({
|
|
1132
1303
|
id: c.caip2,
|
|
1133
1304
|
name: c.label,
|
|
1134
1305
|
type: chainType(c.caip2),
|
|
@@ -1141,7 +1312,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
|
|
|
1141
1312
|
const wantTo = options?.toChain != null ? toCaip2(options.toChain, "") : void 0;
|
|
1142
1313
|
if (!this.protocolEnabled() || wantFrom && wantTo && !this.pairSupported(wantFrom, wantTo)) return [];
|
|
1143
1314
|
const out = [];
|
|
1144
|
-
for (const c of
|
|
1315
|
+
for (const c of import_swap2_assets2.CC_SOURCE_CHAINS) {
|
|
1145
1316
|
if (!this.chainSupported(c.caip2)) continue;
|
|
1146
1317
|
if ((wantFrom || wantTo) && c.caip2 !== wantFrom && c.caip2 !== wantTo) continue;
|
|
1147
1318
|
for (const a of c.assets) {
|