unify address format labels; address explorer now uses both labels and shortened addresses; axi updated to track last 4 addr chars or MenuItem label (multisig)
(cherry picked from commit 63debfebaf)
This commit is contained in:
parent
b05bd09998
commit
aa7d17bf8f
@ -9,7 +9,7 @@ from uhashlib import sha256
|
||||
from uasyncio import sleep_ms
|
||||
from ubinascii import hexlify as b2a_hex
|
||||
from utils import imported, pretty_short_delay, problem_file_line, import_prompt_builder
|
||||
from utils import xfp2str, decrypt_tapsigner_backup, B2A
|
||||
from utils import xfp2str, decrypt_tapsigner_backup, B2A, addr_fmt_label
|
||||
from ux import ux_show_story, the_ux, ux_confirm, ux_dramatic_pause, ux_aborted
|
||||
from ux import ux_enter_bip32_index, ux_input_text
|
||||
from export import make_json_wallet, make_summary_file, make_descriptor_wallet_export
|
||||
@ -1095,9 +1095,12 @@ async def electrum_skeleton(*a):
|
||||
# 'classic' instead of 'legacy' personallly.
|
||||
rv = []
|
||||
|
||||
rv.append(MenuItem("Legacy (P2PKH)", f=electrum_skeleton_step2, arg=(AF_CLASSIC, account_num)))
|
||||
rv.append(MenuItem("P2SH-Segwit", f=electrum_skeleton_step2, arg=(AF_P2WPKH_P2SH, account_num)))
|
||||
rv.append(MenuItem("Native Segwit", f=electrum_skeleton_step2, arg=(AF_P2WPKH, account_num)))
|
||||
rv.append(MenuItem(addr_fmt_label(AF_CLASSIC), f=electrum_skeleton_step2,
|
||||
arg=(AF_CLASSIC, account_num)))
|
||||
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH_P2SH), f=electrum_skeleton_step2,
|
||||
arg=(AF_P2WPKH_P2SH, account_num)))
|
||||
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH), f=electrum_skeleton_step2,
|
||||
arg=(AF_P2WPKH, account_num)))
|
||||
|
||||
return MenuSystem(rv)
|
||||
|
||||
@ -1134,16 +1137,15 @@ async def ss_descriptor_skeleton(label, _, item):
|
||||
# 'classic' instead of 'legacy' personallly.
|
||||
rv = []
|
||||
|
||||
rv.append(MenuItem("Legacy (P2PKH)", f=descriptor_skeleton_step2,
|
||||
rv.append(MenuItem(addr_fmt_label(AF_CLASSIC), f=descriptor_skeleton_step2,
|
||||
arg=(AF_CLASSIC, account_num, int_ext)))
|
||||
rv.append(MenuItem("P2SH-Segwit", f=descriptor_skeleton_step2,
|
||||
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH_P2SH), f=descriptor_skeleton_step2,
|
||||
arg=(AF_P2WPKH_P2SH, account_num, int_ext)))
|
||||
rv.append(MenuItem("Native Segwit", f=descriptor_skeleton_step2,
|
||||
rv.append(MenuItem(addr_fmt_label(AF_P2WPKH), f=descriptor_skeleton_step2,
|
||||
arg=(AF_P2WPKH, account_num, int_ext)))
|
||||
rv.append(MenuItem("Taproot (P2TR)", f=descriptor_skeleton_step2,
|
||||
rv.append(MenuItem(addr_fmt_label(AF_P2TR), f=descriptor_skeleton_step2,
|
||||
arg=(AF_P2TR, account_num, int_ext)))
|
||||
|
||||
|
||||
return MenuSystem(rv)
|
||||
|
||||
async def samourai_post_mix_descriptor_export(*a):
|
||||
|
||||
@ -14,6 +14,7 @@ from uhashlib import sha256
|
||||
from ubinascii import hexlify as b2a_hex
|
||||
from glob import settings
|
||||
from auth import write_sig_file
|
||||
from utils import addr_fmt_label
|
||||
|
||||
def truncate_address(addr):
|
||||
# Truncates address to width of screen, replacing middle chars
|
||||
@ -98,10 +99,10 @@ class PickAddrFmtMenu(MenuSystem):
|
||||
def __init__(self, path, parent):
|
||||
self.parent = parent
|
||||
items = [
|
||||
MenuItem("Classic P2PKH", f=self.done, arg=(path, AF_CLASSIC)),
|
||||
MenuItem("Segwit P2WPKH", f=self.done, arg=(path, AF_P2WPKH)),
|
||||
MenuItem("P2SH-P2WPKH", f=self.done, arg=(path, AF_P2WPKH_P2SH)),
|
||||
MenuItem("Taproot P2TR", f=self.done, arg=(path, AF_P2TR)),
|
||||
MenuItem(addr_fmt_label(AF_CLASSIC), f=self.done, arg=(path, AF_CLASSIC)),
|
||||
MenuItem(addr_fmt_label(AF_P2WPKH), f=self.done, arg=(path, AF_P2WPKH)),
|
||||
MenuItem(addr_fmt_label(AF_P2WPKH_P2SH), f=self.done, arg=(path, AF_P2WPKH_P2SH)),
|
||||
MenuItem(addr_fmt_label(AF_P2TR), f=self.done, arg=(path, AF_P2TR)),
|
||||
]
|
||||
super().__init__(items)
|
||||
if path.startswith("m/84'"):
|
||||
@ -181,10 +182,15 @@ class AddressListMenu(MenuSystem):
|
||||
|
||||
stash.blank_object(node)
|
||||
|
||||
items = [MenuItem(address, f=self.pick_single, arg=(path, addr_fmt))
|
||||
for i, (address, path, addr_fmt) in enumerate(choices)]
|
||||
items = []
|
||||
for i, (address, path, addr_fmt) in enumerate(choices):
|
||||
axi = address[-4:] # last 4 address characters
|
||||
items.append(MenuItem(" "+addr_fmt_label(addr_fmt), f=self.pick_single,
|
||||
arg=(path, addr_fmt, axi)))
|
||||
items.append(MenuItem(address, f=self.pick_single,
|
||||
arg=(path, addr_fmt, axi)))
|
||||
|
||||
# some other choices
|
||||
# some other choices
|
||||
if self.account_num == 0:
|
||||
items.append(MenuItem("Applications", menu=ApplicationsMenu(self)))
|
||||
items.append(MenuItem("Account Number", f=self.change_account))
|
||||
@ -197,22 +203,27 @@ class AddressListMenu(MenuSystem):
|
||||
else:
|
||||
items.append(MenuItem("Account: %d" % self.account_num, f=self.change_account))
|
||||
|
||||
self.goto_idx(settings.get('axi', 0)) # weak
|
||||
|
||||
self.replace_items(items)
|
||||
axi = settings.get('axi', 0)
|
||||
if isinstance(axi, str):
|
||||
ok = self.goto_label(axi)
|
||||
if not ok:
|
||||
self.goto_idx(0)
|
||||
else:
|
||||
self.goto_idx(axi)
|
||||
|
||||
async def change_account(self, *a):
|
||||
self.account_num = await ux_enter_bip32_index('Account Number:') or 0
|
||||
await self.render()
|
||||
|
||||
async def pick_single(self, _1, menu_idx, item):
|
||||
settings.put('axi', menu_idx) # update last clicked address
|
||||
path, addr_fmt = item.arg
|
||||
async def pick_single(self, _1, _2, item):
|
||||
path, addr_fmt, axi = item.arg
|
||||
settings.put('axi', axi) # update last clicked address
|
||||
await self.show_n_addresses(path, addr_fmt, None)
|
||||
|
||||
async def pick_multisig(self, _1, menu_idx, item):
|
||||
async def pick_multisig(self, _1, _2, item):
|
||||
ms_wallet = item.arg
|
||||
settings.put('axi', menu_idx) # update last clicked address
|
||||
settings.put('axi', item.label) # update last clicked address
|
||||
await self.show_n_addresses(None, None, ms_wallet)
|
||||
|
||||
async def make_custom(self, *a):
|
||||
|
||||
@ -166,9 +166,17 @@ class MenuSystem:
|
||||
if not keep_position:
|
||||
self.cursor = 0
|
||||
self.ypos = 0
|
||||
|
||||
self.items = [m for m in menu_items if not getattr(m, 'predicate', None) or m.predicate()]
|
||||
self.count = len(self.items)
|
||||
|
||||
def goto_label(self, label):
|
||||
for i, m in enumerate(self.items):
|
||||
if m.label == label or m.label[-4:] == label:
|
||||
self.goto_idx(i)
|
||||
return True
|
||||
return False
|
||||
|
||||
def show(self):
|
||||
#
|
||||
# Redraw the menu.
|
||||
|
||||
@ -53,9 +53,9 @@ class PaperWalletMaker:
|
||||
self.is_taproot = False
|
||||
|
||||
def atype(self):
|
||||
if self.is_taproot: return 2, 'Taproot Address'
|
||||
if self.is_segwit: return 1, 'Segwit Address'
|
||||
return 0, 'Classic Address'
|
||||
if self.is_taproot: return 2, 'Taproot P2TR'
|
||||
if self.is_segwit: return 1, 'Segwit P2WPKH'
|
||||
return 0, 'Classic P2PKPH'
|
||||
|
||||
async def pick_template(self, *a):
|
||||
fn = await file_picker('Pick PDF template to use, or X for none.',
|
||||
@ -71,7 +71,7 @@ class PaperWalletMaker:
|
||||
self.is_segwit = idx == 1
|
||||
self.is_taproot = idx == 2
|
||||
self.update_menu()
|
||||
return self.atype()[0], ['Classic', 'Segwit/Bech32', 'Taproot'], set
|
||||
return self.atype()[0], ['Classic P2PKPH', 'Segwit P2WPKH', 'Taproot P2TR'], set
|
||||
|
||||
@staticmethod
|
||||
def can_do_qr():
|
||||
|
||||
@ -539,4 +539,12 @@ def decrypt_tapsigner_backup(backup_key, data):
|
||||
|
||||
return decrypted.split("\n")
|
||||
|
||||
def addr_fmt_label(addr_fmt):
|
||||
return {
|
||||
AF_CLASSIC: "Classic P2PKH",
|
||||
AF_P2WPKH_P2SH: "P2SH-Segwit",
|
||||
AF_P2WPKH: "Segwit P2WPKH",
|
||||
AF_P2TR: "Taproot P2TR"
|
||||
}[addr_fmt]
|
||||
|
||||
# EOF
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
import pytest, time, io, csv
|
||||
from ckcc_protocol.constants import *
|
||||
from pycoin.key.BIP32Node import BIP32Node
|
||||
from pycoin.contrib.segwit_addr import encode as sw_encode
|
||||
from pycoin.encoding import a2b_hashed_base58, hash160
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -154,14 +156,15 @@ def test_stub_menu(sim_execfile, goto_address_explorer, need_keypress, cap_menu,
|
||||
need_keypress('4')
|
||||
time.sleep(.01)
|
||||
m = cap_menu()
|
||||
|
||||
gap = iter(range(1, 10))
|
||||
for idx, (path, addr_format) in enumerate(common_derivs):
|
||||
# derive index=0 address
|
||||
_id = next(gap) + idx
|
||||
subpath = path.format(account=0, change=0, idx=0) # e.g. "m/44'/1'/0'/0/0"
|
||||
sk = node_prv.subkey_for_path(subpath[2:])
|
||||
|
||||
# capture full index=0 address from display screen & validate it
|
||||
goto_address_explorer(click_idx=idx)
|
||||
goto_address_explorer(click_idx=_id)
|
||||
addr_dict = parse_display_screen(0, 10)
|
||||
if subpath not in addr_dict:
|
||||
raise Exception('Subpath ("%s") not found in address explorer display' % subpath)
|
||||
@ -169,7 +172,7 @@ def test_stub_menu(sim_execfile, goto_address_explorer, need_keypress, cap_menu,
|
||||
validate_address(expected_addr, sk)
|
||||
|
||||
# validate that stub is correct
|
||||
[start, end] = m[idx].split('-')
|
||||
[start, end] = m[_id].split('-')
|
||||
assert expected_addr.startswith(start)
|
||||
assert expected_addr.endswith(end)
|
||||
|
||||
@ -191,7 +194,7 @@ def test_applications_samourai(chain, change, option, goto_address_explorer, cap
|
||||
node_prv = BIP32Node.from_wallet_key(
|
||||
sim_execfile('devtest/dump_private.py').strip()
|
||||
)
|
||||
goto_address_explorer(click_idx=4) # "applications" at index 3
|
||||
goto_address_explorer(click_idx=6) # "applications" at index 3
|
||||
menu = cap_menu()
|
||||
assert "Samourai" in menu
|
||||
pick_menu_item("Samourai")
|
||||
@ -224,8 +227,10 @@ def test_address_display(goto_address_explorer, parse_display_screen, mk_common_
|
||||
sim_execfile('devtest/dump_private.py').strip()
|
||||
)
|
||||
common_derivs = mk_common_derivations(node_prv.netcode())
|
||||
gap = iter(range(1, 10))
|
||||
for click_idx, (path, addr_format) in enumerate(common_derivs):
|
||||
# Click on specified derivation idx in explorer
|
||||
_id = next(gap) + click_idx
|
||||
goto_address_explorer(click_idx=click_idx)
|
||||
|
||||
# perform keypad press sequence
|
||||
@ -239,7 +244,7 @@ def test_address_display(goto_address_explorer, parse_display_screen, mk_common_
|
||||
sk = node_prv.subkey_for_path(subpath[2:])
|
||||
validate_address(given_addr, sk)
|
||||
|
||||
@pytest.mark.parametrize('click_idx', range(4))
|
||||
@pytest.mark.parametrize('click_idx', [1,3,5,7])
|
||||
@pytest.mark.parametrize("change", [True, False])
|
||||
@pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"])
|
||||
def test_dump_addresses(way, change, generate_addresses_file, mk_common_derivations, sim_execfile, validate_address,
|
||||
@ -286,7 +291,9 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, goto_addre
|
||||
assert f'Account: {account_num}' in m
|
||||
|
||||
which = 0
|
||||
gap = iter(range(1,10))
|
||||
for idx, (path, addr_format) in enumerate(common_derivs):
|
||||
_id = next(gap) + idx
|
||||
# derive index=0 address
|
||||
assert '{account}' in path
|
||||
|
||||
@ -297,7 +304,7 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, goto_addre
|
||||
|
||||
# go down menu to expected derivation spot
|
||||
m = cap_menu()
|
||||
pick_menu_item(m[idx])
|
||||
pick_menu_item(m[_id])
|
||||
time.sleep(0.1)
|
||||
|
||||
addr_dict = parse_display_screen(0, 10)
|
||||
@ -307,7 +314,7 @@ def test_account_menu(way, account_num, sim_execfile, pick_menu_item, goto_addre
|
||||
validate_address(expected_addr, sk)
|
||||
|
||||
# validate that stub is correct
|
||||
[start, end] = m[idx].split('-')
|
||||
[start, end] = m[_id].split('-')
|
||||
assert expected_addr.startswith(start)
|
||||
assert expected_addr.endswith(end)
|
||||
|
||||
@ -388,14 +395,14 @@ def test_custom_path(path, which_fmt, addr_vs_path, pick_menu_item, goto_address
|
||||
m = cap_menu()
|
||||
assert m[0] == 'Classic P2PKH'
|
||||
assert m[1] == 'Segwit P2WPKH'
|
||||
assert m[2] == 'P2SH-P2WPKH'
|
||||
assert m[2] == 'P2SH-Segwit'
|
||||
assert m[3] == 'Taproot P2TR'
|
||||
|
||||
fmts = {
|
||||
AF_CLASSIC: 'Classic P2PKH',
|
||||
AF_P2WPKH: 'Segwit P2WPKH',
|
||||
AF_P2TR: 'Taproot P2TR',
|
||||
AF_P2WPKH_P2SH: 'P2SH-P2WPKH',
|
||||
AF_P2WPKH_P2SH: 'P2SH-Segwit',
|
||||
}
|
||||
|
||||
pick_menu_item(fmts[which_fmt])
|
||||
@ -486,7 +493,7 @@ def test_bitcoind_descriptor_address(addr_fmt, acct_num, bitcoind, goto_home, pi
|
||||
|
||||
sig_check = True
|
||||
if addr_fmt == AF_P2WPKH:
|
||||
menu_item = "Native Segwit"
|
||||
menu_item = "Segwit P2WPKH"
|
||||
desc_prefix = "wpkh("
|
||||
click_idx = 2
|
||||
elif addr_fmt == AF_P2WPKH_P2SH:
|
||||
@ -494,13 +501,13 @@ def test_bitcoind_descriptor_address(addr_fmt, acct_num, bitcoind, goto_home, pi
|
||||
desc_prefix = "sh(wpkh("
|
||||
click_idx = 1
|
||||
elif addr_fmt == AF_P2TR:
|
||||
menu_item = "Taproot (P2TR)"
|
||||
menu_item = "Taproot P2TR"
|
||||
desc_prefix = "tr("
|
||||
click_idx = 3
|
||||
sig_check = False
|
||||
else:
|
||||
# addr_fmt == AF_CLASSIC:
|
||||
menu_item = "Legacy (P2PKH)"
|
||||
menu_item = "Classic P2PKH"
|
||||
desc_prefix = "pkh("
|
||||
click_idx = 0
|
||||
|
||||
|
||||
@ -220,7 +220,7 @@ def test_export_wasabi(way, dev, pick_menu_item, goto_home, cap_story, need_keyp
|
||||
assert got.sec() == expect.sec()
|
||||
|
||||
|
||||
@pytest.mark.parametrize('mode', [ "Legacy (P2PKH)", "P2SH-Segwit", "Native Segwit"])
|
||||
@pytest.mark.parametrize('mode', [ "Classic P2PKH", "P2SH-Segwit", "Segwit P2WPKH"])
|
||||
@pytest.mark.parametrize('acct_num', [ None, '0', '9897'])
|
||||
@pytest.mark.parametrize('way', ["sd", "vdisk", "nfc"])
|
||||
@pytest.mark.parametrize('testnet', [True, False])
|
||||
@ -606,7 +606,7 @@ def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, setting
|
||||
|
||||
menu = cap_menu()
|
||||
if addr_fmt == AF_P2WPKH:
|
||||
menu_item = "Native Segwit"
|
||||
menu_item = "Segwit P2WPKH"
|
||||
desc_prefix = "wpkh("
|
||||
bip44_purpose = 84
|
||||
elif addr_fmt == AF_P2WPKH_P2SH:
|
||||
@ -619,7 +619,7 @@ def test_generic_descriptor_export(chain, addr_fmt, acct_num, goto_home, setting
|
||||
bip44_purpose = 86
|
||||
else:
|
||||
# addr_fmt == AF_CLASSIC:
|
||||
menu_item = "Legacy (P2PKH)"
|
||||
menu_item = "Classic P2PKH"
|
||||
desc_prefix = "pkh("
|
||||
bip44_purpose = 44
|
||||
|
||||
@ -673,7 +673,7 @@ def test_samourai_vs_generic(chain, account, settings_set, pick_menu_item, goto_
|
||||
need_keypress(ch)
|
||||
need_keypress("y")
|
||||
need_keypress("y") # int_ext <0;1>
|
||||
pick_menu_item("Native Segwit") # both postmix and premix are p2wpkh only
|
||||
pick_menu_item("Segwit P2WPKH") # both postmix and premix are p2wpkh only
|
||||
file_desc_generic = load_export("sd", label="Descriptor", is_json=False, addr_fmt=AF_P2WPKH)
|
||||
need_keypress("y") # written
|
||||
need_keypress("x") # go back to advanced
|
||||
|
||||
@ -40,8 +40,8 @@ def test_generate(mode, chain, pdf, cap_menu, pick_menu_item, goto_home, cap_sto
|
||||
|
||||
time.sleep(0.1)
|
||||
if mode == 'segwit':
|
||||
pick_menu_item('Classic Address')
|
||||
pick_menu_item('Segwit/Bech32')
|
||||
pick_menu_item('Classic P2PKH')
|
||||
pick_menu_item('Segwit P2WPKH')
|
||||
time.sleep(0.5)
|
||||
|
||||
if mode == 'taproot':
|
||||
|
||||
Loading…
Reference in New Issue
Block a user