Last active
May 28, 2024 17:21
-
-
Save NotoriousPyro/fca4c7ab8fe4bf740785f8869ad534dd to your computer and use it in GitHub Desktop.
Quicknode /markets implementation (for adding new markets)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// define a couple of fetchers, one for /quote and one for everything else | |
// if the endpoint url is a QN endpoint, use the custom fetcher that appends the param useQNMarketCache=true | |
export const quoteFetcher = createJupiterApiClient({ | |
basePath: config.jupiter.endpoint, | |
fetchApi: config.jupiter.endpoint.search(/https:\/\/jupiter-swap-api.quiknode.pro\/[A-Z0-9]*/) !== -1 | |
? QuicknodeQuoteFetcherWithCustomAgent(agent) | |
: FetcherWithCustomAgent(agent), | |
}) | |
export const swapInstructionFetcher = createJupiterApiClient({ | |
basePath: config.jupiter.endpoint, | |
fetchApi: FetcherWithCustomAgent(agent), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// define some customised fetchers (the last one is most important). | |
import * as nodeFetch from 'node-fetch'; | |
import fetch from 'fetch-retry' | |
import https from 'https'; | |
const _fetch = fetch(nodeFetch.default); | |
type FetchFn = typeof nodeFetch.default; | |
export type Fetcher = (...args: Parameters<FetchFn>) => ReturnType<FetchFn>; | |
export const RetryFetcher: Fetcher = (...args) => { | |
const [url, init] = args; | |
return _fetch(url, { | |
...init, | |
retries: 3, | |
retryDelay: 1000, | |
retryOn: function (attempt, error, response) { | |
if (attempt > 3) return false; | |
if (response?.status === 429) { | |
return false; | |
} | |
if (error) { | |
return true; | |
} | |
return false; | |
} | |
}); | |
} | |
export type FetcherWithCustomAgent = (agent: https.Agent) => Fetcher; | |
export const FetcherWithCustomAgent: FetcherWithCustomAgent = (agent: https.Agent) => { | |
const fetcher: Fetcher = (...args) => { | |
const [url, init] = args; | |
return RetryFetcher(url, { | |
...init, | |
agent | |
}) | |
} | |
return fetcher; | |
} | |
/** | |
* Workaround for quicknode market cache. Appends useQNMarketCache=true to the url | |
* @param agent https.Agent | |
* @returns a fetcher with custom agent and url modified to append useQNMarketCache=true to the url | |
*/ | |
export const QuicknodeQuoteFetcherWithCustomAgent: FetcherWithCustomAgent = (agent: https.Agent) => { | |
const fetcher: Fetcher = (...args) => { | |
const [url, init] = args; | |
return RetryFetcher(`${url}&useQNMarketCache=true`, { | |
...init, | |
agent | |
}) | |
} | |
return fetcher; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// outside the function, something to hold all the created markets so we don't keep trying within a short window: | |
const createdMarkets = new Set<string>(); | |
// get your quotes and catch any exceptions: | |
try { | |
quoteFetcher.quoteGet(...); | |
} catch (e) { | |
if (e instanceof ResponseError) { | |
const response: Response = e.response | |
const respText = await response.text(); | |
try { | |
const parsed = JSON.parse(respText); | |
switch (parsed?.error) { | |
case "Could not find any route": | |
logger.error(e.message, token, parsed.error); | |
return; | |
} | |
switch (parsed?.errorCode) { | |
case "MARKET_NOT_FOUND": { | |
const market = (parsed.error as string).match(/Market (.*) not found/)?.[1]; | |
if (!createdMarkets.has(market)) { | |
RetryFetcher(`${config.jupiter.endpoint}/markets`, { | |
method: "POST", | |
body: JSON.stringify({ | |
"poolAddress": market | |
}) | |
}).then(() => createdMarkets.add(market)); | |
} | |
return; | |
} | |
} | |
logger.error(e.message, token, parsed); | |
return; | |
} | |
catch (e) { | |
logger.error("failed to parse response error", e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment