From 7df1bf1bfe94e7f181664d85fd2c3c8126cf97fa Mon Sep 17 00:00:00 2001 From: kingrichie Date: Fri, 28 Aug 2026 20:41:35 +0100 Subject: [PATCH] feat(pathRouter): add findPath with configurable fallback threshold --- src/pathRouter.ts | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/pathRouter.ts b/src/pathRouter.ts index 46c47bc..bee0f8d 100644 --- a/src/pathRouter.ts +++ b/src/pathRouter.ts @@ -39,6 +39,15 @@ export interface PathResult { destinationAmount: bigint; /** Amount sent from the source (in the source asset's base unit). */ sourceAmount: bigint; + /** Flag indicating if the path was found using the fallback threshold. */ + usedFallback?: boolean; +} + +export interface FindPathParams { + sourceAsset: Asset; + destinationAsset: Asset; + threshold: bigint; + fallbackSlippagePct?: number; } /** Parameters for pathfinding. */ @@ -184,6 +193,47 @@ export class PathRouter { } } + /** + * Find a path using a primary threshold, with an optional fallback. + */ + async findPath(params: FindPathParams): Promise { + const sourceAssetType = assetType(params.sourceAsset); + const destAssetType = assetType(params.destinationAsset); + + const trySend = async (amount: bigint) => { + const query = this.queryBuilder.forStrictSend({ + sourceAsset: params.sourceAsset, + sourceAmount: amount, + destinationAssets: [params.destinationAsset], + }); + return await this.queryBuilder.execute(query); + }; + + let results = await trySend(params.threshold); + let usedFallback = false; + + if (results.length === 0 && params.fallbackSlippagePct !== undefined) { + const pct = params.fallbackSlippagePct; + const multiplier = 1 + pct / 100; + const fallbackAmount = BigInt(Math.floor(Number(params.threshold) * multiplier)); + + results = await trySend(fallbackAmount); + usedFallback = true; + } + + if (results.length === 0) { + throw new PathNotFoundError(sourceAssetType, destAssetType, params.threshold); + } + + const best = results[0]!; + return { + path: best.path, + destinationAmount: best.destinationAmount, + sourceAmount: best.sourceAmount, + ...(usedFallback ? { usedFallback: true } : {}) + }; + } + /** * Find the best path to receive exactly `destAmount` of `destinationAsset` * while spending as little of `sourceAsset` as possible.