@anywalletkit/protocol-swap2-core 0.10.3 → 0.11.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/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@ export { Swap2ConfigurationError, Swap2Error, Swap2ErrorCode, Swap2ExecutionErro
3
3
  export { SLIPPAGE_ROUNDING_BPS, remotePinRefusal, slippageFloor, validQuote } from './validate.cjs';
4
4
  export { RemoteProviderOptions, remoteProvider } from './remote.cjs';
5
5
  export { evmRef, isEvm, namespace, redactUrls, sourceAssetOf, tonRawAddress } from './util.cjs';
6
- export { BaseSwap2Protocol, NATIVE_DECIMALS, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPhase, Swap2ExecutionPhaseDetail, Swap2ExecutionPlan, TonBodySummary, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.cjs';
6
+ export { BaseSwap2Protocol, NATIVE_DECIMALS, NATIVE_FEE_CEILING_MAX_MULTIPLE, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPhase, Swap2ExecutionPhaseDetail, Swap2ExecutionPlan, Swap2NativeFeeCeilingContext, TonBodySummary, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.cjs';
7
7
  export { SingleProviderSwap2 } from './swap2/single.cjs';
8
8
  export { SwapActivityOptions, assetLabel, assetMetaFor, callSelector, calledContract, callsContract, chainLabel, describeSwapLike, matchesCall, ownerAssets, shortAddress } from './activity.cjs';
9
9
  export { SlippageClass, SlippageContext, SlippageOptions, SlippageSuggestion, slippageClassOf, suggestSlippage } from './slippage.cjs';
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { Swap2ConfigurationError, Swap2Error, Swap2ErrorCode, Swap2ExecutionErro
3
3
  export { SLIPPAGE_ROUNDING_BPS, remotePinRefusal, slippageFloor, validQuote } from './validate.js';
4
4
  export { RemoteProviderOptions, remoteProvider } from './remote.js';
5
5
  export { evmRef, isEvm, namespace, redactUrls, sourceAssetOf, tonRawAddress } from './util.js';
6
- export { BaseSwap2Protocol, NATIVE_DECIMALS, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPhase, Swap2ExecutionPhaseDetail, Swap2ExecutionPlan, TonBodySummary, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.js';
6
+ export { BaseSwap2Protocol, NATIVE_DECIMALS, NATIVE_FEE_CEILING_MAX_MULTIPLE, SWAP2_CHAIN_ALIASES, SWAP2_ID_PREFIX, SerializedExecutionExpectation, Swap2Account, Swap2EngineConfig, Swap2ExecutionPhase, Swap2ExecutionPhaseDetail, Swap2ExecutionPlan, Swap2NativeFeeCeilingContext, TonBodySummary, nativeDecimals, nativeUnits, swap2ChainId } from './swap2/base.js';
7
7
  export { SingleProviderSwap2 } from './swap2/single.js';
8
8
  export { SwapActivityOptions, assetLabel, assetMetaFor, callSelector, calledContract, callsContract, chainLabel, describeSwapLike, matchesCall, ownerAssets, shortAddress } from './activity.js';
9
9
  export { SlippageClass, SlippageContext, SlippageOptions, SlippageSuggestion, slippageClassOf, suggestSlippage } from './slippage.js';
package/dist/index.js CHANGED
@@ -12,16 +12,17 @@ import {
12
12
  } from "./chunk-J4WXUNK2.js";
13
13
  import {
14
14
  SingleProviderSwap2
15
- } from "./chunk-RVO3VODH.js";
15
+ } from "./chunk-HADKPUH4.js";
16
16
  import {
17
17
  BaseSwap2Protocol,
18
18
  NATIVE_DECIMALS,
19
+ NATIVE_FEE_CEILING_MAX_MULTIPLE,
19
20
  SWAP2_CHAIN_ALIASES,
20
21
  SWAP2_ID_PREFIX,
21
22
  nativeDecimals,
22
23
  nativeUnits,
23
24
  swap2ChainId
24
- } from "./chunk-2YDSKVIL.js";
25
+ } from "./chunk-MVEAEYYJ.js";
25
26
  import "./chunk-55J6XMHW.js";
26
27
  import {
27
28
  Swap2ConfigurationError,
@@ -60,6 +61,7 @@ import {
60
61
  export {
61
62
  BaseSwap2Protocol,
62
63
  NATIVE_DECIMALS,
64
+ NATIVE_FEE_CEILING_MAX_MULTIPLE,
63
65
  SLIPPAGE_ROUNDING_BPS,
64
66
  SWAP2_CHAIN_ALIASES,
65
67
  SWAP2_ID_PREFIX,
@@ -22,6 +22,7 @@ var base_exports = {};
22
22
  __export(base_exports, {
23
23
  BaseSwap2Protocol: () => BaseSwap2Protocol,
24
24
  NATIVE_DECIMALS: () => NATIVE_DECIMALS,
25
+ NATIVE_FEE_CEILING_MAX_MULTIPLE: () => NATIVE_FEE_CEILING_MAX_MULTIPLE,
25
26
  SWAP2_CHAIN_ALIASES: () => SWAP2_CHAIN_ALIASES,
26
27
  SWAP2_ID_PREFIX: () => SWAP2_ID_PREFIX,
27
28
  nativeDecimals: () => nativeDecimals,
@@ -239,12 +240,62 @@ var NATIVE_FEE_CAP = Object.freeze({
239
240
  // 0.1 HYPE
240
241
  });
241
242
  var DEFAULT_NATIVE_FEE_CAP = 5000000000000000n;
242
- function declaredNativeFee(q, chain) {
243
+ var NATIVE_FEE_CEILING_MAX_MULTIPLE = 20n;
244
+ function describeCeilingAnswer(value) {
245
+ if (value === null) return "null";
246
+ if (typeof value === "bigint") return String(value);
247
+ if (typeof value === "string") return `the string "${value.slice(0, 40)}"`;
248
+ if (typeof value === "number" || typeof value === "boolean") return `the ${typeof value} ${String(value)}`;
249
+ if (typeof value === "function") return "a function";
250
+ let thenable = false;
251
+ try {
252
+ thenable = typeof value.then === "function";
253
+ if (thenable) value.then(void 0, () => {
254
+ });
255
+ } catch {
256
+ }
257
+ return thenable ? "a Promise (the hook must answer synchronously)" : typeof value === "object" ? "an object" : `a ${typeof value}`;
258
+ }
259
+ function nativeFeeCap(chain, fee, route) {
260
+ const defaultCap = NATIVE_FEE_CAP[chain] ?? DEFAULT_NATIVE_FEE_CAP;
261
+ const hook = route?.ceiling;
262
+ if (hook === void 0) return defaultCap;
263
+ const maxCeiling = defaultCap * NATIVE_FEE_CEILING_MAX_MULTIPLE;
264
+ const where = `${route.provider} ${chain} \u2192 ${route.destChain}`;
265
+ if (typeof hook !== "function") {
266
+ throw new Swap2ConfigurationError(`swap2: nativeFeeCeiling is ${describeCeilingAnswer(hook)}, not a function \u2014 the native fee of ${where} is refused`);
267
+ }
268
+ const ctx = Object.freeze({
269
+ provider: route.provider,
270
+ intentId: route.intentId,
271
+ fromChain: chain,
272
+ destChain: route.destChain,
273
+ nativeFee: fee,
274
+ defaultCap,
275
+ maxCeiling
276
+ });
277
+ let answer;
278
+ try {
279
+ answer = hook(ctx);
280
+ } catch (error) {
281
+ const why = (error instanceof Error ? error.message : String(error)).slice(0, 160);
282
+ throw new Swap2ConfigurationError(`swap2: nativeFeeCeiling threw for ${where} (${why}) \u2014 the native fee is refused`, { cause: error });
283
+ }
284
+ if (answer === void 0) return defaultCap;
285
+ if (typeof answer !== "bigint" || answer < 0n) {
286
+ throw new Swap2ConfigurationError(`swap2: nativeFeeCeiling returned ${describeCeilingAnswer(answer)} for ${where}, not a non-negative bigint or undefined \u2014 the native fee is refused`);
287
+ }
288
+ if (answer > maxCeiling) {
289
+ throw new Swap2ConfigurationError(`swap2: nativeFeeCeiling returned ${answer} for ${where}, above the hard maximum ${maxCeiling} (${NATIVE_FEE_CEILING_MAX_MULTIPLE} \xD7 the default cap ${defaultCap}) \u2014 the native fee is refused`);
290
+ }
291
+ return answer;
292
+ }
293
+ function declaredNativeFee(q, chain, route) {
243
294
  const raw = q.txRequest?.nativeFee;
244
295
  if (raw === void 0) return 0n;
245
296
  if (!/^\d+$/.test(raw)) throw new Error("swap2: quote declares a malformed native fee");
246
297
  const fee = BigInt(raw);
247
- const cap = NATIVE_FEE_CAP[chain] ?? DEFAULT_NATIVE_FEE_CAP;
298
+ const cap = nativeFeeCap(chain, fee, route);
248
299
  if (fee > cap) throw new Error(`swap2: quoted native fee ${fee} exceeds the cap ${cap} for ${chain}`);
249
300
  return fee;
250
301
  }
@@ -868,16 +919,18 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
868
919
  const source = this.sourceAsset(executionOptions);
869
920
  if (!source) throw new Error(`swap2: unknown source token '${executionOptions.fromToken}' on ${this.fromChain}`);
870
921
  const executionValue = BigInt(unsigned.value);
922
+ const ceiling = this._config.nativeFeeCeiling;
923
+ const feeRoute = { provider: q.provider, intentId: q.intentId, destChain: params.destChain, ...ceiling !== void 0 ? { ceiling } : {} };
871
924
  if (serialized) {
872
925
  if (executionValue !== (source.contract ? 0n : BigInt(q.sourceAmount))) {
873
926
  throw new Error("swap2: provider execution amount does not match the validated quote");
874
927
  }
875
928
  } else if (source.contract && this.fromChain.startsWith("eip155:")) {
876
- const declared = declaredNativeFee(q, this.fromChain);
929
+ const declared = declaredNativeFee(q, this.fromChain, feeRoute);
877
930
  if (executionValue !== declared) {
878
931
  throw new Error(declared === 0n ? "swap2: token execution attempted to attach native value" : `swap2: token execution value ${executionValue} does not match the quoted native fee ${declared}`);
879
932
  }
880
- } else if (!unsigned.typedData && !unsigned.bodyBoc && executionValue !== BigInt(q.sourceAmount) + declaredNativeFee(q, this.fromChain)) {
933
+ } else if (!unsigned.typedData && !unsigned.bodyBoc && executionValue !== BigInt(q.sourceAmount) + declaredNativeFee(q, this.fromChain, feeRoute)) {
881
934
  throw new Error("swap2: provider execution amount does not match the validated quote");
882
935
  }
883
936
  let tonBody;
@@ -886,13 +939,13 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
886
939
  throw new Swap2ValidationError(`swap2: TON cell-body build refused \u2014 ${why}`);
887
940
  };
888
941
  const raw = this._config.tonGasCeiling;
889
- const ceiling = raw === void 0 ? DEFAULT_TON_GAS_CEILING : BigInt(raw);
890
- if (ceiling < 0n) throw new Swap2ConfigurationError("swap2: tonGasCeiling must be non-negative");
942
+ const ceiling2 = raw === void 0 ? DEFAULT_TON_GAS_CEILING : BigInt(raw);
943
+ if (ceiling2 < 0n) throw new Swap2ConfigurationError("swap2: tonGasCeiling must be non-negative");
891
944
  if (provider.remote === true && provider.verifiesBuilds !== true) refuse("a remote provider's cell body needs the app's own validator (remoteProvider verifyBuild)");
892
945
  tonBody = readTonBody(cellBody);
893
946
  const input = BigInt(q.sourceAmount);
894
947
  if (source.contract) {
895
- if (executionValue > ceiling) refuse(`it attaches ${executionValue} nanoTON to a jetton transfer, more than the ${ceiling} gas ceiling`);
948
+ if (executionValue > ceiling2) refuse(`it attaches ${executionValue} nanoTON to a jetton transfer, more than the ${ceiling2} gas ceiling`);
896
949
  const t = tonBody.jettonTransfer;
897
950
  if (!t) refuse("a jetton-source body must be a jetton transfer");
898
951
  if (t.amount !== input) refuse(`the jetton transfer moves ${t.amount}, not the swap's ${input}`);
@@ -902,7 +955,7 @@ var BaseSwap2Protocol = class extends import_core.Swap2Protocol {
902
955
  if (!own) refuse("the account cannot name its own jetton wallet (getJettonWalletAddress), so the target cannot be checked");
903
956
  if (tonRawAddress(unsigned.to) !== own) refuse(`it is sent to ${unsigned.to}, not this account's ${source.symbol ?? "source"} jetton wallet`);
904
957
  } else {
905
- if (executionValue < input || executionValue - input > ceiling) refuse(`it attaches ${executionValue} nanoTON for a ${input} input, more than the ${ceiling} gas ceiling on top`);
958
+ if (executionValue < input || executionValue - input > ceiling2) refuse(`it attaches ${executionValue} nanoTON for a ${input} input, more than the ${ceiling2} gas ceiling on top`);
906
959
  const pinned = provider.remote === true ? [...provider.callTargets?.(this.fromChain) ?? [], ...q.depositAddress ? [q.depositAddress] : []].map(tonRawAddress).filter((a) => !!a) : [];
907
960
  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)`);
908
961
  }