Skip to content

Encode_Multi_Hop_Swap

Elnaril edited this page Oct 13, 2026 · 1 revision

How to encode a multi-hop swap ?

A multi-hop swap routes through one or more intermediate tokens, for example to swap token A for token C when there is no direct A/C pool, by going through token B (A → B → C).

V2 multi-hop swap

For a V2 swap, the path simply lists the tokens, from the input token to the output token, with the intermediate tokens in between:

from uniswap_universal_router_decoder import FunctionRecipient, RouterCodec

codec = RouterCodec()
encoded_data = codec.encode.chain().v2_swap_exact_in(
        FunctionRecipient.SENDER,  # the output tokens are sent to the transaction sender
        amount_in,  # the exact amount of tokens to send, in Wei
        amount_out_min,  # the minimum amount of tokens to receive, in Wei
        [
            in_token_address,  # token_in
            intermediate_token_address,  # token_mid
            out_token_address,  # token_out
        ],
    ).build(codec.get_default_deadline())  # unix timestamp after which the trx is not valid any more

V3 multi-hop swap

For a V3 swap, the path alternates tokens and pool fees:

encoded_data = codec.encode.chain().v3_swap_exact_in(
        FunctionRecipient.SENDER,  # the output tokens are sent to the transaction sender
        amount_in,  # the exact amount of tokens to send, in Wei
        amount_out_min,  # the minimum amount of tokens to receive, in Wei
        [
            in_token_address,  # token_in
            pool_fee_1,  # ex: 3000 for a 0.3% pool
            intermediate_token_address,  # token_mid
            pool_fee_2,  # ex: 3000 for a 0.3% pool
            out_token_address,  # token_out
        ],
    ).build(codec.get_default_deadline())  # unix timestamp after which the trx is not valid any more

Minimum price per hop

The swap methods accept an optional min_hop_price_x36 parameter to protect each hop of the swap individually. It is a list of minimum prices, one per pair in the path, expressed as output / input x 1e36.

  • An empty list (the default) disables the check.
  • 0 disables the check for a specific pair.

For a 2-hop swap (token_in → token_mid → token_out), it is passed as a keyword argument:

min_hop_price_x36 = [
    min_price_in_mid_x36,  # minimum price for the token_in -> token_mid pair
    min_price_mid_out_x36,  # minimum price for the token_mid -> token_out pair
]

With a V2 swap

encoded_data = codec.encode.chain().v2_swap_exact_in(
        FunctionRecipient.SENDER,
        amount_in,
        amount_out_min,
        [
            in_token_address,
            intermediate_token_address,
            out_token_address,
        ],
        min_hop_price_x36=min_hop_price_x36,
    ).build(codec.get_default_deadline())

With a V3 swap

encoded_data = codec.encode.chain().v3_swap_exact_in(
        FunctionRecipient.SENDER,
        amount_in,
        amount_out_min,
        [
            in_token_address,
            pool_fee_1,
            intermediate_token_address,
            pool_fee_2,
            out_token_address,
        ],
        min_hop_price_x36=min_hop_price_x36,
    ).build(codec.get_default_deadline())

The same parameter is also available on v2_swap_exact_in_from_balance() and v3_swap_exact_in_from_balance().

Ending words

Only the input data is built here. See How to build a full transaction to the Universal Router ? to build the whole transaction.

Clone this wiki locally