support THORChain address generation
Example:
$ mmgen-addrgen --coin=rune 1-10
Testing:
$ test/tooltest2.py -q --coin=rune
$ test/modtest.py -v bip_hd.multicoin
This commit is contained in:
parent
427834255e
commit
ba3b40c5b6
14 changed files with 135 additions and 5 deletions
|
|
@ -50,6 +50,7 @@ class MMGenAddrType(HiliteStr, InitErrors, MMGenObject):
|
||||||
'C': ati('compressed','std', True, 'p2pkh', 'p2pkh', 'wif', (), 'Compressed P2PKH address'),
|
'C': ati('compressed','std', True, 'p2pkh', 'p2pkh', 'wif', (), 'Compressed P2PKH address'),
|
||||||
'S': ati('segwit', 'std', True, 'segwit', 'p2sh', 'wif', (), 'Segwit P2SH-P2WPKH address'),
|
'S': ati('segwit', 'std', True, 'segwit', 'p2sh', 'wif', (), 'Segwit P2SH-P2WPKH address'),
|
||||||
'B': ati('bech32', 'std', True, 'bech32', 'bech32', 'wif', (), 'Native Segwit (Bech32) address'),
|
'B': ati('bech32', 'std', True, 'bech32', 'bech32', 'wif', (), 'Native Segwit (Bech32) address'),
|
||||||
|
'X': ati('bech32x', 'std', True, 'p2pkh', 'bech32', 'wif', (), 'Cross-chain Bech32 address'),
|
||||||
'E': ati('ethereum', 'std', False,'ethereum','p2pkh', 'privkey', ('wallet_passwd',),'Ethereum address'),
|
'E': ati('ethereum', 'std', False,'ethereum','p2pkh', 'privkey', ('wallet_passwd',),'Ethereum address'),
|
||||||
'Z': ati('zcash_z','zcash_z',False,'zcash_z', 'zcash_z', 'wif', ('viewkey',), 'Zcash z-address'),
|
'Z': ati('zcash_z','zcash_z',False,'zcash_z', 'zcash_z', 'wif', ('viewkey',), 'Zcash z-address'),
|
||||||
'M': ati('monero', 'monero', False,'monero', 'monero', 'spendkey',('viewkey','wallet_passwd'),'Monero address'),
|
'M': ati('monero', 'monero', False,'monero', 'monero', 'spendkey',('viewkey','wallet_passwd'),'Monero address'),
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ def AddrGenerator(cfg, proto, addr_type):
|
||||||
'compressed': 'btc',
|
'compressed': 'btc',
|
||||||
'segwit': 'btc',
|
'segwit': 'btc',
|
||||||
'bech32': 'btc',
|
'bech32': 'btc',
|
||||||
|
'bech32x': 'xchain',
|
||||||
'monero': 'xmr',
|
'monero': 'xmr',
|
||||||
'ethereum': 'eth',
|
'ethereum': 'eth',
|
||||||
'zcash_z': 'zec',
|
'zcash_z': 'zec',
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ def check_privkey(key_int):
|
||||||
|
|
||||||
class BipHDConfig(Lockable):
|
class BipHDConfig(Lockable):
|
||||||
|
|
||||||
supported_coins = ('btc', 'eth', 'doge', 'ltc', 'bch')
|
supported_coins = ('btc', 'eth', 'doge', 'ltc', 'bch', 'rune')
|
||||||
|
|
||||||
def __init__(self, base_cfg, coin, *, network, addr_type, from_path, no_path_checks):
|
def __init__(self, base_cfg, coin, *, network, addr_type, from_path, no_path_checks):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ def parse_data():
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
# RUNE derivation is SLIP-10, not BIP-44, but we treat them as equivalent
|
||||||
|
|
||||||
_data_in = """
|
_data_in = """
|
||||||
|
|
||||||
[defaults]
|
[defaults]
|
||||||
|
|
@ -105,6 +107,7 @@ IDX CHAIN CURVE NW ADDR_CLS VB_PRV VB_PUB VB_WIF VB_ADDR DFL_PA
|
||||||
784 SUI edw m Sui x x - - 0'/0'/0' Sui
|
784 SUI edw m Sui x x - - 0'/0'/0' Sui
|
||||||
818 VET x m Eth x x - - x VeChain Token
|
818 VET x m Eth x x - - x VeChain Token
|
||||||
888 NEO nist m Neo x x - spec x NEO
|
888 NEO nist m Neo x x - spec x NEO
|
||||||
|
931 RUNE x m BechP2PKH x x - h:thor x THORChain
|
||||||
996 OKT x m Okex x x - - x OKChain Token
|
996 OKT x m Okex x x - - x OKChain Token
|
||||||
1023 ONE x m One x x - - x HARMONY-ONE (Legacy)
|
1023 ONE x m One x x - - x HARMONY-ONE (Legacy)
|
||||||
1024 ONT nist m Neo x x - spec x Ontology
|
1024 ONT nist m Neo x x - spec x Ontology
|
||||||
|
|
@ -896,7 +899,6 @@ IDX CHAIN NAME
|
||||||
921 AVN - Avian Network
|
921 AVN - Avian Network
|
||||||
925 DIP - Dipper Network
|
925 DIP - Dipper Network
|
||||||
928 GHM - HermitMatrixNetwork
|
928 GHM - HermitMatrixNetwork
|
||||||
931 RUNE - THORChain (RUNE)
|
|
||||||
941 --- - reserved
|
941 --- - reserved
|
||||||
945 UNLOCK - Jasiri protocol
|
945 UNLOCK - Jasiri protocol
|
||||||
955 LTP - LifetionCoin
|
955 LTP - LifetionCoin
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
15.1.dev37
|
15.1.dev38
|
||||||
|
|
|
||||||
63
mmgen/proto/rune/params.py
Executable file
63
mmgen/proto/rune/params.py
Executable file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/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
|
||||||
|
|
||||||
|
"""
|
||||||
|
proto.rune.params: THORChain protocol
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ...protocol import CoinProtocol, decoded_addr, _nw
|
||||||
|
from ...addr import CoinAddr
|
||||||
|
from ...contrib import bech32
|
||||||
|
|
||||||
|
from ..btc.params import mainnet as btc_mainnet
|
||||||
|
|
||||||
|
class mainnet(CoinProtocol.Secp256k1):
|
||||||
|
mod_clsname = 'THORChain'
|
||||||
|
network_names = _nw('mainnet', 'stagenet', 'testnet')
|
||||||
|
mmtypes = ('X',)
|
||||||
|
preferred_mmtypes = ('X',)
|
||||||
|
dfl_mmtype = 'X'
|
||||||
|
coin_amt = 'UniAmt'
|
||||||
|
max_tx_fee = 1 # TODO
|
||||||
|
caps = ()
|
||||||
|
mmcaps = ()
|
||||||
|
base_proto = 'THORChain'
|
||||||
|
base_proto_coin = 'RUNE'
|
||||||
|
base_coin = 'RUNE'
|
||||||
|
bech32_hrp = 'thor'
|
||||||
|
sign_mode = 'standalone'
|
||||||
|
avg_bdi = 6 # TODO
|
||||||
|
address_reuse_ok = False
|
||||||
|
|
||||||
|
wif_ver_num = btc_mainnet.wif_ver_num
|
||||||
|
coin_cfg_opts = btc_mainnet.coin_cfg_opts
|
||||||
|
encode_wif = btc_mainnet.encode_wif
|
||||||
|
decode_wif = btc_mainnet.decode_wif
|
||||||
|
|
||||||
|
def decode_addr(self, addr):
|
||||||
|
hrp, data = bech32.bech32_decode(addr)
|
||||||
|
assert hrp == self.bech32_hrp, f'{hrp!r}: invalid bech32 hrp (should be {self.bech32_hrp!r})'
|
||||||
|
return decoded_addr(
|
||||||
|
bytes(bech32.convertbits(data, 5, 8)),
|
||||||
|
None,
|
||||||
|
'bech32') if data else False
|
||||||
|
|
||||||
|
def encode_addr_bech32x(self, pubhash):
|
||||||
|
return CoinAddr(
|
||||||
|
self,
|
||||||
|
bech32.bech32_encode(
|
||||||
|
hrp = self.bech32_hrp,
|
||||||
|
data = bech32.convertbits(list(pubhash), 8, 5)))
|
||||||
|
|
||||||
|
class stagenet(mainnet):
|
||||||
|
bech32_hrp = 'sthor'
|
||||||
|
|
||||||
|
class testnet(stagenet): # testnet is deprecated
|
||||||
|
bech32_hrp = 'tthor'
|
||||||
22
mmgen/proto/xchain/addrgen.py
Executable file
22
mmgen/proto/xchain/addrgen.py
Executable file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/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
|
||||||
|
|
||||||
|
"""
|
||||||
|
proto.xchain.addrgen: Cross-chain address generation classes for the MMGen suite
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ...addrgen import addr_generator, check_data
|
||||||
|
from ..btc.common import hash160
|
||||||
|
|
||||||
|
class bech32x(addr_generator.base):
|
||||||
|
|
||||||
|
@check_data
|
||||||
|
def to_addr(self, data):
|
||||||
|
return self.proto.encode_addr_bech32x(hash160(data.pubkey))
|
||||||
|
|
@ -46,7 +46,8 @@ class CoinProtocol(MMGenObject):
|
||||||
'eth': proto_info('Ethereum', 4),
|
'eth': proto_info('Ethereum', 4),
|
||||||
'etc': proto_info('EthereumClassic', 4),
|
'etc': proto_info('EthereumClassic', 4),
|
||||||
'zec': proto_info('Zcash', 2),
|
'zec': proto_info('Zcash', 2),
|
||||||
'xmr': proto_info('Monero', 4)
|
'xmr': proto_info('Monero', 4),
|
||||||
|
'rune': proto_info('THORChain', 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Base(Lockable):
|
class Base(Lockable):
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,8 @@ class tool_cmd(tool_cmd_base):
|
||||||
return self.proto.pubhash2segwitaddr(pubhash)
|
return self.proto.pubhash2segwitaddr(pubhash)
|
||||||
elif self.mmtype.name == 'bech32':
|
elif self.mmtype.name == 'bech32':
|
||||||
return self.proto.pubhash2bech32addr(pubhash)
|
return self.proto.pubhash2bech32addr(pubhash)
|
||||||
|
elif self.mmtype.name == 'bech32x':
|
||||||
|
return self.proto.encode_addr_bech32x(pubhash)
|
||||||
else:
|
else:
|
||||||
return self.proto.pubhash2addr(pubhash, self.mmtype.addr_fmt)
|
return self.proto.pubhash2addr(pubhash, self.mmtype.addr_fmt)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,9 @@ packages =
|
||||||
mmgen.proto.eth.tx
|
mmgen.proto.eth.tx
|
||||||
mmgen.proto.eth.tw
|
mmgen.proto.eth.tw
|
||||||
mmgen.proto.ltc
|
mmgen.proto.ltc
|
||||||
|
mmgen.proto.rune
|
||||||
mmgen.proto.secp256k1
|
mmgen.proto.secp256k1
|
||||||
|
mmgen.proto.xchain
|
||||||
mmgen.proto.xmr
|
mmgen.proto.xmr
|
||||||
mmgen.proto.zec
|
mmgen.proto.zec
|
||||||
mmgen.swap
|
mmgen.swap
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ vectors_multicoin = {
|
||||||
'bch_compressed': 'bitcoincash:qpqpcllprftg4s0chdgkpxhxv23wfymq3gj7n0a9vw',
|
'bch_compressed': 'bitcoincash:qpqpcllprftg4s0chdgkpxhxv23wfymq3gj7n0a9vw',
|
||||||
'bsc_smart': '0x373731f4d885Fc7Da05498F9f0804a87A14F891b',
|
'bsc_smart': '0x373731f4d885Fc7Da05498F9f0804a87A14F891b',
|
||||||
'bnb_beacon': 'bnb179c3ymltqm4utlp089zxqeta5dvn48a305rhe5',
|
'bnb_beacon': 'bnb179c3ymltqm4utlp089zxqeta5dvn48a305rhe5',
|
||||||
|
'rune': 'thor1nr6fye3nznyn20m5w6fey6w8a8l4q599cdqmpc',
|
||||||
}
|
}
|
||||||
|
|
||||||
def wif2addr(cfg, wif):
|
def wif2addr(cfg, wif):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
# MMGen address file
|
||||||
|
#
|
||||||
|
# This file is editable.
|
||||||
|
# Everything following a hash symbol '#' is a comment and ignored by MMGen.
|
||||||
|
# A text label of 80 screen cells or less may be added to the right of each
|
||||||
|
# address, and it will be appended to the tracking wallet label upon import.
|
||||||
|
# The label may contain any printable ASCII symbol.
|
||||||
|
#
|
||||||
|
# Address data checksum for 98831F3A-RUNE-X[1,31-33,500-501,1010-1011]: 00C6 1930 557F 5E99
|
||||||
|
# Record this value to a secure location.
|
||||||
|
98831F3A RUNE:BECH32X {
|
||||||
|
1 thor137aqwpky5muxw7rvrdy6kxegt838k04xp4rnge
|
||||||
|
31 thor1w758u285uqv5h3wuksylvxtahql9tjsdllurug
|
||||||
|
32 thor18srpqhu8q8ppp4zc3zje3yp5lf3jpmq8hu4phh
|
||||||
|
33 thor16hgd6g3cutx8dhslvdgxljss4w7prq32u9x20y
|
||||||
|
500 thor14q7m5jyajjnlqgccu3vh2dx0m2323558faxlz6
|
||||||
|
501 thor1gyaexk8l3rvt7vsfd693y33ate989r64ak65gk
|
||||||
|
1010 thor1g95knu2elqt8l0d5vcyf0hyuspn4mhsjrym8g9
|
||||||
|
1011 thor12f6lgkjy7amxdz7eznv33xypvzux9kxslkqvzq
|
||||||
|
}
|
||||||
|
|
@ -299,9 +299,10 @@ init_tests() {
|
||||||
e $tooltest2_py --coin=eth --token=mm1
|
e $tooltest2_py --coin=eth --token=mm1
|
||||||
e $tooltest2_py --coin=eth --token=mm1 --testnet=1
|
e $tooltest2_py --coin=eth --token=mm1 --testnet=1
|
||||||
e $tooltest2_py --coin=etc
|
e $tooltest2_py --coin=etc
|
||||||
|
t $tooltest2_py --coin=rune
|
||||||
- $tooltest2_py --fork # run once with --fork so commands are actually executed
|
- $tooltest2_py --fork # run once with --fork so commands are actually executed
|
||||||
"
|
"
|
||||||
[ "$SKIP_ALT_DEP" ] && t_tool2_skip='a e' # skip ETH,ETC: txview requires py_ecc
|
[ "$SKIP_ALT_DEP" ] && t_tool2_skip='a e t' # skip ETH,ETC: txview requires py_ecc
|
||||||
|
|
||||||
d_tool="'mmgen-tool' utility (all supported coins)"
|
d_tool="'mmgen-tool' utility (all supported coins)"
|
||||||
t_tool="
|
t_tool="
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ eth_pubhex2 = '9166c289b9f905e55f9e3df9f69d7f356b4a22095f894f4715714aa4b56606aff
|
||||||
xmr_pubhex1 = '1ed49357e217e79dab3c5503822f2bdb561e302e24476ee6ff33242c7551d4e78944790c0cfa9998c2f196061be89b2b8387f9d397db20ea8e049899cdc947d1'
|
xmr_pubhex1 = '1ed49357e217e79dab3c5503822f2bdb561e302e24476ee6ff33242c7551d4e78944790c0cfa9998c2f196061be89b2b8387f9d397db20ea8e049899cdc947d1'
|
||||||
zec_pubhex1 = 'e6a4edbff547f21bcc2a825b6cf70f06e266a452d2da9d6dc5c1da3d99d7e996f488704dcdfe8d92cafe47772b3f692a98d59de1e99e00ff815f64ae59910f0c'
|
zec_pubhex1 = 'e6a4edbff547f21bcc2a825b6cf70f06e266a452d2da9d6dc5c1da3d99d7e996f488704dcdfe8d92cafe47772b3f692a98d59de1e99e00ff815f64ae59910f0c'
|
||||||
|
|
||||||
|
rune_addr1 = 'thor1xptlvmwaymaxa7pxkr2u5pn7c0508stcr9tw2z'
|
||||||
|
|
||||||
tests = {
|
tests = {
|
||||||
'Mnemonic': {
|
'Mnemonic': {
|
||||||
'hex2mn': (
|
'hex2mn': (
|
||||||
|
|
@ -407,6 +409,9 @@ tests = {
|
||||||
([btc_addr5], pubhash1),
|
([btc_addr5], pubhash1),
|
||||||
([btc_addr6], pubhash2),
|
([btc_addr6], pubhash2),
|
||||||
],
|
],
|
||||||
|
'rune_mainnet': [
|
||||||
|
([rune_addr1], pubhash2),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
'eth_checksummed_addr': {
|
'eth_checksummed_addr': {
|
||||||
'eth_mainnet': [
|
'eth_mainnet': [
|
||||||
|
|
@ -423,6 +428,9 @@ tests = {
|
||||||
['--type=segwit'], 'segwit'),
|
['--type=segwit'], 'segwit'),
|
||||||
([pubhash2], btc_addr6, ['--type=bech32'], 'bech32'),
|
([pubhash2], btc_addr6, ['--type=bech32'], 'bech32'),
|
||||||
],
|
],
|
||||||
|
'rune_mainnet': [
|
||||||
|
([pubhash2], rune_addr1, ['--type=X'], 'bech32x'),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
'addr2scriptpubkey': {
|
'addr2scriptpubkey': {
|
||||||
'btc_mainnet': [
|
'btc_mainnet': [
|
||||||
|
|
@ -665,6 +673,12 @@ tests = {
|
||||||
'E97A D796 B495 E8BC'
|
'E97A D796 B495 E8BC'
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
'rune_mainnet': [
|
||||||
|
(
|
||||||
|
['test/ref/thorchain/98831F3A-RUNE-X[1,31-33,500-501,1010-1011].addrs'],
|
||||||
|
'00C6 1930 557F 5E99'
|
||||||
|
),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
'viewkeyaddrfile_chksum': {
|
'viewkeyaddrfile_chksum': {
|
||||||
'xmr_mainnet': [
|
'xmr_mainnet': [
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue