Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/core/modes/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ vi.mock("./inter", () => ({
findBestInterOrderbookTrade: vi.fn(),
}));

// vi.mock("./balancer", () => ({
// findBestBalancerTrade: vi.fn(),
// }));

vi.mock("./raindex", () => ({
findBestRaindexRouterTrade: vi.fn(),
}));
Expand Down Expand Up @@ -321,7 +317,7 @@ describe("Test findBestTrade", () => {
oppBlockNumber: 123,
});
const raindexResult = Result.ok({
type: "interOrderbook",
type: "raindex",
spanAttributes: { foundOpp: true },
estimatedProfit: 120n,
oppBlockNumber: 123,
Expand Down Expand Up @@ -671,7 +667,7 @@ describe("Test getEnabledTrades", () => {
expect(result.findBestInterOrderbookTrade).toBe(findBestInterOrderbookTrade);
});

it("should return only inter-orderbook trade when orderbook is in raindex router set", () => {
it("should return only raindex routed trade when orderbook is in raindex router set", () => {
const orderbookTradeTypes: OrderbookTradeTypes = {
router: new Set(),
intraOrderbook: new Set(),
Expand Down
17 changes: 8 additions & 9 deletions src/core/modes/raindex/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
}),
},
router: {
cache: new Map(),
sushi: {
tryQuote: vi.fn(),
},
Expand Down Expand Up @@ -128,9 +129,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
expect(extendObjectWithHeader).not.toHaveBeenCalled();
expect(isV4OrderbookV6Spy).toHaveBeenCalledWith(orderDetails);
expect(solver.state.contracts.getAddressesForTrade).not.toHaveBeenCalledWith();
expect(
solver.orderManager.getCounterpartyOrdersAgainstBaseTokens,
).not.toHaveBeenCalledWith();
expect(solver.orderManager.getCounterpartyOrdersAgainstBaseTokens).not.toHaveBeenCalled();
expect(solver.state.router.sushi!.tryQuote).not.toHaveBeenCalledWith();
expect(routeProcessor4ParamsSpy).not.toHaveBeenCalled();
expect(visualizeRouteSpy).not.toHaveBeenCalled();
Expand Down Expand Up @@ -315,7 +314,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
amountIn: expect.any(BigInt),
gasPrice: solver.state.gasPrice,
blockNumber,
skipFetch: true,
skipFetch: false,
sushiRouteType: solver.state.appOptions.route,
});
expect(routeProcessor4ParamsSpy).not.toHaveBeenCalled();
Expand Down Expand Up @@ -435,7 +434,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
amountIn: expect.any(BigInt),
gasPrice: solver.state.gasPrice,
blockNumber,
skipFetch: true,
skipFetch: false,
sushiRouteType: solver.state.appOptions.route,
});
expect(routeProcessor4ParamsSpy).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -546,7 +545,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
amountIn: expect.any(BigInt),
gasPrice: solver.state.gasPrice,
blockNumber,
skipFetch: true,
skipFetch: false,
sushiRouteType: solver.state.appOptions.route,
});
expect(routeProcessor4ParamsSpy).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -700,7 +699,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
amountIn: expect.any(BigInt),
gasPrice: solver.state.gasPrice,
blockNumber,
skipFetch: true,
skipFetch: false,
sushiRouteType: solver.state.appOptions.route,
});
expect(solver.state.router.sushi!.tryQuote).toHaveBeenNthCalledWith(2, {
Expand All @@ -709,7 +708,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
amountIn: expect.any(BigInt),
gasPrice: solver.state.gasPrice,
blockNumber,
skipFetch: true,
skipFetch: false,
sushiRouteType: solver.state.appOptions.route,
});
expect(routeProcessor4ParamsSpy).toHaveBeenCalledTimes(2);
Expand Down Expand Up @@ -861,7 +860,7 @@ describe("Test findBestRaindexRouterTrade function", () => {
amountIn: expect.any(BigInt),
gasPrice: solver.state.gasPrice,
blockNumber,
skipFetch: true,
skipFetch: false,
sushiRouteType: solver.state.appOptions.route,
});
expect(routeProcessor4ParamsSpy).toHaveBeenCalledTimes(1);
Expand Down
5 changes: 3 additions & 2 deletions src/core/modes/raindex/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export enum RouteLegType {
/**
* Tries to find the best raindex routed trade for the given order,
* it will simultaneously try to find the best trade against other
* orders routed through a middle base token swaped through sushi RP
* orders routed through a middle base token swapped through sushi RP
* @param this - RainSolver instance
* @param orderDetails - The details of the order to be processed
* @param signer - The signer to be used for the trade
Expand Down Expand Up @@ -87,13 +87,14 @@ export async function findBestRaindexRouterTrade(
});

// get route details from sushi dataFetcher
const key = `${fromToken.address.toLowerCase()}-${toToken.address.toLowerCase()}`;
const quoteResult = await this.state.router.sushi?.tryQuote({
fromToken,
toToken,
amountIn: maximumInput,
gasPrice: this.state.gasPrice,
blockNumber,
skipFetch: true,
skipFetch: this.state.router.cache.has(key),
sushiRouteType: this.state.appOptions.route,
});

Expand Down
18 changes: 17 additions & 1 deletion src/core/modes/raindex/simulation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,13 @@ describe("Test RaindexRouterTradeSimulator", () => {
expect(simulator.spanAttributes["counterpartyOutputToEthPrice"]).toBe(
formatUnits(tradeArgs.counterpartyOutputToEthPrice, 18),
);
expect(simulator.spanAttributes["route"]).toEqual(tradeArgs.routeVisual);
expect(simulator.spanAttributes["route"]).toEqual([
`${tradeArgs.orderDetails.sellTokenSymbol} (order output)`,
...tradeArgs.routeVisual,
`${tradeArgs.counterpartyOrderDetails.buyTokenSymbol} (counterparty input)/${
tradeArgs.counterpartyOrderDetails.sellTokenSymbol
} (counterparty output - order input)`,
]);
expect(simulator.spanAttributes["routeQuote"]).toBe(
formatUnits(tradeArgs.quote.price, 18),
);
Expand Down Expand Up @@ -250,10 +256,16 @@ describe("Test RaindexRouterTradeSimulator", () => {

// First order (main order)
expect(takeOrders[0].IOIsInput).toBe(false);
expect(takeOrders[0].maximumIO).toBe(maxFloat(18));
expect(takeOrders[0].minimumIO).toBe(minFloat(18));
expect(takeOrders[0].maximumIORatio).toBe(maxFloat(18));
expect(takeOrders[0].data).toBe("0x");

// Second order (counterparty)
expect(takeOrders[1].IOIsInput).toBe(false);
expect(takeOrders[1].maximumIO).toBe(maxFloat(18));
expect(takeOrders[1].minimumIO).toBe(minFloat(18));
expect(takeOrders[1].maximumIORatio).toBe(maxFloat(18));
expect(takeOrders[1].data).toBe("0x");
});
});
Expand Down Expand Up @@ -302,13 +314,17 @@ describe("Test RaindexRouterTradeSimulator", () => {
EnsureBountyTaskErrorType.ComposeError,
);
(getEnsureBountyTaskBytecode as Mock).mockResolvedValueOnce(Result.err(error));
const getCalldataSpy = vi.spyOn(simulator, "getCalldata");

const result = await simulator.setTransactionData(preparedParams);
assert(result.isErr());
expect(result.error.type).toBe(TradeType.Raindex);
expect(result.error.reason).toBe(SimulationHaltReason.FailedToGetTaskBytecode);
expect(result.error.spanAttributes["isNodeError"]).toBe(false);
expect(result.error.spanAttributes["duration"]).toBeGreaterThan(0);
expect(getCalldataSpy).not.toHaveBeenCalled();

getCalldataSpy.mockRestore();
});

it("should return success with bytecode when gasCoveragePercentage is not zero", async () => {
Expand Down
22 changes: 13 additions & 9 deletions src/core/modes/raindex/simulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
getEnsureBountyTaskBytecode,
} from "../../../task";

/** Arguments for simulating inter-orderbook trade */
/** Arguments for simulating raindex routed trade */
export type SimulateRaindexRouterTradeArgs = {
/** The type of trade */
type: TradeType.Raindex;
Expand Down Expand Up @@ -57,7 +57,7 @@ export type RaindexRouterTradePreparedParams = {
};

/**
* Simulates a trade between 2 orders wwith different IO through a external route
* Simulates a trade between 2 orders wwith different IO through an external route
*
* The `RaindexRouterTradeSimulator` class extends {@link TradeSimulatorBase} and is responsible for:
* - Simulating trades between two order with external route such as A/B (order) -> B/C (external) -> C/A (order)
Expand All @@ -80,13 +80,10 @@ export class RaindexRouterTradeSimulator extends TradeSimulatorBase {
counterpartyOrderDetails,
maximumInputFixed,
blockNumber,
// type,
// solver,
// signer,
counterpartyInputToEthPrice,
counterpartyOutputToEthPrice,
quote,
// profit,
profit,
rpParams,
routeVisual,
} = this.tradeArgs;
Expand All @@ -101,7 +98,14 @@ export class RaindexRouterTradeSimulator extends TradeSimulatorBase {
counterpartyOutputToEthPrice,
18,
);
this.spanAttributes["route"] = routeVisual;
this.spanAttributes["initEstimatedProfitETH"] = formatUnits(profit, 18);
this.spanAttributes["route"] = [
`${orderDetails.sellTokenSymbol} (order output)`,
...routeVisual,
`${counterpartyOrderDetails.buyTokenSymbol} (counterparty input)/${
counterpartyOrderDetails.sellTokenSymbol
} (counterparty output - order input)`,
];
this.spanAttributes["routeQuote"] = formatUnits(quote.price, 18);
this.spanAttributes["oppBlockNumber"] = Number(blockNumber);
this.spanAttributes["counterpartyPair"] =
Expand Down Expand Up @@ -156,8 +160,8 @@ export class RaindexRouterTradeSimulator extends TradeSimulatorBase {
IOIsInput: false,
},
{
minimumIO: minFloat(this.tradeArgs.orderDetails.buyTokenDecimals),
maximumIO: maxFloat(this.tradeArgs.orderDetails.buyTokenDecimals),
minimumIO: minFloat(this.tradeArgs.counterpartyOrderDetails.buyTokenDecimals),
maximumIO: maxFloat(this.tradeArgs.counterpartyOrderDetails.buyTokenDecimals),
maximumIORatio: maxFloat(18),
orders: [this.tradeArgs.counterpartyOrderDetails.takeOrder.struct],
data: "0x",
Expand Down
5 changes: 5 additions & 0 deletions src/core/modes/raindex/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,9 @@ describe("Test calcCounterpartyInputToEthPrice function", () => {
// (1e18 * 1e18) / 0.5e18 = 2e18
expect(result).toBe(parseUnits("2", 18));
});

it("should return zero when quote price is zero", () => {
const quote = { amountOut: 100n, price: 0n } as any;
expect(calcCounterpartyInputToEthPrice(quote, "2.0")).toBe(0n);
});
});
1 change: 1 addition & 0 deletions src/core/modes/raindex/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ export function calcCounterpartyInputToEthPrice(
): bigint {
if (!outputToEthPrice) return 0n;
const outputEthPrice = parseUnits(outputToEthPrice, 18);
if (quote.price === 0n) return 0n; // not reachable, but handled just in case
return (outputEthPrice * ONE18) / quote.price;
}
2 changes: 1 addition & 1 deletion src/order/pair.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ describe("Test getOptimalSortedList function", () => {
expect(result[2].takeOrder.quote?.maxOutput).toBe(100n);
});

it("should handle edge case where all pairs have same input and output", () => {
it("should handle edge case where all pairs have same input but different output", () => {
const pairs = [
createPair("hash1", { ratio: 2n, maxOutput: 50n }), // input: 100, output: 50
createPair("hash2", { ratio: 5n, maxOutput: 20n }), // input: 100, output: 20
Expand Down
1 change: 0 additions & 1 deletion src/order/pair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ export function removeFromPairMap(
* @param output - The output token address to get pairs from
* @param input - The input token address to get pairs from
* @param counterpartySource - Determines the type of counterparty orders source to return
* @param sortBy - Either by ratio first (default) or by max out first
*/
export function getSortedPairList<
counterpartySource extends CounterpartySource = CounterpartySource.IntraOrderbook,
Expand Down
9 changes: 5 additions & 4 deletions src/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { Pair } from "../order";
import { SushiRouter } from "./sushi";
import { Token } from "sushi/currency";
import { Err, Result } from "../common";
import { MultiRoute } from "sushi/tines";
import { StabullRouter } from "./stabull";
import { LiquidityProviders } from "sushi";
import { BalancerRouter } from "./balancer";
import { Account, Chain, PublicClient, Transport, parseUnits } from "viem";
import { StabullRouterError, StabullRouterErrorType } from "./stabull/error";
import {
TradeParamsType,
GetTradeParamsArgs,
Expand All @@ -20,8 +23,6 @@ import {
BalancerRouterErrorType,
RainSolverRouterErrorType,
} from "./error";
import { StabullRouter } from "./stabull";
import { StabullRouterError, StabullRouterErrorType } from "./stabull/error";

export type RainSolverRouterConfig = {
/** The chain id of the operating chain */
Expand Down Expand Up @@ -139,7 +140,7 @@ export class RainSolverRouter extends RainSolverRouterBase {
*/
async getMarketPrice(
params: RainSolverRouterQuoteParams,
): Promise<Result<{ price: string }, RainSolverRouterError>> {
): Promise<Result<{ price: string; route?: MultiRoute }, RainSolverRouterError>> {
const key = `${params.fromToken.address.toLowerCase()}-${params.toToken.address.toLowerCase}`;
let value = this.cache.get(key);
if (typeof value === "number") {
Expand Down Expand Up @@ -170,7 +171,7 @@ export class RainSolverRouter extends RainSolverRouterBase {
if (results.every((res) => !res?.isOk())) {
return Result.err(getError("Failed to get market price", results));
}
return results[0] as Result<{ price: string }, RainSolverRouterError>;
return results[0] as Result<{ price: string; route?: MultiRoute }, RainSolverRouterError>;
}

/**
Expand Down
Loading
Loading