@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.
- package/dist/abi.d.ts +0 -2
- package/dist/abi.js +0 -2
- package/dist/dexs/magpie.d.ts +2 -1
- package/dist/dexs/magpie.js +3 -1
- package/dist/dexs/uni.d.ts +3 -1
- package/dist/dexs/uni.js +23 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -1
- package/dist/quote.d.ts +20 -3
- package/dist/quote.js +3 -3
- package/dist/verify/calldata.d.ts +13 -9
- package/dist/verify/calldata.js +22 -44
- package/dist/verify/contracts.d.ts +1 -1
- package/dist/verify/contracts.js +11 -7
- package/dist/verify/sdk.d.ts +1 -2
- package/dist/verify/sdk.js +1 -4
- package/package.json +2 -7
- package/dist/calldata/chain.d.ts +0 -1
- package/dist/calldata/chain.js +0 -9
- package/dist/calldata/magpie/abi.d.ts +0 -1
- package/dist/calldata/magpie/abi.js +0 -3
- package/dist/calldata/magpie/dexAggregator.d.ts +0 -3
- package/dist/calldata/magpie/dexAggregator.js +0 -30
- package/dist/calldata/magpie/index.d.ts +0 -3
- package/dist/calldata/magpie/index.js +0 -65
- package/dist/calldata/magpie/packed.d.ts +0 -16
- package/dist/calldata/magpie/packed.js +0 -30
- package/dist/calldata/types.d.ts +0 -22
- package/dist/calldata/types.js +0 -1
- package/dist/calldata/uni/abi.d.ts +0 -3
- package/dist/calldata/uni/abi.js +0 -6
- package/dist/calldata/uni/assets.d.ts +0 -5
- package/dist/calldata/uni/assets.js +0 -65
- package/dist/calldata/uni/index.d.ts +0 -2
- package/dist/calldata/uni/index.js +0 -40
- package/dist/calldata/uni/shared.d.ts +0 -45
- package/dist/calldata/uni/shared.js +0 -222
- package/dist/calldata/uni/universalRouter/commands.d.ts +0 -3
- package/dist/calldata/uni/universalRouter/commands.js +0 -92
- package/dist/calldata/uni/universalRouter/profiles.d.ts +0 -6
- package/dist/calldata/uni/universalRouter/profiles.js +0 -27
- package/dist/calldata/uni/universalRouter/sdk.d.ts +0 -11
- package/dist/calldata/uni/universalRouter/sdk.js +0 -21
- package/dist/calldata/uni/universalRouter/v2.d.ts +0 -1
- package/dist/calldata/uni/universalRouter/v2.js +0 -18
- package/dist/calldata/uni/universalRouter/v4/index.d.ts +0 -3
- package/dist/calldata/uni/universalRouter/v4/index.js +0 -139
package/dist/abi.d.ts
CHANGED
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 = [
|
package/dist/dexs/magpie.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CHAINS_ENUM } from "@debank/common";
|
|
2
|
-
|
|
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;
|
package/dist/dexs/magpie.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/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
|
+
};
|
package/dist/dexs/uni.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { CHAINS_ENUM } from "@debank/common";
|
|
2
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
3
|
-
|
|
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
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare const
|
|
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
|
-
/**
|
|
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;
|
package/dist/verify/calldata.js
CHANGED
|
@@ -1,66 +1,44 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
2
|
import { DEX_ENUM } from "../consts";
|
|
3
|
-
import {
|
|
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
|
-
/**
|
|
11
|
-
|
|
12
|
-
|
|
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
|
|
15
|
+
return decodeCalldata(dexId, tx);
|
|
16
16
|
}
|
|
17
17
|
catch (_a) {
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
|
-
/** token
|
|
22
|
-
export const matchDecodedCalldata = (decoded, quote, slippageRatio
|
|
23
|
-
const
|
|
24
|
-
return ((
|
|
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(
|
|
30
|
-
.div(
|
|
28
|
+
.minus(estimateMinReceive)
|
|
29
|
+
.div(estimateMinReceive)
|
|
31
30
|
.abs()
|
|
32
31
|
.lte(CALLDATA_MIN_RECEIVE_TOLERANCE));
|
|
33
32
|
};
|
|
34
|
-
/**
|
|
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
|
-
|
|
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
|
|
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;
|
package/dist/verify/contracts.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
52
|
+
routerPass,
|
|
49
53
|
skipSpender ? true : isSameAddress(spenderWhitelist || "", spender),
|
|
50
54
|
];
|
|
51
55
|
};
|
package/dist/verify/sdk.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { CHAINS_ENUM } from "@debank/common";
|
|
2
2
|
import { DEX_ENUM } from "../consts";
|
|
3
|
-
import
|
|
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;
|
package/dist/verify/sdk.js
CHANGED
|
@@ -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
|
|
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": {
|
package/dist/calldata/chain.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const getNativeTokenAddress: (chainId: number, nativeTokenAddress?: string) => string;
|
package/dist/calldata/chain.js
DELETED
|
@@ -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,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
|
-
}
|
package/dist/calldata/types.d.ts
DELETED
|
@@ -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
|
-
}
|
package/dist/calldata/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/calldata/uni/abi.js
DELETED
|
@@ -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];
|