new mmgen-cli utility
Communicate with all your coin daemons from a single utility!
Usage information and examples:
$ mmgen-cli --help
This commit is contained in:
parent
ef8e994266
commit
94bee46cb8
11 changed files with 179 additions and 14 deletions
16
cmds/mmgen-cli
Executable file
16
cmds/mmgen-cli
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
||||
# Copyright (C)2013-2025 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-cli: Communicate with a coin daemon via its JSON-RPC interface
|
||||
"""
|
||||
|
||||
from mmgen.main import launch
|
||||
launch(mod='cli')
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
* [mmgen-addrgen](commands/command-help-addrgen.md)
|
||||
* [mmgen-addrimport](commands/command-help-addrimport.md)
|
||||
* [mmgen-autosign](commands/command-help-autosign.md)
|
||||
* [mmgen-cli](commands/command-help-cli.md)
|
||||
* [mmgen-keygen](commands/command-help-keygen.md)
|
||||
* [mmgen-msg](commands/command-help-msg.md)
|
||||
* [mmgen-passchg](commands/command-help-passchg.md)
|
||||
|
|
|
|||
35
doc/wiki/commands/command-help-cli.md
Normal file
35
doc/wiki/commands/command-help-cli.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
```text
|
||||
MMGEN-CLI: Communicate with a coin daemon via its JSON-RPC interface
|
||||
USAGE: mmgen-cli [opts] <command> <command args>
|
||||
OPTIONS:
|
||||
-h, --help Print this help message
|
||||
--longhelp Print help message for long (global) options
|
||||
-a, --ascii-output Ensure that output is ASCII encoded
|
||||
-w, --wallet NAME Use tracking wallet with name NAME
|
||||
|
||||
|
||||
The utility accepts all MMGen global configuration options and sources the user
|
||||
config file, allowing users to preconfigure hosts, ports, passwords, datadirs,
|
||||
tracking wallets and so forth, thus saving a great deal of typing at the
|
||||
command line. This behavior may be overridden with the --skip-cfg-file option.
|
||||
|
||||
Arguments are given in JSON format, with lowercase ‘true’, ‘false’ and ‘null’
|
||||
for booleans and None, and double-quoted strings in dicts and lists.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
|
||||
$ mmgen-cli --wallet=wallet2 listreceivedbyaddress 0 true
|
||||
|
||||
$ mmgen-cli --coin=ltc --rpc-host=orion getblockcount
|
||||
|
||||
$ mmgen-cli --regtest=1 --wallet=bob getbalance
|
||||
|
||||
$ mmgen-cli --coin=eth eth_getBalance 0x00000000219ab540356cBB839Cbe05303d7705Fa latest
|
||||
|
||||
$ mmgen-cli createrawtransaction \
|
||||
'[{"txid":"832f5aa9af55dc453314e26869c8f96db1f2a9acac9f23ae18d396903971e0c6","vout":0}]' \
|
||||
'[{"1111111111111111111114oLvT2":0.001}]'
|
||||
|
||||
MMGEN v15.1.dev19 March 2025 MMGEN-CLI(1)
|
||||
```
|
||||
|
|
@ -62,6 +62,7 @@ class GlobalConstants(Lockable):
|
|||
'addrgen': _cc(True, False, True, None, [], 'lmw'),
|
||||
'addrimport': _cc(True, True, True, None, ['tw'], 'lmw'),
|
||||
'autosign': _cc(True, True, False, '-rRb', ['rpc'], 'lm'),
|
||||
'cli': _cc(True, True, True, None, ['tw'], 'lmw'),
|
||||
'keygen': _cc(True, False, True, None, [], 'lmw'),
|
||||
'msg': _cc(True, True, True, None, ['msg'], 'lmw'),
|
||||
'passchg': _cc(False, False, False, None, [], 'lmw'),
|
||||
|
|
|
|||
74
mmgen/main_cli.py
Executable file
74
mmgen/main_cli.py
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# MMGen Wallet, a terminal-based cryptocurrency wallet
|
||||
# Copyright (C)2013-2025 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-cli: Communicate with a coin daemon via its JSON-RPC interface
|
||||
"""
|
||||
|
||||
import asyncio, json
|
||||
|
||||
from .util2 import cliargs_convert
|
||||
from .cfg import gc, Config
|
||||
from .rpc import rpc_init, json_encoder
|
||||
|
||||
opts_data = {
|
||||
'text': {
|
||||
'desc': 'Communicate with a coin daemon via its JSON-RPC interface',
|
||||
'usage': '[opts] <command> <command args>',
|
||||
'options': """
|
||||
-h, --help Print this help message
|
||||
--, --longhelp Print help message for long (global) options
|
||||
-a, --ascii-output Ensure that output is ASCII encoded
|
||||
-w, --wallet=NAME Use tracking wallet with name NAME
|
||||
""",
|
||||
'notes': """
|
||||
|
||||
The utility accepts all {pn} global configuration options and sources the user
|
||||
config file, allowing users to preconfigure hosts, ports, passwords, datadirs,
|
||||
tracking wallets and so forth, thus saving a great deal of typing at the
|
||||
command line. This behavior may be overridden with the --skip-cfg-file option.
|
||||
|
||||
Arguments are given in JSON format, with lowercase ‘true’, ‘false’ and ‘null’
|
||||
for booleans and None, and double-quoted strings in dicts and lists.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
|
||||
$ mmgen-cli --wallet=wallet2 listreceivedbyaddress 0 true
|
||||
|
||||
$ mmgen-cli --coin=ltc --rpc-host=orion getblockcount
|
||||
|
||||
$ mmgen-cli --regtest=1 --wallet=bob getbalance
|
||||
|
||||
$ mmgen-cli --coin=eth eth_getBalance 0x00000000219ab540356cBB839Cbe05303d7705Fa latest
|
||||
|
||||
$ mmgen-cli createrawtransaction \\
|
||||
'[{{"txid":"832f5aa9af55dc453314e26869c8f96db1f2a9acac9f23ae18d396903971e0c6","vout":0}}]' \\
|
||||
'[{{"1111111111111111111114oLvT2":0.001}}]'
|
||||
"""
|
||||
},
|
||||
'code': {
|
||||
'notes': lambda cfg, s, help_notes: s.format(
|
||||
pn = gc.proj_name)
|
||||
}
|
||||
}
|
||||
|
||||
cfg = Config(opts_data=opts_data)
|
||||
cmd, *args = cfg._args
|
||||
|
||||
async def main():
|
||||
|
||||
c = await rpc_init(cfg)
|
||||
ret = await c.call(cmd, *cliargs_convert(args), wallet=cfg.wallet)
|
||||
print(
|
||||
(ascii(ret) if cfg.ascii_output else ret) if isinstance(ret, str) else
|
||||
json.dumps(ret, cls=json_encoder, indent=4, ensure_ascii=cfg.ascii_output))
|
||||
|
||||
asyncio.run(main())
|
||||
|
|
@ -22,6 +22,7 @@ proto.btc.regtest: Coin daemon regression test mode setup and operations
|
|||
|
||||
import os, shutil, json
|
||||
from ...util import msg, gmsg, die, capfirst, suf
|
||||
from ...util2 import cliargs_convert
|
||||
from ...protocol import init_proto
|
||||
from ...rpc import rpc_init, json_encoder
|
||||
from ...objmethods import MMGenObject
|
||||
|
|
@ -46,16 +47,6 @@ def create_data_dir(cfg, data_dir):
|
|||
except:
|
||||
pass
|
||||
|
||||
def cliargs_convert(args):
|
||||
def gen():
|
||||
for arg in args:
|
||||
try:
|
||||
yield json.loads(arg) # list, dict, bool, int, null
|
||||
except:
|
||||
yield arg # arbitrary string
|
||||
|
||||
return tuple(gen())
|
||||
|
||||
class MMGenRegtest(MMGenObject):
|
||||
|
||||
rpc_user = 'bobandalice'
|
||||
|
|
|
|||
|
|
@ -197,6 +197,22 @@ def decode_pretty_hexdump(data):
|
|||
msg('Data not in hexdump format')
|
||||
return False
|
||||
|
||||
def cliargs_convert(args):
|
||||
|
||||
# return str instead of float for input into JSON-RPC
|
||||
def float_parser(n):
|
||||
return n
|
||||
|
||||
import json
|
||||
def gen():
|
||||
for arg in args:
|
||||
try:
|
||||
yield json.loads(arg, parse_float=float_parser) # list, dict, bool, int, null, float
|
||||
except json.decoder.JSONDecodeError:
|
||||
yield arg # arbitrary string
|
||||
|
||||
return tuple(gen())
|
||||
|
||||
class ExpInt(int):
|
||||
'encode or parse an integer in exponential notation with specified precision'
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ scripts =
|
|||
cmds/mmgen-addrgen
|
||||
cmds/mmgen-addrimport
|
||||
cmds/mmgen-autosign
|
||||
cmds/mmgen-cli
|
||||
cmds/mmgen-keygen
|
||||
cmds/mmgen-msg
|
||||
cmds/mmgen-passchg
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
|
|||
('addrimport', 'importing addresses'),
|
||||
('addrimport_dev_addr', "importing dev faucet address 'Ox00a329c..'"),
|
||||
('fund_dev_address', 'funding the default (Parity dev) address'),
|
||||
('cli_dev_balance', 'mmgen-cli eth_getBalance'),
|
||||
),
|
||||
'msg': (
|
||||
'message signing',
|
||||
|
|
@ -568,6 +569,14 @@ class CmdTestEthdev(CmdTestBase, CmdTestShared):
|
|||
t.expect('version')
|
||||
return t
|
||||
|
||||
def cli_dev_balance(self):
|
||||
t = self.spawn(
|
||||
'mmgen-cli',
|
||||
[f'--coin={self.proto.coin}', '--regtest=1', 'eth_getBalance', '0x'+dfl_devaddr, 'latest'])
|
||||
if self.daemon.id == 'geth':
|
||||
t.expect('0x33b2e3c91ec0e9113986000')
|
||||
return t
|
||||
|
||||
async def _wallet_upgrade(self, src_fn, expect1, expect2=None):
|
||||
if self.proto.coin == 'ETC':
|
||||
msg(f'skipping test {self.test_name!r} for ETC')
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
|
|||
'miscellaneous commands',
|
||||
('daemon_version', 'mmgen-tool daemon_version'),
|
||||
('halving_calculator_bob', 'halving calculator (Bob)'),
|
||||
('cli_txcreate', '‘mmgen-cli createrawtransaction’'),
|
||||
),
|
||||
'init_bob': (
|
||||
'creating Bob’s MMGen wallet and tracking wallet',
|
||||
|
|
@ -223,7 +224,7 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
|
|||
('fund_bob', 'funding Bob’s wallet'),
|
||||
('fund_alice', 'funding Alice’s wallet'),
|
||||
('generate', 'mining a block'),
|
||||
('bob_bal1', 'Bob’s balance'),
|
||||
('bob_bal1_cli', 'Bob’s balance (via ‘mmgen-cli’)'),
|
||||
('generate_extra_deterministic', 'generate extra blocks for deterministic run'),
|
||||
),
|
||||
'msg': (
|
||||
|
|
@ -547,6 +548,18 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
|
|||
t.expect('time until halving')
|
||||
return t
|
||||
|
||||
def cli_txcreate(self):
|
||||
txid = 'beadcafe' * 8
|
||||
return self.spawn(
|
||||
'mmgen-cli',
|
||||
[
|
||||
'--regtest=1',
|
||||
f'--coin={self.proto.coin}',
|
||||
'createrawtransaction',
|
||||
f'[{{"txid":"{txid}","vout":7}}]',
|
||||
f'[{{"{self.burn_addr}":0.001}}]'
|
||||
])
|
||||
|
||||
def walletgen(self, user):
|
||||
t = self.spawn('mmgen-walletgen', ['-q', '-r0', '-p1', f'--{user}'], no_passthru_opts=True)
|
||||
t.passphrase_new(f'new {dfl_wcls.desc}', rt_pw)
|
||||
|
|
@ -777,8 +790,12 @@ class CmdTestRegtest(CmdTestBase, CmdTestShared):
|
|||
def alice_bal2(self):
|
||||
return self.user_bal('alice', rtBals[8])
|
||||
|
||||
def bob_bal1(self):
|
||||
return self.user_bal('bob', rtFundAmt, self._cashaddr_opt(0))
|
||||
def bob_bal1_cli(self):
|
||||
t = self.spawn(
|
||||
'mmgen-cli',
|
||||
['--regtest=1', '--wallet=bob', f'--coin={self.proto.coin}', 'getbalance', '*', '0', 'true'])
|
||||
t.expect(rtFundAmt + '.00')
|
||||
return t
|
||||
|
||||
def bob_bal2(self):
|
||||
return self.user_bal('bob', rtBals[0], self._cashaddr_opt(1))
|
||||
|
|
|
|||
|
|
@ -230,7 +230,11 @@ init_tests() {
|
|||
t_ltc_rt="- $cmdtest_py --coin=ltc regtest"
|
||||
|
||||
d_eth="operations for Ethereum using devnet"
|
||||
t_eth="geth $cmdtest_py --coin=eth ethdev"
|
||||
t_eth="
|
||||
geth $cmdtest_py --coin=eth ethdev
|
||||
reth $cmdtest_py --coin=eth --daemon-id=reth ethdev
|
||||
"
|
||||
[ "$FAST" ] && t_eth_skip='reth'
|
||||
|
||||
d_etc="operations for Ethereum Classic using devnet"
|
||||
t_etc="parity $cmdtest_py --coin=etc ethdev"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue