mirror of
https://github.com/SeedSigner/seedsigner.git
synced 2026-10-05 23:18:25 +00:00
add ur xpub export
This commit is contained in:
@@ -10,6 +10,8 @@ from seedsigner.helpers.ur2.ur_decoder import URDecoder
|
||||
from seedsigner.helpers.bcur import (cbor_decode, bc32decode)
|
||||
from seedsigner.models import QRType, Seed
|
||||
|
||||
from urtypes.crypto import PSBT as UR_PSBT
|
||||
|
||||
###
|
||||
### DecodeQR Class
|
||||
### Purpose: used to process images or string data from animated qr codes with psbt data to create binary/base64 psbt
|
||||
@@ -141,7 +143,8 @@ class DecodeQR:
|
||||
if self.complete:
|
||||
if self.qr_type == QRType.PSBTUR2:
|
||||
cbor = self.ur_decoder.result_message().cbor
|
||||
return cbor_decode(cbor)
|
||||
return UR_PSBT.from_cbor(cbor).data
|
||||
# return cbor_decode(cbor)
|
||||
elif self.qr_type == QRType.PSBTSPECTER:
|
||||
return self.specter_qr.getData()
|
||||
elif self.qr_type == QRType.PSBTURLEGACY:
|
||||
|
||||
@@ -9,6 +9,9 @@ from seedsigner.helpers.bcur import (bc32encode, cbor_encode, bcur_encode)
|
||||
from seedsigner.helpers.qr import QR
|
||||
from seedsigner.models import Seed, QRType, EncodeQRDensity
|
||||
|
||||
from urtypes.crypto import PSBT as UR_PSBT
|
||||
from urtypes.crypto import Account, HDKey, Output, Keypath, PathComponent, SCRIPT_EXPRESSION_TAG_MAP
|
||||
|
||||
###
|
||||
### EncodeQR Class
|
||||
### Purpose: used to encode psbt for displaying as qr image
|
||||
@@ -64,7 +67,7 @@ class EncodeQR:
|
||||
elif self.qr_type == QRType.SEEDSSQR:
|
||||
self.encoder = SeedSSQR(self.seed_phrase, self.wordlist)
|
||||
elif self.qr_type == QRType.XPUBQR:
|
||||
self.encoder = XPubQR(self.seed_phrase, self.passphrase, self.derivation, self.network, self.wordlist)
|
||||
self.encoder = URXPubQR(self.seed_phrase, self.passphrase, self.derivation, self.network, self.qr_density, self.wordlist)
|
||||
elif self.qr_type == QRType.SPECTERXPUBQR:
|
||||
self.encoder = SpecterXPubQR(self.seed_phrase, self.passphrase, self.derivation, self.network, self.qr_density, self.wordlist)
|
||||
else:
|
||||
@@ -100,10 +103,8 @@ class UREncodePSBTQR:
|
||||
def __init__(self, p, qr_density):
|
||||
self.psbt = p
|
||||
self.qr_max_fragement_size = 20
|
||||
|
||||
cbor_encoder = CBOREncoder()
|
||||
cbor_encoder.encodeBytes(self.psbt.serialize())
|
||||
qr_ur_bytes = UR("crypto-psbt", cbor_encoder.get_bytes())
|
||||
|
||||
qr_ur_bytes = UR("crypto-psbt", UR_PSBT(self.psbt.serialize()).to_cbor())
|
||||
|
||||
if qr_density == EncodeQRDensity.LOW:
|
||||
self.qr_max_fragement_size = 10
|
||||
@@ -313,4 +314,79 @@ class SpecterXPubQR(XPubQR):
|
||||
return len(self.parts)
|
||||
|
||||
def isComplete(self):
|
||||
return self.sent_complete
|
||||
return self.sent_complete
|
||||
|
||||
class URXPubQR(XPubQR):
|
||||
|
||||
def __init__(self, seed_phrase, passphrase, derivation, network, qr_density, wordlist):
|
||||
|
||||
XPubQR.__init__(self, seed_phrase, passphrase, derivation, network, wordlist)
|
||||
|
||||
if qr_density == EncodeQRDensity.LOW:
|
||||
self.qr_max_fragement_size = 10
|
||||
elif qr_density == EncodeQRDensity.MEDIUM:
|
||||
self.qr_max_fragement_size = 30
|
||||
elif qr_density == EncodeQRDensity.HIGH:
|
||||
self.qr_max_fragement_size = 120
|
||||
|
||||
def derivation_to_keypath(path: str) -> list:
|
||||
arr = path.split("/")
|
||||
if arr[0] == "m":
|
||||
arr = arr[1:]
|
||||
if len(arr) == 0:
|
||||
return Keypath([],self.root.my_fingerprint, None)
|
||||
if arr[-1] == "":
|
||||
# trailing slash
|
||||
arr = arr[:-1]
|
||||
|
||||
for i, e in enumerate(arr):
|
||||
if e[-1] == "h" or e[-1] == "'":
|
||||
arr[i] = PathComponent(int(e[:-1]), True)
|
||||
else:
|
||||
arr[i] = PathComponent(int(e), False)
|
||||
|
||||
return Keypath(arr, self.root.my_fingerprint, None)
|
||||
|
||||
origin = derivation_to_keypath(derivation)
|
||||
|
||||
self.ur_hdkey = HDKey({ 'key': self.xpub.key.serialize(),
|
||||
'chain_code': self.xpub.chain_code,
|
||||
'origin': origin,
|
||||
'parent_fingerprint': self.xpub.fingerprint})
|
||||
|
||||
ur_outputs = []
|
||||
|
||||
if len(origin.components) > 0:
|
||||
if origin.components[0].index == 84: # Native Single Sig
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
|
||||
elif origin.components[0].index == 49: # Nested Single Sig
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
|
||||
elif origin.components[0].index == 48: # Multisig
|
||||
if len(origin.components) >= 4:
|
||||
if origin.components[3].index == 2: # Native Multisig
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
|
||||
elif origin.components[3].index == 1: # Nested Multisig
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
|
||||
|
||||
# If empty, add all script types
|
||||
if len(ur_outputs) == 0:
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
|
||||
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[403]],self.ur_hdkey))
|
||||
|
||||
ur_account = Account(self.root.my_fingerprint, ur_outputs)
|
||||
|
||||
qr_ur_bytes = UR("crypto-account", ur_account.to_cbor())
|
||||
|
||||
self.ur2_encode = UREncoder(qr_ur_bytes, self.qr_max_fragement_size, 0)
|
||||
|
||||
def seqLen(self):
|
||||
return self.ur2_encode.fountain_encoder.seq_len()
|
||||
|
||||
def nextPart(self) -> str:
|
||||
return self.ur2_encode.next_part().upper()
|
||||
|
||||
def isComplete(self):
|
||||
return self.ur2_encode.is_complete()
|
||||
Reference in New Issue
Block a user