Browse Source

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

The MMGen Project 7 months ago
parent
commit
67ef5d3987

+ 9 - 1
mmgen/main_txcreate.py

@@ -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()
 

+ 42 - 5
mmgen/swap/asset.py

@@ -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

+ 12 - 8
mmgen/swap/proto/thorchain/asset.py

@@ -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')

+ 10 - 1
mmgen/tx/new_swap.py

@@ -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)
 

+ 9 - 0
test/cmdtest_d/swap.py

@@ -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)

+ 15 - 6
test/overlay/fakemods/mmgen/swap/proto/thorchain/asset.py

@@ -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)