From 8e75f9f23d0d35f4a1145fee916ca0cfdcab8503 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Wed, 7 Oct 2026 16:40:39 +0000 Subject: [PATCH] Thornode.get_quote(): get data via remote RPC interface --- mmgen/proto/rune/rpc/remote.py | 19 +++++++++++ mmgen/swap/proto/thorchain/thornode.py | 47 +++++++------------------- mmgen/tx/new_swap.py | 2 +- test/cmdtest_d/ethbump.py | 2 +- test/cmdtest_d/ethswap.py | 2 +- test/cmdtest_d/remote.py | 2 +- 6 files changed, 36 insertions(+), 38 deletions(-) diff --git a/mmgen/proto/rune/rpc/remote.py b/mmgen/proto/rune/rpc/remote.py index 3421a66c..462bc102 100644 --- a/mmgen/proto/rune/rpc/remote.py +++ b/mmgen/proto/rune/rpc/remote.py @@ -11,6 +11,7 @@ proto.rune.rpc.remote: THORChain base protocol remote RPC client for the MMGen P """ import json +from decimal import Decimal from ....http import RemoteJSONClient from ....rpc.remote import RemoteRPCClient @@ -38,6 +39,10 @@ class RESTClient(RemoteJSONClient): # same endpoint as RPCClient for test suite params = 'rpc_remote_rest_params' timeout = 15 +class SwapClient(RemoteJSONClient): # same endpoint as RESTClient for mainnet + params = 'rpc_remote_swap_params' + timeout = 15 + class MidgardClient(RemoteJSONClient): params = 'rpc_remote_midgard_params' timeout = 30 @@ -46,6 +51,7 @@ class THORChainRemoteRPCClient(RemoteRPCClient): "retrieve data from a remote THORChain JSON-RPC endpoint" server_proto = 'THORChain' + swap_proto = 'thorchain' mods = { 'get': ( 'ping', @@ -66,6 +72,7 @@ class THORChainRemoteRPCClient(RemoteRPCClient): self.caps = ('lbl_id',) self.rest_api = RESTClient(cfg, proto) self.rpc_api = RPCClient(cfg, proto) + self.swap_api = SwapClient(cfg, proto) self.midgard_api = MidgardClient(cfg, proto) @staticmethod @@ -131,6 +138,18 @@ class THORChainRemoteRPCClient(RemoteRPCClient): assert len(rune_res) == 1, f'{rune_res}: result length is not one!' return self.proto.coin_amt(int(rune_res[0]['amount']), from_unit='satoshi') + def get_quote(self, from_asset, to_asset, amt, *, amt_is_atomic=False): + from ....swap.util import get_swap_proto_mod + swap_cfg = get_swap_proto_mod(self.swap_proto).SwapCfg(self.cfg) + qs = make_query_string({ + 'from_asset': from_asset.full_name, + 'to_asset': to_asset.full_name, + 'amount': amt if amt_is_atomic else amt.to_unit('atomic'), + 'streaming_interval': swap_cfg.stream_interval}) + return process_response( + self.swap_api.get(path=f'/thorchain/quote/swap?{qs}'), + errmsg = 'swap quote request failed') + def tx_info(self, txid: str): "get information for a transaction by TxID" return process_response( diff --git a/mmgen/swap/proto/thorchain/thornode.py b/mmgen/swap/proto/thorchain/thornode.py index 2f38286c..11a19717 100644 --- a/mmgen/swap/proto/thorchain/thornode.py +++ b/mmgen/swap/proto/thorchain/thornode.py @@ -10,12 +10,12 @@ swap.proto.thorchain.thornode: THORChain swap protocol network query ops """ -import time, json +import time from collections import namedtuple from ....protocol import init_proto from ....amt import UniAmt -from ....http import RemoteJSONClient +from ....rpc import get_remote_rpc _gd = namedtuple('gas_unit_data', ['code', 'disp']) gas_unit_data = { @@ -23,54 +23,33 @@ gas_unit_data = { 'gwei': _gd('G', 'Gwei'), } -class ThornodeSwapClient(RemoteJSONClient): - params = 'rpc_remote_swap_params' - timeout = 5 - class Thornode: def __init__(self, tx, amt): self.tx = tx self.in_amt = UniAmt(f'{amt:.8f}') - self.rpc = ThornodeSwapClient(tx.cfg, init_proto(tx.cfg, 'rune')) + self.rpc = get_remote_rpc(tx.cfg, init_proto(tx.cfg, 'rune')) def get_quote(self, swap_cfg): - - def get_data(send, recv, amt): - get_str = ( - '/thorchain/quote/swap?' - f'from_asset={send}&' - f'to_asset={recv}&' - f'amount={amt}&' - f'streaming_interval={swap_cfg.stream_interval}') - data = json.loads(self.rpc.get(path=get_str)) - if not 'expiry' in data: - from ....util import pp_fmt, die - die(2, pp_fmt(data)) - return data - if ( (self.tx.proto.tokensym or self.tx.recv_asset.tokensym) and self.tx.send_asset.chain != 'THOR'): # token swap - in_data = get_data( - self.tx.send_asset.full_name, - 'THOR.RUNE', - self.in_amt.to_unit('satoshi')) + from ....swap.util import get_swap_asset + rune_asset = get_swap_asset(self.tx.cfg, 'RUNE') + in_data = self.rpc.get_quote(self.tx.send_asset, rune_asset, self.in_amt) if self.tx.proto.network != 'regtest': time.sleep(1.1) # ninerealms max request rate 1/sec - out_data = get_data( - 'THOR.RUNE', - self.tx.recv_asset.full_name, - in_data['expected_amount_out']) + out_data = self.rpc.get_quote( + rune_asset, + self.tx.recv_asset, + in_data['expected_amount_out'], + amt_is_atomic = True) self.data = in_data | { 'expected_amount_out': out_data['expected_amount_out'], 'fees': out_data['fees'], 'expiry': min(in_data['expiry'], out_data['expiry'])} else: - self.data = get_data( - self.tx.send_asset.full_name, - self.tx.recv_asset.full_name, - self.in_amt.to_unit('satoshi')) + self.data = self.rpc.get_quote(self.tx.send_asset, self.tx.recv_asset, self.in_amt) async def format_quote(self, trade_limit, *, deduct_est_fee=False): from ....util import make_timestr, ymsg @@ -131,7 +110,7 @@ class Thornode: fees_t = UniAmt(int(fees['total']), from_unit='satoshi') fees_pct_disp = str(fees['total_bps'] / 100) + '%' slip_pct_disp = str(fees['slippage_bps'] / 100) + '%' - hdr = f'SWAP QUOTE (source: {self.rpc.host})' + hdr = f'SWAP QUOTE (source: {self.rpc.swap_api.host})' vault_info = '' if tx.send_asset.chain == 'THOR' else """ Vault address: {}""".format(cyan(self.inbound_address)) diff --git a/mmgen/tx/new_swap.py b/mmgen/tx/new_swap.py index b8edce55..9a997cc8 100644 --- a/mmgen/tx/new_swap.py +++ b/mmgen/tx/new_swap.py @@ -197,7 +197,7 @@ class NewSwap(New): return UniAmt(int(c.data['expected_amount_out']), from_unit='satoshi') * x while True: - self.cfg._util.qmsg(f'Retrieving data from {c.rpc.host}...') + self.cfg._util.qmsg(f'Retrieving data from {c.rpc.swap_api.host}...') c.get_quote(self.swap_cfg) self.cfg._util.qmsg('OK') self.swap_quote_refresh_time = time.time() diff --git a/test/cmdtest_d/ethbump.py b/test/cmdtest_d/ethbump.py index 83edc792..8cc4c48d 100644 --- a/test/cmdtest_d/ethbump.py +++ b/test/cmdtest_d/ethbump.py @@ -117,7 +117,7 @@ class CmdTestEthBump(CmdTestEthBumpMethods, CmdTestEthSwapMethods, CmdTestSwapMe networks = ('eth',) tmpdir_nums = [42] - thornode_servers = ('swap',) + thornode_servers = ('rpc', 'swap') dfl_devnet_block_period = {'geth': 7, 'reth': 9} fund_amt = 100000 token_fund_amt = 1000 diff --git a/test/cmdtest_d/ethswap.py b/test/cmdtest_d/ethswap.py index 3adfa23c..a1e132db 100644 --- a/test/cmdtest_d/ethswap.py +++ b/test/cmdtest_d/ethswap.py @@ -121,7 +121,7 @@ class CmdTestEthSwap(CmdTestSwapMethods, CmdTestRegtest): bdb_wallet = True tmpdir_nums = [47] networks = ('btc',) - thornode_servers = ('swap',) + thornode_servers = ('rpc', 'swap') passthru_opts = ('coin', 'rpc_backend', 'eth_daemon_id') cross_group = 'ethswap_eth' cross_coin = 'eth' diff --git a/test/cmdtest_d/remote.py b/test/cmdtest_d/remote.py index e5a62424..96d0c8f7 100644 --- a/test/cmdtest_d/remote.py +++ b/test/cmdtest_d/remote.py @@ -19,7 +19,7 @@ class CmdTestRemote(CmdTestBase, CmdTestSwapMethods, CmdTestRuneMethods): networks = ('btc',) tmpdir_nums = [37] - thornode_servers = ('rpc', 'midgard') + thornode_servers = ('rpc', 'midgard', 'swap') cmd_group = ( ('ping', 'pinging remote REST server'),