# How the Osmosis Agent Toolkit Handles Multi-Hop Routes with Split Routes Swap Messages

> Discover how the Osmosis Agent Toolkit processes multi-hop routes and split routes swap messages efficiently. Learn about atomic transactions and specialized constructors.

- Repository: [Jon Ator/osmosis-agent-toolkit](https://github.com/jonator/osmosis-agent-toolkit)
- Tags: how-to-guide
- Published: 2026-03-05

---

**The Osmosis Agent Toolkit converts multi-hop swap quotes into atomic split-route swap messages by detecting route length in the encoder layer and routing to specialized protobuf constructors that handle multiple pools in a single transaction.**

The `jonator/osmosis-agent-toolkit` abstracts complex Osmosis DEX routing into developer-friendly agent tools. When users request swaps that traverse multiple liquidity pools—known as **multi-hop routes**—the toolkit automatically packages these into **split routes swap messages** that the Osmosis Pool Manager executes atomically.

## Retrieving Multi-Hop Quotes from the Sidecar Query Server

The toolkit queries the Osmosis Sidecar Query Server (SQS) to calculate optimal paths across multiple pools. In [`packages/core/src/queries/sqs/router.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/queries/sqs/router.ts), the response type defines the `route` array that represents each hop:

```typescript
// packages/core/src/queries/sqs/router.ts
export type SidecarOutGivenInQuoteResponse = {
  // ...
  route: {
    in_amount: string
    out_amount: string
    'has-cw-pool': boolean
    pools: {
      id: number
      token_out_denom: string
      // ...
    }[]
  }[]
}

```

Each element in the `route` array corresponds to a specific hop. If the best price requires swapping through OSMO → USDC → ATOM, the `route` array contains two entries, each detailing the pool ID and token denominations for that leg.

## Encoding Logic for Split-Route Swaps

The encoder layer in [`packages/core/src/tx/swap.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/tx/swap.ts) determines whether to generate a single-hop message or a multi-hop split-route message. The `makeSwapExactAmountOutEncodeObject` and `makeSwapExactAmountInEncodeObject` functions inspect `quote.route.length`:

```typescript
// packages/core/src/tx/swap.ts (exact-out path)
if (quote.route.length === 1) {
  return makeSwapExactAmountOutMsg(/* single pool params */)
}
return makeSplitRoutesSwapExactAmountOutMsg({ /* multi-hop params */ })

// Exact-in follows identical branching logic
if (quote.route.length === 1) {
  return makeSwapExactAmountInMsg(/* single pool params */)
}
return makeSplitRoutesSwapExactAmountInMsg({ /* multi-hop params */ })

```

This branching ensures that single-pool swaps use the standard `MsgSwapExactAmountIn` or `MsgSwapExactAmountOut`, while multi-hop routes trigger the split-route constructors.

## Constructing Osmosis Protobuf Messages

The final message assembly occurs in [`packages/core/src/tx/msg.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/tx/msg.ts). The toolkit maps the SQS route data into the Osmosis `poolmanager` protobuf types `splitRouteSwapExactAmountOut` and `splitRouteSwapExactAmountIn`.

For exact-out swaps:

```typescript
// packages/core/src/tx/msg.ts
export function makeSplitRoutesSwapExactAmountOutMsg({ 
  routes, 
  tokenOutDenom, 
  tokenInMaxAmount, 
  userOsmoAddress 
}) {
  return osmosis.poolmanager.v1beta1.MessageComposer.withTypeUrl.splitRouteSwapExactAmountOut({
    sender: userOsmoAddress,
    routes: routes.map(({ pools, tokenOutAmount }) => ({
      pools: pools.map(({ id, tokenInDenom }) => ({
        poolId: BigInt(id),
        tokenInDenom,
      })),
      tokenOutAmount,
    })),
    tokenOutDenom,
    tokenInMaxAmount,
  })
}

```

For exact-in swaps:

```typescript
// packages/core/src/tx/msg.ts
export function makeSplitRoutesSwapExactAmountInMsg({ 
  routes, 
  tokenInDenom, 
  tokenOutMinAmount, 
  userOsmoAddress 
}) {
  return osmosis.poolmanager.v1beta1.MessageComposer.withTypeUrl.splitRouteSwapExactAmountIn({
    sender: userOsmoAddress,
    routes: routes.map(({ pools, tokenInAmount }) => ({
      pools: pools.map(({ id, tokenOutDenom }) => ({
        poolId: BigInt(id),
        tokenOutDenom,
      })),
      tokenInAmount,
    })),
    tokenInDenom,
    tokenOutMinAmount,
  })
}

```

These functions transform the toolkit's internal route representation into the exact protobuf structure required by the Osmosis chain, ensuring type safety and correct BigInt handling for pool IDs.

## Practical Implementation with Agent Tools

End-to-end multi-hop swaps are executed through the toolkit's tool classes in [`packages/core/src/tools/swap.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/tools/swap.ts). The workflow involves two stages: quoting and transaction broadcasting.

First, retrieve a quote that may contain multiple hops:

```typescript
import { SwapQuoteOutGivenInTool } from 'packages/core/src/tools/swap.js'
import { OsmosisSqsQueryClient } from 'packages/core/src/queries/sqs/client.js'

const sqs = new OsmosisSqsQueryClient()
const quoteTool = new SwapQuoteOutGivenInTool(sqs)

// Request quote for 100 OSMO → ATOM (potentially via USDC)
const quote = await quoteTool.call({
  tickerIn: 'OSMO',
  amountIn: '100',
  tickerOut: 'ATOM',
})

console.log('Route length:', quote.route.length) // >1 indicates multi-hop

```

Then, execute the swap. The `SendSwapOutGivenInQuoteTxTool` automatically handles the split-route encoding:

```typescript
import { SendSwapOutGivenInQuoteTxTool } from 'packages/core/src/tools/swap.js'
import { MyAccount } from './myAccount.js'
import { MemoryMap } from 'packages/core/src/tools/tool.js'

const memory = new MemoryMap<string, SidecarOutGivenInQuoteResponse>()
const account = new MyAccount(/* wallet implementation */)
const sendTool = new SendSwapOutGivenInQuoteTxTool(account, memory)

const { txHash } = await sendTool.call({
  quoteId: quote.id,
  slippageTolerancePercent: 0.5,
})

console.log('Multi-hop swap submitted:', txHash)

```

The toolkit abstracts the complexity: developers work with high-level `quote` and `send` tools while the encoder layer in [`swap.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/swap.ts) and [`msg.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/msg.ts) transparently constructs the appropriate split-route protobuf messages.

## Summary

- **Multi-hop detection** occurs in [`packages/core/src/tx/swap.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/tx/swap.ts), where `quote.route.length` determines whether to generate a single-hop or split-route message.
- **Quote retrieval** relies on the SQS client defined in [`packages/core/src/queries/sqs/router.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/queries/sqs/router.ts), which returns a `route` array containing pool IDs and token amounts for each hop.
- **Message construction** happens in [`packages/core/src/tx/msg.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/tx/msg.ts) via `makeSplitRoutesSwapExactAmountInMsg` and `makeSplitRoutesSwapExactAmountOutMsg`, which map toolkit data to Osmosis `poolmanager` protobuf types.
- **Atomic execution** ensures that multi-hop swaps either complete entirely or fail, preventing partial fills across the route.

## Frequently Asked Questions

### What is a split-route swap message in Osmosis?

A **split-route swap message** is a protobuf transaction type (`MsgSplitRouteSwapExactAmountIn` or `MsgSplitRouteSwapExactAmountOut`) that allows a single transaction to execute swaps through multiple consecutive liquidity pools. Instead of submitting separate transactions for each hop (e.g., OSMO → USDC, then USDC → ATOM), the split-route message encodes the entire path with specific pool IDs and token amounts, which the Osmosis Pool Manager executes atomically.

### How does the toolkit decide between single-hop and multi-hop messages?

The toolkit inspects the `route` array length returned by the Sidecar Query Server. In [`packages/core/src/tx/swap.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/tx/swap.ts), the encoder helpers `makeSwapExactAmountInEncodeObject` and `makeSwapExactAmountOutEncodeObject` check `quote.route.length`. If the length equals 1, they call the single-hop constructors (`makeSwapExactAmountInMsg` or `makeSwapExactAmountOutMsg`). If the length is greater than 1, they route to the split-route constructors (`makeSplitRoutesSwapExactAmountInMsg` or `makeSplitRoutesSwapExactAmountOutMsg`).

### Can developers manually construct multi-hop routes without using the quote tools?

While the toolkit is designed to work with SQS-generated quotes, developers can manually construct the `route` array expected by the encoder functions. The `makeSplitRoutesSwapExactAmountInMsg` and `makeSplitRoutesSwapExactAmountOutMsg` functions in [`packages/core/src/tx/msg.ts`](https://github.com/jonator/osmosis-agent-toolkit/blob/main/packages/core/src/tx/msg.ts) accept any array of routes containing `pools` (with `id` and token denominations) and token amounts. However, using the `SwapQuoteOutGivenInTool` or `SwapQuoteInGivenOutTool` is recommended to ensure optimal routing and correct slippage calculations based on current pool liquidity.