Smart Order Router
The Smart Order Router enables optimal trade execution by finding the most efficient trades across all available liquidity pools on the StoryHunt protocol.
Overview
AlphaRouter
: The core routing engine responsible for pathfinding, quote simulation, gas estimation, and execution preparation.SwapAlphaRouter
: A singleton wrapper around the low-levelAlphaRouter
algorithm which is a public interface to query optimal swap routes.
graph TD
A[SwapAlphaRouter]
B[AlphaRouter]
A --> B
B --> C[On-chain Providers]
B --> D[Subgraph Pool Providers]
B --> E[Gas Price Estimator]
B --> F[Simulators]
B --> G[Route Cache]
Installation & Setup
Ensure the project has access to the required SDK:
npm install @storyhunt/smart-order-router
npm install @storyhunt/sdk-core
SwapAlphaRouter
SwapAlphaRouter
acts as a singleton utility class to interact with the router logic.
Initialization
const router = SwapAlphaRouter.getInstance(
'https://mainnet.storyrpc.io/', // RPC endpoint
{
url: '',
auth: '',
},
ChainId.STORY
);
Core Function: Get Swap Route
const { data, error } = await router.getSwapRouteData({
tokenIn: '<INPUT_TOKEN_ADDRESS>',
tokenOut: '<OUTPUT_TOKEN_ADDRESS>',
amount: '1000000000000000000', // 1 token in wei
exactIn: true,
recipient: '<RECIPIENT_ADDRESS>',
slippageTolerance: 100, // e.g., 1.00%
deadline: Math.floor(Date.now() / 1000) + 300,
});
Sample Output
{
blockNumber: '17923412',
quote: 0.9856,
quoteGasAdjusted: 0.9731,
estimatedGasUsed: 145000,
estimatedGasUsedUSD: 1.45,
methodParameters: {
calldata: '0x123abc...',
value: '0'
},
route: [
{
path: ['TokenA', 'TokenB', 'TokenC'],
poolIds: ['pool1', 'pool2'],
type: 'v3'
}
]
}
Path Discovery: getPaths
getPaths
Returns all possible candidate token paths (via pools) between two tokens. Useful for visualizing or debugging router behavior.
const { data: paths } = await router.getPaths({
tokenIn: '<INPUT_TOKEN_ADDRESS>',
tokenOut: '<OUTPUT_TOKEN_ADDRESS>',
exactIn: true,
});
console.log(paths);
AlphaRouter: Parameters
The AlphaRouter
uses a comprehensive set of providers to accurately compute the best route.
export type AlphaRouterParams = {
chainId: ChainId;
provider: BaseProvider;
multicall2Provider?: StoryHuntMulticallProvider;
v3SubgraphProvider: IV3SubgraphProvider;
v3PoolProvider?: IV3PoolProvider;
onChainQuoteProvider?: IOnChainQuoteProvider;
tokenProvider?: ITokenProvider;
gasPriceProvider?: IGasPriceProvider;
v3GasModelFactory?: IOnChainGasModelFactory<V3RouteWithValidQuote>;
blockedTokenListProvider?: ITokenListProvider;
swapRouterProvider?: ISwapRouterProvider;
simulator?: Simulator;
routeCachingProvider?: IRouteCachingProvider;
portionProvider?: IPortionProvider;
cachedRoutesCacheInvalidationFixRolloutPercentage?: number;
};
Each of these components can be extended or replaced, enabling a high degree of modularity for advanced use cases like simulation, cache control, or risk-adjusted routing.
Full Example
import { ChainId } from '@storyhunt/sdk-core';
import { routeAmountsToString, SwapAlphaRouter } from '@storyhunt/smart-order-router';
const router = SwapAlphaRouter.getInstance(
'https://mainnet.storyrpc.io/',
{
url: '',
auth: '',
},
ChainId.STORY
);
class RouteTest {
static async run() {
const { data, error } = await router.getSwapRouteData({
tokenIn: '0x25f9c9715d1d700a50b2a9a06d80fe9f98ccb549',
tokenOut: '0x0000000000000000000000000000000000000000',
amount: '100',
exactIn: false,
recipient: '0xAACc28fA97b7765E483e64cF640a0075FC97bED2',
slippageTolerance: 3933,
deadline: 1743129769,
debugRouting: false,
simulate: false,
});
if (data) {
const {
blockNumber,
estimatedGasUsed,
estimatedGasUsedQuoteToken,
estimatedGasUsedUSD,
gasPriceWei,
methodParameters,
quote,
quoteGasAdjusted,
route: routeAmounts,
} = data;
log.debug(`Best Route:`);
log.debug(`${routeAmountsToString(routeAmounts)}`);
log.debug(`\tRaw Quote`);
log.debug(`\t\t${quote.toFixed(2)}`);
log.debug(`\tGas Adjusted Quote:`);
log.debug(`\t\t${quoteGasAdjusted.toFixed(2)}`);
log.debug(``);
log.debug(
`Gas Used Quote Token: ${estimatedGasUsedQuoteToken.toFixed(6)}`
);
log.debug(`Gas Used USD: ${estimatedGasUsedUSD.toFixed(6)}`);
log.debug(`Calldata: ${methodParameters?.calldata}`);
log.debug(`Value: ${methodParameters?.value}`);
log.debug({
blockNumber: blockNumber.toString(),
estimatedGasUsed: estimatedGasUsed.toString(),
gasPriceWei: gasPriceWei.toString(),
});
} else {
console.error(`No data returned`);
}
return data;
}
}
class PathTest {
static async run() {
const { data: paths, error: pathError } = await router.getPaths({
tokenIn: '0x210e36b5cdb47c010c3225a065467ea193ded463',
tokenOut: '0x0000000000000000000000000000000000000000',
exactIn: true,
});
if (paths) {
console.log(`PATHS:`, paths);
}
return paths;
}
}
(async () => {
await PathTest.run();
await RouteTest.run();
})();
Notes
ExactIn/ExactOut: The router supports both
exactIn
andexactOut
trade types.Simulation: By enabling
simulate: true
, a backend simulation can be triggered to return more accurate gas and slippage data.Calldata: The router returns the calldata necessary to execute the trade via a smart contract.
Debugging Tips
Use
debugRouting: true
in development to see intermediate routing decisions.Use
getPaths()
to check for missing pools or broken liquidity routes.Ensure RPC and Subgraph URLs are up to date and synced.
Last updated