From ef6522f7cb1686df1ec646788c6c2769cd2fb8ee Mon Sep 17 00:00:00 2001 From: c4605 Date: Tue, 18 Mar 2025 15:38:33 +0100 Subject: [PATCH] feat(swapHelpers): add batchSize option to FetchRoutesImpl factories --- examples/cross-chain-swap/package.json | 2 +- examples/cross-chain-swap/pnpm-lock.yaml | 11 +++--- .../src/components/SwapRouteSelector.tsx | 34 +++---------------- .../src/utils/getSwapRoutesViaEVMDEX.ts | 8 ++--- .../fetchIceScreamSwapPossibleRoutes.ts | 28 +++++++++++---- .../fetchMatchaPossibleRoutes.ts | 33 ++++++++++++++---- 6 files changed, 60 insertions(+), 56 deletions(-) diff --git a/examples/cross-chain-swap/package.json b/examples/cross-chain-swap/package.json index b3ea8a9..24574c8 100644 --- a/examples/cross-chain-swap/package.json +++ b/examples/cross-chain-swap/package.json @@ -16,7 +16,7 @@ "@stacks/stacks-blockchain-api-types": "^7.14.1", "@stacks/transactions": "^7.0.5", "@xlink-network/xlink-sdk": "file:../..", - "alex-sdk": "github:alexgo-io/alex-sdk#feat/detailed-swap-route-info", + "alex-sdk": "^3.2.0", "c32check": "^2.0.0", "lodash-es": "^4.17.21", "react": "^19.0.0", diff --git a/examples/cross-chain-swap/pnpm-lock.yaml b/examples/cross-chain-swap/pnpm-lock.yaml index fffaeed..1ff1e2a 100644 --- a/examples/cross-chain-swap/pnpm-lock.yaml +++ b/examples/cross-chain-swap/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: file:../.. version: file:../..(@stacks/common@7.0.2)(typescript@5.8.2) alex-sdk: - specifier: github:alexgo-io/alex-sdk#feat/detailed-swap-route-info - version: https://codeload.github.com/alexgo-io/alex-sdk/tar.gz/15171aec2fec824ce3593982ba254748588c1303(@stacks/common@7.0.2)(@stacks/network@7.0.2)(@stacks/transactions@7.0.5) + specifier: ^3.2.0 + version: 3.2.0(@stacks/common@7.0.2)(@stacks/network@7.0.2)(@stacks/transactions@7.0.5) c32check: specifier: ^2.0.0 version: 2.0.0 @@ -550,9 +550,8 @@ packages: zod: optional: true - alex-sdk@https://codeload.github.com/alexgo-io/alex-sdk/tar.gz/15171aec2fec824ce3593982ba254748588c1303: - resolution: {tarball: https://codeload.github.com/alexgo-io/alex-sdk/tar.gz/15171aec2fec824ce3593982ba254748588c1303} - version: 3.0.4 + alex-sdk@3.2.0: + resolution: {integrity: sha512-5Y83pTK3T7wN/SzgFQdjddzYutUuarTsKV6Wt7l4j081RECMYteeiga320iR17MY4R7Jekkw+Rsb0KtvuGnO4Q==} engines: {node: '>=10'} peerDependencies: '@stacks/network': ^7.0.2 @@ -1578,7 +1577,7 @@ snapshots: optionalDependencies: typescript: 5.8.2 - alex-sdk@https://codeload.github.com/alexgo-io/alex-sdk/tar.gz/15171aec2fec824ce3593982ba254748588c1303(@stacks/common@7.0.2)(@stacks/network@7.0.2)(@stacks/transactions@7.0.5): + alex-sdk@3.2.0(@stacks/common@7.0.2)(@stacks/network@7.0.2)(@stacks/transactions@7.0.5): dependencies: '@stacks/network': 7.0.2 '@stacks/transactions': 7.0.5 diff --git a/examples/cross-chain-swap/src/components/SwapRouteSelector.tsx b/examples/cross-chain-swap/src/components/SwapRouteSelector.tsx index 1077e1d..db1655a 100644 --- a/examples/cross-chain-swap/src/components/SwapRouteSelector.tsx +++ b/examples/cross-chain-swap/src/components/SwapRouteSelector.tsx @@ -7,23 +7,18 @@ import { XLinkSDK, } from "@xlink-network/xlink-sdk" import { AlexSDK } from "alex-sdk" -import { FC, Fragment, useEffect, useState } from "react" +import { FC, Fragment, useState } from "react" import { useQuery } from "react-query" +import { useDebouncedValue } from "../hooks/useDebouncedValue" +import { formatXLinkSDKChainName } from "../utils/formatXLinkSDKChainName" import { getAvailableRoutes } from "../utils/getAvailableRoutes" import { getSwapRoutesViaALEX } from "../utils/getSwapRoutesViaALEX" import { getSwapRoutesViaEVMDEX } from "../utils/getSwapRoutesViaEVMDEX" -import { formatXLinkSDKChainName } from "../utils/formatXLinkSDKChainName" -import { useDebouncedValue } from "../hooks/useDebouncedValue" - -const STORAGE_KEY = "xlink_matcha_api_key" export const SwapRouteSelector: FC<{ alexSDK: AlexSDK xlinkSDK: XLinkSDK }> = ({ alexSDK, xlinkSDK }) => { - const [matchaAPIKey, setMatchaAPIKey] = useState(() => { - return localStorage.getItem(STORAGE_KEY) || "" - }) const [swapAmount, setSwapAmount] = useState("") const [selectedRoute, setSelectedRoute] = useState(null) const [selectedSwapRoute, setSelectedSwapRoute] = @@ -31,11 +26,6 @@ export const SwapRouteSelector: FC<{ const debouncedSwapAmount = useDebouncedValue(swapAmount, 500) const debouncedRoute = useDebouncedValue(selectedRoute, 500) - const debouncedAPIKey = useDebouncedValue(matchaAPIKey, 500) - - useEffect(() => { - localStorage.setItem(STORAGE_KEY, matchaAPIKey) - }, [matchaAPIKey]) const availableRoutes = useQuery({ queryKey: ["availableRoutes"], @@ -72,7 +62,7 @@ export const SwapRouteSelector: FC<{ }) const evmDexRoutes = useQuery({ - enabled: !!debouncedRoute && !!debouncedSwapAmount && !!debouncedAPIKey, + enabled: !!debouncedRoute && !!debouncedSwapAmount, queryKey: [ "evmDexRoutes", JSON.stringify(debouncedRoute), @@ -82,9 +72,6 @@ export const SwapRouteSelector: FC<{ if (debouncedRoute == null) { throw new Error("No route selected") } - if (!debouncedAPIKey) { - throw new Error("No matcha API key") - } if (!isNumber(debouncedSwapAmount)) { throw new Error("No swap amount") } @@ -92,7 +79,6 @@ export const SwapRouteSelector: FC<{ return getSwapRoutesViaEVMDEX( { xlinkSDK: xlinkSDK, - matchaAPIKey: debouncedAPIKey, }, { ...debouncedRoute, @@ -163,18 +149,6 @@ export const SwapRouteSelector: FC<{ )} -
-

Basic Information

-
- setMatchaAPIKey(e.target.value)} - /> -
-
-

Swap Settings

diff --git a/examples/cross-chain-swap/src/utils/getSwapRoutesViaEVMDEX.ts b/examples/cross-chain-swap/src/utils/getSwapRoutesViaEVMDEX.ts index 72ba982..93684fb 100644 --- a/examples/cross-chain-swap/src/utils/getSwapRoutesViaEVMDEX.ts +++ b/examples/cross-chain-swap/src/utils/getSwapRoutesViaEVMDEX.ts @@ -7,15 +7,14 @@ import { XLinkSDK, } from "@xlink-network/xlink-sdk" import { + fetchIceScreamSwapPossibleRoutesFactory, getDexAggregatorRoutes, getPossibleEVMDexAggregatorSwapParameters, - fetchMatchaPossibleRoutesFactory, } from "@xlink-network/xlink-sdk/swapHelpers" export async function getSwapRoutesViaEVMDEX( context: { xlinkSDK: XLinkSDK - matchaAPIKey: string }, swapRequest: KnownRoute & { amount: SDKNumber @@ -38,10 +37,7 @@ export async function getSwapRoutesViaEVMDEX( } const routes = await getDexAggregatorRoutes(xlinkSDK, { - routeFetcher: fetchMatchaPossibleRoutesFactory({ - baseUrl: "/api/matcha", - apiKey: context.matchaAPIKey, - }), + routeFetcher: fetchIceScreamSwapPossibleRoutesFactory({}), routes: possibleSwapParameters.map(p => ({ evmChain: p.evmChain, fromToken: p.fromToken, diff --git a/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchIceScreamSwapPossibleRoutes.ts b/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchIceScreamSwapPossibleRoutes.ts index 74799b2..f751307 100644 --- a/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchIceScreamSwapPossibleRoutes.ts +++ b/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchIceScreamSwapPossibleRoutes.ts @@ -1,4 +1,5 @@ import { toSDKNumberOrUndefined } from "../../../xlinkSdkUtils/types" +import { arraySplit } from "../../arrayHelpers" import { BigNumber } from "../../BigNumber" import { XLinkSDKErrorBase } from "../../errors" import { FetchRoutesImpl, QueryableRoute } from "./helpers" @@ -10,6 +11,12 @@ export class FetchIceScreamSwapPossibleRoutesFailedError extends XLinkSDKErrorBa } export const fetchIceScreamSwapPossibleRoutesFactory = (options: { + /** + * The maximum number of routes to fetch in same time + * + * @default 1 + */ + batchSize?: number baseUrl?: string debug?: boolean }): FetchRoutesImpl => { @@ -20,17 +27,26 @@ export const fetchIceScreamSwapPossibleRoutesFactory = (options: { const baseUrl = options.baseUrl ?? "https://aggregator.icecreamswap.com" + const batchSize = options.batchSize ?? 1 + return async info => { - const res: Awaited> = [] - for (const route of info.possibleRoutes) { + const batches = arraySplit( + (_, idx) => Math.floor(idx / batchSize), + info.possibleRoutes, + ) + + const res: Awaited>[] = [] + for (const batch of batches) { res.push( - ...(await fetchIceScreamSwapPossibleRouteImpl( - { debugLog, baseUrl }, - route, + ...(await Promise.all( + batch.map(route => + fetchIceScreamSwapPossibleRouteImpl({ debugLog, baseUrl }, route), + ), )), ) } - return res + + return res.flat() } } diff --git a/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchMatchaPossibleRoutes.ts b/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchMatchaPossibleRoutes.ts index 1c3ff38..c52a27e 100644 --- a/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchMatchaPossibleRoutes.ts +++ b/src/utils/swapHelpers/fetchDexAggregatorPossibleRoutes/fetchMatchaPossibleRoutes.ts @@ -1,16 +1,23 @@ import { toSDKNumberOrUndefined } from "../../../xlinkSdkUtils/types" +import { arraySplit } from "../../arrayHelpers" import { BigNumber } from "../../BigNumber" import { XLinkSDKErrorBase } from "../../errors" import { FetchRoutesImpl, QueryableRoute } from "./helpers" export class FetchMatchaPossibleRoutesFailedError extends XLinkSDKErrorBase { constructor(message: null | string, options: ErrorConstructorOptions) { - super(message ?? "Request Matcha.xyz api failed", options) + super(message ?? "Request 0x.org api failed", options) } } export const fetchMatchaPossibleRoutesFactory = (options: { apiKey: string + /** + * The maximum number of routes to fetch in same time + * + * @default 10 (0x.org api limit, see https://0x.org/docs/developer-resources/rate-limits#what-are-the-rate-limits-for-the-0x-apis) + */ + batchSize?: number baseUrl?: string debug?: boolean }): FetchRoutesImpl => { @@ -21,17 +28,29 @@ export const fetchMatchaPossibleRoutesFactory = (options: { const baseUrl = options.baseUrl ?? "https://api.0x.org" + const batchSize = options.batchSize ?? 10 + return async info => { - const res: Awaited> = [] - for (const route of info.possibleRoutes) { + const batches = arraySplit( + (_, idx) => Math.floor(idx / batchSize), + info.possibleRoutes, + ) + + const res: Awaited>[] = [] + for (const batch of batches) { res.push( - ...(await fetchMatchaPossibleRouteImpl( - { apiKey: options.apiKey, baseUrl, debugLog }, - route, + ...(await Promise.all( + batch.map(route => + fetchMatchaPossibleRouteImpl( + { debugLog, baseUrl, apiKey: options.apiKey }, + route, + ), + ), )), ) } - return res + + return res.flat() } }