@rabby-wallet/rabby-swap 0.0.2 → 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/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 { QuoteParams, Tx, QuoteResult } from "../quote";
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 = 'ETH';
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: options.fromToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.fromToken,
78
- buyToken: options.toToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.toToken,
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,
@@ -83,11 +98,11 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
83
98
  };
84
99
 
85
100
  if (options.feeRate) {
86
- params.buyTokenPercentageFee = options.feeRate;
101
+ params.buyTokenPercentageFee = options.feeRate / 100;
87
102
  params.feeRecipient = options.feeAddress;
88
103
  }
89
104
 
90
- const { data } = await request.get<SwapResponse>('/swap/v1/quote', {
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 === NATIVE_TOKEN ? CHAINS[options.chain].nativeTokenAddress : 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 === NATIVE_TOKEN ? CHAINS[options.chain].nativeTokenAddress : data.buyTokenAddress,
105
- toTokenAmount: data.buyAmount
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 { QuoteParams, Tx, QuoteResult } from "../quote";
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 = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
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: options.fromToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.fromToken,
80
- toTokenAddress: options.toToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.toToken,
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: data.fromToken.address === NATIVE_TOKEN ? CHAINS[options.chain].nativeTokenAddress : data.fromToken.address,
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: data.toToken.address === NATIVE_TOKEN ? CHAINS[options.chain].nativeTokenAddress : data.toToken.address,
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
+ };
@@ -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 { QuoteParams, Tx, QuoteResult } from "../quote";
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
 
@@ -100,18 +109,30 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
100
109
 
101
110
  const { priceRoute } = await getPriceRoute({
102
111
  srcDecimals: options.fromTokenDecimals,
103
- srcToken: options.fromToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.fromToken,
104
- destToken: options.toToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.toToken,
112
+ srcToken:
113
+ options.fromToken === CHAINS[options.chain].nativeTokenAddress
114
+ ? NATIVE_TOKEN
115
+ : options.fromToken,
116
+ destToken:
117
+ options.toToken === CHAINS[options.chain].nativeTokenAddress
118
+ ? NATIVE_TOKEN
119
+ : options.toToken,
105
120
  amount: options.amount,
106
121
  userAddress: options.userAddress,
107
122
  network: chainId,
108
- includeContractMethods: 'simpleSwap,multiSwap,megaSwap',
123
+ includeContractMethods: "simpleSwap,multiSwap,megaSwap",
109
124
  });
110
125
 
111
126
  const params: SwapParams = {
112
- srcToken: options.fromToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.fromToken,
127
+ srcToken:
128
+ options.fromToken === CHAINS[options.chain].nativeTokenAddress
129
+ ? NATIVE_TOKEN
130
+ : options.fromToken,
113
131
  srcDecimals: options.fromTokenDecimals,
114
- destToken: options.toToken === CHAINS[options.chain].nativeTokenAddress ? NATIVE_TOKEN : options.toToken,
132
+ destToken:
133
+ options.toToken === CHAINS[options.chain].nativeTokenAddress
134
+ ? NATIVE_TOKEN
135
+ : options.toToken,
115
136
  srcAmount: options.amount,
116
137
  userAddress: options.userAddress,
117
138
  slippage: Math.floor(options.slippage * 100),
@@ -123,22 +144,122 @@ export const getQuote = async (options: QuoteParams): Promise<QuoteResult> => {
123
144
  params.partnerAddress = options.feeAddress;
124
145
  }
125
146
 
126
- const { data } = await request.get<Tx>(`/transactions/${chainId}`, {
147
+ const { data } = await request.post<Tx>(`/transactions/${chainId}`, params, {
127
148
  params: {
128
149
  ignoreChecks: true,
129
150
  ignoreGasEstimate: true,
130
151
  },
131
- data: params,
132
152
  });
133
-
153
+
134
154
  return {
135
155
  tx: data,
136
- fromToken: priceRoute.srcToken === NATIVE_TOKEN ? CHAINS[options.chain].nativeTokenAddress : priceRoute.srcToken,
156
+ fromToken:
157
+ priceRoute.srcToken === NATIVE_TOKEN
158
+ ? CHAINS[options.chain].nativeTokenAddress
159
+ : priceRoute.srcToken,
137
160
  fromTokenAmount: priceRoute.srcAmount,
138
161
  fromTokenDecimals: priceRoute.srcDecimals,
139
- toToken: priceRoute.destToken === NATIVE_TOKEN ? CHAINS[options.chain].nativeTokenAddress : priceRoute.destToken,
162
+ toToken:
163
+ priceRoute.destToken === NATIVE_TOKEN
164
+ ? CHAINS[options.chain].nativeTokenAddress
165
+ : priceRoute.destToken,
140
166
  toTokenAmount: priceRoute.destAmount,
141
167
  toTokenDecimals: priceRoute.destDecimals,
142
168
  spender: data.to,
143
169
  };
144
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
+ };
@@ -1,4 +1,4 @@
1
- import abiCoder, { AbiCoder } from "web3-eth-abi";
1
+ import abiCoder from "web3-eth-abi";
2
2
  import { CHAINS_ENUM, CHAINS } from "@debank/common";
3
3
  import { WrapTokenAddressMap } from "../consts";
4
4
  import { QuoteParams, Tx, QuoteResult } from "../quote";
package/src/index.ts CHANGED
@@ -1,6 +1,17 @@
1
- import { WrapTokenAddressMap, DEX_ENUM, DEX_SUPPORT_CHAINS } from './consts';
2
- import { getQuote } from './quote';
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, DEX_ENUM, DEX_SUPPORT_CHAINS, getQuote
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
+ };
@@ -0,0 +1,11 @@
1
+ module.exports = {
2
+ process() {
3
+ return {
4
+ code: 'module.exports = {};'
5
+ };
6
+ },
7
+ getCacheKey() {
8
+ // The output is always the same.
9
+ return 'svgTransform';
10
+ }
11
+ };