@@ -23,8 +23,23 @@ import { TransactionOverrides } from '@setprotocol/set-protocol-v2/dist/typechai
23
23
import { BigNumber } from 'ethers/lib/ethers' ;
24
24
25
25
import TradeModuleWrapper from '../wrappers/set-protocol-v2/TradeModuleWrapper' ;
26
+ import SetTokenAPI from './SetTokenAPI' ;
26
27
import Assertions from '../assertions' ;
27
28
29
+ import {
30
+ TradeQuoter ,
31
+ CoinGeckoDataService ,
32
+ GasOracleService
33
+ } from './utils' ;
34
+
35
+ import {
36
+ TradeQuote ,
37
+ CoinGeckoTokenData ,
38
+ CoinGeckoTokenMap ,
39
+ GasOracleSpeed ,
40
+ CoinGeckoCoinPrices
41
+ } from '../types' ;
42
+
28
43
/**
29
44
* @title TradeAPI
30
45
* @author Set Protocol
@@ -36,14 +51,20 @@ import Assertions from '../assertions';
36
51
export default class TradeAPI {
37
52
private tradeModuleWrapper : TradeModuleWrapper ;
38
53
private assert : Assertions ;
54
+ private provider : Provider ;
55
+ private tradeQuoter : TradeQuoter ;
56
+ private coinGecko : CoinGeckoDataService ;
57
+ private chainId : number ;
39
58
40
59
public constructor (
41
60
provider : Provider ,
42
61
tradeModuleAddress : Address ,
43
- assertions ?: Assertions
62
+ zeroExApiKey ?: string ,
44
63
) {
64
+ this . provider = provider ;
45
65
this . tradeModuleWrapper = new TradeModuleWrapper ( provider , tradeModuleAddress ) ;
46
- this . assert = assertions || new Assertions ( ) ;
66
+ this . assert = new Assertions ( ) ;
67
+ this . tradeQuoter = new TradeQuoter ( zeroExApiKey ) ;
47
68
}
48
69
49
70
/**
@@ -113,4 +134,130 @@ export default class TradeAPI {
113
134
txOpts
114
135
) ;
115
136
}
137
+
138
+ /**
139
+ * Call 0x API to generate a trade quote for two SetToken components.
140
+ *
141
+ * @param fromToken Address of token being sold
142
+ * @param toToken Address of token being bought
143
+ * @param fromTokenDecimals Token decimals of token being sold (ex: 18)
144
+ * @param toTokenDecimals Token decimals of token being bought (ex: 18)
145
+ * @param rawAmount String quantity of token to sell (ex: "0.5")
146
+ * @param fromAddress SetToken address which holds the buy / sell components
147
+ * @param setToken SetTokenAPI instance
148
+ * @param gasPrice (Optional) gasPrice to calculate gas costs with (Default: fetched from GasNow)
149
+ * @param slippagePercentage (Optional) maximum slippage, determines min receive quantity. (Default: 2%)
150
+ * @param isFirmQuote (Optional) Whether quote request is indicative or firm
151
+ * @param feePercentage (Optional) Default: 0
152
+ * @param feeRecipient (Optional) Default: 0xD3D555Bb655AcBA9452bfC6D7cEa8cC7b3628C55
153
+ * @param excludedSources (Optional) Exchanges to exclude (Default: ['Kyber', 'Eth2Dai', 'Uniswap', 'Mesh'])
154
+ *
155
+ * @return {Promise<TradeQuote> }
156
+ */
157
+ public async fetchTradeQuoteAsync (
158
+ fromToken : Address ,
159
+ toToken : Address ,
160
+ fromTokenDecimals : number ,
161
+ toTokenDecimals : number ,
162
+ rawAmount : string ,
163
+ fromAddress : Address ,
164
+ setToken : SetTokenAPI ,
165
+ gasPrice ?: number ,
166
+ slippagePercentage ?: number ,
167
+ isFirmQuote ?: boolean ,
168
+ feePercentage ?: number ,
169
+ feeRecipient ?: Address ,
170
+ excludedSources ?: string [ ] ,
171
+ ) : Promise < TradeQuote > {
172
+ this . assert . schema . isValidAddress ( 'fromToken' , fromToken ) ;
173
+ this . assert . schema . isValidAddress ( 'toToken' , toToken ) ;
174
+ this . assert . schema . isValidAddress ( 'fromAddress' , fromAddress ) ;
175
+ this . assert . schema . isValidJsNumber ( 'fromTokenDecimals' , fromTokenDecimals ) ;
176
+ this . assert . schema . isValidJsNumber ( 'toTokenDecimals' , toTokenDecimals ) ;
177
+ this . assert . schema . isValidString ( 'rawAmount' , rawAmount ) ;
178
+
179
+ const chainId = ( await this . provider . getNetwork ( ) ) . chainId ;
180
+
181
+ return this . tradeQuoter . generate ( {
182
+ fromToken,
183
+ toToken,
184
+ fromTokenDecimals,
185
+ toTokenDecimals,
186
+ rawAmount,
187
+ fromAddress,
188
+ chainId,
189
+ tradeModule : this . tradeModuleWrapper ,
190
+ provider : this . provider ,
191
+ setToken,
192
+ gasPrice,
193
+ slippagePercentage,
194
+ isFirmQuote,
195
+ feePercentage,
196
+ feeRecipient,
197
+ excludedSources,
198
+ } ) ;
199
+ }
200
+
201
+ /**
202
+ * Fetches a list of tokens and their metadata from CoinGecko. Each entry includes
203
+ * the token's address, proper name, decimals, exchange symbol and a logo URI if available.
204
+ * For Ethereum, this is a list of tokens tradeable on Uniswap, for Polygon it's a list of
205
+ * tokens tradeable on Sushiswap's Polygon exchange. Method is useful for acquiring token decimals
206
+ * necessary to generate a trade quote and images for representing available tokens in a UI.
207
+ *
208
+ * @return List of tradeable tokens for chain platform
209
+ */
210
+ public async fetchTokenListAsync ( ) : Promise < CoinGeckoTokenData [ ] > {
211
+ await this . initializeForChain ( ) ;
212
+ return this . coinGecko . fetchTokenList ( ) ;
213
+ }
214
+
215
+ /**
216
+ * Fetches the same info as `fetchTokenList` in the form of a map indexed by address. Method is
217
+ * useful if you're cacheing the token list and want quick lookups for a variety of trades.
218
+ *
219
+ * @return Map of token addresses to token metadata
220
+ */
221
+ public async fetchTokenMapAsync ( ) : Promise < CoinGeckoTokenMap > {
222
+ await this . initializeForChain ( ) ;
223
+ return this . coinGecko . fetchTokenMap ( ) ;
224
+ }
225
+
226
+ /**
227
+ * Fetches a list of prices vs currencies for the specified inputs from CoinGecko
228
+ *
229
+ * @param contractAddresses String array of contract addresses
230
+ * @param vsCurrencies String array of currency codes (see CoinGecko api for a complete list)
231
+ *
232
+ * @return List of prices vs currencies
233
+ */
234
+ public async fetchCoinPricesAsync (
235
+ contractAddresses : string [ ] ,
236
+ vsCurrencies : string [ ]
237
+ ) : Promise < CoinGeckoCoinPrices > {
238
+ await this . initializeForChain ( ) ;
239
+ return this . coinGecko . fetchCoinPrices ( { contractAddresses, vsCurrencies} ) ;
240
+ }
241
+
242
+ /**
243
+ * Fetches the recommended gas price for a specified execution speed.
244
+ *
245
+ * @param speed (Optional) string value: "average" | "fast" | "fastest" (Default: fast)
246
+ *
247
+ * @return Number: gas price
248
+ */
249
+ public async fetchGasPriceAsync ( speed ?: GasOracleSpeed ) : Promise < number > {
250
+ await this . initializeForChain ( ) ;
251
+ const oracle = new GasOracleService ( this . chainId ) ;
252
+ return oracle . fetchGasPrice ( speed ) ;
253
+ }
254
+
255
+
256
+ private async initializeForChain ( ) {
257
+ if ( this . coinGecko === undefined ) {
258
+ const network = await this . provider . getNetwork ( ) ;
259
+ this . chainId = network . chainId ;
260
+ this . coinGecko = new CoinGeckoDataService ( network . chainId ) ;
261
+ }
262
+ }
116
263
}
0 commit comments