Skip to content

feat(swap): rpc to find best swap with liquidity routing for ask#2362

Merged
shamardy merged 71 commits intodevfrom
lr-swap-wip
Jul 2, 2025
Merged

feat(swap): rpc to find best swap with liquidity routing for ask#2362
shamardy merged 71 commits intodevfrom
lr-swap-wip

Conversation

@dimxy
Copy link
Copy Markdown
Collaborator

@dimxy dimxy commented Feb 16, 2025

Initial code for liquidity routing (LR) support for KDF.

The added RPC finds best (most price efficient) swap path from a list of provided ask orders, to fill them with a User token converting into orders' tokens with an interim LR-swap.

This PR covers only finding the best quote for one case (the ask order when 'rel' is token). Next steps are adding/fixing RPCs to get quotes for order types (bids) and RPCs to run swaps with LR.

TODO:

  • validation code for requests in new RPCs
  • add support trade_preimage_rpc for TPU to calculate total fees, return total fees including fees for LR with this PR's best quote RPC
  • getting quotes for bid orders when rel=token_x, with routing token_x into my_token after the dex-swap
  • getting quotes for ask orders when base=token_x, with routing token_x into my_token after the dex-swap
  • getting quotes for bid orders when base=token_x, with routing User's my_token into token_x before the dex-swap
  • add RPC to run swaps with LR (using LR swap data from the best quote RPCs), extending TPU swaps workflow

TODO to research:

  • stream the best quote price to the GUI so the user could wait for better price or refuse from staring the swap if price becomes unsatisfying
  • study the provider RPC how to find most liquid tokens for LR (use the KDF orderbook as the source for tokens) and return them to the user, to use them in the find best swap with LR RPC

dimxy added 10 commits January 21, 2025 20:35
* dev:
  fix(derive_key_from_path): check length of current_key_material (#2356)
  chore(release): bump mm2 version to 2.4.0-beta (#2346)
  fix(tests): add additional testnet sepolia nodes to test code (#2358)
  fix(swaps): maintain legacy compatibility for negotiation messages (#2353)
  refactor(SwapOps): impl defaults for protocol specific swapops fns (#2354)
  feat(tpu-v2): provide swap protocol versioning (#2324)
  feat(wallet): add change mnemonic password rpc (#2317)
  fix(tpu-v2): fix tpu-v2 wait for payment spend and extract secret (#2261)
  feat(tendermint): unstaking/undelegation (#2330)
  fix(utxo-withdraw): get hw ctx only when `PrivKeyPolicy` is trezor (#2333)
  feat(event-streaming): API-driven subscription management (#2172)
  fix(hash-types): remove panic, enforce fixed-size arrays (#2279)
  fix(ARRR): store unconfirmed change output (#2276)
  feat(tendermint): staking/delegation (#2322)
  chore(deps): `timed-map` migration (#2247)
  fix(mem-leak): `running_swap` never shrinks (#2301)
  chore(dep-bump): libp2p (#2326)
  refactor(build script): rewrite the main build script (#2319)
@dimxy dimxy added status: in progress priority: medium Moderately important tasks that should be completed but are not urgent. feature: swap feature: RPC labels Feb 16, 2025
@dimxy dimxy changed the title feat(swap): rpc to find best swap with liquidity routing to fill ask when rel is token feat(swap): rpc to find best swap with liquidity routing for ask Feb 16, 2025
@shamardy shamardy self-requested a review February 17, 2025 10:10
@shamardy shamardy added priority: high Important tasks that need attention soon. status: pending review and removed priority: medium Moderately important tasks that should be completed but are not urgent. status: in progress labels Feb 21, 2025
@mariocynicys mariocynicys self-requested a review February 21, 2025 13:27
Copy link
Copy Markdown
Collaborator

@mariocynicys mariocynicys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! esp for the excessive comments :)

this was a light review to grasp new thigns. nothing is blocking from my side.

will read the SoW for more context and review again next review week if this is still unmerged.

@dimxy
Copy link
Copy Markdown
Collaborator Author

dimxy commented Jun 20, 2025

Regarding this: #2362 (comment)

I suggest I use the 'Close' price in the next PR (which actually does swaps with LR)
and we will see how this affect swaps (We may see empty prices response more often but maybe this is just okay as we should skip tokens with temp low liquidity)

@dimxy
Copy link
Copy Markdown
Collaborator Author

dimxy commented Jun 22, 2025

I improved functions and structs naming (well, at least I tried).
Also I extended the rpc structs to accept not only one currently supported but different kinds of sell/buy options. The new fields still are not used but reserved for next code iteration and should move us closer to the goal structure for RPCs for LR.
@shamardy

PS. Some tests are failing but looks like it's QRC tests

shamardy
shamardy previously approved these changes Jun 23, 2025
Copy link
Copy Markdown
Collaborator

@shamardy shamardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes! The below comments can be done here or in next PRs.

@@ -0,0 +1,299 @@
//! RPC implementations for swaps with liquidity routing (LR) of EVM tokens
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose the RPCs in this file will be for all kind of tokens in the future not EVM only, maybe we should remove any mention of EVMs from the docs. Not a blocker for this PR though.

Comment on lines +41 to +58
/// Request to find best swap path with LR to fill an order from list.
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LrFindBestQuoteRequest {
/// Base coin to fill an atomic swap maker order with possible liquidity routing from this coin over a coin/token in an ask/bid
pub user_base: Ticker,
/// List of maker atomic swap ask orders, to find best swap path with liquidity routing from user_base or user_rel coin
pub asks: Vec<AsksForCoin>,
/// List of maker atomic swap bid orders, to find best swap path with liquidity routing from user_base or user_rel coin
pub bids: Vec<BidsForCoin>,
/// Buy or sell volume (in coin units, i.e. with fraction)
pub volume: MmNumber,
/// Method buy or sell
/// TODO: use this field, now we support 'buy' only
pub method: String,
/// Rel coin to fill an atomic swap maker order with possible liquidity routing from this coin over a coin/token in an ask/bid
pub user_rel: Ticker,
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still very confusing, I suggested something like this

#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LrFindBestQuoteRequest {
    /// The currency the user wants to acquire (e.g., "BTC").
    pub target_coin: Ticker,

    /// The amount of the `target_coin` the user wishes to buy.
    pub target_amount: MmNumber,

    /// The token the user holds and will use to pay for the trade.
    /// If this token is not accepted by the best candidate order,
    /// it will be swapped through a liquidity provider.
    pub payment_token: Ticker,

    /// A list of potential orders (asks) from the order book that are selling
    /// the `target_coin`. The system will evaluate these to find the best trade route.
    pub candidate_orders: Vec<RpcOrderbookEntryV2>,
}

Do you have any objections to this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target_coin, payment_token is good, I like this.
Only this assumes the User would always be creating 'sell' orders (no 'buy'). It's easier for development,
but for ordinary atomic swaps we allow both sell and buy (although 'buy' is just an inversion of 'sell').

About this:
pub candidate_orders: Vec<RpcOrderbookEntryV2>,. The problem is that RpcOrderbookEntryV2 contains only one coin and another coin is returned as separate a base or rel property in the orderbook rpc response.
So I made it as a new AsksForCoin like in the orderbook rpc response.
(Not sure though we should send orders into the LR rpcs as they are on the orderbook, but this is how it's done now. I thought GUI would be selecting orders and send them to LR rpcs for adding liquidity routing steps)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only this assumes the User would always be creating 'sell' orders (no 'buy').

Why is that? target_coin and payment_token should work with either sell or buy

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have these in lp_commands? I will allow it for now since we want this PR merged asap but I don't think this is the best place for it. IMHO, lp_commands should be for rpc methods (the wrappers) and the requests/responses/errors of these RPC methods only.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha!
I have already moved this out of lp_command in the follow-up code to this PR. Will create a new PR with this in the next few days

@shamardy
Copy link
Copy Markdown
Collaborator

shamardy commented Jul 2, 2025

@smk762 please note no docs are needed for this PR as the API may change in next PRs

@shamardy shamardy merged commit 8c9326e into dev Jul 2, 2025
18 of 24 checks passed
@shamardy shamardy deleted the lr-swap-wip branch July 2, 2025 10:12
dimxy pushed a commit that referenced this pull request Jul 13, 2025
* dev:
  fix(eth): Correctly implement ETH max withdrawal logic (#2531)
  feat(use-clap-for-cli): use clap to parse CLI-Args #2215 (#2510)
  feat(orderbook): expirable maker orders (#2516)
  improvement(eth): drop parity support (#2527)
  chore(release): finalize changelog for v2.5.0-beta (#2524)
  chore(toolchain): upgrade toolchain to nightly 1.86.0 (#2444)
  feat(swap): rpc to find best swap with liquidity routing for ask (#2362)
  fix(kdf_walletconnect): apply explicit MmError mapping (#2514)
  fix(walletconnect): centralize connection and retry logic (#2508)
  fix(hw-wallet): avoid calling `get_enabled_address` in trezor-based coin init (#2504)
dimxy pushed a commit to dimxy/komodo-defi-framework that referenced this pull request Jul 16, 2025
* refactor-gas-fee-policy: (30 commits)
  revert change in test_enable_custom_erc20
  fix(test) disable get_swap_gas_fee_policy for tests (no platform coin in tests)
  revert tokio test and use block_on for eth docker test
  Refactor gas fee code: get max_eth_tx_type from platform coin, add gas fee adjust coin params, rename "set_swap_transaction_fee_policy" rpc to "set_swap_gas_fee_policy", force set_swap_gas_fee_policy to store policy in the platform coin
  fix(eth): Propagate structured EIP-1559 fee errors (GLEECBTC#2532)
  fix(eth): Correctly implement ETH max withdrawal logic (GLEECBTC#2531)
  feat(use-clap-for-cli): use clap to parse CLI-Args GLEECBTC#2215 (GLEECBTC#2510)
  feat(orderbook): expirable maker orders (GLEECBTC#2516)
  improvement(eth): drop parity support (GLEECBTC#2527)
  chore(release): finalize changelog for v2.5.0-beta (GLEECBTC#2524)
  chore(toolchain): upgrade toolchain to nightly 1.86.0 (GLEECBTC#2444)
  feat(swap): rpc to find best swap with liquidity routing for ask (GLEECBTC#2362)
  fix(kdf_walletconnect): apply explicit MmError mapping (GLEECBTC#2514)
  fix(walletconnect): centralize connection and retry logic (GLEECBTC#2508)
  fix(hw-wallet): avoid calling `get_enabled_address` in trezor-based coin init (GLEECBTC#2504)
  chore(core): replace hash_raw_entry with stable entry() API (GLEECBTC#2473)
  chore(core): adapt `MmError` and usages for compatibility with new rustc versions (GLEECBTC#2443)
  feat(wallet): add `delete_wallet` RPC (GLEECBTC#2497)
  chore(release): add changelog entries for v2.5.0-beta (GLEECBTC#2494)
  chore(release): bump kdf version to 2.5.0-beta (GLEECBTC#2492)
  ...

# Conflicts:
#	mm2src/coins/eth.rs
#	mm2src/coins/eth/eth_swap_v2/eth_maker_swap_v2.rs
#	mm2src/coins/eth/eth_swap_v2/eth_taker_swap_v2.rs
#	mm2src/coins/eth/eth_utils.rs
#	mm2src/coins/eth/eth_withdraw.rs
#	mm2src/coins/eth/v2_activation.rs
#	mm2src/coins/lp_coins.rs
#	mm2src/coins/qrc20.rs
#	mm2src/coins/qrc20/swap.rs
#	mm2src/coins_activation/src/platform_coin_with_tokens.rs
#	mm2src/coins_activation/src/token.rs
#	mm2src/mm2_main/src/lp_swap/check_balance.rs
#	mm2src/mm2_main/src/lp_swap/maker_swap.rs
#	mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs
#	mm2src/mm2_main/src/rpc/lp_commands/ext_api/ext_api_types.rs
#	mm2src/mm2_main/src/rpc/lp_commands/mod.rs
#	mm2src/mm2_main/src/rpc/lp_commands/one_inch/errors.rs
#	mm2src/mm2_main/src/rpc/lp_commands/one_inch/rpcs.rs
#	mm2src/mm2_main/src/rpc/lp_commands/tokens.rs
#	mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs
#	mm2src/trading_api/src/one_inch_api/classic_swap_types.rs
#	mm2src/trading_api/src/one_inch_api/client.rs
#	mm2src/trading_api/src/one_inch_api/portfolio_types.rs
dimxy pushed a commit that referenced this pull request Oct 15, 2025
This introduces a new experimental RPC, `experimental::liquidity_routing::find_best_quote`, to find the most cost-effective swap path by aggregating atomic swaps with external liquidity routing via the 1inch API.

The new endpoint allows users to execute token swaps even if they do not directly hold the tokens required by maker orders. It evaluates possible swap paths by combining external liquidity routing with atomic swaps to find the most price-effective route.

Key changes include:
- A new RPC endpoint `experimental::liquidity_routing::find_best_quote` for pathfinding.
- Core logic in `mm2src/mm2_main/src/rpc/lp_commands/lr_swap/lr_impl.rs` to process orders and query the 1inch API.
- Refactored the 1inch API client in `trading_api` to use a `UrlBuilder` for more robust URL construction and added support for the Portfolio API.
- Extracted common Ethereum utility functions into a new `coins/eth/eth_utils.rs` module to improve code organization.
- Updated `RpcOrderbookEntryV2` and `MmNumberMultiRepr` to be deserializable.

Currently, this feature only supports filling `ask` orders with liquidity routing performed before the atomic swap.
@smk762 smk762 added the status: pending docs Adding this label will automatically open an issue in the docs repo label Nov 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2.6.0-beta feature: RPC feature: swap priority: urgent Critical tasks requiring immediate action. status: pending docs Adding this label will automatically open an issue in the docs repo status: pending review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants