Best route selector

The Best Route Selector is an Advanced preset that evaluates multiple sub-strategy branches at execution time and runs the one that produces the best output for the taker. It is a composition pattern built on the Extruction instruction of SwapVM (the Aqua swap engine), not a registered core opcode of its own. At runtime, _extruction delegates to an external selector contract that runs each branch's quote() and returns the winning branch.

This pattern lets a single signed order expose multiple AMM curves (or any mix of strategies) and automatically route to the best one for current market conditions. It is one of the Advanced presets, alongside Conditional Access.

Best Route Selector is a preset program, not a core opcode. It is assembled from the deployed Extruction instruction in the SwapVM opcode set; there is no dedicated selector opcode registered on-chain.

Warning: Programs with _extruction and conditional branches are the most complex to reason about. Test every branch path independently before production use.


Underlying instruction

Best Route Selector is not itself a core opcode; it reuses the Extruction core instruction to delegate branch selection.

Instruction Role
_extruction Delegate to external contract with packed branch bytecodes

Program: XYC vs Pegged selector

Solidity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Program memory program = ProgramBuilder.init(_opcodes());

bytes memory strategy1 = program.build(_xycSwapXD);
bytes memory strategy2 = program.build(
    _peggedSwapGrowPriceRange2D,
    PeggedSwapArgsBuilder.build(PeggedSwapArgsBuilder.Args({
        x0: 50e18,
        y0: 50e18,
        linearWidth: 0.02e9,
        rateLt: 1,
        rateGt: 1
    }))
);

bytes memory selectorArgs = abi.encodePacked(
    address(bestRouteSelectorTarget), // External selector contract
    uint8(2),                         // Number of branches
    uint16(strategy1.length), strategy1,
    uint16(strategy2.length), strategy2
);

bytes memory bytecode = bytes.concat(
    program.build(_dynamicBalancesXD, BalancesArgsBuilder.build(
        dynamic([tokenA, tokenB]),
        dynamic([uint256(100e18), uint256(100e18)])
    )),
    program.build(_extruction, selectorArgs)
);

Reference test: test/RunLoop.t.soltest_BestRouteSelector_XYC_vs_Pegged.


How it works

  1. _extruction calls bestRouteSelectorTarget with the packed branch data.

  2. The selector contract runs quote() for each branch against the current state.

  3. It returns the branch index with the best output.

  4. _extruction executes only the winning branch via ctx.runLoop().


_extruction args format

[target: 20 bytes][N: 1 byte uint8][branch_0_len: 2 bytes][branch_0: N bytes]...[branch_N_len][branch_N]
  • target: address of the external selector implementing IExtruction or IStaticExtruction.

  • N: number of branches.

  • Each branch: uint16 length prefix followed by the branch bytecode.


Invariants to verify

  • Branch determinism: same inputs always select the same branch (no randomness or block-state dependence unless intentional).

  • Quote/swap path consistency: quote() and swap() must select the same branch and return identical amounts.

  • All branches individually safe: each sub-program must satisfy its own invariants (monotonicity, rounding, balance sufficiency).

  • No dead paths: every branch must be reachable and must terminate correctly.

  • Authorization correctness: the selector contract must not be manipulable by the taker.

  • Non-upgradeable selector: the external selector target must be non-upgradeable, so its pricing logic cannot change between quote and fill.


Did you find what you need?