add ability to switch between slip132 and bip32 representations of extended public keys in Export XPUB
(cherry picked from commit de0a679eef)
This commit is contained in:
parent
718c0ca354
commit
53b7aae325
@ -6,6 +6,7 @@ This lists the new changes that have not yet been published in a normal release.
|
||||
|
||||
- Enhancement: Hide Secure Notes & Passwords in Deltamode. Wipe seed if notes menu accessed.
|
||||
- Enhancement: Hide Seed Vault in Deltamode. Wipe seed if Seed Vault menu accessed.
|
||||
- Enhancement: Ability to switch between BIP-32 XPUB and SLIP-132 garbage in `Export XPUB`
|
||||
- Bugfix: Sometimes see a struck screen after _Verifying..._ in boot up sequence.
|
||||
On Q, result is blank screen, on Mk4, result is three-dots screen.
|
||||
- Bugfix: Do not allow to enable/disable Seed Vault feature when in temporary seed mode
|
||||
@ -16,6 +17,7 @@ This lists the new changes that have not yet been published in a normal release.
|
||||
- Change: Testnet3 -> Testnet4 (all parameters are the same)
|
||||
|
||||
|
||||
|
||||
# Mk4 Specific Changes
|
||||
|
||||
## 5.4.1 - 2024-??-??
|
||||
|
||||
@ -1018,6 +1018,7 @@ async def export_xpub(label, _2, item):
|
||||
|
||||
chain = chains.current_chain()
|
||||
acct = 0
|
||||
slip132 = False # non-slip is default from Oct 2024
|
||||
|
||||
# decode menu code => standard derivation
|
||||
mode = item.arg
|
||||
@ -1033,24 +1034,44 @@ async def export_xpub(label, _2, item):
|
||||
else:
|
||||
remap = {44:0, 49:1, 84:2,86:3}[mode]
|
||||
_, path, addr_fmt = chains.CommonDerivations[remap]
|
||||
path = path.format(account='{acct}', coin_type=chain.b44_cointype, change=0, idx=0)[:-4]
|
||||
|
||||
# always show SLIP-132 style, because defacto
|
||||
show_slip132 = (addr_fmt != AF_CLASSIC)
|
||||
path = path.format(account=acct, coin_type=chain.b44_cointype,
|
||||
change=0, idx=0)[:-4]
|
||||
|
||||
while 1:
|
||||
msg = '''Show QR of the XPUB for path:\n\n%s\n\n''' % path
|
||||
msg = 'Show QR of the XPUB for path:\n\n%s\n\n' % path
|
||||
esc = ""
|
||||
if path != "m":
|
||||
esc += "1"
|
||||
msg += "Press (1) to select account other than %s. " % (acct or "zero")
|
||||
if addr_fmt != AF_CLASSIC:
|
||||
esc += "2"
|
||||
slp_af = addr_fmt
|
||||
if slip132:
|
||||
slp_af = AF_CLASSIC
|
||||
|
||||
if '{acct}' in path:
|
||||
msg += "Press (1) to select account other than zero. "
|
||||
slp = chain.slip132[slp_af].hint + "pub"
|
||||
msg += " Press (2) to show %s %s." % (
|
||||
slp, "(BIP-32)" if slip132 else "(SLIP-132)"
|
||||
)
|
||||
if glob.NFC:
|
||||
msg += "Press %s to share via NFC. " % (KEY_NFC if version.has_qwerty else "(3)")
|
||||
if version.has_qwerty:
|
||||
esc += KEY_NFC
|
||||
key_hint = KEY_NFC
|
||||
else:
|
||||
esc += "3"
|
||||
key_hint = "(3)"
|
||||
msg += " Press %s to share via NFC. " % key_hint
|
||||
|
||||
ch = await ux_show_story(msg, escape='13')
|
||||
ch = await ux_show_story(msg, escape=esc)
|
||||
if ch == 'x': return
|
||||
if ch == "2":
|
||||
slip132 = not slip132
|
||||
continue
|
||||
if ch == '1':
|
||||
acct = await ux_enter_bip32_index('Account Number:') or 0
|
||||
path = path.format(acct=acct)
|
||||
pth_split = path.split("/")
|
||||
pth_split[-1] = ("%dh" % acct)
|
||||
path = "/".join(pth_split)
|
||||
continue
|
||||
|
||||
# assume zero account if not picked
|
||||
@ -1062,7 +1083,7 @@ async def export_xpub(label, _2, item):
|
||||
# render xpub/ypub/zpub
|
||||
with stash.SensitiveValues() as sv:
|
||||
node = sv.derive_path(path) if path != 'm' else sv.node
|
||||
xpub = chain.serialize_public(node, addr_fmt)
|
||||
xpub = chain.serialize_public(node, addr_fmt if slip132 else AF_CLASSIC)
|
||||
|
||||
from ownership import OWNERSHIP
|
||||
OWNERSHIP.note_wallet_used(addr_fmt, acct)
|
||||
@ -1072,8 +1093,6 @@ async def export_xpub(label, _2, item):
|
||||
else:
|
||||
await show_qr_code(xpub, False)
|
||||
|
||||
break
|
||||
|
||||
|
||||
def electrum_export_story(background=False):
|
||||
# saves memory being in a function
|
||||
|
||||
@ -180,7 +180,7 @@ XpubExportMenu = [
|
||||
MenuItem("Segwit (BIP-84)", f=export_xpub, arg=84),
|
||||
MenuItem("Classic (BIP-44)", f=export_xpub, arg=44),
|
||||
MenuItem("Taproot/P2TR(86)", f=export_xpub, arg=86),
|
||||
MenuItem("P2WPKH/P2SH (49)", f=export_xpub, arg=49),
|
||||
MenuItem("P2WPKH/P2SH "+("(BIP-49)"if version.has_qwerty else "(49)"), f=export_xpub, arg=49),
|
||||
MenuItem("Master XPUB", f=export_xpub, arg=0),
|
||||
MenuItem("Current XFP", f=export_xpub, arg=-1),
|
||||
]
|
||||
|
||||
@ -547,15 +547,15 @@ def test_export_public_txt(way, dev, pick_menu_item, goto_home, press_select, mi
|
||||
|
||||
|
||||
@pytest.mark.qrcode
|
||||
@pytest.mark.parametrize('chain', ["BTC", "XTN"])
|
||||
@pytest.mark.parametrize('acct_num', [ None, 0, 99, 8989])
|
||||
@pytest.mark.parametrize('use_nfc', [False, True])
|
||||
def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home,
|
||||
def test_export_xpub(chain, acct_num, dev, cap_menu, pick_menu_item, goto_home,
|
||||
cap_story, need_keypress, enter_number, cap_screen_qr,
|
||||
use_mainnet, nfc_read_text, is_q1, press_select, press_cancel,
|
||||
settings_set, nfc_read_text, is_q1, press_select, press_cancel,
|
||||
press_nfc, expect_acctnum_captured):
|
||||
# XPUB's via QR
|
||||
use_mainnet()
|
||||
|
||||
settings_set("chain", chain)
|
||||
chain_num = 0 if chain == "BTC" else 1
|
||||
goto_home()
|
||||
pick_menu_item('Advanced/Tools')
|
||||
pick_menu_item('Export Wallet')
|
||||
@ -565,13 +565,13 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home
|
||||
for m in top_items:
|
||||
is_xfp = False
|
||||
if '-84' in m:
|
||||
expect = "m/84h/0h/{acct}h"
|
||||
elif '86' in m and 'P2TR' in m:
|
||||
expect = "m/86h/0h/{acct}h"
|
||||
expect = f"m/84h/{chain_num}h/{{acct}}h"
|
||||
elif '-86' in m:
|
||||
expect = f"m/86h/{chain_num}h/{{acct}}h"
|
||||
elif '-44' in m:
|
||||
expect = "m/44h/0h/{acct}h"
|
||||
expect = f"m/44h/{chain_num}h/{{acct}}h"
|
||||
elif '49' in m:
|
||||
expect = "m/49h/0h/{acct}h"
|
||||
expect = f"m/49h/{chain_num}h/{{acct}}h"
|
||||
elif 'Master' in m:
|
||||
expect = "m"
|
||||
elif 'XFP' in m:
|
||||
@ -581,17 +581,21 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home
|
||||
time.sleep(0.3)
|
||||
if is_xfp:
|
||||
got = cap_screen_qr().decode('ascii')
|
||||
if use_nfc:
|
||||
press_nfc()
|
||||
assert got == xfp2str(simulator_fixed_xfp).upper()
|
||||
press_cancel()
|
||||
time.sleep(.1)
|
||||
press_nfc()
|
||||
time.sleep(.2)
|
||||
nfc_got = nfc_read_text()
|
||||
time.sleep(.2)
|
||||
assert nfc_got == got == xfp2str(simulator_fixed_xfp).upper()
|
||||
press_cancel() # cancel animation
|
||||
press_cancel() # cancel QR
|
||||
continue
|
||||
|
||||
time.sleep(0.3)
|
||||
title, story = cap_story()
|
||||
assert expect in story
|
||||
assert expect.format(acct=0) in story
|
||||
|
||||
if 'acct' in expect:
|
||||
if expect != "m":
|
||||
assert "Press (1) to select account" in story
|
||||
if acct_num is not None:
|
||||
need_keypress('1')
|
||||
@ -601,24 +605,52 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home
|
||||
expect = expect.format(acct=acct_num)
|
||||
title, story = cap_story()
|
||||
assert expect in story
|
||||
assert "Press (1) to select account" not in story
|
||||
assert "Press (1) to select account" in story
|
||||
|
||||
expect = expect.format(acct=0)
|
||||
if not use_nfc:
|
||||
press_select()
|
||||
got_pub = cap_screen_qr().decode('ascii')
|
||||
else:
|
||||
if f'Press {KEY_NFC if is_q1 else "(3)"}' not in story:
|
||||
raise pytest.skip("NFC disabled")
|
||||
expect = expect.format(acct=0)
|
||||
|
||||
press_select()
|
||||
got_pub = cap_screen_qr().decode('ascii')
|
||||
|
||||
if f'Press {KEY_NFC if is_q1 else "(3)"}' in story:
|
||||
assert 'NFC' in story
|
||||
press_nfc()
|
||||
time.sleep(0.2)
|
||||
got_pub = nfc_read_text()
|
||||
got_nfc_pub = nfc_read_text()
|
||||
time.sleep(0.1)
|
||||
#press_select()
|
||||
press_cancel() # cancel animation
|
||||
press_cancel() # cancel QR
|
||||
assert got_nfc_pub == got_pub
|
||||
|
||||
if got_pub[0] not in 'xt':
|
||||
got_pub,*_ = slip132undo(got_pub)
|
||||
time.sleep(.1)
|
||||
_, story = cap_story()
|
||||
assert got_pub[0] in 'xt'
|
||||
if "Press (2)" in story:
|
||||
if chain == "BTC":
|
||||
assert f"{'z' if expect[:5] == 'm/84h' else 'y'}pub (SLIP-132)" in story
|
||||
else:
|
||||
assert f"{'v' if expect[:5] == 'm/84h' else 'u'}pub (SLIP-132)" in story
|
||||
need_keypress("2")
|
||||
time.sleep(.1)
|
||||
_, story = cap_story()
|
||||
assert ("%spub (BIP-32)" % ("x" if chain == "BTC" else "t")) in story
|
||||
assert "Press (2)" in story
|
||||
|
||||
press_select()
|
||||
got_slip_pub = cap_screen_qr().decode('ascii')
|
||||
got_unslip, *_ = slip132undo(got_slip_pub)
|
||||
assert got_unslip == got_pub
|
||||
|
||||
if f'Press {KEY_NFC if is_q1 else "(3)"}' in story:
|
||||
assert 'NFC' in story
|
||||
press_nfc()
|
||||
time.sleep(0.2)
|
||||
got_nfc_slip_pub = nfc_read_text()
|
||||
time.sleep(0.1)
|
||||
press_cancel() # cancel animation
|
||||
assert got_slip_pub == got_nfc_slip_pub
|
||||
|
||||
press_cancel() # cancel QR
|
||||
|
||||
expect_acctnum_captured(acct_num)
|
||||
|
||||
@ -628,7 +660,6 @@ def test_export_xpub(use_nfc, acct_num, dev, cap_menu, pick_menu_item, goto_home
|
||||
if expect != 'm':
|
||||
wallet = wallet.subkey_for_path(expect[2:].replace('h', "'"))
|
||||
assert got.sec() == wallet.sec()
|
||||
|
||||
press_cancel()
|
||||
|
||||
@pytest.mark.parametrize("chain", ["BTC", "XTN", "XRT"])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user