-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add trade quote utility #60
Conversation
d2acb92
to
05f9027
Compare
One idea for api is const set = new Set({
...
chainId // We could get this from the provider but it's async ...
zeroExApiKey?
}) // Generate and cache tokenList / Map for chainId
async set.trade.fetchTradeQuote(params....)
async set.trade.fetchTokenList()
async set.trade.fetchTokenMap()
async set.trade.fetchCoinPrices(params...)
async set.trade.fetchGasPrice(speed?: string) |
cea3ce6
to
45b0b6b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great and thorough. One question: is the token mapping still being used? I couldn't find it as I was looking through.
Can we have the same redundancies around fetching gas price as we do for CoinGecko returning 0? Also considering redundancies for when the entire API call to CoinGecko or GasNow has status code > 400
@@ -123,7 +123,7 @@ class Set { | |||
assertions | |||
); | |||
this.system = new SystemAPI(ethersProvider, config.controllerAddress); | |||
this.trade = new TradeAPI(ethersProvider, config.tradeModuleAddress); | |||
this.trade = new TradeAPI(ethersProvider, config.tradeModuleAddress, config.zeroExApiKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if people can generate their own API keys for 0x. We may have to supply it for it to be used by anyone else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 0x API is configured with a list of API keys which are permitted to access RFQ-T liquidity. For the instance at api.0x.org, the 0x team is maintaining a list of trusted integrators
@asoong based on the statement from their docs it's not possible to request one. If I understand correctly it will still works but I just may not get the best deal available, right?
* @param fromAddress SetToken address which holds the buy / sell components | ||
* @param setToken SetTokenAPI instance | ||
* @param gasPrice (Optional) gasPrice to calculate gas costs with (Default: fetched from GasNow) | ||
* @param slippagePercentage (Optional) maximum slippage, determines min receive quantity. (Default: 2%) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you grab these defaults from the service?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes... from heroku, here: https://dashboard.heroku.com/apps/set-core-production/settings
The whole number percentage is then divided by 100 before being passed to Zero Ex here:
set.js/src/api/utils/tradeQuoter.ts
Line 231 in 2c360f0
(slippagePercentage / 100), |
* | ||
* @return List of tradeable tokens for chain platform | ||
*/ | ||
public async fetchTokenListAsync(): Promise<CoinGeckoTokenData[]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just want to confirm this is not currently being consumed? It was part of the old flow for grabbing the decimals? This might belong in a different utils type of API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're using this stuff in the admin UI. This API is helpful I think.
* | ||
* @return Map of token addresses to token metadata | ||
*/ | ||
public async fetchTokenMapAsync(): Promise<CoinGeckoTokenMap> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
* | ||
* @return List of prices vs currencies | ||
*/ | ||
public async fetchCoinPricesAsync( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think most of these below belong in a different API, perhaps ERC20 API or something of the sort
|
||
const amount = this.sanitizeAmount(options.rawAmount, options.fromTokenDecimals); | ||
|
||
const setOnChainDetails = await options.setToken.fetchSetDetailsAsync( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot we also make this call. Feels redundant since the client will have all of this information as well as the manager address.. The data only serves a check that the component is a component in the Set.
The manager address is going to be required to fetch a gas estimate since only the manager can submit the trade.
const coinGecko = new CoinGeckoDataService(chainId); | ||
const coinPrices = await coinGecko.fetchCoinPrices({ | ||
contractAddresses: [this.chainCurrencyAddress(chainId), fromTokenAddress, toTokenAddress], | ||
vsCurrencies: [ USD_CURRENCY_CODE, USD_CURRENCY_CODE, USD_CURRENCY_CODE ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you only need USD currency code once, not contractAddresses.length()
times
}; | ||
} | ||
|
||
private sanitizeAddress(fromToken: Address, toToken: Address, fromAddress: Address) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sanitization was only useful so that we could map to the token list for the decimals in a standardized way. if the decimals are already being passed in then this is not necessary
} | ||
|
||
it('should call the TradeQuoter with correct params', async () => { | ||
const expectedQuoteOptions = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I usually like the expected values to be defined right before the expectation (line 272)
|
||
describe('when the rawAmount quantity is invalid', () => { | ||
beforeEach(async () => { | ||
subjectRawAmount = <unknown>5 as string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is <unknowng>
👀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TS complains if you make an incoherent cast (like number to string) ... you have to cast to unknown so it forgets 5 is a number
Maybe this should be part of an opt in "tolerant" setting. I don't think we'd want this to quietly return 0 when fetching prices for a rebalance for example. |
Admin merging per suggestion in Telegram. The only remainder from the review is to create an ERC20 api that houses the price fetching, token data collection stuff. |
TODO
Adds utilities for Ethereum and Polygon chains to
A
tradeQuote
property has been added to the Set object and the Set config now takes an (optional) zeroExApiKey property. Usage looks like:Example Quote