mmgen-swaptxcreate: new --list-assets option; related cleanups

This commit is contained in:
The MMGen Project 2025-04-26 10:38:55 +00:00
commit 67ef5d3987
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
6 changed files with 97 additions and 21 deletions

View file

@ -22,7 +22,7 @@ mmgen-txcreate: Create a cryptocoin transaction with MMGen- and/or non-MMGen
"""
from .cfg import gc, Config
from .util import fmt_list, async_run
from .util import Msg, fmt_list, async_run
target = gc.prog_name.split('-')[1].removesuffix('create')
@ -73,6 +73,7 @@ opts_data = {
+ according to BIP 125)
-s -s, --swap-proto Swap protocol to use (Default: {x_dfl},
+ Choices: {x_all})
-s -S, --list-assets List available swap assets
-- -v, --verbose Produce more verbose output
b- -V, --vsize-adj= f Adjust transaction's estimated vsize by factor 'f'
-s -x, --proxy=P Fetch the swap quote via SOCKS5 proxy P (host:port)
@ -104,6 +105,13 @@ opts_data = {
cfg = Config(opts_data=opts_data)
if cfg.list_assets:
import sys
from .tx.new_swap import get_swap_proto_mod
sp = get_swap_proto_mod(cfg.swap_proto)
Msg('AVAILABLE SWAP ASSETS:\n' + sp.SwapAsset('BTC', 'send').fmt_assets_data(indent=' '))
sys.exit(0)
if not (cfg.info or cfg.contract_data) and len(cfg._args) < {'tx': 1, 'swaptx': 2}[target]:
cfg._usage()

View file

@ -18,19 +18,56 @@ from ..util import die
class SwapAsset:
_ad = namedtuple('swap_asset_data', ['desc', 'name', 'full_name', 'abbr'])
_ad = namedtuple('swap_asset_data', ['desc', 'name', 'full_name', 'abbr', 'tested'])
assets_data = {}
send = ()
recv = ()
evm_contracts = {}
unsupported = ()
blacklisted = {}
evm_chains = ()
def fmt_assets_data(self, indent=''):
def gen_good():
fs = '%s{:10} {:23} {:9} {}' % indent
yield fs.format('ASSET', 'DESCRIPTION', 'STATUS', 'CONTRACT ADDRESS')
for k, v in self.assets_data.items():
if not k in self.blacklisted:
if k in self.send or k in self.recv:
yield fs.format(
k,
v.desc,
'tested' if v.tested else 'untested',
self.evm_contracts.get(k,'-'))
def gen_bad():
if self.blacklisted:
fs = '%s{:10} {:23} {}' % indent
yield '\n\nBlacklisted assets:'
yield fs.format('ASSET', 'DESCRIPTION', 'REASON')
for k, v in self.blacklisted.items():
yield fs.format(k, self.assets_data[k].desc, v)
return '\n'.join(gen_good()) + '\n'.join(gen_bad())
@classmethod
def get_full_name(self, s):
for d in self.assets_data.values():
def get_full_name(cls, s):
for d in cls.assets_data.values():
if s in (d.abbr, d.full_name):
return d.full_name or f'{d.name}.{d.name}'
die('SwapAssetError', f'{s!r}: unrecognized asset name or abbreviation')
@property
def tested(self):
return [k for k, v in self.assets_data.items() if v.tested]
@property
def send(self):
return set(self.assets_data) - set(self.unsupported) - set(self.blacklisted)
@property
def recv(self):
return set(self.assets_data) - set(self.unsupported) - set(self.blacklisted)
@property
def chain(self):
return self.data.full_name.split('.', 1)[0] if self.data.full_name else self.name

View file

@ -18,14 +18,18 @@ class THORChainSwapAsset(SwapAsset):
_ad = SwapAsset._ad
assets_data = {
'BTC': _ad('Bitcoin', 'BTC', None, 'b'),
'LTC': _ad('Litecoin', 'LTC', None, 'l'),
'BCH': _ad('Bitcoin Cash', 'BCH', None, 'c'),
'ETH': _ad('Ethereum', 'ETH', None, 'e'),
'DOGE': _ad('Dogecoin', 'DOGE', None, 'd'),
'RUNE': _ad('Rune (THORChain)', 'RUNE', 'THOR.RUNE', 'r'),
'BTC': _ad('Bitcoin', 'BTC', None, 'b', True),
'LTC': _ad('Litecoin', 'LTC', None, 'l', True),
'BCH': _ad('Bitcoin Cash', 'BCH', None, 'c', True),
'ETH': _ad('Ethereum', 'ETH', None, 'e', True),
'DOGE': _ad('Dogecoin', 'DOGE', None, 'd', False),
'RUNE': _ad('Rune (THORChain)', 'RUNE', 'THOR.RUNE', 'r', False),
}
send = ('BTC', 'LTC', 'BCH', 'ETH')
recv = ('BTC', 'LTC', 'BCH', 'ETH')
evm_contracts = {}
unsupported = ('DOGE', 'RUNE')
blacklisted = {}
evm_chains = ('ETH', 'AVAX', 'BSC', 'BASE')

View file

@ -107,7 +107,7 @@ class NewSwap(New):
arg = get_arg()
# arg 3: chg_spec (change address spec)
if args.send_amt and not (self.proto.is_evm or arg in sp.SwapAsset.recv): # is change arg
if args.send_amt and not (self.proto.is_evm or arg in sa.recv): # is change arg
nonlocal chg_output
chg_output = await self.get_chg_output(arg, addrfiles)
arg = get_arg()
@ -124,12 +124,21 @@ class NewSwap(New):
self.cfg._usage()
sp = self.swap_proto_mod
sa = sp.SwapAsset('BTC', 'send')
args_in = list(cmd_args)
args = CmdlineArgs()
chg_output = None
await parse()
for a in (self.send_asset, self.recv_asset):
if a.name not in sa.tested:
from ..util import msg, ymsg
from ..term import get_char
ymsg(f'Warning: {a.direction} asset {a.name} is untested by the MMGen Project')
get_char('Press any key to continue: ')
msg('')
if args.send_amt and not (chg_output or self.proto.is_evm):
chg_output = await self.get_chg_output(None, addrfiles)

View file

@ -272,6 +272,7 @@ class CmdTestSwap(CmdTestSwapMethods, CmdTestRegtest, CmdTestAutosignThreaded):
need_daemon = True
cmd_group_in = (
('list_assets', 'listing swap assets'),
('subgroup.init_data', []),
('subgroup.data', ['init_data']),
('subgroup.init_swap', []),
@ -416,6 +417,14 @@ class CmdTestSwap(CmdTestSwapMethods, CmdTestRegtest, CmdTestAutosignThreaded):
def sid(self):
return self._user_sid('bob')
def list_assets(self):
t = self.spawn('mmgen-swaptxcreate', ['--list-assets'])
t.expect('AVAILABLE')
t.expect('ETH.MM1')
t.expect('Blacklisted')
t.expect('ETH.JUNK')
return t
def walletcreate_bob(self):
dest = Path(self.tr.data_dir, 'regtest', 'bob')
dest.mkdir(exist_ok=True)

View file

@ -3,12 +3,21 @@ from .asset_orig import *
class overlay_fake_THORChainSwapAsset:
assets_data = {
'ETH.MM1': THORChainSwapAsset._ad('MM1 Token (ETH)', None, 'ETH.MM1', None),
'ETH.USDT': THORChainSwapAsset._ad('Tether (ETH)', None, 'ETH.USDT', None)
'ETH.USDT': THORChainSwapAsset._ad('Tether (ETH)', None, 'ETH.USDT', None, True),
'ETH.MM1': THORChainSwapAsset._ad('MM1 Token (ETH)', None, 'ETH.MM1', None, True),
'ETH.JUNK': THORChainSwapAsset._ad('Junk Token (ETH)', None, 'ETH.JUNK', None, True),
'ETH.NONE': THORChainSwapAsset._ad('Unavailable Token (ETH)', None, 'ETH.NONE', None, True)
}
evm_contracts = {
'ETH.MM1': 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeef'
}
unsupported = ('ETH.NONE',)
blacklisted = {
'ETH.JUNK': 'Because it’s junk',
}
send = ('ETH.MM1',)
recv = ('ETH.MM1', 'ETH.USDT')
THORChainSwapAsset.assets_data |= overlay_fake_THORChainSwapAsset.assets_data
THORChainSwapAsset.send += overlay_fake_THORChainSwapAsset.send
THORChainSwapAsset.recv += overlay_fake_THORChainSwapAsset.recv
THORChainSwapAsset.unsupported += overlay_fake_THORChainSwapAsset.unsupported
THORChainSwapAsset.blacklisted.update(overlay_fake_THORChainSwapAsset.blacklisted)
THORChainSwapAsset.evm_contracts.update(overlay_fake_THORChainSwapAsset.evm_contracts)