@rabby-wallet/rabby-swap 0.0.88-alpha.3 → 0.0.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/abi.d.ts +0 -2
  2. package/dist/abi.js +0 -2
  3. package/dist/dexs/magpie.d.ts +2 -1
  4. package/dist/dexs/magpie.js +3 -1
  5. package/dist/dexs/uni.d.ts +3 -1
  6. package/dist/dexs/uni.js +23 -1
  7. package/dist/index.d.ts +0 -2
  8. package/dist/index.js +0 -1
  9. package/dist/quote.d.ts +20 -3
  10. package/dist/quote.js +3 -3
  11. package/dist/verify/calldata.d.ts +13 -9
  12. package/dist/verify/calldata.js +22 -44
  13. package/dist/verify/contracts.d.ts +1 -1
  14. package/dist/verify/contracts.js +11 -7
  15. package/dist/verify/sdk.d.ts +1 -2
  16. package/dist/verify/sdk.js +1 -4
  17. package/package.json +2 -7
  18. package/dist/calldata/chain.d.ts +0 -1
  19. package/dist/calldata/chain.js +0 -9
  20. package/dist/calldata/magpie/abi.d.ts +0 -1
  21. package/dist/calldata/magpie/abi.js +0 -3
  22. package/dist/calldata/magpie/dexAggregator.d.ts +0 -3
  23. package/dist/calldata/magpie/dexAggregator.js +0 -30
  24. package/dist/calldata/magpie/index.d.ts +0 -3
  25. package/dist/calldata/magpie/index.js +0 -65
  26. package/dist/calldata/magpie/packed.d.ts +0 -16
  27. package/dist/calldata/magpie/packed.js +0 -30
  28. package/dist/calldata/types.d.ts +0 -22
  29. package/dist/calldata/types.js +0 -1
  30. package/dist/calldata/uni/abi.d.ts +0 -3
  31. package/dist/calldata/uni/abi.js +0 -6
  32. package/dist/calldata/uni/assets.d.ts +0 -5
  33. package/dist/calldata/uni/assets.js +0 -65
  34. package/dist/calldata/uni/index.d.ts +0 -2
  35. package/dist/calldata/uni/index.js +0 -40
  36. package/dist/calldata/uni/shared.d.ts +0 -45
  37. package/dist/calldata/uni/shared.js +0 -222
  38. package/dist/calldata/uni/universalRouter/commands.d.ts +0 -3
  39. package/dist/calldata/uni/universalRouter/commands.js +0 -92
  40. package/dist/calldata/uni/universalRouter/profiles.d.ts +0 -6
  41. package/dist/calldata/uni/universalRouter/profiles.js +0 -27
  42. package/dist/calldata/uni/universalRouter/sdk.d.ts +0 -11
  43. package/dist/calldata/uni/universalRouter/sdk.js +0 -21
  44. package/dist/calldata/uni/universalRouter/v2.d.ts +0 -1
  45. package/dist/calldata/uni/universalRouter/v2.js +0 -18
  46. package/dist/calldata/uni/universalRouter/v4/index.d.ts +0 -3
  47. package/dist/calldata/uni/universalRouter/v4/index.js +0 -139
package/dist/abi.d.ts CHANGED
@@ -335,6 +335,4 @@ export declare const SushiABI: ({
335
335
  stateMutability: string;
336
336
  type: string;
337
337
  })[];
338
- export { UniABI } from "./calldata/uni/abi";
339
- export { MagpieABI } from "./calldata/magpie/abi";
340
338
  export declare const PancakeSwapABI: string[];
package/dist/abi.js CHANGED
@@ -1652,8 +1652,6 @@ export const ZeroXABIV2 = [
1652
1652
  { stateMutability: "payable", type: "fallback" },
1653
1653
  ];
1654
1654
  export const SushiABI = [{ "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [{ "internalType": "address", "name": "tokenOut", "type": "address" }, { "internalType": "uint256", "name": "amountOut", "type": "uint256" }], "name": "MinimalOutputBalanceViolation", "type": "error" }, { "inputs": [], "name": "safeExecutor", "outputs": [{ "internalType": "contract SafeExecutor", "name": "", "type": "address" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "contract IERC20", "name": "tokenIn", "type": "address" }, { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "contract IERC20", "name": "tokenOut", "type": "address" }, { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }, { "internalType": "address", "name": "executor", "type": "address" }, { "internalType": "bytes", "name": "executorData", "type": "bytes" }], "name": "snwap", "outputs": [{ "internalType": "uint256", "name": "amountOut", "type": "uint256" }], "stateMutability": "payable", "type": "function" }, { "inputs": [{ "components": [{ "internalType": "contract IERC20", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "amountIn", "type": "uint256" }, { "internalType": "address", "name": "transferTo", "type": "address" }], "internalType": "struct InputToken[]", "name": "inputTokens", "type": "tuple[]" }, { "components": [{ "internalType": "contract IERC20", "name": "token", "type": "address" }, { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amountOutMin", "type": "uint256" }], "internalType": "struct OutputToken[]", "name": "outputTokens", "type": "tuple[]" }, { "components": [{ "internalType": "address", "name": "executor", "type": "address" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bytes", "name": "data", "type": "bytes" }], "internalType": "struct Executor[]", "name": "executors", "type": "tuple[]" }], "name": "snwapMultiple", "outputs": [{ "internalType": "uint256[]", "name": "amountOut", "type": "uint256[]" }], "stateMutability": "payable", "type": "function" }];
1655
- export { UniABI } from "./calldata/uni/abi";
1656
- export { MagpieABI } from "./calldata/magpie/abi";
1657
1655
  // IAggregator.swapExactIn from the official router's verified implementation:
1658
1656
  // https://sourcify.dev/server/v2/contract/56/0x88b20da52208607e3bf06a59605acebbe7d2e3d6?fields=abi,sources
1659
1657
  export const PancakeSwapABI = [
@@ -1,4 +1,5 @@
1
1
  import { CHAINS_ENUM } from "@debank/common";
2
- export { decodeCalldata } from "../calldata/magpie";
2
+ import { TxWithChainId, DecodeCalldataResult } from "../quote";
3
3
  export declare const SUPPORT_CHAINS: CHAINS_ENUM[];
4
4
  export declare const getQuote: (options: import("../quote").QuoteParams, api: import("@rabby-wallet/rabby-api").OpenApiService) => Promise<import("../quote").QuoteResult>;
5
+ export declare const decodeCalldata: (tx: TxWithChainId) => DecodeCalldataResult | null;
@@ -1,7 +1,6 @@
1
1
  import { CHAINS_ENUM } from "@debank/common";
2
2
  import { generateGetQuote } from "../utils";
3
3
  import { DEX_ENUM } from "../consts";
4
- export { decodeCalldata } from "../calldata/magpie";
5
4
  export const SUPPORT_CHAINS = [
6
5
  CHAINS_ENUM.ETH,
7
6
  CHAINS_ENUM.OP,
@@ -38,3 +37,6 @@ export const getQuote = generateGetQuote({
38
37
  id: "magpie",
39
38
  dex: DEX_ENUM.MAGPIE,
40
39
  });
40
+ export const decodeCalldata = (tx) => {
41
+ return null;
42
+ };
@@ -1,5 +1,7 @@
1
1
  import { CHAINS_ENUM } from "@debank/common";
2
- export { decodeCalldata } from "../calldata/uni";
2
+ import { TxWithChainId, DecodeCalldataResult } from "../quote";
3
3
  export declare const SUPPORT_CHAINS: CHAINS_ENUM[];
4
4
  export declare const UNI_NATIVE_TO_ADDRESSES: Record<CHAINS_ENUM, string>;
5
+ export declare const UNI_LEGACY_NATIVE_TO_ADDRESSES: Record<CHAINS_ENUM, string>;
5
6
  export declare const getQuote: (options: import("../quote").QuoteParams, api: import("@rabby-wallet/rabby-api").OpenApiService) => Promise<import("../quote").QuoteResult>;
7
+ export declare const decodeCalldata: (tx: TxWithChainId) => DecodeCalldataResult | null;
package/dist/dexs/uni.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { CHAINS_ENUM } from "@debank/common";
2
2
  import { generateGetQuote } from "../utils";
3
3
  import { DEX_ENUM } from "../consts";
4
- export { decodeCalldata } from "../calldata/uni";
5
4
  export const SUPPORT_CHAINS = [
6
5
  CHAINS_ENUM.ETH,
7
6
  CHAINS_ENUM.OP,
@@ -19,7 +18,27 @@ export const SUPPORT_CHAINS = [
19
18
  "HOOD",
20
19
  "ARC",
21
20
  ];
21
+ // Native-input tx.to: UR 2.1.2, zkSync 2.0, or SwapProxy on Celo/Tempo.
22
+ // https://github.com/Uniswap/universal-router/tree/543e1a19d6e21e31ced2512eec5792b50f13a0ba/deploy-addresses
22
23
  export const UNI_NATIVE_TO_ADDRESSES = {
24
+ [CHAINS_ENUM.ETH]: "0x23617e59A5925b2A4Bf75d73ff6711cD0b29De85",
25
+ [CHAINS_ENUM.OP]: "0xC09255D86DB563cBc11C2fCf4a0C512e160111B4",
26
+ [CHAINS_ENUM.BSC]: "0xDc264714F68d84CF29BC605589405E78bDBE7C9f",
27
+ [CHAINS_ENUM.POLYGON]: "0xDc264714F68d84CF29BC605589405E78bDBE7C9f",
28
+ [CHAINS_ENUM.ARBITRUM]: "0x2d01411773c8C24805306E89A41F7855C3c4Fe65",
29
+ [CHAINS_ENUM.AVAX]: "0x661E93cca42AfacB172121EF892830cA3b70F08d",
30
+ [CHAINS_ENUM.BASE]: "0xd6145b2D3F379919E8CdEda7B97e37c4b2Ca9c40",
31
+ [CHAINS_ENUM.BLAST]: "0x661E93cca42AfacB172121EF892830cA3b70F08d",
32
+ [CHAINS_ENUM.CELO]: "0x02E5be68D46DAc0B524905bfF209cf47EE6dB2a9",
33
+ [CHAINS_ENUM.ERA]: "0x28731BCC616B5f51dD52CF2e4dF0E78dD1136C06",
34
+ ["UNI"]: "0xD1b797D92d87B688193A2B976eFc8D577D204343",
35
+ ["TEMPO"]: "0x02E5be68D46DAc0B524905bfF209cf47EE6dB2a9",
36
+ ["MONAD"]: "0xa6CE4F10d83dBdDAc17E68e1837ca9cE6a1b596e",
37
+ ["HOOD"]: "0x204FAca1764B154221e35c0d20aBb3c525710498",
38
+ ["ARC"]: "0x8702463e73f74d0b6765aBceb314Ef07aCb92650",
39
+ };
40
+ // Keep the pre-upgrade native entry points valid during the backend rollout.
41
+ export const UNI_LEGACY_NATIVE_TO_ADDRESSES = {
23
42
  [CHAINS_ENUM.ETH]: "0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af",
24
43
  [CHAINS_ENUM.OP]: "0x851116D9223fabED8E56C0E6b8Ad0c31d98B3507",
25
44
  [CHAINS_ENUM.BSC]: "0x1906c1d672b88cD1B9aC7593301cA990F94Eae07",
@@ -41,3 +60,6 @@ export const getQuote = generateGetQuote({
41
60
  id: "uni",
42
61
  dex: DEX_ENUM.UNI,
43
62
  });
63
+ export const decodeCalldata = (tx) => {
64
+ return null;
65
+ };
package/dist/index.d.ts CHANGED
@@ -5,5 +5,3 @@ import { UNI_NATIVE_TO_ADDRESSES } from "./dexs/uni";
5
5
  export * from "./tokenPools";
6
6
  export * from "./verify";
7
7
  export { WrapTokenAddressMap, ARC_ERC20_USDC, DEX_ENUM, DEX_SUPPORT_CHAINS, getQuote, DEX_ROUTER_WHITELIST, DEX_SPENDER_WHITELIST, UNI_NATIVE_TO_ADDRESSES, };
8
- export { decodeCalldata } from "./quote";
9
- export type { DecodeCalldataOptions, DecodeCalldataResult, TxWithChainId, } from "./calldata/types";
package/dist/index.js CHANGED
@@ -5,4 +5,3 @@ import { UNI_NATIVE_TO_ADDRESSES } from "./dexs/uni";
5
5
  export * from "./tokenPools";
6
6
  export * from "./verify";
7
7
  export { WrapTokenAddressMap, ARC_ERC20_USDC, DEX_ENUM, DEX_SUPPORT_CHAINS, getQuote, DEX_ROUTER_WHITELIST, DEX_SPENDER_WHITELIST, UNI_NATIVE_TO_ADDRESSES, };
8
- export { decodeCalldata } from "./quote";
package/dist/quote.d.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import { CHAINS_ENUM } from "@debank/common";
2
2
  import { OpenApiService } from "@rabby-wallet/rabby-api";
3
3
  import { DEX_ENUM } from "./consts";
4
- import type { Tx, TxWithChainId, DecodeCalldataOptions, DecodeCalldataResult } from "./calldata/types";
5
- export type { Tx, TxWithChainId, DecodeCalldataOptions, DecodeCalldataResult, } from "./calldata/types";
6
4
  export interface QuoteParams {
7
5
  fromToken: string;
8
6
  fromTokenDecimals: number;
@@ -19,6 +17,18 @@ export interface QuoteParams {
19
17
  chainServerId: string;
20
18
  nativeTokenAddress: string;
21
19
  }
20
+ export interface Tx {
21
+ from: string;
22
+ to: string;
23
+ data: string;
24
+ value: string;
25
+ chainId?: number;
26
+ gas?: number;
27
+ gasPrice?: string;
28
+ }
29
+ export interface TxWithChainId extends Tx {
30
+ chainId: number;
31
+ }
22
32
  export interface QuoteResult {
23
33
  tx: Tx;
24
34
  fromToken: string;
@@ -33,4 +43,11 @@ export interface QuoteResult {
33
43
  origin?: Awaited<ReturnType<OpenApiService["getSwapQuote"]>>;
34
44
  }
35
45
  export declare const getQuote: (id: DEX_ENUM, params: QuoteParams, api: OpenApiService) => Promise<QuoteResult>;
36
- export declare const decodeCalldata: (id: DEX_ENUM, tx: TxWithChainId, options?: DecodeCalldataOptions) => DecodeCalldataResult | null;
46
+ export interface DecodeCalldataResult {
47
+ fromToken: string;
48
+ fromTokenAmount: string;
49
+ toToken: string;
50
+ minReceiveToTokenAmount: string;
51
+ toTokenReceiver: string;
52
+ }
53
+ export declare const decodeCalldata: (id: DEX_ENUM, tx: TxWithChainId) => DecodeCalldataResult | null;
package/dist/quote.js CHANGED
@@ -56,7 +56,7 @@ export const getQuote = (id, params, api) => __awaiter(void 0, void 0, void 0, f
56
56
  throw new Error(`${id} is not supported!`);
57
57
  }
58
58
  });
59
- export const decodeCalldata = (id, tx, options = {}) => {
59
+ export const decodeCalldata = (id, tx) => {
60
60
  switch (id) {
61
61
  case DEX_ENUM.ONEINCH:
62
62
  return oneInchDecodeCalldata(tx);
@@ -75,13 +75,13 @@ export const decodeCalldata = (id, tx, options = {}) => {
75
75
  case DEX_ENUM.ZEROXAPIV2:
76
76
  return zeroXV2DecodeCalldata(tx);
77
77
  case DEX_ENUM.MAGPIE:
78
- return magpieDecodeCalldata(tx, options);
78
+ return magpieDecodeCalldata(tx);
79
79
  case DEX_ENUM.RABBY:
80
80
  return rabbyDecodeCalldata(tx);
81
81
  case DEX_ENUM.SUSHI:
82
82
  return sushiDecodeCalldata(tx);
83
83
  case DEX_ENUM.UNI:
84
- return uniDecodeCalldata(tx, options);
84
+ return uniDecodeCalldata(tx);
85
85
  case DEX_ENUM.PANCAKESWAP:
86
86
  return pancakeDecodeCalldata(tx);
87
87
  default:
@@ -1,21 +1,25 @@
1
1
  import { DEX_ENUM } from "../consts";
2
- import type { DecodeCalldataOptions, DecodeCalldataResult, TxWithChainId } from "../calldata/types";
3
- import type { QuoteResult } from "../quote";
4
- /** 解码出的 minReceive 相对「报价 × (1-滑点)」允许的相对偏差。 */
2
+ import { DecodeCalldataResult, QuoteResult, TxWithChainId } from "../quote";
3
+ /** 解码出的 minReceive 相对「报价 × (1-滑点)」允许的相对偏差。两端现网均为 5%。 */
5
4
  export declare const CALLDATA_MIN_RECEIVE_TOLERANCE = 0.05;
6
- /** wrap、无 dex、无 tx、解码失败时返回 null。 */
7
- export declare const decodeSwapCalldata: (dexId: DEX_ENUM | null, tx?: TxWithChainId, options?: DecodeCalldataOptions) => DecodeCalldataResult | null;
8
- /** token、支付数量、最低到手比对;收款地址由 receiver 模块校验。 */
9
- export declare const matchDecodedCalldata: (decoded: DecodeCalldataResult, quote: QuoteResult, slippageRatio: string | number, requirePositiveMinimum?: boolean) => boolean;
5
+ /**
6
+ * 尝试解码。wrap、无 dex、无 tx、解码抛错或解不出时返回 null。
7
+ */
8
+ export declare const decodeSwapCalldata: (dexId: DEX_ENUM | null, tx?: TxWithChainId) => DecodeCalldataResult | null;
9
+ /** 纯比对:token、支付数量、最低到手(相对滑点带)。 */
10
+ export declare const matchDecodedCalldata: (decoded: DecodeCalldataResult, quote: QuoteResult, slippageRatio: string | number) => boolean;
10
11
  export type VerifyCalldataParams = {
11
12
  data: QuoteResult | null;
12
13
  dexId: DEX_ENUM | null;
13
14
  /** 已换算成小数的滑点,如 1% → 0.01。 */
14
15
  slippage: string | number;
15
16
  tx?: TxWithChainId;
17
+ /** 传入则不再解码。 */
16
18
  decoded?: DecodeCalldataResult | null;
17
- nativeTokenAddress?: string;
18
19
  };
19
- /** 其他 DEX 沿用的跳过策略;Uni/Magpie 必须完成字段校验。 */
20
+ /** 解不出、无滑点或无报价时跳过比对(现网视为通过)。 */
20
21
  export declare const shouldSkipCalldataMatch: (slippage: string | number, decoded: DecodeCalldataResult | null, data: QuoteResult | null, tx?: TxWithChainId) => boolean;
22
+ /**
23
+ * 解码并与报价比对。解码成功后不再依赖应用链目录。
24
+ */
21
25
  export declare const verifyCalldata: (p: VerifyCalldataParams) => boolean;
@@ -1,66 +1,44 @@
1
1
  import BigNumber from "bignumber.js";
2
2
  import { DEX_ENUM } from "../consts";
3
- import { getNativeTokenAddress } from "../calldata/chain";
4
- import { decodeInputFee } from "../calldata/magpie";
5
- import { getComparableUniInputAmount } from "../calldata/uni/assets";
6
- import { decodeCalldata } from "../quote";
3
+ import { decodeCalldata, } from "../quote";
7
4
  import { isSameAddress } from "../utils";
8
- /** 解码出的 minReceive 相对「报价 × (1-滑点)」允许的相对偏差。 */
5
+ /** 解码出的 minReceive 相对「报价 × (1-滑点)」允许的相对偏差。两端现网均为 5%。 */
9
6
  export const CALLDATA_MIN_RECEIVE_TOLERANCE = 0.05;
10
- /** wrap、无 dex、无 tx、解码失败时返回 null。 */
11
- export const decodeSwapCalldata = (dexId, tx, options = {}) => {
12
- if (!dexId || dexId === DEX_ENUM.WRAPTOKEN || !tx)
7
+ /**
8
+ * 尝试解码。wrap、无 dex、无 tx、解码抛错或解不出时返回 null。
9
+ */
10
+ export const decodeSwapCalldata = (dexId, tx) => {
11
+ if (!dexId || dexId === DEX_ENUM.WRAPTOKEN || !tx) {
13
12
  return null;
13
+ }
14
14
  try {
15
- return decodeCalldata(dexId, tx, options);
15
+ return decodeCalldata(dexId, tx);
16
16
  }
17
17
  catch (_a) {
18
18
  return null;
19
19
  }
20
20
  };
21
- /** token、支付数量、最低到手比对;收款地址由 receiver 模块校验。 */
22
- export const matchDecodedCalldata = (decoded, quote, slippageRatio, requirePositiveMinimum = false) => {
23
- const minimum = new BigNumber(quote.toTokenAmount).times(new BigNumber(1).minus(slippageRatio));
24
- return ((!requirePositiveMinimum || minimum.gt(0)) &&
25
- isSameAddress(decoded.fromToken, quote.fromToken) &&
21
+ /** 纯比对:token、支付数量、最低到手(相对滑点带)。 */
22
+ export const matchDecodedCalldata = (decoded, quote, slippageRatio) => {
23
+ const estimateMinReceive = new BigNumber(quote.toTokenAmount).times(new BigNumber(1).minus(slippageRatio));
24
+ return (isSameAddress(decoded.fromToken, quote.fromToken) &&
26
25
  decoded.fromTokenAmount === quote.fromTokenAmount &&
27
26
  isSameAddress(decoded.toToken, quote.toToken) &&
28
27
  new BigNumber(decoded.minReceiveToTokenAmount)
29
- .minus(minimum)
30
- .div(minimum)
28
+ .minus(estimateMinReceive)
29
+ .div(estimateMinReceive)
31
30
  .abs()
32
31
  .lte(CALLDATA_MIN_RECEIVE_TOLERANCE));
33
32
  };
34
- /** 其他 DEX 沿用的跳过策略;Uni/Magpie 必须完成字段校验。 */
33
+ /** 解不出、无滑点或无报价时跳过比对(现网视为通过)。 */
35
34
  export const shouldSkipCalldataMatch = (slippage, decoded, data, tx) => !slippage || !decoded || !data || !tx;
35
+ /**
36
+ * 解码并与报价比对。解码成功后不再依赖应用链目录。
37
+ */
36
38
  export const verifyCalldata = (p) => {
37
- const decoded = p.decoded !== undefined
38
- ? p.decoded
39
- : decodeSwapCalldata(p.dexId, p.tx, {
40
- nativeTokenAddress: p.nativeTokenAddress,
41
- });
42
- if (p.dexId === DEX_ENUM.UNI || p.dexId === DEX_ENUM.MAGPIE) {
43
- if (!p.tx || !decoded || !p.data)
44
- return false;
45
- let requestedAmount = p.data.fromTokenAmount;
46
- let inputAmount = decoded.fromTokenAmount;
47
- try {
48
- if (p.dexId === DEX_ENUM.MAGPIE) {
49
- // Encoded input-asset fees are transferred separately from amountIn.
50
- inputAmount = new BigNumber(inputAmount)
51
- .plus(decodeInputFee(p.tx, decoded))
52
- .toFixed(0);
53
- }
54
- else {
55
- requestedAmount = getComparableUniInputAmount(requestedAmount, decoded, p.tx.chainId, getNativeTokenAddress(p.tx.chainId, p.nativeTokenAddress));
56
- }
57
- }
58
- catch (_a) {
59
- return false;
60
- }
61
- return matchDecodedCalldata(Object.assign(Object.assign({}, decoded), { fromTokenAmount: inputAmount }), Object.assign(Object.assign({}, p.data), { fromTokenAmount: requestedAmount }), p.slippage, true);
62
- }
63
- if (shouldSkipCalldataMatch(p.slippage, decoded, p.data, p.tx))
39
+ const decoded = p.decoded !== undefined ? p.decoded : decodeSwapCalldata(p.dexId, p.tx);
40
+ if (shouldSkipCalldataMatch(p.slippage, decoded, p.data, p.tx)) {
64
41
  return true;
42
+ }
65
43
  return matchDecodedCalldata(decoded, p.data, p.slippage);
66
44
  };
@@ -1,6 +1,6 @@
1
1
  import { CHAINS_ENUM } from "@debank/common";
2
2
  import { DEX_ENUM } from "../consts";
3
- /** Uni 的 native 输入(含 Arc ERC20 USDC)直接走 Universal Router,其余走 proxy。 */
3
+ /** Uni 的 native 输入(含 Arc ERC20 USDC)按链选择执行入口,其余走 proxy。 */
4
4
  export declare const getRouter: (dexId: DEX_ENUM, chain: CHAINS_ENUM, payTokenId: string, nativeTokenAddress: string) => string | undefined;
5
5
  /** wrap 无 spender;其余读白名单。 */
6
6
  export declare const getSpender: (dexId: DEX_ENUM, chain: CHAINS_ENUM) => string | undefined;
@@ -1,15 +1,16 @@
1
1
  import { ARC_ERC20_USDC, DEX_ENUM } from "../consts";
2
- import { UNI_NATIVE_TO_ADDRESSES } from "../dexs/uni";
2
+ import { UNI_LEGACY_NATIVE_TO_ADDRESSES, UNI_NATIVE_TO_ADDRESSES, } from "../dexs/uni";
3
3
  import { DEX_ROUTER_WHITELIST, DEX_SPENDER_WHITELIST } from "../list";
4
4
  import { isSameAddress } from "../utils";
5
5
  import { isSwapWrapToken } from "./wrap";
6
6
  const isNativeToken = (tokenId, nativeTokenAddress) => isSameAddress(tokenId, nativeTokenAddress);
7
- /** Uni 的 native 输入(含 Arc ERC20 USDC)直接走 Universal Router,其余走 proxy。 */
7
+ const isUniNativeInput = (dexId, chain, payTokenId, nativeTokenAddress) => dexId === DEX_ENUM.UNI &&
8
+ (isNativeToken(payTokenId, nativeTokenAddress) ||
9
+ (chain === "ARC" &&
10
+ isSameAddress(payTokenId, ARC_ERC20_USDC)));
11
+ /** Uni 的 native 输入(含 Arc ERC20 USDC)按链选择执行入口,其余走 proxy。 */
8
12
  export const getRouter = (dexId, chain, payTokenId, nativeTokenAddress) => {
9
- if (dexId === DEX_ENUM.UNI &&
10
- (isNativeToken(payTokenId, nativeTokenAddress) ||
11
- (chain === "ARC" &&
12
- isSameAddress(payTokenId, ARC_ERC20_USDC)))) {
13
+ if (isUniNativeInput(dexId, chain, payTokenId, nativeTokenAddress)) {
13
14
  return UNI_NATIVE_TO_ADDRESSES[chain];
14
15
  }
15
16
  const list = DEX_ROUTER_WHITELIST[dexId];
@@ -41,11 +42,14 @@ export const verifyRouterAndSpender = (p) => {
41
42
  }
42
43
  const routerWhitelist = getRouter(dexId, chain, payTokenId, nativeTokenAddress);
43
44
  const spenderWhitelist = getSpender(dexId, chain);
45
+ const routerPass = isSameAddress(routerWhitelist || "", router) ||
46
+ (isUniNativeInput(dexId, chain, payTokenId, nativeTokenAddress) &&
47
+ isSameAddress(UNI_LEGACY_NATIVE_TO_ADDRESSES[chain] || "", router));
44
48
  const skipSpender = !spender ||
45
49
  isNativeToken(payTokenId, nativeTokenAddress) ||
46
50
  isSwapWrapToken(payTokenId, receiveTokenId, chain, nativeTokenAddress);
47
51
  return [
48
- isSameAddress(routerWhitelist || "", router),
52
+ routerPass,
49
53
  skipSpender ? true : isSameAddress(spenderWhitelist || "", spender),
50
54
  ];
51
55
  };
@@ -1,7 +1,6 @@
1
1
  import { CHAINS_ENUM } from "@debank/common";
2
2
  import { DEX_ENUM } from "../consts";
3
- import type { DecodeCalldataResult } from "../calldata/types";
4
- import type { QuoteResult } from "../quote";
3
+ import { DecodeCalldataResult, QuoteResult } from "../quote";
5
4
  export type VerifySdkParams = {
6
5
  chain: CHAINS_ENUM;
7
6
  dexId: DEX_ENUM;
@@ -26,16 +26,13 @@ export const verifySdk = (p) => {
26
26
  });
27
27
  const tx = toTxWithChainId(p.data, p.chainId);
28
28
  const slippageRatio = new BigNumber(p.slippage).div(100).toFixed();
29
- const decoded = decodeSwapCalldata(actualDexId, tx, {
30
- nativeTokenAddress: p.nativeTokenAddress,
31
- });
29
+ const decoded = decodeSwapCalldata(actualDexId, tx);
32
30
  const callDataPass = verifyCalldata({
33
31
  data: p.data,
34
32
  dexId: actualDexId,
35
33
  slippage: slippageRatio,
36
34
  tx,
37
35
  decoded,
38
- nativeTokenAddress: p.nativeTokenAddress,
39
36
  });
40
37
  const receiverPass = isSwapCalldataReceiverAllowed(decoded === null || decoded === void 0 ? void 0 : decoded.toTokenReceiver, p.userAddress);
41
38
  return {
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@rabby-wallet/rabby-swap",
3
- "version": "0.0.88-alpha.3",
3
+ "version": "0.0.88",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "test": "jest",
8
8
  "build": "rimraf dist && tsc",
9
9
  "preversion": "npm run build",
10
- "prepublishOnly": "npm test && npm run build",
11
- "test:swap-calldata": "jest --runInBand --watchman=false --runTestsByPath __tests__/swapCalldata.test.ts __tests__/swapCalldataFixtures.test.ts"
10
+ "prepublishOnly": "npm test && npm run build"
12
11
  },
13
12
  "files": [
14
13
  "dist"
@@ -19,12 +18,8 @@
19
18
  },
20
19
  "dependencies": {
21
20
  "@ethersproject/abi": "^5.7.0",
22
- "@uniswap/sdk-core": "7.19.4",
23
- "@uniswap/universal-router-sdk": "5.14.0",
24
- "@uniswap/v2-sdk": "4.21.5",
25
21
  "axios": "^0.27.2",
26
22
  "bignumber.js": "^9.1.1",
27
- "ethers": "5.8.0",
28
23
  "web3-eth-abi": "^1.8.1"
29
24
  },
30
25
  "devDependencies": {
@@ -1 +0,0 @@
1
- export declare const getNativeTokenAddress: (chainId: number, nativeTokenAddress?: string) => string;
@@ -1,9 +0,0 @@
1
- import { CHAINS } from "@debank/common";
2
- export const getNativeTokenAddress = (chainId, nativeTokenAddress) => {
3
- var _a;
4
- const native = nativeTokenAddress !== null && nativeTokenAddress !== void 0 ? nativeTokenAddress : (_a = Object.values(CHAINS).find((chain) => chain.id === chainId)) === null || _a === void 0 ? void 0 : _a.nativeTokenAddress;
5
- if (!native) {
6
- throw new Error(`Native token is not configured for chain ${chainId}`);
7
- }
8
- return native;
9
- };
@@ -1 +0,0 @@
1
- export declare const MagpieABI: string[];
@@ -1,3 +0,0 @@
1
- export const MagpieABI = [
2
- "function swapWithBackendSignature(bytes swapData) payable returns (uint256 amountOut)",
3
- ];
@@ -1,3 +0,0 @@
1
- import { PackedReader, PackedSwap } from "./packed";
2
- export declare const decodeDexAggregator: (data: PackedReader) => PackedSwap;
3
- export declare const decodeDexAggregatorInputFee: (data: PackedReader) => string;
@@ -1,30 +0,0 @@
1
- import BigNumber from "bignumber.js";
2
- // DexAggregator LibRouter.getData(), verified Arbitrum source:
3
- // https://sourcify.dev/server/v2/contract/42161/0x20F6ee51340aDEed01A59B0e65cB3703f3dc860c?fields=sources
4
- export const decodeDexAggregator = (data) => ({
5
- receiver: data.address(72),
6
- fromAsset: data.address(92),
7
- toAsset: data.address(112),
8
- amountIn: data.uint(132),
9
- amountOutMin: data.compact(167, 168),
10
- });
11
- // LibRouter.getData(): byte 274 holds the fee count, followed by three
12
- // arrays of compact descriptors (asset, receiver, amount), 3 bytes per entry.
13
- // transferFees() transfers these separately from the swap's amountIn.
14
- // Only fees paid in the input asset belong in its total debit.
15
- // https://sourcify.dev/server/v2/contract/42161/0x20F6ee51340aDEed01A59B0e65cB3703f3dc860c?fields=sources
16
- // https://docs.fly.trade/developers/api-reference/evm-swap-integration-guide#step-1-get-a-quote
17
- export const decodeDexAggregatorInputFee = (data) => {
18
- const count = Number(data.uint(274, 1));
19
- const inputAsset = new BigNumber(data.address(92).slice(2), 16);
20
- let total = new BigNumber(0);
21
- for (let index = 0; index < count; index++) {
22
- const assetOffset = 275 + index * 3;
23
- const amountOffset = 275 + (count * 2 + index) * 3;
24
- const asset = data.compact(assetOffset, assetOffset + 1);
25
- const amount = data.compact(amountOffset, amountOffset + 1);
26
- if (inputAsset.eq(asset))
27
- total = total.plus(amount);
28
- }
29
- return total.toFixed(0);
30
- };
@@ -1,3 +0,0 @@
1
- import type { DecodeCalldataOptions, DecodeCalldataResult, TxWithChainId } from "../types";
2
- export declare const decodeInputFee: (tx: TxWithChainId, decoded?: DecodeCalldataResult) => string;
3
- export declare const decodeCalldata: (tx: TxWithChainId, options?: DecodeCalldataOptions) => DecodeCalldataResult;
@@ -1,65 +0,0 @@
1
- import { utils } from "ethers";
2
- import BigNumber from "bignumber.js";
3
- import { getNativeTokenAddress } from "../chain";
4
- import { isSameAddress, NULL_ADDRESS } from "../../utils";
5
- import { MagpieABI } from "./abi";
6
- import { decodeDexAggregator, decodeDexAggregatorInputFee, } from "./dexAggregator";
7
- import { PackedReader } from "./packed";
8
- const magpieInterface = new utils.Interface(MagpieABI);
9
- const dexAggregatorSelector = magpieInterface.getSighash("swapWithBackendSignature");
10
- // Keep parsing details private and tied to the decoded result's lifetime.
11
- const decodedPayloads = new WeakMap();
12
- const readPayload = (tx) => {
13
- const selector = tx.data.slice(0, 10).toLowerCase();
14
- if (selector !== dexAggregatorSelector) {
15
- throw new Error(`Unsupported Magpie calldata selector: ${selector}`);
16
- }
17
- const transaction = magpieInterface.parseTransaction({ data: tx.data });
18
- const payloadLength = utils.arrayify(transaction.args[0]).length;
19
- return new PackedReader(tx.data, payloadLength);
20
- };
21
- export const decodeInputFee = (tx, decoded) => {
22
- var _a;
23
- const cached = decoded && decodedPayloads.get(decoded);
24
- if (cached && cached.data === tx.data) {
25
- return ((_a = cached.inputFee) !== null && _a !== void 0 ? _a : (cached.inputFee = decodeDexAggregatorInputFee(cached.payload)));
26
- }
27
- return decodeDexAggregatorInputFee(readPayload(tx));
28
- };
29
- export const decodeCalldata = (tx, options = {}) => {
30
- const native = getNativeTokenAddress(tx.chainId, options.nativeTokenAddress);
31
- const payload = readPayload(tx);
32
- const swap = decodeDexAggregator(payload);
33
- const nativeInput = isSameAddress(swap.fromAsset, NULL_ADDRESS);
34
- let amountIn = new BigNumber(swap.amountIn);
35
- // DexAggregator.adjustAmountIn(): zero means automatic input, not a zero
36
- // debit. Native input is known from value minus encoded native fees;
37
- // ERC20 input depends on min(balance, allowance), unavailable offline.
38
- // https://sourcify.dev/server/v2/contract/42161/0x20F6ee51340aDEed01A59B0e65cB3703f3dc860c?fields=sources
39
- const inputFee = nativeInput ? decodeDexAggregatorInputFee(payload) : "0";
40
- if (amountIn.isZero()) {
41
- if (!nativeInput)
42
- throw new Error("Automatic ERC20 input depends on onchain balance and allowance; it cannot be determined from calldata alone");
43
- amountIn = new BigNumber(tx.value).minus(inputFee);
44
- }
45
- if (!amountIn.gt(0))
46
- throw new Error("Original input amount is zero or unresolved");
47
- if (nativeInput && !amountIn.plus(inputFee).eq(tx.value))
48
- throw new Error("Native transaction value does not equal input amount plus encoded native fees");
49
- const decoded = {
50
- fromToken: isSameAddress(swap.fromAsset, NULL_ADDRESS)
51
- ? native
52
- : swap.fromAsset,
53
- fromTokenAmount: amountIn.toFixed(0),
54
- toToken: isSameAddress(swap.toAsset, NULL_ADDRESS) ? native : swap.toAsset,
55
- minReceiveToTokenAmount: swap.amountOutMin,
56
- // LibRouter reads toAddress literally; zero is not a msg.sender sentinel.
57
- toTokenReceiver: swap.receiver,
58
- };
59
- decodedPayloads.set(decoded, {
60
- data: tx.data,
61
- payload,
62
- inputFee: nativeInput ? inputFee : undefined,
63
- });
64
- return decoded;
65
- };
@@ -1,16 +0,0 @@
1
- export interface PackedSwap {
2
- receiver: string;
3
- fromAsset: string;
4
- toAsset: string;
5
- amountIn: string;
6
- amountOutMin: string;
7
- }
8
- export declare class PackedReader {
9
- private readonly payloadLength;
10
- private readonly hex;
11
- constructor(data: string, payloadLength: number);
12
- private read;
13
- address(offset: number): string;
14
- uint(offset: number, length?: number): string;
15
- compact(shiftOffset: number, pointerOffset: number): string;
16
- }
@@ -1,30 +0,0 @@
1
- import BigNumber from "bignumber.js";
2
- // Offsets include the selector. Reads must stay inside the declared bytes payload.
3
- export class PackedReader {
4
- constructor(data, payloadLength) {
5
- this.payloadLength = payloadLength;
6
- this.hex = data.slice(2);
7
- }
8
- read(offset, length) {
9
- if (offset < 68 || offset + length > 68 + this.payloadLength) {
10
- throw new Error(`Packed field points outside the Magpie bytes payload (offset ${offset}, length ${length})`);
11
- }
12
- return this.hex.slice(offset * 2, (offset + length) * 2);
13
- }
14
- address(offset) {
15
- return `0x${this.read(offset, 20)}`.toLowerCase();
16
- }
17
- uint(offset, length = 32) {
18
- return new BigNumber(this.read(offset, length), 16).toFixed(0);
19
- }
20
- compact(shiftOffset, pointerOffset) {
21
- const shift = Number(this.uint(shiftOffset, 1));
22
- const pointer = Number(this.uint(pointerOffset, 2));
23
- // Only the high (256 - shift) bits survive Solidity's shr.
24
- const significantBits = 256 - shift;
25
- const length = Math.ceil(significantBits / 8);
26
- return new BigNumber(this.uint(pointer, length))
27
- .idiv(new BigNumber(2).pow(length * 8 - significantBits))
28
- .toFixed(0);
29
- }
30
- }
@@ -1,22 +0,0 @@
1
- export interface Tx {
2
- from: string;
3
- to: string;
4
- data: string;
5
- value: string;
6
- chainId?: number;
7
- gas?: number;
8
- gasPrice?: string;
9
- }
10
- export interface TxWithChainId extends Tx {
11
- chainId: number;
12
- }
13
- export interface DecodeCalldataOptions {
14
- nativeTokenAddress?: string;
15
- }
16
- export interface DecodeCalldataResult {
17
- fromToken: string;
18
- fromTokenAmount: string;
19
- toToken: string;
20
- minReceiveToTokenAmount: string;
21
- toTokenReceiver: string;
22
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,3 +0,0 @@
1
- export declare const UniversalRouterABI: import("ethers/lib/utils").FunctionFragment[];
2
- export declare const SwapProxyABI: import("ethers/lib/utils").FunctionFragment[];
3
- export declare const UniABI: import("ethers/lib/utils").FunctionFragment[];
@@ -1,6 +0,0 @@
1
- import { SwapRouter } from "@uniswap/universal-router-sdk";
2
- // The current quote flow uses execute directly or through SwapProxy.
3
- // Keep the official ABI as the source of truth, excluding signed execution.
4
- export const UniversalRouterABI = Object.values(SwapRouter.INTERFACE.functions).filter((fragment) => fragment.name === "execute");
5
- export const SwapProxyABI = Object.values(SwapRouter.PROXY_INTERFACE.functions);
6
- export const UniABI = [...UniversalRouterABI, ...SwapProxyABI];