-
Notifications
You must be signed in to change notification settings - Fork 113
feat(LR): add buy action, bid order and LR_1 support to find_best_quote RPC #2545
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
|
@dimxy can you please supply request examples of |
The full path for this method is How It WorksThe method analyzes a list of available P2P orders and determines the most economical path, which could be:
It calculates the User Scenario: Trading Across Different Liquidity PoolsScenarioA user, Alex, wants to buy 1 BTC. He holds WETH on the Ethereum network. He checks the Komodo DeFi Framework orderbook and finds two promising orders from sellers:
Alex has WETH, not DAI or USDC. Manually, he would have to go to an external exchange, sell his WETH for DAI or USDC (paying fees), withdraw the tokens, and then place the P2P order. This is slow, complex, and error-prone. Solution using the APIAlex's application can use the
What find_best_quote Does
The ResponseThe RPC returns a single, optimal path. For instance, if the WETH → DAI route is cheaper, the response will detail the two required steps:
Alex's application can then present this unified quote to him. If he accepts, the application would use the response data to call Use Cases and ExamplesHere are examples for different scenarios that Use Case 1: Direct Atomic Swap (No LR Needed)This is the simplest case where the user already holds the required asset. Request: The user wants to buy 1 BTC and already has DAI. The provided order is a BTC-DAI ask order. NOTE:
.. should be flattened (removed the level of aggregation of orders by the "DAI" ticker) and sent in the Same should be done for bids.
{
"user_base": "BTC",
"user_rel": "DAI",
"method": "buy",
"volume": "1",
"asks": [
{
"base": "BTC",
"orders": [
{
"coin": "DAI",
"address": {
"address_type": "Transparent",
"address_data": "0x123...abc"
},
"price": "35000",
"pubkey": "maker_pubkey",
"uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"is_mine": false,
"base_max_volume": "1.5",
"base_min_volume": "0.1",
"rel_max_volume": "52500",
"rel_min_volume": "3500",
"conf_settings": null
}
]
}
],
"bids": []
}Response: No LR is needed, so {
"lr_data_0": null,
"lr_data_1": null,
"atomic_swap": {
"volume": "1",
"base": "DAI",
"rel": "BTC",
"price": "35000",
"method": "sell",
"order_uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"match_by": null,
"order_type": null
},
"total_price": "35000"
}Use Case 2: LR Before Atomic Swap (LR_0)This matches our user scenario. The user has one token ( Request: The user wants to buy 1 BTC with WETH. The best order requires DAI. {
"user_base": "BTC",
"user_rel": "WETH-ERC20",
"method": "buy",
"volume": "1",
"asks": [
{
"base": "BTC",
"orders": [
{
"coin": "DAI",
"address": {
"address_type": "Transparent",
"address_data": "0x123...abc"
},
"price": "35000",
"pubkey": "maker_pubkey",
"uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"is_mine": false,
"base_max_volume": "1.5",
"base_min_volume": "0.1",
"rel_max_volume": "52500",
"rel_min_volume": "3500",
"conf_settings": null
}
]
}
],
"bids": []
}Response: The response includes details for the WETH → DAI swap in {
"lr_data_0": {
"src_amount": "12.52",
"dst_amount": {
"amount": "35000.123"
},
"src_token": {
"address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"symbol": "WETH",
"name": "Wrapped Ether",
"decimals": 18,
"symbol_kdf": "WETH-ERC20"
},
"dst_token": {
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"symbol": "DAI",
"name": "Dai Stablecoin",
"decimals": 18,
"symbol_kdf": "DAI"
},
"tx": null,
"gas": 150000
},
"lr_data_1": null,
"atomic_swap": {
"volume": "35000.123",
"base": "DAI",
"rel": "BTC",
"price": "35000",
"method": "sell",
"order_uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"match_by": null,
"order_type": null
},
"total_price": "12.52"
}Use Case 3: LR After Atomic Swap (LR_1)The user has the token required for the P2P swap but wants the final asset to be a different token. Request: The user wants to sell 1 BTC and ultimately receive USDC. The best available order is from a buyer who will pay in DAI. {
"user_base": "BTC",
"user_rel": "USDC",
"method": "sell",
"volume": "1",
"asks": [],
"bids": [
{
"rel": "BTC",
"orders": [
{
"coin": "DAI",
"address": {
"address_type": "Transparent",
"address_data": "0x123...abc"
},
"price": "0.00002857",
"pubkey": "maker_pubkey",
"uuid": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
"is_mine": false,
"base_max_volume": "52500",
"base_min_volume": "3500",
"rel_max_volume": "1.5",
"rel_min_volume": "0.1",
"conf_settings": null
}
]
}
]
}Response: The response includes details for the DAI → USDC swap in {
"lr_data_0": null,
"lr_data_1": {
"src_amount": "35000",
"dst_amount": {
"amount": "34995"
},
"src_token": {
"address": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
"symbol": "DAI",
"name": "Dai Stablecoin",
"decimals": 18,
"symbol_kdf": "DAI"
},
"dst_token": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"symbol": "USDC",
"name": "USD Coin",
"decimals": 6,
"symbol_kdf": "USDC"
},
"tx": null,
"gas": 120000
},
"atomic_swap": {
"volume": "1",
"base": "BTC",
"rel": "DAI",
"price": "0.00002857",
"method": "sell",
"order_uuid": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
"match_by": null,
"order_type": null
},
"total_price": "34995"
}Use Case 4: Cross-Chain Swap with LR Before and After (LR_0 and LR_1)This is the most advanced use case, demonstrating how liquidity routing can be used to bridge assets across two different EVM-compatible blockchains. The P2P atomic swap acts as the trustless bridge between the two ecosystems. Scenario: Alex can use the
Request: Alex wants to sell 5 WETH on Polygon and wants to know how many JOE tokens on Avalanche he will receive by routing through the MATIC/AVAX P2P order. {
"user_base": "WETH-ERC20",
"user_rel": "JOE-ERC20",
"method": "sell",
"volume": "5",
"asks": [
{
"base": "AVAX",
"orders": [
{
"coin": "MATIC",
"address": {
"address_type": "Transparent",
"address_data": "0x123...abc"
},
"price": "500",
"pubkey": "maker_pubkey_on_avax",
"uuid": "d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8g",
"is_mine": false,
"base_max_volume": "100",
"base_min_volume": "10",
"rel_max_volume": "50000",
"rel_min_volume": "5000",
"conf_settings": null
}
]
}
],
"bids": []
}Response: The response will detail all three steps of the cross-chain swap. {
"lr_data_0": {
"src_amount": "5",
"dst_amount": {
"amount": "21428.5"
},
"src_token": {
"address": "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619",
"symbol": "WETH",
"name": "Wrapped Ether",
"decimals": 18,
"symbol_kdf": "WETH-ERC20"
},
"dst_token": {
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"symbol": "MATIC",
"name": "Matic",
"decimals": 18,
"symbol_kdf": "MATIC"
},
"tx": null,
"gas": 145000
},
"atomic_swap": {
"volume": "21428.5",
"base": "MATIC",
"rel": "AVAX",
"price": "500",
"method": "sell",
"order_uuid": "d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8g",
"match_by": null,
"order_type": null
},
"lr_data_1": {
"src_amount": "42.857",
"dst_amount": {
"amount": "2995.5"
},
"src_token": {
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"symbol": "AVAX",
"name": "Avalanche",
"decimals": 18,
"symbol_kdf": "AVAX"
},
"dst_token": {
"address": "0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd",
"symbol": "JOE",
"name": "JOE",
"decimals": 18,
"symbol_kdf": "JOE-ERC20"
},
"tx": null,
"gas": 155000
},
"total_price": "599.1"
}Conceptual Use Case: Bridging EVM and Non-EVM ChainsWhile the current implementation focuses on 1inch for EVM-to-EVM liquidity routing, the underlying architecture is designed to be extensible. The Scenario: A future version of the
Setup Required for 1inch IntegrationTo use the liquidity routing features powered by 1inch, some initial setup is required in KDF. 1. KDF/MM2 Configuration (MM2.json)Your MM2 configuration file must contain the necessary information for the software to communicate with the 1inch API. API Endpoint URL: You need to specify the 1inch API endpoint, this can be provided through komodo proxy. The code reads this from the {
"1inch_api": "https://api.1inch.dev"
}API Key: The 1inch API requires an authentication key. The KDF codebase includes the logic to send this key as a Add Configuration for All Required Coins and tokens: Every token involved in the swap path must be enabled in your MM2 configuration. For the scenario above, your coins array would need to include configurations for WETH-ERC20, DAI, AAVE-ERC20, and USDC. MM2 uses this configuration to find contract addresses, decimals, and other essential on-chain information. Normally this is done by wallet developers. 2. Wallet and On-Chain SetupBefore executing a swap, the user's wallet must be prepared. Fund the Wallet:
Activate (enable) coins and tokens used in swaps with liquidity routing Handling allowance for tokens used in swaps In summary, a successful integration requires configuring the API endpoint and key, enabling all relevant coins in MM2, and ensuring the user's wallet is funded. |
|
@smk762 About this
|
shamardy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First review from my side! Will continue reviewing this while it's being tested. If any of the comments you want to fix in next PRs, it's fine, but we need a tracking issue for all these things.
| let dex_fee_rate = DexFee::dex_fee_rate(&taker_ticker, &maker_ticker); | ||
| volume_with_fees / (MmNumber::from("1") + dex_fee_rate) // Deduct dex fee to get the atomic swap taker amount | ||
| } else { | ||
| user_sell_amount.clone() // TODO: use atomic_swap_taker_amount |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain this todo?
|
|
||
| /// Select the best swap path, by minimum of total swap price, including LR steps and atomic swap) | ||
| #[allow(clippy::result_large_err)] | ||
| async fn select_best_swap(self, ctx: &MmArc) -> MmResult<(LrSwapCandidateInfo, MmNumber), LrSwapError> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do all 1inch swaps use the same gas amount? I see that the ClassicSwapData fetched from the 1inch API provides an estimated gas cost, and this should be factored in, as a swap with a better price might have a higher gas cost, making it more expensive overall
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gas limits returned from the find_best_quote are not used in the execute_routed_trade RPC as in the trade RPC a new 1inch request is made, to get the actual 1inch swap transaction details. The gas limit is used from this new request.
I edited #2545 (comment) and added my changes: |
…p and do it only in the test itself
* dev: fix build script failing to find .git/HEAD (#2601) refactor(EVM): rename fn, fix timeouts, add activation req validation (#2543) improvement(`static mut`s): `static mut` removal (#2590) fix(orders): set subscription on kickstart and skip GC of own pubkeys (#2597) fix(ordermatch): ignore loop-back; clear on null root; reject stale keep-alives (#2580) fix(clippy): fix clippy warnings for #2565 (#2589) fix(Trezor): fix utxo and eth calls due to firmware changes (#2565)
Please add any details to this issue (and DM me API keys etc) and I'll set it up GLEECBTC/komodo-defi-proxy#28 |
Added a note to this PR description. |
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@smk762 |
|
@smk762 |
|
@smk762 |
|
@smk762 |
1 similar comment
|
@smk762 |
Next phase of liquidity routing (LR) development (WIP).
Fixes and new features to the
find_best_quoteRPC:Improved code, RPC params, fixed total price calculations.
Details for the find_best_quote RPC are here: https://github.com/KomodoPlatform/komodo-defi-framework/blob/342fb1b520a56b2e25c7adaf5abb756c338be0cd/mm2src/mm2_main/src/rpc/lp_commands/lr_swap_api.rs#L18
This code requires setting up 1inch API service as an LR provider.
Setting Up 1inch Provider in KDF
The MM2.json should contain "1inch_api" param pointing to a url to the 1inch API server ("https://api.1inch.dev") or KDF proxy.
The KDF proxy must re-route requests to the 1inch API server and add an "Authorization" HTTP header set to "Bearer <1inch-API-KEY>" value.
@smk762