@rabby-wallet/rabby-swap 0.0.3 → 0.0.4
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/__tests__/decodeCalldata.ts +279 -0
- package/dist/abi.d.ts +106 -0
- package/dist/abi.js +545 -0
- package/dist/consts.d.ts +61 -1
- package/dist/consts.js +74 -14
- package/dist/dexs/0xapi.d.ts +2 -1
- package/dist/dexs/0xapi.js +42 -7
- package/dist/dexs/1inch.d.ts +2 -1
- package/dist/dexs/1inch.js +41 -5
- package/dist/dexs/paraswap.d.ts +2 -1
- package/dist/dexs/paraswap.js +70 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/quote.d.ts +11 -0
- package/dist/quote.js +15 -3
- package/package.json +2 -1
- package/src/abi.ts +548 -0
- package/src/consts.ts +81 -20
- package/src/dexs/0xapi.ts +57 -8
- package/src/dexs/1inch.ts +65 -6
- package/src/dexs/paraswap.ts +105 -1
- package/src/dexs/wrapToken.ts +1 -1
- package/src/index.ts +15 -4
- package/src/quote.ts +29 -4
- package/svgTransform.js +11 -0
package/src/dexs/0xapi.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
+
import { Interface } from "@ethersproject/abi";
|
|
2
3
|
import { CHAINS_ENUM, CHAINS } from "@debank/common";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
QuoteParams,
|
|
6
|
+
Tx,
|
|
7
|
+
QuoteResult,
|
|
8
|
+
TxWithChainId,
|
|
9
|
+
DecodeCalldataResult,
|
|
10
|
+
} from "../quote";
|
|
11
|
+
import { isSameAddress } from "../utils";
|
|
12
|
+
import { ZeroXABI } from "../abi";
|
|
4
13
|
|
|
5
|
-
const NATIVE_TOKEN =
|
|
14
|
+
const NATIVE_TOKEN = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
|
6
15
|
|
|
7
16
|
const API_DOMAINS = {
|
|
8
17
|
[CHAINS_ENUM.ETH]: "https://api.0x.org",
|
|
@@ -74,8 +83,14 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
|
|
|
74
83
|
});
|
|
75
84
|
|
|
76
85
|
const params: SwapParams = {
|
|
77
|
-
sellToken:
|
|
78
|
-
|
|
86
|
+
sellToken:
|
|
87
|
+
options.fromToken === CHAINS[options.chain].nativeTokenAddress
|
|
88
|
+
? NATIVE_TOKEN
|
|
89
|
+
: options.fromToken,
|
|
90
|
+
buyToken:
|
|
91
|
+
options.toToken === CHAINS[options.chain].nativeTokenAddress
|
|
92
|
+
? NATIVE_TOKEN
|
|
93
|
+
: options.toToken,
|
|
79
94
|
sellAmount: options.amount,
|
|
80
95
|
takerAddress: options.userAddress,
|
|
81
96
|
slippagePercentage: options.slippage / 100,
|
|
@@ -87,7 +102,7 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
|
|
|
87
102
|
params.feeRecipient = options.feeAddress;
|
|
88
103
|
}
|
|
89
104
|
|
|
90
|
-
const { data } = await request.get<SwapResponse>(
|
|
105
|
+
const { data } = await request.get<SwapResponse>("/swap/v1/quote", {
|
|
91
106
|
params,
|
|
92
107
|
});
|
|
93
108
|
|
|
@@ -98,10 +113,44 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
|
|
|
98
113
|
value: data.value,
|
|
99
114
|
from: data.from,
|
|
100
115
|
},
|
|
101
|
-
fromToken: data.sellTokenAddress
|
|
116
|
+
fromToken: isSameAddress(data.sellTokenAddress, NATIVE_TOKEN)
|
|
117
|
+
? CHAINS[options.chain].nativeTokenAddress
|
|
118
|
+
: data.sellTokenAddress,
|
|
102
119
|
spender: data.allowanceTarget,
|
|
103
120
|
fromTokenAmount: data.sellAmount,
|
|
104
|
-
toToken: data.buyTokenAddress
|
|
105
|
-
|
|
121
|
+
toToken: isSameAddress(data.buyTokenAddress, NATIVE_TOKEN)
|
|
122
|
+
? CHAINS[options.chain].nativeTokenAddress
|
|
123
|
+
: data.buyTokenAddress,
|
|
124
|
+
toTokenAmount: data.buyAmount,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const decodeCalldata = (
|
|
129
|
+
tx: TxWithChainId
|
|
130
|
+
): DecodeCalldataResult | null => {
|
|
131
|
+
const chain = Object.values(CHAINS).find((item) => item.id === tx.chainId);
|
|
132
|
+
if (!chain) return null;
|
|
133
|
+
const contractInterface = new Interface(ZeroXABI);
|
|
134
|
+
const result = contractInterface.parseTransaction({ data: tx.data });
|
|
135
|
+
if (result.name !== "transformERC20") {
|
|
136
|
+
return null;
|
|
106
137
|
}
|
|
138
|
+
|
|
139
|
+
const [inputToken, outputToken, inputTokenAmount, minOutputTokenAmount] =
|
|
140
|
+
result.args;
|
|
141
|
+
|
|
142
|
+
if (!inputToken || !outputToken || !inputTokenAmount || !minOutputTokenAmount)
|
|
143
|
+
return null;
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
fromToken: isSameAddress(inputToken, NATIVE_TOKEN)
|
|
147
|
+
? chain.nativeTokenAddress
|
|
148
|
+
: inputToken,
|
|
149
|
+
fromTokenAmount: inputTokenAmount.toString(),
|
|
150
|
+
toToken: isSameAddress(outputToken, NATIVE_TOKEN)
|
|
151
|
+
? chain.nativeTokenAddress
|
|
152
|
+
: outputToken,
|
|
153
|
+
minReceiveToTokenAmount: minOutputTokenAmount.toString(),
|
|
154
|
+
toTokenReceiver: tx.from,
|
|
155
|
+
};
|
|
107
156
|
};
|
package/src/dexs/1inch.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { CHAINS_ENUM, CHAINS } from "@debank/common";
|
|
3
|
-
import {
|
|
3
|
+
import { Interface } from "@ethersproject/abi";
|
|
4
|
+
import {
|
|
5
|
+
QuoteParams,
|
|
6
|
+
Tx,
|
|
7
|
+
QuoteResult,
|
|
8
|
+
TxWithChainId,
|
|
9
|
+
DecodeCalldataResult,
|
|
10
|
+
} from "../quote";
|
|
11
|
+
import { isSameAddress } from "../utils";
|
|
12
|
+
import { OneInchABI } from "../abi";
|
|
4
13
|
|
|
5
|
-
const NATIVE_TOKEN =
|
|
14
|
+
const NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
6
15
|
|
|
7
16
|
const request = axios.create({
|
|
8
17
|
baseURL: "https://api.1inch.io/v5.0",
|
|
@@ -76,8 +85,14 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
|
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
const params: SwapParams = {
|
|
79
|
-
fromTokenAddress:
|
|
80
|
-
|
|
88
|
+
fromTokenAddress:
|
|
89
|
+
options.fromToken === CHAINS[options.chain].nativeTokenAddress
|
|
90
|
+
? NATIVE_TOKEN
|
|
91
|
+
: options.fromToken,
|
|
92
|
+
toTokenAddress:
|
|
93
|
+
options.toToken === CHAINS[options.chain].nativeTokenAddress
|
|
94
|
+
? NATIVE_TOKEN
|
|
95
|
+
: options.toToken,
|
|
81
96
|
amount: options.amount,
|
|
82
97
|
fromAddress: options.userAddress,
|
|
83
98
|
slippage: options.slippage,
|
|
@@ -95,12 +110,56 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
|
|
|
95
110
|
|
|
96
111
|
return {
|
|
97
112
|
tx: data.tx,
|
|
98
|
-
fromToken:
|
|
113
|
+
fromToken:
|
|
114
|
+
data.fromToken.address === NATIVE_TOKEN
|
|
115
|
+
? CHAINS[options.chain].nativeTokenAddress
|
|
116
|
+
: data.fromToken.address,
|
|
99
117
|
fromTokenAmount: data.fromTokenAmount,
|
|
100
118
|
fromTokenDecimals: data.fromToken.decimals,
|
|
101
|
-
toToken:
|
|
119
|
+
toToken:
|
|
120
|
+
data.toToken.address === NATIVE_TOKEN
|
|
121
|
+
? CHAINS[options.chain].nativeTokenAddress
|
|
122
|
+
: data.toToken.address,
|
|
102
123
|
toTokenAmount: data.toTokenAmount,
|
|
103
124
|
toTokenDecimals: data.toToken.decimals,
|
|
104
125
|
spender: data.tx.to,
|
|
105
126
|
};
|
|
106
127
|
};
|
|
128
|
+
|
|
129
|
+
export const decodeCalldata = (
|
|
130
|
+
tx: TxWithChainId
|
|
131
|
+
): DecodeCalldataResult | null => {
|
|
132
|
+
const chain = Object.values(CHAINS).find((item) => item.id === tx.chainId);
|
|
133
|
+
if (!chain) return null;
|
|
134
|
+
const contractInterface = new Interface(OneInchABI);
|
|
135
|
+
const result = contractInterface.parseTransaction({ data: tx.data });
|
|
136
|
+
|
|
137
|
+
if (result.name !== "swap") {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const [executor, desc] = result.args;
|
|
142
|
+
const [
|
|
143
|
+
srcToken,
|
|
144
|
+
dstToken,
|
|
145
|
+
srcReceiver,
|
|
146
|
+
dstReceiver,
|
|
147
|
+
amount,
|
|
148
|
+
minReturnAmount,
|
|
149
|
+
] = desc;
|
|
150
|
+
|
|
151
|
+
if (!srcToken || !dstToken || !dstReceiver || !amount || !minReturnAmount)
|
|
152
|
+
return null;
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
fromToken: isSameAddress(srcToken, NATIVE_TOKEN)
|
|
156
|
+
? chain.nativeTokenAddress
|
|
157
|
+
: srcToken,
|
|
158
|
+
fromTokenAmount: amount.toString(),
|
|
159
|
+
toToken: isSameAddress(dstToken, NATIVE_TOKEN)
|
|
160
|
+
? chain.nativeTokenAddress
|
|
161
|
+
: dstToken,
|
|
162
|
+
minReceiveToTokenAmount: minReturnAmount.toString(),
|
|
163
|
+
toTokenReceiver: dstReceiver,
|
|
164
|
+
};
|
|
165
|
+
};
|
package/src/dexs/paraswap.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
+
import { Interface } from "@ethersproject/abi";
|
|
2
3
|
import { CHAINS_ENUM, CHAINS } from "@debank/common";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
QuoteParams,
|
|
6
|
+
Tx,
|
|
7
|
+
QuoteResult,
|
|
8
|
+
TxWithChainId,
|
|
9
|
+
DecodeCalldataResult,
|
|
10
|
+
} from "../quote";
|
|
11
|
+
import { isSameAddress } from "../utils";
|
|
12
|
+
import { OneInchABI, ParaSwapABI } from "../abi";
|
|
4
13
|
|
|
5
14
|
const NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
6
15
|
|
|
@@ -159,3 +168,98 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
|
|
|
159
168
|
spender: data.to,
|
|
160
169
|
};
|
|
161
170
|
};
|
|
171
|
+
|
|
172
|
+
export const decodeCalldata = (
|
|
173
|
+
tx: TxWithChainId
|
|
174
|
+
): DecodeCalldataResult | null => {
|
|
175
|
+
const chain = Object.values(CHAINS).find((item) => item.id === tx.chainId);
|
|
176
|
+
const nullAddress = "0x0000000000000000000000000000000000000000";
|
|
177
|
+
|
|
178
|
+
if (!chain) return null;
|
|
179
|
+
|
|
180
|
+
const contractInterface = new Interface(ParaSwapABI);
|
|
181
|
+
const result = contractInterface.parseTransaction({
|
|
182
|
+
data: tx.data,
|
|
183
|
+
});
|
|
184
|
+
switch (result.name) {
|
|
185
|
+
case "simpleSwap": {
|
|
186
|
+
const [data] = result.args;
|
|
187
|
+
const [
|
|
188
|
+
fromToken,
|
|
189
|
+
toToken,
|
|
190
|
+
fromAmount,
|
|
191
|
+
toAmount,
|
|
192
|
+
expectedAmount,
|
|
193
|
+
callees,
|
|
194
|
+
exchangeData,
|
|
195
|
+
startIndexes,
|
|
196
|
+
values,
|
|
197
|
+
beneficiary,
|
|
198
|
+
] = data;
|
|
199
|
+
if (!fromToken || !toToken || !fromAmount || !toAmount) return null;
|
|
200
|
+
return {
|
|
201
|
+
fromToken: isSameAddress(fromToken, NATIVE_TOKEN)
|
|
202
|
+
? chain.nativeTokenAddress
|
|
203
|
+
: fromToken,
|
|
204
|
+
fromTokenAmount: fromAmount.toString(),
|
|
205
|
+
toToken: isSameAddress(toToken, NATIVE_TOKEN)
|
|
206
|
+
? chain.nativeTokenAddress
|
|
207
|
+
: toToken,
|
|
208
|
+
minReceiveToTokenAmount: toAmount.toString(),
|
|
209
|
+
toTokenReceiver: beneficiary === nullAddress ? tx.from : beneficiary,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
case "multiSwap": {
|
|
213
|
+
const [data] = result.args;
|
|
214
|
+
const [
|
|
215
|
+
fromToken,
|
|
216
|
+
fromAmount,
|
|
217
|
+
toAmount,
|
|
218
|
+
expectedAmount,
|
|
219
|
+
beneficiary,
|
|
220
|
+
path,
|
|
221
|
+
] = data;
|
|
222
|
+
if (!fromToken || !fromAmount || !toAmount || !path || path.length <= 0)
|
|
223
|
+
return null;
|
|
224
|
+
const [toToken] = path[path.length - 1];
|
|
225
|
+
return {
|
|
226
|
+
fromToken: isSameAddress(fromToken, NATIVE_TOKEN)
|
|
227
|
+
? chain.nativeTokenAddress
|
|
228
|
+
: fromToken,
|
|
229
|
+
fromTokenAmount: fromAmount.toString(),
|
|
230
|
+
toToken: isSameAddress(toToken, NATIVE_TOKEN)
|
|
231
|
+
? chain.nativeTokenAddress
|
|
232
|
+
: toToken,
|
|
233
|
+
minReceiveToTokenAmount: toAmount.toString(),
|
|
234
|
+
toTokenReceiver: beneficiary === nullAddress ? tx.from : beneficiary,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
case "megaSwap":
|
|
238
|
+
const [data] = result.args;
|
|
239
|
+
const [
|
|
240
|
+
fromToken,
|
|
241
|
+
fromAmount,
|
|
242
|
+
toAmount,
|
|
243
|
+
expectedAmount,
|
|
244
|
+
beneficiary,
|
|
245
|
+
path,
|
|
246
|
+
] = data;
|
|
247
|
+
if (!fromToken || !fromAmount || !toAmount || !path || path.length <= 0)
|
|
248
|
+
return null;
|
|
249
|
+
const [fromAmountPercent, swapPath] = path[0];
|
|
250
|
+
const [toToken] = swapPath[swapPath.length - 1];
|
|
251
|
+
return {
|
|
252
|
+
fromToken: isSameAddress(fromToken, NATIVE_TOKEN)
|
|
253
|
+
? chain.nativeTokenAddress
|
|
254
|
+
: fromToken,
|
|
255
|
+
fromTokenAmount: fromAmount.toString(),
|
|
256
|
+
toToken: isSameAddress(toToken, NATIVE_TOKEN)
|
|
257
|
+
? chain.nativeTokenAddress
|
|
258
|
+
: toToken,
|
|
259
|
+
minReceiveToTokenAmount: toAmount.toString(),
|
|
260
|
+
toTokenReceiver: beneficiary === nullAddress ? tx.from : beneficiary,
|
|
261
|
+
};
|
|
262
|
+
default:
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
};
|
package/src/dexs/wrapToken.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
WrapTokenAddressMap,
|
|
3
|
+
DEX_ENUM,
|
|
4
|
+
DEX_SUPPORT_CHAINS,
|
|
5
|
+
DEX_ROUTER_WHITELIST,
|
|
6
|
+
DEX_SPENDER_WHITELIST,
|
|
7
|
+
} from "./consts";
|
|
8
|
+
import { getQuote } from "./quote";
|
|
3
9
|
|
|
4
10
|
export {
|
|
5
|
-
WrapTokenAddressMap,
|
|
6
|
-
|
|
11
|
+
WrapTokenAddressMap,
|
|
12
|
+
DEX_ENUM,
|
|
13
|
+
DEX_SUPPORT_CHAINS,
|
|
14
|
+
getQuote,
|
|
15
|
+
DEX_ROUTER_WHITELIST,
|
|
16
|
+
DEX_SPENDER_WHITELIST,
|
|
17
|
+
};
|
package/src/quote.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { CHAINS_ENUM } from '@debank/common';
|
|
2
2
|
import { DEX_ENUM } from './consts';
|
|
3
3
|
import { getQuote as wrapTokenGetQuote } from './dexs/wrapToken';
|
|
4
|
-
import { getQuote as oneInchGetQuote } from './dexs/1inch';
|
|
5
|
-
import { getQuote as zeroXGetQuote } from './dexs/0xapi';
|
|
6
|
-
import { getQuote as paraSwapGetQuote } from './dexs/paraswap';
|
|
4
|
+
import { getQuote as oneInchGetQuote, decodeCalldata as oneInchDecodeCalldata } from './dexs/1inch';
|
|
5
|
+
import { getQuote as zeroXGetQuote, decodeCalldata as zeroXDecodeCalldata } from './dexs/0xapi';
|
|
6
|
+
import { getQuote as paraSwapGetQuote, decodeCalldata as paraSwapDecodeCalldata } from './dexs/paraswap';
|
|
7
7
|
|
|
8
8
|
export interface QuoteParams {
|
|
9
9
|
fromToken: string;
|
|
@@ -27,6 +27,10 @@ export interface Tx {
|
|
|
27
27
|
gasPrice?: string;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
export interface TxWithChainId extends Tx {
|
|
31
|
+
chainId: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
30
34
|
export interface QuoteResult {
|
|
31
35
|
tx: Tx;
|
|
32
36
|
fromToken: string;
|
|
@@ -51,4 +55,25 @@ export const getQuote = async (id: DEX_ENUM, params: QuoteParams) => {
|
|
|
51
55
|
default:
|
|
52
56
|
throw new Error(`${id} is not supported!`);
|
|
53
57
|
}
|
|
54
|
-
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface DecodeCalldataResult {
|
|
61
|
+
fromToken: string;
|
|
62
|
+
fromTokenAmount: string;
|
|
63
|
+
toToken: string;
|
|
64
|
+
minReceiveToTokenAmount: string;
|
|
65
|
+
toTokenReceiver: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const decodeCalldata = (id: DEX_ENUM, tx: TxWithChainId): DecodeCalldataResult | null => {
|
|
69
|
+
switch(id) {
|
|
70
|
+
case DEX_ENUM.ONEINCH:
|
|
71
|
+
return oneInchDecodeCalldata(tx);
|
|
72
|
+
case DEX_ENUM.PARASWAP:
|
|
73
|
+
return paraSwapDecodeCalldata(tx);
|
|
74
|
+
case DEX_ENUM.ZEROXAPI:
|
|
75
|
+
return zeroXDecodeCalldata(tx);
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`${id} is not supported!`);
|
|
78
|
+
}
|
|
79
|
+
};
|