new mmgen-remote utility
Command invocation syntax is the same as for the `mmgen-tool` utility.
Currently, only THORChain public endpoints are supported
Help:
$ mmgen-remote --coin=rune --help
Sample invocation:
$ mmgen-remote --log --proxy=localhost:9050 --coin=rune lastblock coin=btc
Testing:
$ test/cmdtest.py -e remote
This commit is contained in:
parent
bc03ffc69e
commit
8a23f9867f
17 changed files with 414 additions and 7 deletions
16
cmds/mmgen-remote
Executable file
16
cmds/mmgen-remote
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
||||
# Copyright (C)2013-2026 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen-wallet
|
||||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
mmgen-remote: Retrieve data from a remote JSON-RPC server
|
||||
"""
|
||||
|
||||
from mmgen.main import launch
|
||||
launch(mod='remote')
|
||||
|
|
@ -81,6 +81,7 @@ class GlobalConstants(Lockable):
|
|||
'passchg': _cc(False, False, False, None, [], 'lmw'),
|
||||
'passgen': _cc(False, False, False, None, [], 'lmw'),
|
||||
'regtest': _cc(True, True, True, None, ['tw'], 'lmw'),
|
||||
'remote': _cc(True, True, True, None, [], 'lmw'),
|
||||
'seedjoin': _cc(False, False, False, None, [], 'lmw'),
|
||||
'seedsplit': _cc(False, False, False, None, [], 'lmw'),
|
||||
'subwalletgen': _cc(False, False, False, None, [], 'lmw'),
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
September 2026
|
||||
October 2026
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
16.3.0dev11
|
||||
16.3.0dev12
|
||||
|
|
|
|||
46
mmgen/help/remote.py
Executable file
46
mmgen/help/remote.py
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
||||
# Copyright (C)2013-2026 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen-wallet
|
||||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
help.remote: command help for the ‘mmgen-remote’ utility
|
||||
"""
|
||||
|
||||
from ..tool.help import gen_main_help
|
||||
from ..cfg import gc
|
||||
from ..color import yellow
|
||||
from ..util import fmt_with_color
|
||||
|
||||
def help(proto, cfg):
|
||||
|
||||
warning = """
|
||||
Communicating with a remote server can harm your privacy!
|
||||
To improve anonymity, proxy requests via Tor or I2P
|
||||
"""
|
||||
|
||||
footer = f"""
|
||||
For individual command usage, invoke ‘{gc.prog_name} --coin={cfg.coin.lower()} help COMMAND’
|
||||
"""
|
||||
|
||||
match cfg.coin:
|
||||
case 'RUNE':
|
||||
from ..proto.rune.rpc.remote import THORChainRemoteRPCClient as rpc
|
||||
clist = '\n ' + '\n'.join(gen_main_help(
|
||||
mods_data = rpc.mods,
|
||||
get_mod_cls_func = lambda x: rpc,
|
||||
indent = ' '))
|
||||
case _:
|
||||
clist = f'No configured commands for coin {cfg.coin}\n Supported coins: RUNE'
|
||||
warning = ''
|
||||
footer = ''
|
||||
|
||||
return '{a}\nCOMMANDS:\n {b}{c}\n'.format(
|
||||
a = '\n' + fmt_with_color(warning.strip(), yellow) if warning else '',
|
||||
b = clist,
|
||||
c = '\n' + footer.strip() if footer else '')
|
||||
87
mmgen/main_remote.py
Executable file
87
mmgen/main_remote.py
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
||||
# Copyright (C)2013-2026 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen-wallet
|
||||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
mmgen-remote: Retrieve data from a remote JSON-RPC server
|
||||
"""
|
||||
|
||||
from .cfg import Config
|
||||
from .util import Msg, die, fmt_list, async_run
|
||||
|
||||
opts_data = {
|
||||
'filter_codes': ['-'],
|
||||
'text': {
|
||||
'desc': 'Retrieve data from a remote JSON-RPC server',
|
||||
'usage': '[OPTS] COMMAND ARGS',
|
||||
'options': """
|
||||
-- -h, --help Print this help message
|
||||
-- --, --longhelp Print help message for long (global) options
|
||||
-- -d, --outdir=D Output logfile to directory ‘D’ instead of working dir
|
||||
-- -l, --log Log output to file
|
||||
X- -s, --swap-proto Swap protocol to use (Default: {x_dfl}, Choices: {x_all})
|
||||
X- -x, --proxy=P Connect to remote server(s) via SOCKS5h proxy P (host:port)
|
||||
+ Use special value ‘env’ to honor *_PROXY env vars instead.
|
||||
""",
|
||||
'notes': '{n_rc}',
|
||||
},
|
||||
'code': {
|
||||
'options': lambda cfg, proto, help_notes, s: s.format(
|
||||
x_all = fmt_list(cfg._autoset_opts['swap_proto'].choices, fmt='no_spc'),
|
||||
x_dfl = cfg._autoset_opts['swap_proto'].choices[0]),
|
||||
'notes': lambda cfg, help_mod, help_notes, s: s.format(
|
||||
n_rc = help_mod('remote'))
|
||||
}
|
||||
}
|
||||
|
||||
cfg = Config(opts_data=opts_data)
|
||||
|
||||
def log(text, cmd, args, kwargs):
|
||||
args_disp = '-'.join(args) + '-'.join(f'{k}={v}' for k,v in kwargs.items())
|
||||
fn = 'mmgen-remote-{a}-{b}{c}.json'.format(
|
||||
a = cfg.coin,
|
||||
b = cmd.replace('_','-'),
|
||||
c = '-' + args_disp if args_disp else '')
|
||||
from .fileutil import write_data_to_file
|
||||
write_data_to_file(cfg, fn, text)
|
||||
|
||||
async def main():
|
||||
from .tool import get_cmds, process_args
|
||||
|
||||
match cfg.coin:
|
||||
case 'RUNE':
|
||||
from .proto.rune.rpc.remote import THORChainRemoteRPCClient as cls
|
||||
cmds = get_cmds(cls.mods)
|
||||
case _:
|
||||
cmds = ()
|
||||
|
||||
match cfg._args:
|
||||
case ['help']:
|
||||
from .help.remote import help
|
||||
Msg(help(cfg._proto, cfg))
|
||||
case ['help', cmd]:
|
||||
if cmd in cmds:
|
||||
from .tool.help import gen_tool_cmd_usage
|
||||
Msg('\n'.join(gen_tool_cmd_usage(None, cmd, lambda x: cls)))
|
||||
else:
|
||||
fs = '‘{}’: invalid command\n\nSupported commands:\n{}'
|
||||
die(1, fs.format(cmd, fmt_list(cmds, fmt='col', indent=' ' * 4)))
|
||||
case [cmd, *cmd_args] if cmd in cmds:
|
||||
args, kwargs = process_args(cmd, cmd_args, cls)
|
||||
res = getattr(cls(cfg, cfg._proto), cmd)(*args, **kwargs)
|
||||
import json
|
||||
from .ui import colorize_json
|
||||
text = json.dumps(res, indent=2)
|
||||
cfg._util.stdout_or_pager_nl(colorize_json(text) if cfg.color else text)
|
||||
if cfg.log:
|
||||
log(text, cmd, args, kwargs)
|
||||
case _:
|
||||
cfg._usage()
|
||||
|
||||
async_run(cfg, main)
|
||||
|
|
@ -50,6 +50,7 @@ class mainnet(CoinProtocol.Secp256k1):
|
|||
rpc_remote_rest_params = {'host': Hostname('gateway.liquify.com/chain/thorchain_api')}
|
||||
rpc_remote_rpc_params = {'host': Hostname('gateway.liquify.com/chain/thorchain_rpc')}
|
||||
rpc_remote_swap_params = {'host': Hostname('gateway.liquify.com/chain/thorchain_api')}
|
||||
rpc_remote_midgard_params = {'host': Hostname('gateway.liquify.com/chain/thorchain_midgard')}
|
||||
|
||||
def decode_addr(self, addr):
|
||||
hrp, data = bech32.bech32_decode(addr)
|
||||
|
|
@ -82,3 +83,4 @@ class regtest(testnet): # regtest is deprecated testnet
|
|||
'verify': False}
|
||||
rpc_remote_rpc_params = rpc_remote_rest_params
|
||||
rpc_remote_swap_params = rpc_remote_rest_params | {'host': Hostname('localhost:18900')}
|
||||
rpc_remote_midgard_params = rpc_remote_rest_params | {'host': Hostname('localhost:19000')}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,15 @@ from ....rpc.remote import RemoteRPCClient
|
|||
# throws exception on error:
|
||||
def process_response(json_response, errmsg):
|
||||
data = json.loads(json_response)
|
||||
if data['result'] is None:
|
||||
from ....util import die
|
||||
die('RPCFailure', errmsg)
|
||||
return data['result']
|
||||
if isinstance(data, dict) and 'result' in data:
|
||||
if data['result'] is None:
|
||||
from ....util import die
|
||||
die('RPCFailure', errmsg)
|
||||
return data['result']
|
||||
return data
|
||||
|
||||
def data_for_coin(ret, coin):
|
||||
return next(iter([e for e in ret if e['chain'] == coin.upper()] or [None])) if coin else ret
|
||||
|
||||
# HTTP POST, JSON-RPC response:
|
||||
class ThornodeRemoteRPCClient(RemoteJSONClient):
|
||||
|
|
@ -35,10 +40,26 @@ class ThornodeRemoteRESTClient(RemoteJSONClient):
|
|||
params = 'rpc_remote_rest_params'
|
||||
timeout = 15
|
||||
|
||||
class ThornodeRemoteMidgardClient(RemoteJSONClient):
|
||||
params = 'rpc_remote_midgard_params'
|
||||
timeout = 30
|
||||
|
||||
class THORChainRemoteRPCClient(RemoteRPCClient):
|
||||
"retrieve data from a remote THORChain JSON-RPC endpoint"
|
||||
|
||||
server_proto = 'THORChain'
|
||||
mods = {
|
||||
'get': (
|
||||
'ping',
|
||||
'health',
|
||||
'pools',
|
||||
'lastblock',
|
||||
'mimir',
|
||||
'actions',
|
||||
'inbound_addrs',
|
||||
'acct_info',
|
||||
'balance',
|
||||
'tx_info')}
|
||||
|
||||
def __init__(self, cfg, proto):
|
||||
for k, v in proto.rpc_remote_params.items():
|
||||
|
|
@ -47,6 +68,51 @@ class THORChainRemoteRPCClient(RemoteRPCClient):
|
|||
self.caps = ('lbl_id',)
|
||||
self.rest_api = ThornodeRemoteRESTClient(cfg, proto)
|
||||
self.rpc_api = ThornodeRemoteRPCClient(cfg, proto)
|
||||
self.midgard_api = ThornodeRemoteMidgardClient(cfg, proto)
|
||||
|
||||
def ping(self):
|
||||
"ping the remote REST endpoint"
|
||||
return process_response(
|
||||
self.rest_api.get(path='/thorchain/ping'),
|
||||
errmsg = f'pinging remote endpoint {self.rest_api.host} failed')
|
||||
|
||||
def health(self):
|
||||
"check the health of the THORChain network"
|
||||
return process_response(
|
||||
self.midgard_api.get(path='/v2/health'),
|
||||
errmsg = f'getting health status from {self.midgard_api.host} failed')
|
||||
|
||||
def pools(self):
|
||||
"get available pools on the THORChain network"
|
||||
return process_response(
|
||||
self.midgard_api.get(path='/v2/pools'),
|
||||
errmsg = f'getting pools from {self.midgard_api.host} failed')
|
||||
|
||||
def lastblock(self, *, coin: str=None): # noqa: RUF013
|
||||
"get last block info for all coins or a given coin"
|
||||
return data_for_coin(process_response(
|
||||
self.rest_api.get(path='/thorchain/lastblock'),
|
||||
errmsg = 'unable to retrieve lastblock data'), coin)
|
||||
|
||||
def mimir(self):
|
||||
"get Mimir constants for the THORChain network"
|
||||
return process_response(
|
||||
self.rest_api.get(path='/thorchain/mimir'),
|
||||
errmsg = 'get mimir info failed')
|
||||
|
||||
def actions(self, *, addr: str=None, txid: str=None): # noqa: RUF013
|
||||
"get actions for a given address or TxID"
|
||||
assert addr or txid, 'one of addr or txid must be specified'
|
||||
qs = '&'.join(f'{k}={v}' for k, v in (('address', addr), ('txid', txid)) if v)
|
||||
return process_response(
|
||||
self.midgard_api.get(path=f'/v2/actions?{qs}'),
|
||||
errmsg = 'get actions info failed')
|
||||
|
||||
def inbound_addrs(self, *, coin: str=None): # noqa: RUF013
|
||||
"get current inbound (vault) addresses"
|
||||
return data_for_coin(process_response(
|
||||
self.rest_api.get(path='/thorchain/inbound_addresses'),
|
||||
errmsg = 'unable to retrieve inbound (vault) addresses'), coin)
|
||||
|
||||
def acct_info(self, addr: str, *, block=None):
|
||||
"get account information for a given address"
|
||||
|
|
|
|||
|
|
@ -60,8 +60,10 @@ class Util:
|
|||
if cfg.pager:
|
||||
from .ui import do_pager
|
||||
self.stdout_or_pager = do_pager
|
||||
self.stdout_or_pager_nl = do_pager
|
||||
else:
|
||||
self.stdout_or_pager = Msg_r
|
||||
self.stdout_or_pager_nl = Msg
|
||||
|
||||
def compare_chksums(
|
||||
self,
|
||||
|
|
@ -192,6 +194,17 @@ def fmt(s, *, indent='', strip_char=None, append='\n'):
|
|||
+ ('\n'+indent).join(l.lstrip(strip_char) for l in s.strip().splitlines())
|
||||
+ append)
|
||||
|
||||
def fmt_with_color(s, color_func, *, indent='', strip_char=None, append='\n'):
|
||||
"""
|
||||
de-indent multiple lines of text, or indent with specified string, with color
|
||||
|
||||
each line is colored separately as a workaround for a ‘less’ pager ANSI color bug
|
||||
"""
|
||||
return (
|
||||
indent
|
||||
+ ('\n'+indent).join(color_func(l.lstrip(strip_char)) for l in s.strip().splitlines())
|
||||
+ append)
|
||||
|
||||
def fmt_list(iterable, *, fmt='dfl', indent='', conv=None):
|
||||
"pretty-format a list"
|
||||
_conv, sep, lq, rq = {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ scripts =
|
|||
cmds/mmgen-passchg
|
||||
cmds/mmgen-passgen
|
||||
cmds/mmgen-regtest
|
||||
cmds/mmgen-remote
|
||||
cmds/mmgen-seedjoin
|
||||
cmds/mmgen-seedsplit
|
||||
cmds/mmgen-subwalletgen
|
||||
|
|
|
|||
68
test/cmdtest_d/httpd/thornode/midgard.py
Executable file
68
test/cmdtest_d/httpd/thornode/midgard.py
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
||||
# Copyright (C)2013-2026 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen-wallet
|
||||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
test.cmdtest_d.httpd.thornode.midgard: Thornode Midgard HTTP server
|
||||
"""
|
||||
|
||||
import re, json
|
||||
from wsgiref.util import request_uri
|
||||
|
||||
from . import ThornodeServer
|
||||
|
||||
actions_info = {
|
||||
'actions': [{
|
||||
'date': '987654321',
|
||||
'height': '1234',
|
||||
},
|
||||
],
|
||||
'count': '1',
|
||||
'meta': {
|
||||
'nextPageToken': '123456789',
|
||||
'prevPageToken': '123456788'}}
|
||||
|
||||
health_info = {
|
||||
'database': True,
|
||||
'inSync': True,
|
||||
'scannerHeight': '987654321'}
|
||||
|
||||
class ThornodeMidgardServer(ThornodeServer):
|
||||
port = 19000
|
||||
name = 'thornode Midgard server'
|
||||
|
||||
def make_response_body(self, method, environ):
|
||||
|
||||
class responses:
|
||||
|
||||
# pylint: disable=unsubscriptable-object
|
||||
|
||||
def health(m):
|
||||
return health_info
|
||||
|
||||
def actions(m):
|
||||
assert m[1] in ( # FIXME - for now, just check well-formedness of query string
|
||||
'?address=thor1abcdefg',
|
||||
'?txid=deadbeef',
|
||||
'?address=thor1abcdefg&txid=deadbeef')
|
||||
return actions_info
|
||||
|
||||
pat_info = (
|
||||
('health', r'/v2/health'),
|
||||
('actions', r'/v2/actions?(.*)'))
|
||||
|
||||
req_str = request_uri(environ)
|
||||
|
||||
for name, pat in pat_info:
|
||||
if m := re.search(pat, req_str):
|
||||
assert method == 'GET'
|
||||
res = getattr(responses, name)(m)
|
||||
return json.dumps({'result': res}).encode()
|
||||
|
||||
raise ValueError(f'‘{req_str}’: malformed query path')
|
||||
|
|
@ -17,6 +17,19 @@ from wsgiref.util import request_uri
|
|||
|
||||
from . import ThornodeServer
|
||||
|
||||
ping_info = {'ping': 'pong'}
|
||||
|
||||
lastblock_info = [{
|
||||
'chain': 'BTC',
|
||||
'last_observed_in': 969302,
|
||||
'last_signed_out': 28043381,
|
||||
'thorchain': 28043387
|
||||
}, {
|
||||
'chain': 'ETH',
|
||||
'last_observed_in': 26090346,
|
||||
'last_signed_out': 28043381,
|
||||
'thorchain': 28043387}]
|
||||
|
||||
class ThornodeRPCServer(ThornodeServer):
|
||||
port = 18800
|
||||
name = 'thornode RPC server'
|
||||
|
|
@ -74,7 +87,20 @@ class ThornodeRPCServer(ThornodeServer):
|
|||
res.update({'hash': 'BD30B8FD9FC278A26E7A81ABB36C4709260DE64087EB578900BD23CEBF11D1A2'})
|
||||
return res
|
||||
|
||||
def ping(m, length):
|
||||
return ping_info
|
||||
|
||||
def lastblock(m, length):
|
||||
return lastblock_info
|
||||
|
||||
def inbound_addrs(m, length):
|
||||
with open('test/ref/thorchain/inbound.json') as fh:
|
||||
return json.loads(fh.read())
|
||||
|
||||
pat_info = ( # these are matched in order, so more specific patterns must go first
|
||||
('ping', 'GET', r'/thorchain/ping'),
|
||||
('lastblock', 'GET', r'/thorchain/lastblock(.*)'),
|
||||
('inbound_addrs', 'GET', r'/thorchain/inbound_addresses'),
|
||||
('balance', 'GET', r'/bank/balances/(\S+)'),
|
||||
('acct_info', 'GET', r'/auth/accounts/(\S+)'),
|
||||
('tx_info', 'POST', r'/tx$'),
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ cmd_groups_dfl = {
|
|||
'regtest': gd('CmdTestRegtest', {}),
|
||||
'op_return': gd('CmdTestOpReturn', {}),
|
||||
'swap': gd('CmdTestSwap', {}),
|
||||
'remote': gd('CmdTestRemote', {}),
|
||||
'ethswap': gd('CmdTestEthSwap', {}),
|
||||
# 'chainsplit': gd('CmdTestChainsplit', {}),
|
||||
'ethdev': gd('CmdTestEthdev', {}),
|
||||
|
|
|
|||
72
test/cmdtest_d/remote.py
Executable file
72
test/cmdtest_d/remote.py
Executable file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
||||
# Copyright (C)2013-2026 The MMGen Project <mmgen@tuta.io>
|
||||
# Licensed under the GNU General Public License, Version 3:
|
||||
# https://www.gnu.org/licenses
|
||||
# Public project repositories:
|
||||
# https://github.com/mmgen/mmgen-wallet
|
||||
# https://gitlab.com/mmgen/mmgen-wallet
|
||||
|
||||
"""
|
||||
test.cmdtest_d.remote: THORChain remote RPC tests for the cmdtest.py test suite
|
||||
"""
|
||||
|
||||
from .base import CmdTestBase
|
||||
from .swap import CmdTestSwapMethods
|
||||
from .rune import CmdTestRuneMethods
|
||||
|
||||
class CmdTestRemote(CmdTestBase, CmdTestSwapMethods, CmdTestRuneMethods):
|
||||
'fetching data from remote JSON-RPC server'
|
||||
|
||||
networks = ('btc',)
|
||||
tmpdir_nums = [37]
|
||||
thornode_servers = ('rpc', 'midgard')
|
||||
|
||||
cmd_group = (
|
||||
('ping', 'pinging remote REST server'),
|
||||
('health', 'checking health of THORChain network'),
|
||||
('inbounds', 'getting inbound addresses (all coins)'),
|
||||
('inbound_ltc', 'getting inbound address for LTC'),
|
||||
('lastblock', 'getting lastblock info'),
|
||||
('lastblock_btc', 'getting lastblock info for BTC'),
|
||||
('actions_addr', 'getting actions for address'),
|
||||
('actions_txid', 'getting actions for txid'),
|
||||
('actions_addr_txid', 'getting actions for txid and addr'),
|
||||
('stop_thornode_servers','stopping the Thornode RPC and Midgard servers'))
|
||||
|
||||
def __init__(self, cfg, trunner, cfgs, spawn):
|
||||
super().__init__(cfg, trunner, cfgs, spawn)
|
||||
if trunner is None:
|
||||
return
|
||||
self.start_thornode_servers()
|
||||
|
||||
def ping(self, *, asset=None):
|
||||
return self._rune_remote('ping')
|
||||
|
||||
def health(self, *, asset=None):
|
||||
return self._rune_remote('health')
|
||||
|
||||
def inbounds(self):
|
||||
return self._rune_remote('inbound_addrs')
|
||||
|
||||
def inbound_ltc(self):
|
||||
return self._rune_remote('inbound_addrs', ['coin=ltc'])
|
||||
|
||||
def lastblock(self, *, asset=None):
|
||||
return self._rune_remote('lastblock')
|
||||
|
||||
def lastblock_btc(self, *, asset=None):
|
||||
return self._rune_remote('lastblock', ['coin=btc'])
|
||||
|
||||
def actions_addr(self, *, asset=None):
|
||||
return self._rune_remote('actions', ['addr=thor1abcdefg'])
|
||||
|
||||
def actions_txid(self, *, asset=None):
|
||||
return self._rune_remote('actions', ['txid=deadbeef'])
|
||||
|
||||
def actions_addr_txid(self, *, asset=None):
|
||||
return self._rune_remote('actions', ['addr=thor1abcdefg', 'txid=deadbeef'])
|
||||
|
||||
def stop_servers(self):
|
||||
self.stop_thornode_servers(['rpc','midgard'])
|
||||
|
|
@ -16,7 +16,7 @@ from hashlib import md5
|
|||
|
||||
from mmgen.fileutil import get_data_from_file
|
||||
|
||||
from .include.common import dfl_words_file
|
||||
from .include.common import dfl_words_file, cleanup_env
|
||||
from .include.proxy import TestProxy
|
||||
from .ethdev import CmdTestEthdevMethods
|
||||
from .base import CmdTestBase
|
||||
|
|
@ -77,6 +77,12 @@ class CmdTestRuneMethods:
|
|||
return 'ok'
|
||||
return t
|
||||
|
||||
def _rune_remote(self, cmd, cmd_args=(), color=True):
|
||||
return self.spawn(
|
||||
'mmgen-remote',
|
||||
['--coin=rune', '--regtest=1', f'--color={int(color)}'] + [cmd] + list(cmd_args),
|
||||
env = cleanup_env(self.cfg))
|
||||
|
||||
class CmdTestRune(CmdTestRuneMethods, CmdTestEthdevMethods, CmdTestBase, CmdTestShared):
|
||||
'THORChain RUNE tracking wallet and transacting operations'
|
||||
networks = ('rune',)
|
||||
|
|
|
|||
1
test/ref/thorchain/inbound.json
Normal file
1
test/ref/thorchain/inbound.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
[{"chain":"BCH","pub_key":"thorpub1addwnpepqvg02tp8umuqp36wy5ptpeqavkdu58gk0z8e7amnjyh3cpslfq9fqxhlmvp","address":"qpxmqf20pnzywzmjevclquekjzlvq5hx25s4ucj53r","halted":false,"global_trading_paused":false,"chain_trading_paused":false,"chain_lp_actions_paused":false,"observed_fee_rate":"2","gas_rate":"3","gas_rate_units":"satsperbyte","outbound_tx_size":"1500","outbound_fee":"74450","dust_threshold":"10000"},{"chain":"BTC","pub_key":"thorpub1addwnpepqvg02tp8umuqp36wy5ptpeqavkdu58gk0z8e7amnjyh3cpslfq9fqxhlmvp","address":"bc1qfkcz2ncvc3rskuktx8c8xd5shmq99ej45gq8wu","halted":false,"global_trading_paused":false,"chain_trading_paused":false,"chain_lp_actions_paused":false,"observed_fee_rate":"4","gas_rate":"6","gas_rate_units":"satsperbyte","outbound_tx_size":"1000","outbound_fee":"2120","dust_threshold":"1000"},{"chain":"ETH","pub_key":"thorpub1addwnpepqvg02tp8umuqp36wy5ptpeqavkdu58gk0z8e7amnjyh3cpslfq9fqxhlmvp","address":"0x41c88d3c0eda3f4df0bb4e5d0f4c81cc0232902c","router":"0xD37BbE5744D730a1d98d8DC97c42F0Ca46aD7146","halted":false,"global_trading_paused":false,"chain_trading_paused":false,"chain_lp_actions_paused":false,"observed_fee_rate":"10","gas_rate":"15","gas_rate_units":"gwei","outbound_tx_size":"100000","outbound_fee":"9190","dust_threshold":"1000"},{"chain":"LTC","pub_key":"thorpub1addwnpepqvg02tp8umuqp36wy5ptpeqavkdu58gk0z8e7amnjyh3cpslfq9fqxhlmvp","address":"rltc1qlvwym7fha5cuvs0c2vy2l86r7a8ayt8chwqsyr","halted":false,"global_trading_paused":false,"chain_trading_paused":false,"chain_lp_actions_paused":false,"observed_fee_rate":"74","gas_rate":"111","gas_rate_units":"satsperbyte","outbound_tx_size":"250","outbound_fee":"355075","dust_threshold":"100000"}]
|
||||
|
|
@ -311,6 +311,7 @@ init_tests() {
|
|||
t_rune="
|
||||
- $cmdtest_py --coin=rune rune
|
||||
- $cmdtest_py --coin=ltc runeswap
|
||||
- $cmdtest_py remote
|
||||
"
|
||||
|
||||
[ "$SOC" ] && xmr_env=(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue