-
Notifications
You must be signed in to change notification settings - Fork 6
taking Price Impact into account for partial trade size
#433
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,15 +6,24 @@ import { MultiRoute, RouteLeg } from "sushi/tines"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { BlackListSet, poolFilter } from "./blacklist"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { TakeOrdersConfigType } from "../../order/types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { SushiRouterError, SushiRouterErrorType } from "./error"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { calculatePrice18, scaleFrom18, scaleTo18 } from "../../math"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { calculatePrice18, ONE18, scaleFrom18, scaleTo18 } from "../../math"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ChainId, LiquidityProviders, PoolCode, RainDataFetcher, Router } from "sushi"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Chain, Account, Transport, formatUnits, PublicClient, encodeAbiParameters } from "viem"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Chain, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Account, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Transport, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parseUnits, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| formatUnits, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PublicClient, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| encodeAbiParameters, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "viem"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RouterType, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RouteStatus, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GetTradeParamsArgs, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RainSolverRouterBase, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RainSolverRouterQuoteParams, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DEFAULT_PRICE_IMPACT_TOLERANCE, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "../types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ROUTE_PROCESSOR_3_ADDRESS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -153,7 +162,7 @@ export class SushiRouter extends RainSolverRouterBase { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async getMarketPrice( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| params: SushiQuoteParams, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<Result<{ price: string }, SushiRouterError>> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<Result<{ price: string; route?: MultiRoute }, SushiRouterError>> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // return early if from and to tokens are the same | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (params.fromToken.address.toLowerCase() === params.toToken.address.toLowerCase()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Result.ok({ price: "1" }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -163,7 +172,10 @@ export class SushiRouter extends RainSolverRouterBase { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (quoteResult.isErr()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Result.err(quoteResult.error); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Result.ok({ price: formatUnits(quoteResult.value.price, 18) }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Result.ok({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| price: formatUnits(quoteResult.value.price, 18), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| route: quoteResult.value.route.route, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -508,17 +520,23 @@ export class SushiRouter extends RainSolverRouterBase { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (route.status == "NoWay") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput = maximumInput - initAmount / 2n ** i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (absolute) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result.unshift(maxInput18); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput = maximumInput + initAmount / 2n ** i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typeof route.priceImpact === "undefined" || | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| route.priceImpact < DEFAULT_PRICE_IMPACT_TOLERANCE | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result.unshift(maxInput18); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput = maximumInput + initAmount / 2n ** i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput = maximumInput - initAmount / 2n ** i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const price = calculatePrice18( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const effectivePrice = calculateEffectivePrice( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| route.amountOutBI, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fromToken.decimals, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toToken.decimals, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| route, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fromToken, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toToken, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (price < ratio) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (effectivePrice < ratio) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput = maximumInput - initAmount / 2n ** i; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result.unshift(maxInput18); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -534,3 +552,21 @@ export class SushiRouter extends RainSolverRouterBase { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function calculateEffectivePrice( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput: bigint, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| route: MultiRoute, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fromToken: Token, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toToken: Token, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): bigint { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const price = calculatePrice18( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| maximumInput, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| route.amountOutBI, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fromToken.decimals, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| toToken.decimals, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof route.priceImpact === "undefined") { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return price; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return (price * parseUnits((1 - route.priceImpact).toFixed(12), 18)) / ONE18; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+556
to
+571
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result:
So, for example (behavior implied by implementation):
The official docs describe Sources: 🏁 Script executed: # First, let's examine the actual code around lines 556-571
cat -n src/router/sushi/index.ts | sed -n '550,575p'Repository: rainlanguage/rain.solver Length of output: 748 🏁 Script executed: # Check how priceImpact is validated or bounded in the codebase
rg "priceImpact" -B 2 -A 2 --max-count 20Repository: rainlanguage/rain.solver Length of output: 4513 The concern about
While this scenario is unlikely (tests only show - return (price * parseUnits((1 - route.priceImpact).toFixed(12), 18)) / ONE18;
+ const impactMultiplier = Math.max(0, 1 - route.priceImpact);
+ return (price * parseUnits(impactMultiplier.toFixed(12), 18)) / ONE18;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,13 @@ import { | |||||
| TakeOrdersConfigTypeV5, | ||||||
| } from "../order"; | ||||||
|
|
||||||
| /* | ||||||
| * Default price imapct tolerance used for getting unit market price. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo: "imapct" → "impact" - * Default price imapct tolerance used for getting unit market price.
+ * Default price impact tolerance used for getting unit market price.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| * this is not used for actual trade size finding in simulations but | ||||||
| * only for getting market price for unit token. | ||||||
| */ | ||||||
| export const DEFAULT_PRICE_IMPACT_TOLERANCE = 2.5 as const; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check how priceImpact is used/compared throughout the codebase
rg -n "priceImpact" --type=ts -C3Repository: rainlanguage/rain.solver Length of output: 6810 Change
🤖 Prompt for AI Agents |
||||||
|
|
||||||
| /** Represents the different router types */ | ||||||
| export enum RouterType { | ||||||
| /** The Sushi router (RainDataFetcher) */ | ||||||
|
|
||||||
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.
🧹 Nitpick | 🔵 Trivial
Good test coverage for
calculateEffectivePrice.The tests thoroughly cover various scenarios. Consider adding an edge-case test for
priceImpact >= 1(e.g.,1.5) to validate the guard suggested insrc/router/sushi/index.ts, sinceparseUnitswould throw on the resulting negative string.🤖 Prompt for AI Agents