Browse Source

support Monero integrated addresses

The MMGen Project 2 years ago
parent
commit
a78be65214
5 changed files with 28 additions and 7 deletions
  1. 1 1
      mmgen/data/release_date
  2. 1 1
      mmgen/data/version
  3. 7 4
      mmgen/proto/xmr.py
  4. 5 0
      mmgen/xmrwallet.py
  5. 14 1
      test/unit_tests_d/ut_addrparse.py

+ 1 - 1
mmgen/data/release_date

@@ -1 +1 @@
-August 2022
+September 2022

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-13.2.0
+13.3.dev0

+ 7 - 4
mmgen/proto/xmr.py

@@ -16,7 +16,7 @@ from collections import namedtuple
 
 from ..protocol import CoinProtocol,_nw
 
-parsed_addr = namedtuple('parsed_addr',['ver_bytes','data'])
+parsed_addr = namedtuple('parsed_addr',['ver_bytes','data','payment_id'])
 
 # https://github.com/monero-project/monero/blob/master/src/cryptonote_config.h
 class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Base):
@@ -24,8 +24,7 @@ class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Base):
 	network_names  = _nw('mainnet','stagenet',None)
 	base_coin      = 'XMR'
 	base_proto     = 'Monero'
-	addr_ver_bytes = { '12': 'monero', '2a': 'monero_sub' }
-	addr_len       = 64
+	addr_ver_bytes = { '12': 'monero', '2a': 'monero_sub', '13': 'monero_integrated' }
 	wif_ver_num    = {}
 	pubkey_types   = ('monero',)
 	mmtypes        = ('M',)
@@ -37,6 +36,9 @@ class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Base):
 	ignore_daemon_version = False
 	coin_amt       = 'XMRAmt'
 
+	def get_addr_len(self,addr_fmt):
+		return (64,72)[addr_fmt == 'monero_integrated']
+
 	def preprocess_key(self,sec,pubkey_type): # reduce key
 		from ..contrib.ed25519 import l
 		return int.to_bytes(
@@ -68,10 +70,11 @@ class mainnet(CoinProtocol.DummyWIF,CoinProtocol.Base):
 		return parsed_addr(
 			ver_bytes  = ver_bytes,
 			data       = addr_bytes[:addr_len],
+			payment_id = addr_bytes[addr_len:] if fmt == 'monero_integrated' else None,
 		)
 
 	def pubhash2addr(self,*args,**kwargs):
 		raise NotImplementedError('Monero addresses do not support pubhash2addr()')
 
 class testnet(mainnet): # use stagenet for testnet
-	addr_ver_bytes = { '18': 'monero', '24': 'monero_sub' } # testnet is ('35','3f')
+	addr_ver_bytes = { '18': 'monero', '24': 'monero_sub', '19': 'monero_integrated' } # testnet is {'35','3f','36'}

+ 5 - 0
mmgen/xmrwallet.py

@@ -137,6 +137,10 @@ class MoneroMMGenTX:
 				  Dest: {}
 			"""
 
+			pmid = d.dest_address.parsed.payment_id
+			if pmid:
+				fs += '  Payment ID: {pmid}'
+
 			return fmt(fs,strip_char='\t',indent=indent).format(
 					d.seed_id.hl(), d.network.upper(),
 					d.txid.hl(),
@@ -147,6 +151,7 @@ class MoneroMMGenTX:
 					d.amount.hl(),
 					d.fee.hl(),
 					d.dest_address.hl(),
+					pmid = pink(pmid.hex()) if pmid else None
 				)
 
 		def write(self,delete_metadata=False):

+ 14 - 1
test/unit_tests_d/ut_addrparse.py

@@ -19,8 +19,13 @@ vectors = {
 	'xmr_mainnet': [
 		{ # ut_xmrseed.vectors[0]:
 'std': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm',
+# https://github.com/monero-project/monero/tests/functional_tests/integrated_address.py
+'int': '4CMe2PUhs4J4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfSbLRB61BQVATzerHGj',
+'id':  '0123456789abcdef'
 		},{
 'std': '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK',
+'int': '4GYjoMG9Y2BBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCVSs1ZojwrDCGS5rUuo',
+'id':  '1122334455667788'
 		}
 	],
 	'zec_mainnet': [
@@ -43,7 +48,7 @@ def test_network(proto,addrs):
 				addr.parsed.ver_bytes,
 				proto.addr_fmt_to_ver_bytes.get(addr.addr_fmt) )
 		check_equal(
-			addr.parsed.data,
+			addr.parsed.data + ((addr.parsed.payment_id or b'') if proto.coin == 'XMR' else b''),
 			addr.bytes )
 
 	def fmt_addr_data(addr):
@@ -64,6 +69,14 @@ def test_network(proto,addrs):
 		a1 = CoinAddr(proto,addr['std'])
 		print_info(a1)
 		check_bytes(a1)
+		assert not hasattr(a1.parsed,'payment_id') or a1.parsed.payment_id == None
+
+		if 'int' in addr:
+			a2 = CoinAddr(proto,addr['int'])
+			print_info(a2)
+			check_bytes(a2)
+			check_equal( a1.parsed.data, a2.parsed.data )
+			check_equal( a2.parsed.payment_id, bytes.fromhex(addr['id']) )
 
 	msg('OK')
 	vmsg('')