Files
seedsigner/tests/test_decodepsbtqr.py
T
Nick KlockengaandGitHub 7929639378 Merge pull request #601 from newtonick/bbqr_decode
[Enhancement] Add support for BBQr PSBT decoding
2025-07-03 21:08:04 -04:00

532 lines
70 KiB
Python

from seedsigner.models.decode_qr import DecodeQR, DecodeQRStatus
from seedsigner.models.psbt_parser import PSBTParser
from seedsigner.models.qr_type import QRType
from seedsigner.models.seed import Seed
from seedsigner.models.settings_definition import SettingsConstants
# this is an of this bug: https://github.com/Foundation-Devices/foundation-ur-py/issues/3
def test_ur_qr_decode_multisig():
qrcodes = [
"UR:CRYPTO-PSBT/28-29/LPCSCECSCACFCMCPCYBBRSPTSKHDSSJESGHTGYJLCLRHSGLFKPBDRPGHAMIYBBIACWHGRSHHPFMNVLCELPDNDYMYDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEAOAEAEAECPAOAOPMIHLFKBPRAEGOHKBNDTZMBELOKKDLWNZOWKNLHHAEYAGHKTYTVSJSIYNSPEHEMUCEVTLYCWJEDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEAOAEAEAECPAOAOPLYNMOKTBAIYVWNSJLSABYKGZTFGSKCSMUYTDYIDAXLPTBUTJOLFRTCYSTPTRLLUCECSGTATWMDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEAOAEAEAECPAOAXASFGRNDPFEFHJZNDJNUEJSIDHSGRQDSK"
, "UR:CRYPTO-PSBT/29-29/LPCSCACSCACFCMCPCYBBRSPTSKHDSSJYCLTKPFPELTISCMINESYTSGWFBZHTJLLRRSNLCKCEKBURNSHKDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEAOAEAEAECPAOAXSASBZTLSJKHHREFYCPHDBNSEEYWLFGDKKOWDROBGPMHLSPQDPDCPKGYTSTBDCPRECEQZEOVTMDDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEAOAEAEAECPAOAXTDSEBSOTLGIAGMTLRHTSWDCPDKEEBSCEHPJYPASKMSWLOTSTLEZOOLZSFYZOHDCSCEFMFECKZEDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEAOAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEEMEHMHSO"
, "UR:CRYPTO-PSBT/1-29/LPADCSCACFCMCPCYBBRSPTSKHDSSHKCMCTJOJKIDJYZMADAELDAOAEAEAEADOEVWFXYKGYENNSKTCXHPISFEEOLFNNPMPAKENSCXZEKBTTYKJOJYGTEEVDMDLBTYCAAEAEAEAEZCZMZMZMAOUOTIAXAEAEAEAEAECPAECXBDAHGMLSLACKTBGYLGCTFNRKWDEYSNVSIEMHINDAIOMOTAVAEEDYJPRKZTDKNEPAGDSRAEAEAEAEAEAECPAECXNSLPIEMSRKSTBBCNHYNYAAAMCMZTMKLDCYRKTEOYOYPFTDWSCMTPSWJYFDLKMDBGAEAEAEAEGWADAALOPRCKAAAHLFRLTNLAAEAEAOOTZTPMISSTBZBEIYGSFELEURTIAHLGUEMTOTHPDYTLGSIHLALUTTESGYTYETKOVOAXFEBZTTET"
, "UR:CRYPTO-PSBT/2-29/LPAOCSCACFCMCPCYBBRSPTSKHDSSFTUEZSUERESFWDLEBZHLJSHYTITKRHFLBEFGCASFYLJZVYTTMTPYWZPFSBFNMOMHBBKBURNSHKDYAEAELAAEAEAELAAEAEAELAAOAEAELAGWADAALOPRCKAAGMCXWSVDLAAEAEAORHRFBNKEMUHPSBKEURNETNDYLRHGVTMSYKUEZTISLTJPCNBNSTBEKIRSPKRKAHIOAORDREKIPSLBLEWZVDBZGUKEESTNIOAARPTIVWKTFMVELTMSBGTEBEJNHTTOWTNLENBBVTLYCWJEDYAEAELAAEAEAELAAEAEAELAAOAEAELAGWADAALOPRCKAAHEWSAMDMLAAEAEAOWSGEHKUONSIOCLGHDISGWYTAWFCEYKHDJOBBHHJPGTASCFBDPSOXHSBTIOSNFH"
, "UR:CRYPTO-PSBT/3-29/LPAXCSCACFCMCPCYBBRSPTSKHDSSINJOIAZEHSAOAEHLLSLSJESRSPCHKSGLFTKPCKHNKSIHRSLSTIYTFGFWIADTTIAYWDBKLYGMGYLNBBCSGTATWMDYAEAELAAEAEAELAAEAEAELAAOAEAELAGWADAALOPRCKAAHNMHAHGOLAAEAEAOSPBDDRHETNLNBGSTRYDLYLBKTPKBWKKTHYTSIAATDKWYGWFHSSFYDRTBTBMOOTLGAOWNBWPDLDGSFSIDLBLBHPLYRYCXLNCMJLQDSFENDINSFZJNROAMCNIYDKDNTOFHIYBBQZEOVTMDDYAEAELAAEAEAELAAEAEAELAAOAEAELAGWADAALOPRCKAAQZDADIASLAAEAEAOVTLSLUKKAEZCOEEMBSJTCKGDCYSRTLGMURVTYTTIOEPRVWNBDL"
, "UR:CRYPTO-PSBT/4-29/LPAACSCACFCMCPCYBBRSPTSKHDSSFWRHHKTYFRTADNJNHTLGZMAOEMLNLGBSONFGCYCMCPCMTDFSEEUOOSJEWFEEUELUVAEOLSTDLSKKTTWPEMZCMNSGBBLPDNDYMYDYAEAELAAEAEAELAAEAEAELAAOAEAELAGWADAALOPRCKAASELPFZINLAAEAEAOPEJTRHKKFSWMPFLAFZGHPDSSDRAHLRTNGTCTMYGYWZPYESKETKFXTOTLJLCPVTHEAXAHBGMTAMWNSBYAMTENCHZSVDNDCWFDGADPKGAXWTPEGRJKTDRPFGOLLYMKGUPMSPBBFMFECKZEDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEADAEZCAXBNAOAEAEAEAXNSMNIAMKWYMHDWTNSSBZGSCNCFURCFINGDHYCMGABKMWBE"
, "UR:CRYPTO-PSBT/5-29/LPAHCSCACFCMCPCYBBRSPTSKHDSSPSASCFNTRTFNKIIYCYMURNCFGTFWAEAEAEAEZMZMZMZMDPDYNLHPPTTTCAJYTIQDMKCFVAIHJYNTBBHGSNGTFNSRWNYLJYDLINKPVAMOGTHPAOAEAEAEAEZMZMZMZMWPSGRYMEAOENPAMWPRRECAHDMTIOATLGOSWDRYGYLNDPHGMEFNMYQDYTSTRDCEPDBBAEAEAEAEZMZMZMZMHTHPUYAAAEAEAEAEAECHPTBBOYMNWDWYSKCEKBDTDPGMJZSRFSADOEZMYLSKRYKELTJLMNADAEAEAEAEAECHPTBBSTRDAHSBNLKIWTZEGDLPLPESCTIMHKUEKPBGATPSLTLNHDAOAEAEAEAEAECFKOPTBBBBCFAOWMDMONPDMUCMLTTOUERHJZGTLYISRYZO"
, "UR:CRYPTO-PSBT/6-29/LPAMCSCACFCMCPCYBBRSPTSKHDSSMHMDWESKFPLOPSLPUOAHAEAEAEAEAECFKOPTBBHELDQZKBJZBSASFXRDONSFFNIHRFKOIDGSOXDELKLOPSTIAODIAEAEAEAEAECMAEBBRHVSZSZSLABSGUHEFTFLFZAOSWTTGOCWHTISZSLPFRBYAHAEAEAEAEAECFKOPTBBSWNTMHYKEHWTIOYLIAOSJPIADKFYFSLRJEVDTEOYLOPSBGGRAOAEAEAEAEAECHPTBBRFOTFHBYEMHECNRLKONNSOTSLBSBWSTDRPLYDWKPLTBDIMEMAEAEAEAEAECHPTBBKTMKCPOXOSBSFMFGROCHVETTKOVLDWWLIMEEHYLSLTDMAYCHAEAEAEAEAECFKOPTBBFTDSKTAMLPDWBTBAKBEYURLPKPWNOXPRZMCX"
, "UR:CRYPTO-PSBT/7-29/LPATCSCACFCMCPCYBBRSPTSKHDSSCFLTCNSADLKSLOPSLNHDAOAEAEAEAEAECFKOPTBBNTKEENNSPDZSMNWKCNSBWNHPHGWZYTHLTOGDISWLLOPSGAHDAOAEAEAEAEAECMAEBBJYBALOJZCHTKFHUOENONSFLNJPCHIYGUOEDSTEGRBZVEDPAEAEAEAEAECFKOPTBBYTONSFSBDRLGKGLODYCXHHSNWDYLRFIEKBCFKBSGLOPSEYFZAOAEAEAEAEAECFKOPTBBWEYLREAOFDRKFSTEJTJYJPTBMEKEESOTVSPYTASNLOPSYKAYCHAEAEAEAEAECMAEBBRHUYOYSACPHKOLVLDEPSTLFNHTBNTBUEAYCLPRCKFGOXADAEAEAEAEAECHPTBBCPZMESGYPDRHOXHPRYVYAHTYHSIMFZLOSF"
, "UR:CRYPTO-PSBT/8-29/LPAYCSCACFCMCPCYBBRSPTSKHDSSGLMKHGOLHDZTKKLTFLSPADAEAEAEAEAECFKOPTBBVYSWTTSALFVWLNDIESEOCKMOKOSEZTNDSWSKTBKNLOPSTIJLAMAEAEAEAEAECFKOPTBBGDGHEOHGJEJYFDTPHGEHEMIHAXPDKOCYCWGOVLFPLOPSCAGRAOAEAEAEAEAECFKOPTBBGOVLSOMSDPPYRDSBHSWTSGTTMYSBBSTPHKJPAXFLLOPSBSVWAMAEAEAEAEAECFKOPTBBLNWDJYSOCFJESKUONSFHUEKSUEADKSCEFLHDGOKBLOPSFDMDAAAEAEAEAEAECHPTBBTECELTFMMYVAFPVTTEHKKIWYCAVDBZFWRYTIEMASLTDMECAXAEAEAEAEAECFKOPTBBFLLNMDTIKSSAZCREWMIOBYAX"
, "UR:CRYPTO-PSBT/9-29/LPASCSCACFCMCPCYBBRSPTSKHDSSIYFRATVLHYSWUOEOECJZJNCPLOPSWDLEAAAEAEAEAEAECMAEBBBWCTDNLRONEOBSKTSTHKTDRPRSOXKISSKGSKPDKNGSLPAOAEAEAEAEAECFKOPTBBFDLSJEROFRBAYACXDYNSCSOLDIPRSAPTFTDPMDKKLOPSEMOLCWAEAEAEAEAECHPTBBFWFDEEZCMELGSTRNFXGDCNMYEECYHNUORKSTURKBLTBNFPAXAEAEAEAEAECFKOPTBBFNUTJLLGMYCKNELDKPUYHHGTCTBZCTGDKEBTEODSLOPSKOAYCHAEAEAEAEAECHPTBBFSZMJKTLCFNBFYGTHKGSYTPYLNVSRTHGMOOTHTWLLTMHRLGLAEAEAEAEAECFKOPTBBFLMKHYDRLBIOTPPSUTHNWN"
, "UR:CRYPTO-PSBT/10-29/LPBKCSCACFCMCPCYBBRSPTSKHDSSPYCSJTHNZOONFZCPFDLNFWPROTLOPSKIMNADAEAEAEAEAECHPTBBCWTPWLDYSEGTDKJTEMMUKNMHIDKGISFLWKUOOYSBLTKSNBAOAEAEAEAEAECHPTBBRFJKCYWZWNDSLKPSZSHYCTRFDISTSPOTHETKCKHGLTEMMDAAAEAEAEAEAECPAECXHDGWFDVTSPHDOLBNKIGETEECLKOSOXLPJSSNFXSGCLAHESJSVTURDYJZCWSRKNDTKSFZAOAEAEAEAEAECHPTBBMKFXHYPYSFZEEOKEBZNSFHMWKPVERDRTSADABBVTLTIMROAOAEAEAEAEAECHPTBBRESPVDFLDKJNAEVAPFAOJOJLEODEATKKSESTFYDELTCXLDBDAEAEAEAEAECFKOHYCMFNGH"
, "UR:CRYPTO-PSBT/11-29/LPBDCSCACFCMCPCYBBRSPTSKHDSSPTBBWEKBWDJKRNRKIYIEKKTBVDBWPATOFGUEWMROHHDYLOPSTIIOAXAEAEAEAEAECHPTBBTLDAFECTLDJOBNSGJLIEFLRSLSLSMSFNBSTTWKFLLTJOLSAXAEAEAEAEAECHPTBBLNGARENTKKZOVTMWPEDNJOHPZTWMGHSGHEPAYADMLTKNUOAHAEAEAEAEAECHPTBBFRDTJOSOFDJTOTEECXWLVEVOCNPTYTGOHFPFLTLOLTHHWPADAEAEAEAEAECFKOPTBBKNVTLGWMTYJSJOAOYLDPSKGEPYFPVTWYMKCECHZCLOPSIDSPAAAEAEAEAEAECMAEBBMDLYTNMKOTJERSKOJYEYTNSTWLFRMOLGWMJKJKBWNLTLADAEAEAEAEAECMAEBBVORDKSSW"
, "UR:CRYPTO-PSBT/12-29/LPBNCSCACFCMCPCYBBRSPTSKHDSSSSKTTDWDVYBBESBAONPYBBFWFGTECLPFGWCNFGHFJZSPADAEAEAEAEAECHPTBBRYBTISHEFEZEBGOXPYYNKKRHSOHDBWBGPKPFJZBGLTZEEHASAEAEAEAEAECMAEBBRHFXTAZOHPBKFXWNHELSOYGEYKFMCWHTFMEHAETONSETAXAEAEAEAEAECFKOPTBBMDJYWPFMPMGUECDEKTCAMTGRSRRHBKMNEHURPLJLLOPSHYJYCTAEAEAEAEAECFKOPTBBDYBKBTKINECMJNRPAAHDGHUYIMNDPMYAMESBWTCNLOPSMDKPCHAEAEAEAEAECHPTBBCAOLZETDWNFPRTREGSVYEMTLCNBSENRTTBRSDAUELTJEJOAXAEAEAEAEAECHPTBBHFFRECTSMENN"
, "UR:CRYPTO-PSBT/13-29/LPBTCSCACFCMCPCYBBRSPTSKHDSSWEMWENFZLBBGAHLEMWVOHPDYESDPMOEOJKINLTBZWSASAEAEAEAEAECHPTBBFZLUEMFXNDBSGUGRNDFMVDUYCXIEVWVWOSVSPMFELTHYTIAOAEAEAEAEAECFKOPTBBOEIEVDJPYLDLJELGSPLPAYSBGMLBVTMETSFZAXMYLOPSRYJZAXAEAEAEAEAECHPTBBCHFWATRHAHSETAIYFMGDPDGLRLHSHYTYWFWKHNOSLTTODNLNAXAEAEAEAECMAEBBDSRTJPENOYDATNSPGRBABAJTCPPSPYOLJKEYHHRKISHKBTAEAEAEAEAECHPTBBMHFEHSGYBTYLHHEYRLFTOSGYIEFRTEYNHTJPLTMHLTNBTEASAEAEAEAEAECHPTBBPDCYOYRSGOIOQZFGOE"
, "UR:CRYPTO-PSBT/14-29/LPBACSCACFCMCPCYBBRSPTSKHDSSEHWDWEESMYMDJOYNHSLPFNLECAATFPLTIMKBBDAEAEAEAEAECFKOPTBBSOTLCLDMOXASWSFSIAMOSWMSCHCMKOURGHDWKOPELOPSPFPMADAEAEAEAEAECHPTBBUYWSYAPKWKPMWFLPMOAMMUFEINBBCWHDLDGMKGUYLTAXKPCHAEAEAEAEAECFKOPTBBFLMUCFSRVSRNDTHSSBDWHDMSIMMHFTVELGPLVENLLOPSOEGEAOAEAEAEAEAECHPTBBZOVWGDPLMNFELEBZMYVOKBWSWKFTROYLDAFEJYIOLTQDLKAAAEAEAEAEAECMAEBBCYHGWNTSHGFZNEKKHGDLWSURETRNSOLNGOLUZTNBMTPFAAAEAEAEAEAECHPTBBLUBZVDDLEHGUPTIALYCP"
, "UR:CRYPTO-PSBT/15-29/LPBSCSCACFCMCPCYBBRSPTSKHDSSAERKCSSTTKPDMONEFEWLKIBSKELALTGTGTCSAEAEAEAEAECHPTBBCATBNEFDBEPAPSMSWNSROXBKTAMOCHWFGYSBGWEOLTMWBBATAEAEAEAEAECFKOPTBBRPVLHETEVDAYCESODTHDLUMHREJKSPSFDPHGAXGHLOPSLDGAAHAEAEAEAEAECHPTBBTIUYPFOYKSIYDWWNFDCWMKWPTTTPNSVYDMFSWLPALTTDWNHPAEAEAEAEAECHPTBBPKVDNSMNSTLAMDOYDTCTBWUOWFKGZTMHIHAHKOGRLTDLEEAYAEAEAEAEAECHPTBBHGWZYKGORHSGPKCMADZSMKIDGWBEPERSPMVOKOOYLTJYUOAHAEAEAEAEAECHPTBBCWADIYWFHGCTLEZSYTJZLBWE"
, "UR:CRYPTO-PSBT/16-29/LPBECSCACFCMCPCYBBRSPTSKHDSSFGMYDEMNPLDNMKIEUOENTIIDLTTANYADAEAEAEAEAECFKOPTBBHEISASFZFYNYLBINAXHGHLHLMENLMNSTSSCMSRBALOPSSSTKAHAEAEAEAEAECFKOPTBBJSDICLTSAEJZKSPAWKGMYKHSYAKGCPGRCKDLMTKTLOPSDPZSDPAEAEAEAEAECHPTBBMNFGMNGHFDWTGUDMADSSRSDISGLYYASAPDSPIONDLTDWHDAOAEAEAEAEAECFKOPTBBMEFXVLVTATQZSTFENSZMPLUYECIHHLIEATKEFWGULOPSLNGEAOAEAEAEAEAECFKOPTBBWDTNFZDLLYECIANTVYOSCNFXSGWDJYEETAAYHKNTLOPSKONYADAEAEAEAEAECHPTBBJYDELOHFZEVTTPBA"
, "UR:CRYPTO-PSBT/17-29/LPBYCSCACFCMCPCYBBRSPTSKHDSSTKGYADWYOLLPESSEPMNEJEHHESLYGUBKLTEHBZATAEAEAEAEAECMAEBBHFBNZTIHVEMDFGZOTOTIHYKKZSNDCYVSKNLDCHKNAMTLBKAEAEAEAEAECHPTBBJKHKTACHCXENSOAADASWEHRKRTDLAANLSFBGHNAMLTMOLEBDAEAEAEAEAECFKOPTBBJNIADANBGAEODPMTMYMOPTPEMYMYCYSGEOYNVOMDLOPSONSEASAEAEAEAEAECHPTBBLNLEWKAHBWBEFDJKDNQDSPJTCERKKTFHESDSSEMYLTDPEEAOAEAEAEAEAECHPTBBJTUYWDYTFENEKGPSAOVYMWJZSBJSFTMSDLGEMTAHLTJNKPAOAEAEAEAEAECHPTBBWMWSHEOSRODEJYCENLISAE"
, "UR:CRYPTO-PSBT/18-29/LPBGCSCACFCMCPCYBBRSPTSKHDSSPMBEHEHNADVLYTPRVDMOHTLOZTLTSFGEAOAEAEAEAEAECHPTBBQZCNPTSKGUTNNBMDZSCNPSKSPALTEHLUFPGYMENDLTCEGRAOAEAEAEAEAECHPTBBJYLGJORFLBNYTORFQDDIISDRLGJZHDHNHSHLGOCNLTPRNEAHAEAEAEAEAECHPTBBPTFSCSBYYLYNEOTPAODESNYLSOMHLDJYBDRTWYPMLTOEMDAAAEAEAEAEAECHPTBBSSAHTPRFAXBNCYMSMWSEQZNNLPBAPRMSQDURAAOLLTLRBNAMAEAEAEAEAECHPTBBNBBGOEECWZAXDEJESGAXKKUTSNNDBTCKTIMKRTENLTJZBEAOAEAEAEAEAECFKOPTBBNLMDSKKBLONDPDEOHSKKFMCPFXDP"
, "UR:CRYPTO-PSBT/19-29/LPBWCSCACFCMCPCYBBRSPTSKHDSSCFTEGRLRASLDATSATAMELOPSBSTYADAEAEAEAEAECHPTBBVWQZWDHEEYEYSOAXKOQZVDPEIADLJKNTDNUEOXDPLTMHHYAOAEAEAEAEAECFKOPTBBGASSRSLRSAHLFDWECABBGOCMEYLNZTMUKOBYPMYTLOPSLSGEAOAEAEAEAEAECFKOPTBBPYECBGRTFPASBAPAPSSFASGDEEVETOSGDASTCFTOLOPSKIDRASAEAEAEAEAECHPTBBAXTPDKIYKPWMRTFSVDGEDRUTVEYATPZEIDPYMNPRLTPMMDAAAEAEAEAEAECHPTBBKOCSPLMYFYWTMWKPVTSELDZSVEHYONHFVSVSTEHFLTDAKPCHAEAEAEAEAECMAEBBLABDLDVWLBLNGUJPDPCAVDENHD"
, "UR:CRYPTO-PSBT/20-29/LPBBCSCACFCMCPCYBBRSPTSKHDSSDTSBTKDECHRHPKHKVWMDMNKSGDAOAEAEAEAEAECHPTBBEODKPLETLBLDAMJOPMBNPEPLWMFZLTZTHGOEQZTELTLGAYCHAEAEAEAEAECHPTBBFXSAWKIDLTENBSKPJLFEFLMNCLPKEMTPWPMHMHIOLTKECSAMAEAEAEAEAECHPTBBINTKMWZMYNKNKEZCBGKTHDFEZOPAYNPRMEFTHPKGLTAEAEAEAEADADDNEMMDAAAEAEAEAEAECPAECXHDGWFDVTSPHDOLBNKIGETEECLKOSOXLPJSSNFXSGCLAHESJSVTURDYJZCWSRKNDTADAHTKGHCLAOFSTDLNUYSAASIESFDNRKHSMNJZTONLPSLDWFTDMNINOXEHHNKOTODRWPCHRORHDACLAEETWDVL"
, "UR:CRYPTO-PSBT/21-29/LPBZCSCACFCMCPCYBBRSPTSKHDSSAOHYTYLNWFESHNBNMEWLPRGDVWGSRSRSDYYAPRDYKPROTELTDEVTWSHGSACYSKDKFMCLAOSWMKBTHTBWLKWZKPSWJTGECPNLMDLKWSAEKNRELPMYWECPMYRKIDTYINEHRSCPFHCLAXBTDIMERPQZJKFTCSIHZCETSGSBTLPLGRDWHDWNUTWPLTBWTSFGWFZCEEAAIDKNZOCLAXHPFZFZWKBBOELSFGCSFPSRCLISDKESBGAOHSHNZTJYCAWFBTPRGATOBWEOGOAHYTCLAXMYZOWPFWSOYNQZYLZOETHTFYURSBUEHKFNTYFDNNVWTAFWCNHYGMROTYYAVWMDKBHFPLCPAMAOFSTDLNUYSAASIESFDNRKHSMNJZTONLPSLDWFTDMNINOXPTKNSSDR"
, "UR:CRYPTO-PSBT/22-29/LPCMCSCACFCMCPCYBBRSPTSKHDSSEHHNKOTODRWPCHRORHDACEFMFECKZEDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEADAEAEAECPAMAOHYTYLNWFESHNBNMEWLPRGDVWGSRSRSDYYAPRDYKPROTELTDEVTWSHGSACYSKDKFMCEVTLYCWJEDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEADAEAEAECPAMAOSWMKBTHTBWLKWZKPSWJTGECPNLMDLKWSAEKNRELPMYWECPMYRKIDTYINEHRSCPFHCELPDNDYMYDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEADAEAEAECPAMAXBTDIMERPQZJKFTCSIHZCETSGSBTLPLGRDWHDWNUTWPLTBWTSFGWFLTTBCFDR"
, "UR:CRYPTO-PSBT/23-29/LPCHCSCACFCMCPCYBBRSPTSKHDSSZCEEAAIDKNZOCECSGTATWMDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEADAEAEAECPAMAXHPFZFZWKBBOELSFGCSFPSRCLISDKESBGAOHSHNZTJYCAWFBTPRGATOBWEOGOAHYTCEQZEOVTMDDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEADAEAEAECPAMAXMYZOWPFWSOYNQZYLZOETHTFYURSBUEHKFNTYFDNNVWTAFWCNHYGMROTYYAVWMDKBCEKBURNSHKDYAEAELAAEAEAELAAEAEAELAAOAEAELAAEAEAEAEADAEAEAEAEADADTKGHCLAOVWVEPMOXMSKKSBOTDTJTFENBGYLRHSDLOXPMJEJOFZQZVLGLFDFZVSFRTIBZ"
, "UR:CRYPTO-PSBT/24-29/LPCSCSCSCACFCMCPCYBBRSPTSKHDSSRPROLPTSCLSECLAXBAHSMTDLKPDPVYVWDWKGYTHKCKRSSWEMSKGLDYPSHEBYFSEYTEQZSEHETNWYIEVDCLAXBWWKLKUTLYEYFXSKBTAOFRMONYTYKTDIHLYNSENSDIGREMTEHKPSEYLKLBKOKBHKCLAXNENBIDEEENKGHNMYZMPMDNNLMNQDFDIAGAEEBDKSKGDYBYDMPEYTWFDIROBZCHGWCLAXREAMJNKKZCESYKSWJOJPTBRDEOKGBSHHDTIYPSBEPSVWKSYKJPCPDKUYIMPEOSFECLAXWTSOSKSKFNWYBYLBNSHTEEEEECTORFLRBYCWROTKVTEMBDPDQDTEVALECAWNWDVYHFPLCPAOAOVWVEPMOXMSKKSBOTDTJTFENBGYLRHSTYRPGOLN"
, "UR:CRYPTO-PSBT/25-29/LPCSCFCSCACFCMCPCYBBRSPTSKHDSSDLOXPMJEJOFZQZVLGLFDFZRPROLPTSCLSECECSGTATWMDYAEAELAAEAEAELAAEAEAELAAOAEAELAADAEAEAEAEAEAEAECPAOAXBAHSMTDLKPDPVYVWDWKGYTHKCKRSSWEMSKGLDYPSHEBYFSEYTEQZSEHETNWYIEVDCEVTLYCWJEDYAEAELAAEAEAELAAEAEAELAAOAEAELAADAEAEAEAEAEAEAECPAOAXBWWKLKUTLYEYFXSKBTAOFRMONYTYKTDIHLYNSENSDIGREMTEHKPSEYLKLBKOKBHKCEKBURNSHKDYAEAELAAEAEAELAAEAEAELAAOAEAELAADAEAEAEAEAEAEAECPAOAXNENBIDEEENKGHNMYZMPMDNNLMNQDFDIAGAEEBDWFWYAAGH"
, "UR:CRYPTO-PSBT/27-29/LPCSCWCSCACFCMCPCYBBRSPTSKHDSSRPGHAMIYBBIACWHGRSHHPFMNVLCLAOPMIHLFKBPRAEGOHKBNDTZMBELOKKDLWNZOWKNLHHAEYAGHKTYTVSJSIYNSPEHEMUCLAOPLYNMOKTBAIYVWNSJLSABYKGZTFGSKCSMUYTDYIDAXLPTBUTJOLFRTCYSTPTRLLUCLAXASFGRNDPFEFHJZNDJNUEJSIDJYCLTKPFPELTISCMINESYTSGWFBZHTJLLRRSNLCKCLAXSASBZTLSJKHHREFYCPHDBNSEEYWLFGDKKOWDROBGPMHLSPQDPDCPKGYTSTBDCPRECLAXTDSEBSOTLGIAGMTLRHTSWDCPDKEEBSCEHPJYPASKMSWLOTSTLEZOOLZSFYZOHDCSHFPLCPAOAOOEWLYATYBAOYLKOLSWMTTPMW"
, "UR:CRYPTO-PSBT/26-29/LPCSCYCSCACFCMCPCYBBRSPTSKHDSSKSKGDYBYDMPEYTWFDIROBZCHGWCEFMFECKZEDYAEAELAAEAEAELAAEAEAELAAOAEAELAADAEAEAEAEAEAEAECPAOAXREAMJNKKZCESYKSWJOJPTBRDEOKGBSHHDTIYPSBEPSVWKSYKJPCPDKUYIMPEOSFECEQZEOVTMDDYAEAELAAEAEAELAAEAEAELAAOAEAELAADAEAEAEAEAEAEAECPAOAXWTSOSKSKFNWYBYLBNSHTEEEEECTORFLRBYCWROTKVTEMBDPDQDTEVALECAWNWDVYCELPDNDYMYDYAEAELAAEAEAELAAEAEAELAAOAEAELAADAEAEAEAEAEAEAEAEADADTKGHCLAOOEWLYATYBAOYLKOLJESGHTGYJLCLRHSGLFKPBDCLSEHYMT"
]
d = DecodeQR()
for i in qrcodes:
d.add_data(i)
assert d.qr_type == QRType.PSBT__UR2
#complete should be true
assert d.is_complete
base64_psbt = "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"
assert base64_psbt == d.get_base64_psbt()
tx = d.get_psbt()
assert str(tx) == base64_psbt
def test_base64_single_frame_singlsig():
qrcodes = [
"cHNidP8BAHICAAAAAQDo5ey+2HIrNUkExsFhsImv1OK1cYA9x/bRjYQD+0UaAQAAAAD9////Apg6AAAAAAAAF6kUVuVZEcdpQ2zgABa9dRUNYHD4VuaHgSYAAAAAAAAWABQaLE4t0JbDRg4pNnmcf+cAWIcyawAAAAAAAQEfqGEAAAAAAAAWABRyuw9od6yuS0yiZljV0X12wG9e5CIGA/ZlEZvQubb6PmcnK+vlnd8aftYnrQ8wHYSxsD8tDp61GIshjoFUAACAAQAAgAAAAIAAAAAAAAAAAAAAAA=="
]
d = DecodeQR()
for i in qrcodes:
d.add_data(i)
assert d.qr_type == QRType.PSBT__BASE64
#complete should be true
assert d.is_complete
base64_psbt = "cHNidP8BAHICAAAAAQDo5ey+2HIrNUkExsFhsImv1OK1cYA9x/bRjYQD+0UaAQAAAAD9////Apg6AAAAAAAAF6kUVuVZEcdpQ2zgABa9dRUNYHD4VuaHgSYAAAAAAAAWABQaLE4t0JbDRg4pNnmcf+cAWIcyawAAAAAAAQEfqGEAAAAAAAAWABRyuw9od6yuS0yiZljV0X12wG9e5CIGA/ZlEZvQubb6PmcnK+vlnd8aftYnrQ8wHYSxsD8tDp61GIshjoFUAACAAQAAgAAAAIAAAAAAAAAAAAAAAA=="
assert base64_psbt == d.get_base64_psbt()
tx = d.get_psbt()
assert str(tx) == base64_psbt
mnemonic = "height demise useless trap grow lion found off key clown transfer enroll".split()
pw = ""
seed = Seed(mnemonic, passphrase=pw)
assert seed.mnemonic_str == " ".join(mnemonic)
assert seed.seed_bytes != None
pp = PSBTParser(p=tx, seed=seed, network=SettingsConstants.TESTNET)
assert tx.inputs[0].witness_utxo.value == 25000 # input amount in psbt
assert (pp.spend_amount + pp.change_amount + pp.fee_amount) == 25000
assert pp.change_amount == 0 # should have change, but not sure why not
assert pp.spend_amount == 24857
assert len(pp.destination_addresses) == 2
def test_ur2_sparrow_singlesig_to_self():
qrcodes = [
"UR:CRYPTO-PSBT/435-3/LPCFADQDAXCFAOOECYMSTBHDCSHDVYHTAXLATPBEOEDPAYIAWSYNAMSGSARSURCLDRKNFYZEWLHLMDTNATNYNSETJNZOKBGLFMRTMWOTLAFSSTYNTIPTLTTLWPVOZEHTAHTESNYADSHYVYFPDEBTBAIHIYTLWFUERDLKWTLSNLMWCHNDPSBWGRUTKSYLFLATVDCYNTDNGDTNURYLTTGUSSHNAEEEFZSRLEKEHDEMCYOTLDEMOTZORFDPKBCLBEHNREFWIDOSRSLRIOIAOXNLADDYENFMVOGLSGECDKBECSDSLUHNDTWYYTWFSNSPPESAZCGUDLDABAISLNJLWKJPRHBBRTEHYALRJYNYKPEOGLGLOLCPPYSEZTCHVLFMPELDGWCXGMSPHPGWAOKNBALOFXJLKNONPRBAPKYKIEVETEDWFXMDRTVWBYKSZTBTCLSGCSCPIYTPTYGYKIYNRTJLHLIEMNJYCTVYUEHGPRHN"
, "UR:CRYPTO-PSBT/440-3/LPCFADROAXCFAOOECYMSTBHDCSHDVYAOAEAEAEAORTHKYLIDWSLTBGSGTBSNIHDMPKVSAAWYKNIACELDCMGRLULRKNLUMKRSBACNCPTBADAEAEAECNCPAECXJPRPLBLURFIHEMSWRFLNECGOTKGRMHLBCSAXTYJKREPKWEBWEYAYIYNDJPCWFSLSZCZMZMZMDLIHKNPYASHLWECEMEGSSSVTAEEEFZSRNSKEGSVYWNCMAMTNATMWCYMYWTUEPDTDAEAEAEAECNCPAECXONRSTTHSLBCPREBTRHBGJKSEWYPMTNPKEHIHHELPQDLSLPFRWNKBBTVAPMDTBEDAZCZMZMZMAOPKPEAOAEAEAEAEAECHPTBBCAWPEEVAOYIMDISSIDNNRFISRHBDGLATSASWAXGULTPDHSAEAEAEAEAEAECMAEBBJPRKBSISKTPSPLGRGSOEIYHDTLTTKIKORTJLHYVEMNKPCTAEDLFPBASG"
, "UR:CRYPTO-PSBT/441-3/LPCFADRHAXCFAOOECYMSTBHDCSHDVYHTAXLATPBEOEDPAYIAWSYNAMSGSARSURCLDRKNFYZEWLHLMDTNATNYNSETJNZOKBGLFMRTMWOTLAFSSTYNTIPTLTTLWPVOZEHTAHTESNYADSHYVYFPDEBTBAIHIYTLWFUERDLKWTLSNLMWCHNDPSBWGRUTKSYLFLATVDCYNTDNGDTNURYLTTGUSSHNAEEEFZSRLEKEHDEMCYOTLDEMOTZORFDPKBCLBEHNREFWIDOSRSLRIOIAOXNLADDYENFMVOGLSGECDKBECSDSLUHNDTWYYTWFSNSPPESAZCGUDLDABAISLNJLWKJPRHBBRTEHYALRJYNYKPEOGLGLOLCPPYSEZTCHVLFMPELDGWCXGMSPHPGWAOKNBALOFXJLKNONPRBAPKYKIEVETEDWFXMDRTVWBYKSZTBTCLSGCSCPIYTPTYGYKIYNRTJLHLIEMNJYCTVYWZGSVWDN"
, "UR:CRYPTO-PSBT/443-3/LPCFADRKAXCFAOOECYMSTBHDCSHDVYAXADCTPDIARTHKYLIDWSLTAASGSARSUECLSANEPDFZEHDLRNWSGLNNHTYTBNGRYLVYWDCPCLTDAEAEAEAEADDKAXTBCHOSVEHPAHTESNYAUYOYCKRNDRTBGWIHIYTLWFUERDNYWTMSLSROHKRPKELPLONDKOUEJSKBKGIHKNDNAYHLWENSMEGSSSHNAEEEFZSRNSKEGSVYWNEEAATAPYIMPASNHPFWMETEAYBYHFRSBBZCDSRDTTLNADLBEMFTTSSOAHENPFNTVSVEBDHNDTWYKBBDEYTSLPFRJSLBBTVADPDTBEDAKIZEZMZMAOPKPEAOAEAECPAOAXWKGRNLJEVSZMWSIDSOTTEHHETYFTFXCASBMKGTURBWJLIMTLLUFWSTSSKIZMLAFXBALUECZTFTHPISKTDWPEGRGSCPIYHDTLGYKIKORTJLHLVEMNKPCTAERKWPCMJN"
]
d = DecodeQR()
for i in qrcodes:
d.add_data(i)
assert d.qr_type == QRType.PSBT__UR2
#complete should be true
assert d.is_complete
base64_psbt = "cHNidP8BAHECAAAAAQDo5ey+2HIrNUkExsFhsImv1OK1cYA9x/bRjYQD+0UaAQAAAAD9////AttBAAAAAAAAFgAUGixOLdCWw0YOKTZ5nH/nAFiHMmtAHwAAAAAAABYAFNbrl43uCJEN4CVjgbO9UzQYq3lB2XUfAE8BBDWHzwOUjfDCgAAAAIf4/x8q+YwsIsMjQZZKiYxG68KbV4Z0mlcxTbrtu8ApA/iB9364EPRoi0aEmjfRmywFry7wyW6Im2SQIsigPN9KEIshjoFUAACAAQAAgAAAAIAAAQDhAgAAAALAWfdi74cSytbNZS6q6ATuemMciRZLi4R6i5i/DiMi1gEAAAAjIgAgcrZ/i7xlN8a8hjVVz0uQfxgD1HO1qu0TMghmm3IbPYP9////L2V6qwld7RyRTMTgADRAw5x8TOHxFgbaB5Qaj/DeqNIAAAAAIyIAIKW/0WF/IrUNuRJzwe6t2qoxZV+Fs4OFO/F+DeatKRAl/f///wKqrwIAAAAAABepFB3sNOahaifEYp68aLkLTgfCxgNTh6hhAAAAAAAAFgAUcrsPaHesrktMomZY1dF9dsBvXuSOdR8AAQEfqGEAAAAAAAAWABRyuw9od6yuS0yiZljV0X12wG9e5AEDBAEAAAAiBgP2ZRGb0Lm2+j5nJyvr5Z3fGn7WJ60PMB2EsbA/LQ6etRiLIY6BVAAAgAEAAIAAAACAAAAAAAAAAAAAIgIDrP6rQqucOQEIEVa/N98mmnQ50B5IGGLEvCTDXAZJ0coYiyGOgVQAAIABAACAAAAAgAEAAAAAAAAAACICA+PijXYEywnDo/b1PUqGK6TA1kod1Ww5UiMjx8R9/4BDGIshjoFUAACAAQAAgAAAAIAAAAAAAwAAAAA="
assert base64_psbt == d.get_base64_psbt()
tx = d.get_psbt()
assert str(tx) == d.get_base64_psbt()
def test_base64_2_input_p2wsh():
base64_psbt = "cHNidP8BALICAAAAAq1DhxRK+mUH4T6uUNob8bUaZ7MP+44MW4+Y9bOxpjhZAAAAAAD9////aWclWQ+45HKrI07r878E2UrAupT2paT4QurbmtNjYNQBAAAAAP3///8CQEIPAAAAAAAiACCpkDPDhmIzPlkJrjw9A71xjbIUWf3VUB7ooFJhTVm04tjSIQEAAAAAIgAgjQKFDauIXsV5u23LBdYgOwX1FwGGrLiQfWzBtFKZ7dIAAAAATwEENYfPBD5i336AAAACQStJhNVJul7vHKbo83VdmuAW2m0WaXLKDlFANn7dUNoCNbhLMdw4Knz7Q7o6exdL6UFhQegW9nJb0SUStbLEpawUAgjLdzAAAIABAACAAAAAgAIAAIBPAQQ1h88EnbHQAIAAAAI/2Nc7x7iMpJNapTe/OJTV4oifqzQcYY9KV2+PGRjCdQJoww1WnSNqfcxXGyux0q1PqfmzUqgJNqKJCpmqI9t47BQmu4PEMAAAgAEAAIAAAACAAgAAgE8BBDWHzwS6wUg5gAAAAh1Pvr3ZZ+GvcUwJl9OPz2cLXOnTAcBEC7zDtqIOt3IcA1aOofNgUZFu0baQw54SqOcGA7KAvTDOXygfKRilU2OqFHPF2gowAACAAQAAgAAAAIACAACAAAEBK4CWmAAAAAAAIgAgiYAxcG7dnrEiZ4VHFVHOo18XCalvhZYuMqBr9n7HESQBBWlSIQJOjQgMfX26XEf+trHIEk3rYkEX5Y2NfrFKQARPcd2X8iEDBWHUgq25PfHvE+hlcBryJG7wo2y8jKUSPY7sd85OOMchA2iVcuKLD+2p1pgcAjfZ5d7b/sFt5xQ/aAoC7V0Vn3WHU64iBgJOjQgMfX26XEf+trHIEk3rYkEX5Y2NfrFKQARPcd2X8hwmu4PEMAAAgAEAAIAAAACAAgAAgAAAAAABAAAAIgYDBWHUgq25PfHvE+hlcBryJG7wo2y8jKUSPY7sd85OOMccAgjLdzAAAIABAACAAAAAgAIAAIAAAAAAAQAAACIGA2iVcuKLD+2p1pgcAjfZ5d7b/sFt5xQ/aAoC7V0Vn3WHHHPF2gowAACAAQAAgAAAAIACAACAAAAAAAEAAAAAAQErgJaYAAAAAAAiACAzd60wM9EFnPHSNbsSJfyipL8myVLVP2/vwzotVUSNxQEFaVIhAiKCMRLlzIhLkRbLIUIMx5KYJM0v6LcjW/mS6K7eFGwiIQKDzUflU23LeecRgzDo5IBCEvaWGfHW7JkNxzXvuc7FdCEDC5DtLoa61/Kk/pdpu0F9e6nKoRJIB9v7Ni377rZefgFTriIGAiKCMRLlzIhLkRbLIUIMx5KYJM0v6LcjW/mS6K7eFGwiHAIIy3cwAACAAQAAgAAAAIACAACAAAAAAAAAAAAiBgKDzUflU23LeecRgzDo5IBCEvaWGfHW7JkNxzXvuc7FdBwmu4PEMAAAgAEAAIAAAACAAgAAgAAAAAAAAAAAIgYDC5DtLoa61/Kk/pdpu0F9e6nKoRJIB9v7Ni377rZefgEcc8XaCjAAAIABAACAAAAAgAIAAIAAAAAAAAAAAAABAWlSIQKtIdmtKKuZrH7f2R4iIU8RWVOrCdHVWBCS+0e9pZJy/iEDoH074LrWPIA10hyXtBCJDT06GdLkA6+z/PxoJqomPHYhA6GoQ/otQdk71nUpYZFfbkSKdBkkSj4CuPTPYrzGp6JrU64iAgKtIdmtKKuZrH7f2R4iIU8RWVOrCdHVWBCS+0e9pZJy/hwCCMt3MAAAgAEAAIAAAACAAgAAgAEAAAAAAAAAIgIDoH074LrWPIA10hyXtBCJDT06GdLkA6+z/PxoJqomPHYcc8XaCjAAAIABAACAAAAAgAIAAIABAAAAAAAAACICA6GoQ/otQdk71nUpYZFfbkSKdBkkSj4CuPTPYrzGp6JrHCa7g8QwAACAAQAAgAAAAIACAACAAQAAAAAAAAAAAA=="
d = DecodeQR()
d.add_data(base64_psbt)
assert d.qr_type == QRType.PSBT__BASE64
tx = d.get_psbt()
assert str(tx) == base64_psbt
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".split()
pp = PSBTParser(p=tx, seed=Seed(mnemonic), network=SettingsConstants.TESTNET)
assert tx.inputs[0].witness_utxo.value == 10000000 # input amount 1 in psbt
assert tx.inputs[1].witness_utxo.value == 10000000 # input amount 2 in psbt
assert pp.input_amount == 20000000
assert (pp.spend_amount + pp.change_amount + pp.fee_amount) == 20000000
assert pp.destination_addresses[0] == "tb1q35pg2rdt3p0v27dmdh9st43q8vzl29cps6kt3yradnqmg55eahfqfgn83n"
assert len(pp.destination_addresses) == 1
def test_base64_1_input_p2sh_p2wsh():
base64_psbt = "cHNidP8BAHICAAAAAR30J629i3Y/R8woRpLQ9JUa31rKxyM+Ny4NEsme48GWAAAAAAD9////Atw5XQUAAAAAF6kUdSESczdYagEyToVUSXyT8VTNz+OHgJaYAAAAAAAWABTmav7/w4OOcfCiewfjsA7eaujhYAAAAABPAQQ1h88EPmLffoAAAAHdXEj2dn8EYJ+rRdXEYu5laq6lJI5Mp+3t63ckwty05QKrJBNPewhwQaGPYRif6+XaxozFXvTXn7pU24H6fRy1FxQCCMt3MAAAgAEAAIAAAACAAQAAgE8BBDWHzwSdsdAAgAAAAeeOv56oeaaFTrNonMKDHk1C8brbWGFvdlecVue+v0/RAn/g4yI3oYsyen7OOcT7caYl4Mn7nQbyonHcusUR+GhzFCa7g8QwAACAAQAAgAAAAIABAACATwEENYfPBLrBSDmAAAABpzrb4oeEh2NNy/w/fr3osfyZTx7AaGDPAcP+LqeR3bYC5ioqmXPuazp69HwimlvecLylm9BLuyl/VpPXqiVrl20Uc8XaCjAAAIABAACAAAAAgAEAAIAAAQEgAOH1BQAAAAAXqRSv3gkn8731qcPbSDu4TJOlJJZ/PocBBCIAIOeiFBX5x0vX6CacrAUVovrs1DDCcKJS5qptFS3sjpDpAQVpUiECZ+pFYkOTVjB+eG+vQFA3MNjZWiA6DjRcs1Wl36A/zgMhA2Ygckuwjah29wiVRgA6wFx51+6ayrzeCIQ2eE4zfxPtIQOnUlBn22cn2CPCZkMSI6cDaZK2SlLV20rT6pqMoQCJsFOuIgYCZ+pFYkOTVjB+eG+vQFA3MNjZWiA6DjRcs1Wl36A/zgMcc8XaCjAAAIABAACAAAAAgAEAAIAAAAAAAAAAACIGA2Ygckuwjah29wiVRgA6wFx51+6ayrzeCIQ2eE4zfxPtHCa7g8QwAACAAQAAgAAAAIABAACAAAAAAAAAAAAiBgOnUlBn22cn2CPCZkMSI6cDaZK2SlLV20rT6pqMoQCJsBwCCMt3MAAAgAEAAIAAAACAAQAAgAAAAAAAAAAAAAEAIgAgZBwTq05RkpqKv6FV6LQjuM07Qv0/bYfWVc9NUQOFvwQBAWlSIQI32jVSdTgeu7+YZKrWfgOZ2J/LV36c5rBoApTzhrNlDCEC+hEqm3XmRt862AFFeyJ7p1m8A+V7czj6OajUNgCfg4EhA/MUVfxGh4k3Po3LB8CmMRsvIHcGNO0elUgETaITZA3UU64iAgI32jVSdTgeu7+YZKrWfgOZ2J/LV36c5rBoApTzhrNlDBwCCMt3MAAAgAEAAIAAAACAAQAAgAEAAAAAAAAAIgIC+hEqm3XmRt862AFFeyJ7p1m8A+V7czj6OajUNgCfg4EcJruDxDAAAIABAACAAAAAgAEAAIABAAAAAAAAACICA/MUVfxGh4k3Po3LB8CmMRsvIHcGNO0elUgETaITZA3UHHPF2gowAACAAQAAgAAAAIABAACAAQAAAAAAAAAAAA=="
d = DecodeQR()
d.add_data(base64_psbt)
assert d.qr_type == QRType.PSBT__BASE64
tx = d.get_psbt()
assert str(tx) == base64_psbt
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".split()
pp = PSBTParser(p=tx, seed=Seed(mnemonic), network=SettingsConstants.TESTNET)
assert tx.inputs[0].witness_utxo.value == 100000000 # input amount 1 in psbt
assert pp.input_amount == 100000000
assert (pp.spend_amount + pp.change_amount + pp.fee_amount) == 100000000
assert pp.destination_addresses[0] == "tb1que40al7rsw88ru9z0vr78vqwme4w3ctqj694kx"
assert len(pp.destination_addresses) == 1
def test_specter_multisig_animated_qr():
qrcodes = [
"p2of5 OUsU2k9a6Valj6kLb/Bh2gB7YuxenNz7LY5PFJkKc60wAACAAQAAgAAAAIACAACATwEENYfPBEgFouKAAAACOeERUyCmIJuSdQNDB1mxkahw4tc2UCtjxJQoQGnRCtQCZUSXwQF+nA8dl/RG6U1b9ViWJxkzNrDCCagYEWch72cUrnhJ4jAAAIABAACAAAAAgAIAAIAAAQErckUPAAAAAAAiACDwHjagvyTvVDVn+RqxW0xaMLODBm2IVCwDBQm5uK8rDQEFR1IhAi/hk/Tz0aHcNwsVyv86bqQj30sUexPl"
, "p3of5 c738CqJg+flLIQKmgeTdVjPh9P+MPnsTPbFRcGGLPAO3iTyYBR7eYQC4VlKuIgYCL+GT9PPRodw3CxXK/zpupCPfSxR7E+VzvfwKomD5+UscrnhJ4jAAAIABAACAAAAAgAIAAIABAAAACgAAACIGAqaB5N1WM+H0/4w+exM9sVFwYYs8A7eJPJgFHt5hALhWHJkKc60wAACAAQAAgAAAAIACAACAAQAAAAoAAAAAAQErMHUAAAAAAAAiACAUS+ztgOw4wxEOYDdQEZp42Ii3sA39MdXZMWolM3s9VgEFR1Ih"
, "p4of5 Amdcnz6cgLhxNS0Lv3mz7OVOGunGsAlEsekZiQRDLDXHIQLfPg77+MKPe073vgkXRfWAZMxohe3ysPahJ0jIFl3GU1KuIgYCZ1yfPpyAuHE1LQu/ebPs5U4a6cawCUSx6RmJBEMsNcccrnhJ4jAAAIABAACAAAAAgAIAAIAAAAAAQgAAACIGAt8+Dvv4wo97Tve+CRdF9YBkzGiF7fKw9qEnSMgWXcZTHJkKc60wAACAAQAAgAAAAIACAACAAAAAAEIAAAAAAQEr8FUAAAAAAAAiACCcheUwIAj6XLtEe5QO"
, "p5of5 +fTi25/ZvJGX9MuZkpghbW3VMgEFR1IhAkhWBpUeAB+UbbJc8f1fkEMEZgIChQVpMdJnD05uBtU4IQMUAdnwr2UVz6AhNBI5j6an4wHRGVX3uhSLaWy2qS70xlKuIgYCSFYGlR4AH5Rtslzx/V+QQwRmAgKFBWkx0mcPTm4G1TgcmQpzrTAAAIABAACAAAAAgAIAAIAAAAAARAAAACIGAxQB2fCvZRXPoCE0EjmPpqfjAdEZVfe6FItpbLapLvTGHK54SeIwAACAAQAAgAAAAIACAACAAAAAAEQAAAAAAA=="
, "p1of5 cHNidP8BAKQCAAAAA6DLc9RAdKwWQb/7Nrq1FyAtDQ3e0w5E4LkLpcrwBL0aAAAAAAD9////78NG2vqjywKaa0QHfo6C44o1+odXeWZ43FfHy4bLdxABAAAAAP3///8rhueJha90HzgJ6alnJ1uvi0Zbq0JQoXnwDb0Cjn79DwAAAAAA/f///wHWCBAAAAAAABYAFDraKFKubXzlSvRQy8V4X+TwKhLXAAAAAE8BBDWHzwQJeplqgAAAAqmHnnoRR+XJd7gJt/PhLazKeWAfCBLJ4/OF/s0PqqF1AzK8fctt"
]
d = DecodeQR()
for i in qrcodes:
if d.add_data(i) == DecodeQRStatus.COMPLETE:
break
assert d.qr_type == QRType.PSBT__SPECTER
#complete should be true
assert d.is_complete
tx = d.get_psbt()
mnemonic = "zone zone zone zone zone abandon ability able abandon ability able abstract".split()
pp = PSBTParser(p=tx, seed=Seed(mnemonic), network=SettingsConstants.TESTNET)
assert pp.input_amount == 1052818
assert pp.change_amount == 0
assert pp.spend_amount == 1052818 - pp.fee_amount
assert pp.fee_amount == 1980
tx.sign_with(pp.root)
trimmed_tx = PSBTParser.trim(tx)
expected_signed_trimmed_base64 = "cHNidP8BAKQCAAAAA6DLc9RAdKwWQb/7Nrq1FyAtDQ3e0w5E4LkLpcrwBL0aAAAAAAD9////78NG2vqjywKaa0QHfo6C44o1+odXeWZ43FfHy4bLdxABAAAAAP3///8rhueJha90HzgJ6alnJ1uvi0Zbq0JQoXnwDb0Cjn79DwAAAAAA/f///wHWCBAAAAAAABYAFDraKFKubXzlSvRQy8V4X+TwKhLXAAAAAAAiAgKmgeTdVjPh9P+MPnsTPbFRcGGLPAO3iTyYBR7eYQC4VkcwRAIga3QJaZWl+pwWMjMc2PjxNIeFHeg6TF5bb57VYY5qg5cCIGRT9zijaAwbPkBMDqmKQSjEmqWSiAEDkRznqZYggIRGAQAiAgLfPg77+MKPe073vgkXRfWAZMxohe3ysPahJ0jIFl3GU0cwRAIgFEHGf3EbOMs/MPoWmbm/rBqSKyaST4XC+7WLqEsukgUCIFtimNwjtrGq4oI0QbIfJNC2HuedHKE9PyO7HULWTUfHAQAiAgJIVgaVHgAflG2yXPH9X5BDBGYCAoUFaTHSZw9ObgbVOEcwRAIgAsQjpMwk1Hz+LOIc4WWcR4dGA7h/IIqUPpqvVZup1HgCIDkKf/vx5xUQnI3ISjv5/vMd5qpXkMdy6mv8bnn881/pAQAA"
assert str(trimmed_tx) == expected_signed_trimmed_base64
qrcodes2 = [
"p3of5 c738CqJg+flLIQKmgeTdVjPh9P+MPnsTPbFRcGGLPAO3iTyYBR7eYQC4VlKuIgYCL+GT9PPRodw3CxXK/zpupCPfSxR7E+VzvfwKomD5+UscrnhJ4jAAAIABAACAAAAAgAIAAIABAAAACgAAACIGAqaB5N1WM+H0/4w+exM9sVFwYYs8A7eJPJgFHt5hALhWHJkKc60wAACAAQAAgAAAAIACAACAAQAAAAoAAAAAAQErMHUAAAAAAAAiACAUS+ztgOw4wxEOYDdQEZp42Ii3sA39MdXZMWolM3s9VgEFR1Ih"
, "p4of5 Amdcnz6cgLhxNS0Lv3mz7OVOGunGsAlEsekZiQRDLDXHIQLfPg77+MKPe073vgkXRfWAZMxohe3ysPahJ0jIFl3GU1KuIgYCZ1yfPpyAuHE1LQu/ebPs5U4a6cawCUSx6RmJBEMsNcccrnhJ4jAAAIABAACAAAAAgAIAAIAAAAAAQgAAACIGAt8+Dvv4wo97Tve+CRdF9YBkzGiF7fKw9qEnSMgWXcZTHJkKc60wAACAAQAAgAAAAIACAACAAAAAAEIAAAAAAQEr8FUAAAAAAAAiACCcheUwIAj6XLtEe5QO"
, "p5of5 +fTi25/ZvJGX9MuZkpghbW3VMgEFR1IhAkhWBpUeAB+UbbJc8f1fkEMEZgIChQVpMdJnD05uBtU4IQMUAdnwr2UVz6AhNBI5j6an4wHRGVX3uhSLaWy2qS70xlKuIgYCSFYGlR4AH5Rtslzx/V+QQwRmAgKFBWkx0mcPTm4G1TgcmQpzrTAAAIABAACAAAAAgAIAAIAAAAAARAAAACIGAxQB2fCvZRXPoCE0EjmPpqfjAdEZVfe6FItpbLapLvTGHK54SeIwAACAAQAAgAAAAIACAACAAAAAAEQAAAAAAA=="
, "p1of5 cHNidP8BAKQCAAAAA6DLc9RAdKwWQb/7Nrq1FyAtDQ3e0w5E4LkLpcrwBL0aAAAAAAD9////78NG2vqjywKaa0QHfo6C44o1+odXeWZ43FfHy4bLdxABAAAAAP3///8rhueJha90HzgJ6alnJ1uvi0Zbq0JQoXnwDb0Cjn79DwAAAAAA/f///wHWCBAAAAAAABYAFDraKFKubXzlSvRQy8V4X+TwKhLXAAAAAE8BBDWHzwQJeplqgAAAAqmHnnoRR+XJd7gJt/PhLazKeWAfCBLJ4/OF/s0PqqF1AzK8fctt"
, "p2of5 OUsU2k9a6Valj6kLb/Bh2gB7YuxenNz7LY5PFJkKc60wAACAAQAAgAAAAIACAACATwEENYfPBEgFouKAAAACOeERUyCmIJuSdQNDB1mxkahw4tc2UCtjxJQoQGnRCtQCZUSXwQF+nA8dl/RG6U1b9ViWJxkzNrDCCagYEWch72cUrnhJ4jAAAIABAACAAAAAgAIAAIAAAQErckUPAAAAAAAiACDwHjagvyTvVDVn+RqxW0xaMLODBm2IVCwDBQm5uK8rDQEFR1IhAi/hk/Tz0aHcNwsVyv86bqQj30sUexPl"
]
d2 = DecodeQR()
for i in qrcodes2:
if d2.add_data(i) == DecodeQRStatus.COMPLETE:
break
assert d2.qr_type == QRType.PSBT__SPECTER
#complete should be true
assert d2.is_complete
tx2 = d2.get_psbt()
mnemonic2 = "able bacon cable able bacon cable abandon abandon abandon abandon abandon access".split()
pp2 = PSBTParser(p=tx2, seed=Seed(mnemonic2), network=SettingsConstants.TESTNET)
assert pp2.input_amount == 1052818
assert pp2.change_amount == 0
assert pp2.spend_amount == 1052818 - pp.fee_amount
assert pp2.fee_amount == 1980
tx2.sign_with(pp2.root)
trimmed_tx2 = PSBTParser.trim(tx2)
expected_signed_trimmed_base642 = "cHNidP8BAKQCAAAAA6DLc9RAdKwWQb/7Nrq1FyAtDQ3e0w5E4LkLpcrwBL0aAAAAAAD9////78NG2vqjywKaa0QHfo6C44o1+odXeWZ43FfHy4bLdxABAAAAAP3///8rhueJha90HzgJ6alnJ1uvi0Zbq0JQoXnwDb0Cjn79DwAAAAAA/f///wHWCBAAAAAAABYAFDraKFKubXzlSvRQy8V4X+TwKhLXAAAAAAAiAgIv4ZP089Gh3DcLFcr/Om6kI99LFHsT5XO9/AqiYPn5S0cwRAIgMJcGjoczA/ht/oTuE30a5StXa9l72t5+jayaURudfnECIGw+ymYS2RDszHL+KXRuoiNjvAUiIIKE7wa7+RKORevBAQAiAgJnXJ8+nIC4cTUtC795s+zlThrpxrAJRLHpGYkEQyw1x0cwRAIgH5pFuC079UUXzPJU1ya57Lak9Yc4NkAttmOEsNphd/cCIBnVkzO/wVfD5dxWKXbqdHazwUirh2zcY1MIH1skRqkbAQAiAgMUAdnwr2UVz6AhNBI5j6an4wHRGVX3uhSLaWy2qS70xkcwRAIgVrv+vZ9iG1njv8wrSCuhhLIlkMRqk4lxnHBRMHTzVWUCIELRLHVXUTyL0rFWA8aNADWjkOB/pepeQst7u2GryIylAQAA"
assert str(trimmed_tx2) == expected_signed_trimmed_base642
def test_mnemonic_qr():
mnemonic = "height demise useless trap grow lion found off key clown transfer enroll"
d = DecodeQR()
assert d.add_data(mnemonic) == DecodeQRStatus.COMPLETE
assert d.get_seed_phrase() == mnemonic.split()
bad_mnemonic = "height useless trap grow lion found off key clown transfer enroll"
d2 = DecodeQR()
assert d2.add_data(bad_mnemonic) == DecodeQRStatus.INVALID
bad2_mnemonic = "words not in the list of bip39"
d3 = DecodeQR()
assert d3.add_data(bad2_mnemonic) == DecodeQRStatus.INVALID
def test_short_4_letter_mnemonic_qr():
short_nm = "heig demi usel trap grow lion foun off key clow tran enro"
d = DecodeQR()
d.add_data(short_nm)
assert d.is_complete
assert d.get_seed_phrase() == ["height", "demise", "useless", "trap", "grow", "lion", "found", "off", "key", "clown", "transfer", "enroll"]
# Test data for bitcoin address decoding. All generated from test key: ["abandon"] * 11 + ["about"]
legacy_address_mainnet = "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA"
legacy_address_testnet = "mkpZhYtJu2r87Js3pDiWJDmPte2NRZ8bJV"
nested_segwit_address_mainnet = "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf"
nested_segwit_address_testnet = "2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2"
native_segwit_address_mainnet = "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"
native_segwit_address_testnet = "tb1q6rz28mcfaxtmd6v789l9rrlrusdprr9pqcpvkl"
native_segwit_address_regtest = "bcrt1q6rz28mcfaxtmd6v789l9rrlrusdprr9pz3cppk"
taproot_address_mainnet = "bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr"
taproot_address_testnet = "tb1p8wpt9v4frpf3tkn0srd97pksgsxc5hs52lafxwru9kgeephvs7rqlqt9zj"
taproot_address_regtest = "bcrt1p8wpt9v4frpf3tkn0srd97pksgsxc5hs52lafxwru9kgeephvs7rqjeprhg"
def test_bitcoin_address():
"""
Decoder should parse various types of valid bitcoin addresses with or without the
"bitcoin:" prefix and optional query params.
"""
def decode(address, expected_script_type, expected_network=SettingsConstants.MAINNET):
for data in [address, "bitcoin:" + address, "bitcoin:" + address + "?amount=12000"]:
d = DecodeQR()
d.add_data(data)
assert d.get_address() == address
assert d.get_address_type() == (expected_script_type, expected_network)
decode(legacy_address_mainnet, SettingsConstants.LEGACY_P2PKH)
decode(legacy_address_testnet, SettingsConstants.LEGACY_P2PKH, SettingsConstants.TESTNET)
decode(nested_segwit_address_mainnet, SettingsConstants.NESTED_SEGWIT)
decode(nested_segwit_address_testnet, SettingsConstants.NESTED_SEGWIT, SettingsConstants.TESTNET)
decode(native_segwit_address_mainnet, SettingsConstants.NATIVE_SEGWIT)
decode(native_segwit_address_testnet, SettingsConstants.NATIVE_SEGWIT, SettingsConstants.TESTNET)
decode(native_segwit_address_regtest, SettingsConstants.NATIVE_SEGWIT, SettingsConstants.REGTEST)
decode(taproot_address_mainnet, SettingsConstants.TAPROOT)
decode(taproot_address_testnet, SettingsConstants.TAPROOT, SettingsConstants.TESTNET)
decode(taproot_address_regtest, SettingsConstants.TAPROOT, SettingsConstants.REGTEST)
def test_invalid_bitcoin_address():
"""
Decoder should fail to parse invalid address data.
* Test incorrect "bitcoin:" prefix.
* Test invalid addresses.
* Test valid addresses w/additional prefixes (to ensure regexp is not finding
mid-string matches) which make the data invalid.
"""
bad_inputs = [
# wrong separator char
"bitcoin=bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
# Unrecognized addr prefix
"bitcoin:bcfakehrp1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
# valid addr w/garbage addr prefix
"abcbc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
# valid "bitcoin:" prefix w/garbage addr prefix
"bitcoin:abcbc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
# typo in "bitcoin:" prefix
"bitcon:bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq",
]
for bad_input in bad_inputs:
d = DecodeQR()
status = d.add_data(bad_input)
assert status == DecodeQRStatus.INVALID
def test_bitcoin_address_ignores_case_where_allowed():
"""
Decoder should ignore case in QR data prefix and in the address itself (for the
address types where case is ignored).
"""
def decode(address, expected_script_type, is_case_sensitive, expected_network=SettingsConstants.MAINNET):
addr_variations = [address]
if not is_case_sensitive:
# Test as-is and all uppercase
addr_variations.append(address.upper())
for addr_variation in addr_variations:
# First add prefix capitalizations
variations_1 = ["bitcoin:" + addr_variation, "BITCOIN:" + addr_variation]
# Now add query params
variations_2 = [v + "?amount=12000" for v in variations_1]
variations_3 = [v + "?AMOUNT=12000" for v in variations_1]
for data in [addr_variation] + variations_1 + variations_2 + variations_3:
d = DecodeQR()
d.add_data(data)
assert d.get_address_type() == (expected_script_type, expected_network)
if not is_case_sensitive:
assert d.get_address() == addr_variation.lower()
else:
assert d.get_address() == addr_variation
# Case sensitive address types
decode(legacy_address_mainnet, SettingsConstants.LEGACY_P2PKH, is_case_sensitive=True)
decode(legacy_address_testnet, SettingsConstants.LEGACY_P2PKH, is_case_sensitive=True, expected_network=SettingsConstants.TESTNET)
decode(nested_segwit_address_mainnet, SettingsConstants.NESTED_SEGWIT, is_case_sensitive=True)
decode(nested_segwit_address_testnet, SettingsConstants.NESTED_SEGWIT, is_case_sensitive=True, expected_network=SettingsConstants.TESTNET)
# Case insensitive address types
decode(native_segwit_address_mainnet, SettingsConstants.NATIVE_SEGWIT, is_case_sensitive=False)
decode(native_segwit_address_testnet, SettingsConstants.NATIVE_SEGWIT, is_case_sensitive=False, expected_network=SettingsConstants.TESTNET)
decode(native_segwit_address_regtest, SettingsConstants.NATIVE_SEGWIT, is_case_sensitive=False, expected_network=SettingsConstants.REGTEST)
decode(taproot_address_mainnet, SettingsConstants.TAPROOT, is_case_sensitive=False)
decode(taproot_address_testnet, SettingsConstants.TAPROOT, is_case_sensitive=False, expected_network=SettingsConstants.TESTNET)
decode(taproot_address_regtest, SettingsConstants.TAPROOT, is_case_sensitive=False, expected_network=SettingsConstants.REGTEST)
def test_seed_qr():
seed = "121802020768124106400009195602431595117715840445"
d = DecodeQR()
d.add_data(seed)
assert d.qr_type == QRType.SEED__SEEDQR
assert d.get_seed_phrase() == "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash".split()
def test_specter_wallet_json():
parts = [
'p1of3 {"label": "SeedSigner Dev Funds", "blockheight": 692143, "descriptor": "wsh(sortedmulti(4,[e0811b6b/48h/0h/0h/2h]xpub6E8v7uy63pCeJvHe5W8ea8zTnCtKMFgMRb5bueWWcUFMw6sWmUwTqxM8cFiKQRWkA2Fxth9HJZufJwjWTTvU1UGZNpTrh9khrswYMgeHiCt/0/*,[852b308f/48h/0h/0h/2h]xpub6ErhgAWfnEqW7xDBm1iLq5JjNyUS65YUFnjHLrRv9zmdDEtuE75bpWQ8o6bSBnpT6AkrrsA8eA5SmEFArZn11KEPaZJzx9mHTXPWZCsxLyh/0/*,[7edf9c59/48h/0h/0h/2h]xpub6DaFfKoe7Wpofr'
, 'p2of3 bYeNo3Wv2AiLUMeyrPwotXfukFxUHbK4JxaLHTd5394QtH5wnjFzBgr2YnJpHhXv25Zsqv2APmMFvH1DsKHj5LCr3pmXs/0/*,[b433e095/48h/0h/0h/2h]xpub6EF51itHko2YhGTjVeuYbBgJjVbTzzpYzn2a3JwZHpDrMePRVgXGBHMx2Yv1KwgLsUn9i7ExcAo8uqMx4pDjVRY9J7qnceFAwRRj16dd5AS/0/*,[184d07eb/48h/0h/0h/2h]xpub6EEoTpcQu7N4R8D84pJjZ69j3mi'
, 'p3of3 nevnYLDDoo2HBzYBXTQ4rGVf4XGTyCYFwJuZdsF9MyFYJNzYEjg5LGMA1ubTGWuDnjHAZz6ficVRDTSy/0/*,[3e451efe/48h/0h/0h/2h]xpub6ExQPvQxGBMaPxr8Fv7Vq91ztJFFX3VWvtpvex6UPZ1AptTeuAiJGCtKkgwJkrwpMZMagh9ex6rL4sM8axfFcdQbERoFCRUKTJxrBkJh56g/0/*))#c44hel9e", "devices": [{"type": "other", "label": "Keith"}, {"type": "other", "label": "Nick"}, {"type": "other", "label": "Richard"}, {"type": "other", "label": "Stephan"}, {"type": "other", "label": "SeedSigner 1"}, {"type": "other", "label": "SeedSigner 2"}]}'
]
d = DecodeQR()
d.add_data(parts[1])
d.add_data(parts[2])
d.add_data(parts[0])
assert d.qr_type == QRType.WALLET__SPECTER
assert d.is_complete
assert d.get_wallet_descriptor() == "wsh(sortedmulti(4,[e0811b6b/48h/0h/0h/2h]xpub6E8v7uy63pCeJvHe5W8ea8zTnCtKMFgMRb5bueWWcUFMw6sWmUwTqxM8cFiKQRWkA2Fxth9HJZufJwjWTTvU1UGZNpTrh9khrswYMgeHiCt/0/*,[852b308f/48h/0h/0h/2h]xpub6ErhgAWfnEqW7xDBm1iLq5JjNyUS65YUFnjHLrRv9zmdDEtuE75bpWQ8o6bSBnpT6AkrrsA8eA5SmEFArZn11KEPaZJzx9mHTXPWZCsxLyh/0/*,[7edf9c59/48h/0h/0h/2h]xpub6DaFfKoe7WpofrbYeNo3Wv2AiLUMeyrPwotXfukFxUHbK4JxaLHTd5394QtH5wnjFzBgr2YnJpHhXv25Zsqv2APmMFvH1DsKHj5LCr3pmXs/0/*,[b433e095/48h/0h/0h/2h]xpub6EF51itHko2YhGTjVeuYbBgJjVbTzzpYzn2a3JwZHpDrMePRVgXGBHMx2Yv1KwgLsUn9i7ExcAo8uqMx4pDjVRY9J7qnceFAwRRj16dd5AS/0/*,[184d07eb/48h/0h/0h/2h]xpub6EEoTpcQu7N4R8D84pJjZ69j3minevnYLDDoo2HBzYBXTQ4rGVf4XGTyCYFwJuZdsF9MyFYJNzYEjg5LGMA1ubTGWuDnjHAZz6ficVRDTSy/0/*,[3e451efe/48h/0h/0h/2h]xpub6ExQPvQxGBMaPxr8Fv7Vq91ztJFFX3VWvtpvex6UPZ1AptTeuAiJGCtKkgwJkrwpMZMagh9ex6rL4sM8axfFcdQbERoFCRUKTJxrBkJh56g/0/*))#c44hel9e"
def test_specter_wallet_json2():
part = '{"label": "Testnet Single Zone", "blockheight": 2090512, "descriptor": "wpkh([990a73ad/84h/1h/0h]tpubDDHQMDnFdan2GyHBsG32VW9qiygbhVizGRTjiS3H79M49FSvpsvLXqLgp1yC7r43dXVHozWavi2Fc4WHUpZmQYmzoQbit28qJhLjScbAQWU/0/*)#ujr0xunp","devices": [{"type": "seedsigner", "label": "Single Seed Zone Testnet"}]}'
d = DecodeQR()
d.add_data(part)
assert d.qr_type == QRType.WALLET__SPECTER
assert d.is_complete
def test_basic_1_in_2_out_bbqr_psbt_qr():
parts = [
'B$ZP0100FMUE4KXZZ7EHBEUJQGAYDGMXLP2O34WEVGERCKNOQWTY3URDYXHGTXTTHOVHKW6YXZQYEVSN6UGQMEHYB4CP4RI3BJK43MVLSZ7ZRH5R5SB4527A5C6N3LL65GZRPNZZGU2NK332BFLVR7VVKSYTCILLOLCJZ5PGFQGCC2U37YW5J6CTXMW6NHMT533MMPJ3YXQQVGL2ZZ76AADRETFVNCV4MGOMY6GEPPPG5XSZFIOQ6PW2JUFQVDWX5FMIHLHCI3Y23V5WGPPK5OF5GSFOKZI576FTVA5FGM5NNACNMNSAQBLZQZY62PJQS7Q72PQGVTABGZRVEPB4HL5MGCB3SVONS5P7W7BGVVT557AFA33L63OW43GW5BAYVTCMNLH5XCUEDNRF4HXFFLMHCWV25FZM6VQNQFPW2PZWI5MXP3QKHGIKOPMXR6CZGOO6CFSQ42IKN3USTQ44OHX53YYXTSSX74XXZ7ZPFXMRMCDTBDJU3JIJ2Z6ZXJXOK3LD6YHA3NYV4PDUDFR2K2H6RIPZ4BI7V2YOXRXPQY5YJELSQ4EHNXBM6HQX74PC26NXEXI6B7UR6IQMH446CDUR36RHYRKV5DE5ZUUVS5FEIWNKJLGJXHGPK66WGP5YNX3PEW24ZRLTJYAOMEBNXIGEYT2OSSUTLGKFZX7M7VTZUGI5LH5GM6X6PC76XZOO3PM7WV67BCM3D5M3XMAEQBYPJAWRAJZQAMEQA'
]
d = DecodeQR()
for i in parts:
if d.add_data(i) == DecodeQRStatus.COMPLETE:
break
assert d.qr_type == QRType.PSBT__BBQR
#complete should be true
assert d.is_complete
def test_basic_1_in_2_out_bbqr_non_compressed_psbt_qr():
parts = [
'B$2P0200OBZWE5H7AEAMGAQAAAAAGLZDYX3EGIZDZMNR5DQRFVCQAIG3FL5BAHWRJ3PGCJ3NTFFLVFRKBIAAAAAA7X77776SNCAHN5R4BCQGWFWOT7MQUMN7IYDICAIMVZOQWEMKWXPVVJWTZ4AAAAAAAD6777775FCZSAY26LQG5V3DG7J4Y6HFZSAL65OCPEMYB6SLACVNXVAAIOPAAAAAAAAP377774BBAJYAAAAAAAAACYABITRMR72K5TBKF5JQHFEP3N7MTN6BSTVZO6AAAAAAAAAAAALAAFH572746E5HEAFOBJOKAWW3AZSTJ5YGQ4IAAAAAATYBAQ2YPTYD3PPOOG4AAAAABMZKKMFX7N7X3N7UFH3DJ6TPIJJNKDDEZ2V5WXVEFF7ED2KPRLQWAJQJYJPKMVHIF3B567MHOVVTZEREDZ3JU5K7433BO4PCIWIAXMMKCEDF7NB74VAAACAACAAAQAAAAAEAAAAQB7MIAEBAAAAAAFYISWF3KWA2BQJIWFBLOAQUC75FZ7U663FLHY2UPMSMBIORDQQ4ICAAAAAAB7P7777QWEBHAAAAAAAAAALAAFDLBORR4YUXZXUT2AMGPV5STUNSAWXZC3AQE4AAAAAAAAABMAAUGQY57O3ZSGKZQPJIVDDRHCZR26EBKEXBCATQAAAAAAAAAFQACRQDOY52JHJTNRMSBEU3ZNF7MU3CQ67OE7UAGAAAAAAAAAAWAAKHTOIMMYL4F27RNYMKHR27HEACX2GC5OBRAJYAAAAAAAAACYABIUXQGIMLE6T4JV4HB7DBKMD2ZSOAJ3BNWEBHAAAAAAAAAALAAFG6U2YBVVC5EOTPROOXWHTT3NQNDN24INYQE4AAAAAAAAABMAAUCUT7GZTM564L2AHZT2WWKSNMW2XN6SRTTQZSWAAAAAAAAFQACSIVWLYCFXTXUOPJHVTG424NY2MHVFAUJ4ICOAAAAAAAAAAWAAKO5BX4TBBZOLBTGINJPGZXHCHXLSFXOGFRAJYAAAAAAAAACYABJ6E4FYLPW652VRHZ2TXZ',
'B$2P0201MH36EIIPZFAIMEBHAAAAAAAAAALAAFGZMA575IOQ64JRLZ7FDFP5HXDSI7T5TCB3K4TQAAIBD4ICOAAAAAAAAAAWAAKNSYB372Q5B5YTCXT6KGK72POHER7H3GECEBQDUQRHUJOBI3ZLGB5D45DTXHXDO2KR3SYOVVK7B3IWBLBTMZOLAWMBQZP3IP7FIAAAQAAQAAEAAAAABAAAAAAAALAAAAAAAAIAOEBAAAAAAGYGM76R4MFE4PVHWKO7UMETKM7CMCYSGXHLZBKFSTV77SGMMGAIWAIAAAAAB7P7777QF2ADAAAAAAAAAALAAFDVHQFTAZIUYBERQK72U7UJXL4TP4IATCF7VQXQAAAAAAABMAAUJKWTGIZ24GA6VEFIYS3FJBDRMPCZEAN75DGSKAABAEP6QAYAAAAAAAAACYABI5J4BMYGKFGAJEMCX6VH5CN27E37CAEYQIQGALL3CUCJCC5XCJYUJJZQTXXO3YZORCQGK4GZNW3IGGPLOVQF2VCBEGDF7NB74VAAACAACAAAQAAAAAEAAAAAAAAEAAAAAAABABJAEAAAAAA7YEPDL6LPKO5S4PGHT7RSZD7WRGO3JUDPI2L2LPGRPBZ3ORRB5NYAAAAAAAH577776ALCA4AAAAAAAAABMAAUXRNOMGZL4W3EIBN7B33H6UPCYV3NJF32PVLCOAABAEPWEBYAAAAAAAAACYABJPC24YNSXZNWIQC36DXWP5I6FRLW2SLXUIQGALPV276UOSFQ4GYKIORFRCTTGOSCPBCJ7QWFFL2K4UCZDA27YOVQGGDF7NB74VAAACAACAAAQAAAAAEAAAAAAAA6AAAAAABCAIB2VZDSEABFIYX7GUZUJM27QMBDRYRRCHKG6SGYIID7ZDZIBMWDLLAYMX5UH7SUAAAIAAIAACAAAAAAQAAAAAAAGUAAAAAAEIBAENBW7O5JKFANLCOJJSIFIZLZ2JPIDZRECITJNP2QDDZACAOE57MRDBS7WQ76KQAABAABAAAIAAAAACAACAAAAAIQAAAAAA',
]
d = DecodeQR()
for i in parts:
if d.add_data(i) == DecodeQRStatus.COMPLETE:
break
assert d.qr_type == QRType.PSBT__BBQR
#complete should be true
assert d.is_complete
def test_large_multipart_bbqr_psbt_qr():
parts = [
'B$ZP04003WJHSUCTQ4PIK3YSIJKDNJLBCXBGKDICWLEI4D4CBWEBAEIEEJFSCLFSDACSVGGKEJBAQWCBWAUAEATBRHAFHCXMKEQBDGVAMKSFIZBJFCSWAUMUPUVSRMR77N6H7NBTZROGMLDKL5TH5E3E4YTHHPXPTSJ2O7BINMYCAEIOAAAAZH3LXF52M3I63NSBGPULBVT34BA7XQIKWNHBOV7D37BSCX6WIKYV63XCCYDFNVWQ37VDXBIMUH27CQHIGNTLS44FRYBV7QW32CULRZGLY5WO5ZXO6NJRFHY2VCG5IHZ3BJ6RYABDZ7L7R47JFBP5UBXVR46NCVK3OLSXIGCCGO7FUIPWFYLRUH4PDZPEOQAVTQJ7DYBWAMDVMDDXMJOY7OPYAJLROUZR2KBVLUU6H6DPT55OQDW55CXBZW5WARPNAPUQPH4J4BGVI6GGXH2KU42DFLE5NKJQQXX2EOISJVAFG4I5L4MMFYV44ZDWFPKYJS5QHRZGK63T53YJHEIJORCV5F5VFDU233LWQZIPDRORLJDLD7JC3IY2M4EBURPMKHSTNPXRMKXGTKVWSNMXOMCYKQUCR6QBZHYXWMWMUQBZHVQYYCZB3GT52KDFO6ZZHJXA3Y6ZMFOZ7UIQPHGYDKYW4J7VLVFECBJ4PJIHB7C3HRJPJXYXMLHIIZKSOG6HWENEGPLFKCICHNU7RCCOGZEHW7HGGXENTRV4OYJ32HKZEUZ6SJRBLO4TLF3YQVW3LNS4OHEPIBA3ZSXW6JZQM5UTQIM732LBENYKXYDDPMVI6AVN6I22JJTXYEDP23BANCYIKE3MPQ42AIBV5F3EDWGH53GCP5XGYSBC557I2FQJTF7EUQQEZYTOM4DJ2BBIUKCMEDTMUPQFZ4QIEWD4MJZBHIR36DXB336K57AWDDHKQSG3MDHIOCBRBO3YZXPTLZV4LJPL4ZVQ5HFCCHLJ6OBIJE6AJSXJFS7S6N7Y5MCHH6K32CDA6BBIF6OM7SVGUBJ46OT2YSCHGONHGJ4U2GBBYPUEZQDIKMMHRS5OV2WS6DWFTW4MQ5Z55JTR256REQT3S5FMMOSCVKDBJUMWMQINRUVZCCFAE2DBUTIX4Z4VTL4FM52OONLPKAFPPTIKFVSB42FTPMV3',
'B$ZP0401R2NIJC6YGI5PXFPPSXIZIJ6F5MPABQ7JTUK3MABHDBG7WWGCED33GILBH3IMEZENRW77JOMKNVVTZNDY4XGRE5PH7EQFYQ4WTBWIJBVLV7CVL453J47I4EHIPX6D2QRWWCQDPWWCFPSRT5R27HHKS22TMGPIZZMDYLEWXUTPMXHAM7LRETD4ANY5OS4EDCC5XTTO6GTTLYWS6XZT3B2OLEEOWR4UDQSJMATFPSLF7G4WGTHBAJE33CR5U3LN4LKUZQ2VPU3KF3TQUCUFAQPUCOJ6F5TFS3CEDD2D4PRDMEXXYE3FUPKTQME6VJAXRXJRS7JR2YIK7VXXD4K2O6RWAAKXOMNRLSBAWCSXGIIUAXIMESFD7XHCUNPRVXXJZZVM5IAV56NAIWWYGDHUYKQPN4ZZBGJRPB5KS6CYJGQQSSYSECQTRC43ET6BGOECAFU7TDOIJ2AOXR54PO7SPNYBRIZ2MGRS2A6VBDKMJCJ5JXFBUACAQW6TXYH5AHXT4A7S4JIE27BYDNZ4RKFLVYXA3T46WXGXQOHHNUNHPXJHEG2HPKLEVQR2I2SICFW7TILMU2ERRSPV3GQHNDQEUL3GGPHEYWQ3NVQA5EAKVP6NOYQIEJHDWX76IAHRC4H7T5PNATTCYDJH4TJ5WUXCI3A5PYCGCYKV5ZL3IRF6TDAP4LGVUNT7X5IPYUD4LC5G5SH2DULRDITMR2DTKBIGXQXMSOQY7XMIL7643CIEJXX5DIWREMX5SSCAR7GTWNAXLW2XGNPLQPW3UOP4UXQEGB4CDQL4MZ7FLNICT34VGVVEUMM43OITZJUECDQ7IKDIL7GU3GQXUIYTKZM6XMOBERAPWVB2UWIWD3KUTNCPBUQ7RESKCLVYRGUI4Z3ULFYSNM23VETFZGBELD7VFP7N5SRZ3GIS2SKM4376WUWWRZ4T7IO35UVCXNBTKVZHWTKZSYQABQE72N74FPJHY4DOFGUGIL2XCAVZU3NHE57HTSA7OGUWNF7DBE63DSAY4N6OGHMGL4SBFGSLYEBW7HERFLABVNQYLELH2X7VNLYM24WN52CWDZPFSA3YXDAQYOCCQNXIEWSTKNMPBVLXYJNX4SDW5KYPNKOSYJRHYRYB23LRXC7F7SVC7PMCBPMR',
'B$ZP0401R2NIJC6YGI5PXFPPSXIZIJ6F5MPABQ7JTUK3MABHDBG7WWGCED33GILBH3IMEZENRW77JOMKNVVTZNDY4XGRE5PH7EQFYQ4WTBWIJBVLV7CVL453J47I4EHIPX6D2QRWWCQDPWWCFPSRT5R27HHKS22TMGPIZZMDYLEWXUTPMXHAM7LRETD4ANY5OS4EDCC5XTTO6GTTLYWS6XZT3B2OLEEOWR4UDQSJMATFPSLF7G4WGTHBAJE33CR5U3LN4LKUZQ2VPU3KF3TQUCUFAQPUCOJ6F5TFS3CEDD2D4PRDMEXXYE3FUPKTQME6VJAXRXJRS7JR2YIK7VXXD4K2O6RWAAKXOMNRLSBAWCSXGIIUAXIMESFD7XHCUNPRVXXJZZVM5IAV56NAIWWYGDHUYKQPN4ZZBGJRPB5KS6CYJGQQSSYSECQTRC43ET6BGOECAFU7TDOIJ2AOXR54PO7SPNYBRIZ2MGRS2A6VBDKMJCJ5JXFBUACAQW6TXYH5AHXT4A7S4JIE27BYDNZ4RKFLVYXA3T46WXGXQOHHNUNHPXJHEG2HPKLEVQR2I2SICFW7TILMU2ERRSPV3GQHNDQEUL3GGPHEYWQ3NVQA5EAKVP6NOYQIEJHDWX76IAHRC4H7T5PNATTCYDJH4TJ5WUXCI3A5PYCGCYKV5ZL3IRF6TDAP4LGVUNT7X5IPYUD4LC5G5SH2DULRDITMR2DTKBIGXQXMSOQY7XMIL7643CIEJXX5DIWREMX5SSCAR7GTWNAXLW2XGNPLQPW3UOP4UXQEGB4CDQL4MZ7FLNICT34VGVVEUMM43OITZJUECDQ7IKDIL7GU3GQXUIYTKZM6XMOBERAPWVB2UWIWD3KUTNCPBUQ7RESKCLVYRGUI4Z3ULFYSNM23VETFZGBELD7VFP7N5SRZ3GIS2SKM4376WUWWRZ4T7IO35UVCXNBTKVZHWTKZSYQABQE72N74FPJHY4DOFGUGIL2XCAVZU3NHE57HTSA7OGUWNF7DBE63DSAY4N6OGHMGL4SBFGSLYEBW7HERFLABVNQYLELH2X7VNLYM24WN52CWDZPFSA3YXDAQYOCCQNXIEWSTKNMPBVLXYJNX4SDW5KYPNKOSYJRHYRYB23LRXC7F7SVC7PMCBPMR',
'B$ZP0402CZV73DGFLBG3EGYTGIKV35X6GU4QSR7BE43JT5KS7C4DSBBW3CTBEH674AVXGNWAF65UGU65RJALJ5PUVX2KNTYJ6MXTTVFFIZT3FCJZRAG4LXJ3A52IYP7UFTRI2K5FGFJNVOYLK4NZC6ZZAZWMVQEJT7JAMXEN3ENQB6VM4L7N7WMFA35IPRMF6RH4ZALTUHBZI7U4GAN3CK4PQJZMWQTO5F5PZ7EV5R6QKCR27AMNN4H2GTXGJR2YM5CXOLMBSDZKHABOYMD46G2TWREHUOSNGQY3BJ6EBENF5DOF5VOXJF5Z7LN4LJRZR3MLNG4OPOMGNNIPANZB7JJJQ3OUVIU3R6FI2SD4HUINHY2ZOQ4F7ZDWIG6S7PHO6IZZNM3C7KAMAN2TW6CTLY44TAZ2DOQTXHTKOE6UEVHE7JVMJJ5PVTWBLWIRD6SCDXYPIXOXZGTVNGKGPY24F7L4OIFGLJIYF4ZGDFNFAEAFJWF3APPL777XEWHYEKVCAGERBXPKG7ZUYBTRLJE5BXOPHSYDGZ5QMBUJYJVWPB2G4V3I25AJUFAU7NTLHCJAZF4O2P5REH7MEBZVEMLCJX5H52HNRU5EXR7HP5VJORFCHQ62VE3ITYFFH4JESQS5OAJVCHOP5CZOETDGW5JE3OCIEBVD7RSDD3SSLJJVGWHQ2V34EW36JB3OVMHWVHJMEYT4I4A5NVY3RPS7ZKRPXIA5PTVH2Y7JXIQ6WO5AG7JGFLM7WEMKWSLWMNBKNIWL327SMJ7BFD6MIJVTLYFB6N4HWD4WYH62N5P426HB7JWG2KXR6EG34MTHAP6LEOZU2WWQQRC3J7PUU372TQYP7ESDLVVHJZVH54GYVTJUCER3SHQ3ABBYEUHLQXY26SHTYG42LIBQWHC4S473LH6JNLYUEUWH3OC6YY5AVGMJ47OHOXJ4H2ZVFMBHNVPSSKHG34DDHIM2G42OX4K5RYENJ4QPTWFJ2PWKK6ZIOUBVNTRE5F6ZZEDA3HUKK4CARMT3R73TBY73N6ESQBTU6BUZJOUGR367NVNNRZEPHNF5NQYGFFWKPPRMP4RQDCW3M4LBZKPTOJHM56KSX6B5GWYFJD7ETR3SFEANFZLMI6KVAPJZMSRUXHLQUQ2G5UWSSGRI',
'B$ZP0402CZV73DGFLBG3EGYTGIKV35X6GU4QSR7BE43JT5KS7C4DSBBW3CTBEH674AVXGNWAF65UGU65RJALJ5PUVX2KNTYJ6MXTTVFFIZT3FCJZRAG4LXJ3A52IYP7UFTRI2K5FGFJNVOYLK4NZC6ZZAZWMVQEJT7JAMXEN3ENQB6VM4L7N7WMFA35IPRMF6RH4ZALTUHBZI7U4GAN3CK4PQJZMWQTO5F5PZ7EV5R6QKCR27AMNN4H2GTXGJR2YM5CXOLMBSDZKHABOYMD46G2TWREHUOSNGQY3BJ6EBENF5DOF5VOXJF5Z7LN4LJRZR3MLNG4OPOMGNNIPANZB7JJJQ3OUVIU3R6FI2SD4HUINHY2ZOQ4F7ZDWIG6S7PHO6IZZNM3C7KAMAN2TW6CTLY44TAZ2DOQTXHTKOE6UEVHE7JVMJJ5PVTWBLWIRD6SCDXYPIXOXZGTVNGKGPY24F7L4OIFGLJIYF4ZGDFNFAEAFJWF3APPL777XEWHYEKVCAGERBXPKG7ZUYBTRLJE5BXOPHSYDGZ5QMBUJYJVWPB2G4V3I25AJUFAU7NTLHCJAZF4O2P5REH7MEBZVEMLCJX5H52HNRU5EXR7HP5VJORFCHQ62VE3ITYFFH4JESQS5OAJVCHOP5CZOETDGW5JE3OCIEBVD7RSDD3SSLJJVGWHQ2V34EW36JB3OVMHWVHJMEYT4I4A5NVY3RPS7ZKRPXIA5PTVH2Y7JXIQ6WO5AG7JGFLM7WEMKWSLWMNBKNIWL327SMJ7BFD6MIJVTLYFB6N4HWD4WYH62N5P426HB7JWG2KXR6EG34MTHAP6LEOZU2WWQQRC3J7PUU372TQYP7ESDLVVHJZVH54GYVTJUCER3SHQ3ABBYEUHLQXY26SHTYG42LIBQWHC4S473LH6JNLYUEUWH3OC6YY5AVGMJ47OHOXJ4H2ZVFMBHNVPSSKHG34DDHIM2G42OX4K5RYENJ4QPTWFJ2PWKK6ZIOUBVNTRE5F6ZZEDA3HUKK4CARMT3R73TBY73N6ESQBTU6BUZJOUGR367NVNNRZEPHNF5NQYGFFWKPPRMP4RQDCW3M4LBZKPTOJHM56KSX6B5GWYFJD7ETR3SFEANFZLMI6KVAPJZMSRUXHLQUQ2G5UWSSGRI',
'B$ZP0403GGGKSI5N46HND3DI3RFTMMIH6HI6EHTRJWJDZCBB3NGI63AFRYCSF5WNM5YYF3D2TV7W5USN7RXMS7KEOABUA7273S7SDTB7ZXXANY2CQUU72OCVN4SC47CDOY7ZXOHSFCULALBE2FNHTHDDLX3PYAJ25W53KKHOEWFMUMYDHNZODN3H44P5ZPAXZC7H3SL77GCXENXYTB4WB4HWDFBLXZE65ZPRAAQJVBUQPRQPWG2TZSVR3T426MYPK7OSYTFYY2HKLHA46CX2ZMG2EHU3HBHTWZAK4PVIS636I5OBTJUTVP3POGUK73T5DAKW2GH2KV4NLZIE6X4LT4SUJVCT2W4DGFGV5UTPR6EPOM5MF43L5VJT62QNPIDKN4P3QFND6JTPB6ZPLPGWDJUJDBEQ2AFAYLPB34H6AD4LXE2HIHWWN46Z3LABXII53DM3JBGBDNC6366NSSKW62DAZWPSN32LDOAESPZYOMPQ3RKGE2WLFVTHQONBAC5Z3G6XYKA3WGTUS6L5G35VIOVFSFQ62VE3ITYNEH4JESQS5OEJVCHGO5CZOETLGW5JEZOCIEFVD7RSDDZ24KNCI6IQIO3JSHWZBIOAWRHMTPH6EBGZ6U5P7XFETP4N3EX3RBQMGB7XXPMQ4REQMS6PNHY4ED7OEILCS3FHXYWH6IYBRLNWOFQ4VHZXETWO7FJL7A6TLMCUR7SJY5ZCODZ7P65B7R6TLY4F5N33YWAR45KQ2TC3FLI6IXRLBQM3LN5ENCQMIMFGR22J4O2GWORXCL5B3E7PK7VROTOZB5OYQD7QA'
]
d = DecodeQR()
for i in parts:
if d.add_data(i) == DecodeQRStatus.COMPLETE:
break
assert d.qr_type == QRType.PSBT__BBQR
#complete should be true
assert d.is_complete
def test_bbqr_psbt_p2wsh_qr():
base64_psbt = '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'
parts = [
'B$ZP05044YHEDDPOKBPHMMY3URG6GYXLQ5ZR5A4CLN3UXSKVLAYAQQIQ4BTBKU2LUWOKPXE663ZRWTRXGZTDOF3RY4CQINUEMTJJVM3G5OKCCIF5GRB7O2TPT7OF5W7VQTHDDQ4X5M4ZU67C5E255ZYWWD5NMI5IGIELQIRRP5F6R3PZI42R36XT6GO6HRJEFGNU4VIS62QTHHTLJL6JRVAVBBODWWT7EDAOK3RLLFUQNG27K5WFNNUJ3W42W7ODTTR6O3352YNGN5ZBODKI4S46OA56X445SLBKQCTHB4J57YRYJUKZFZXCSNJVVYOZIILKO7ZZIS5AVLGD6PAK6PJCLUB5NYLSD3Y2DMAOLF42I5OAHJSOLEMWAXVZB5L6USJGCHJS6NFQ5GNEDQU3Z7KTETRYWRRU57LSHHIP7R3R26RY2AZLTDYDZAYQLNYEN7IIDABMYPFNZ3FUGMBNN7MXWBWLFK5WLC2MVJO4B4NJ6XNU2O7C7SSN3IBQCFL2QTOTFJ526I7U4ZXDMQFAXUNCWINWPDDXSRPXPXP74ODKLQTKGICLJX5F6M2D2SZEL5GPWPSN4XAUMTQ4LNTRPX2H6TUOMGPMJXG3XAUDYAEN3NMDANWB5ZZUYTIYK7R3SWSAWSWENNZ3XSXRG6H3YV35SO5GSDIEE32PKZBGRYMGYTV6SVVUBOXSJIL4HU5BCW6GA7C2UPGKB3R3YXQPEERJADYRALFJIDGFFJIA4I2WASJN44I4XARFYXFCGVIJJOFJKR22E4WCSVQ6NFI3BJEYPHKH6AA',
'B$ZP0503KUEKQJY5P37EIJDAYR75LV37UXPX2IJ7V3WD2GVR6NO44MLTGHNCRPZJBCARXNQ4PNBSVQSN7DOVL6CHAOBU3TRRNJPMRC4F5Y453TAW23M2G6AUAKHXBPND5FLHK7PA6LEEMNLWCKWSITNPTN6VK2EJN6WIYOKRHEOPOAQC2OPNVCRXHCGWUJJ4VBLYRBECPE2T27DY5WAGJJIGGOOL64XBBVU2MQ6EIGYA5O4W66AHIDKYQ7FXTRB2MEO3F4SIKXBDUZHFSGLAL24Q6V7KJETBDV3LCHCGVVNHCODUOIRFFFBKKFOYQPV25PW2SEBSXWAFUGU6RQVV6J36GNOV6Z677QPQ5QKYWOF75MLOB6PXQVITDTCQFMRN3IFAG6OTMKA4C4XXPFA7TFSRBDIBV7UGXU6VGNOMKB42TXZYVHZWUUKWW6UVRI3PRW5UP7FCOZJGMDAEHRHVT44G2T5KGNWCE5OOZPEJUOIXB7BM6Z5LKJO2OSBWFZHMS7UXYCAY4EYNKIZVO7R6QUCC33FTNJ6GB5CKPCYLNRVVLN2XSWVFSVQEKZB2AC2YUK6PWUORONEWPHXITVISATY3YFTGXL7466V6XJZPAWF6VVG3INQDB5N5JQ2JWEPXA5RUM77LUMAPYVVRGGIVF3F2Q6QQML5G6464W7GPOSEHQFKYQ5RWZP7WRB2FCWEHVQ6FEWNQB2L7HCEPQR24RSRD2UEOXEDVP4SA5MAOTF42NQ3Z5YKYPHD3RBVYFJK5ZQGBPLG37HFJ56MOT4PDFMIMPTOVX4DJICHOELCL7XBSDSVB',
'B$ZP0503KUEKQJY5P37EIJDAYR75LV37UXPX2IJ7V3WD2GVR6NO44MLTGHNCRPZJBCARXNQ4PNBSVQSN7DOVL6CHAOBU3TRRNJPMRC4F5Y453TAW23M2G6AUAKHXBPND5FLHK7PA6LEEMNLWCKWSITNPTN6VK2EJN6WIYOKRHEOPOAQC2OPNVCRXHCGWUJJ4VBLYRBECPE2T27DY5WAGJJIGGOOL64XBBVU2MQ6EIGYA5O4W66AHIDKYQ7FXTRB2MEO3F4SIKXBDUZHFSGLAL24Q6V7KJETBDV3LCHCGVVNHCODUOIRFFFBKKFOYQPV25PW2SEBSXWAFUGU6RQVV6J36GNOV6Z677QPQ5QKYWOF75MLOB6PXQVITDTCQFMRN3IFAG6OTMKA4C4XXPFA7TFSRBDIBV7UGXU6VGNOMKB42TXZYVHZWUUKWW6UVRI3PRW5UP7FCOZJGMDAEHRHVT44G2T5KGNWCE5OOZPEJUOIXB7BM6Z5LKJO2OSBWFZHMS7UXYCAY4EYNKIZVO7R6QUCC33FTNJ6GB5CKPCYLNRVVLN2XSWVFSVQEKZB2AC2YUK6PWUORONEWPHXITVISATY3YFTGXL7466V6XJZPAWF6VVG3INQDB5N5JQ2JWEPXA5RUM77LUMAPYVVRGGIVF3F2Q6QQML5G6464W7GPOSEHQFKYQ5RWZP7WRB2FCWEHVQ6FEWNQB2L7HCEPQR24RSRD2UEOXEDVP4SA5MAOTF42NQ3Z5YKYPHD3RBVYFJK5ZQGBPLG37HFJ56MOT4PDFMIMPTOVX4DJICHOELCL7XBSDSVB',
'B$ZP05044YHEDDPOKBPHMMY3URG6GYXLQ5ZR5A4CLN3UXSKVLAYAQQIQ4BTBKU2LUWOKPXE663ZRWTRXGZTDOF3RY4CQINUEMTJJVM3G5OKCCIF5GRB7O2TPT7OF5W7VQTHDDQ4X5M4ZU67C5E255ZYWWD5NMI5IGIELQIRRP5F6R3PZI42R36XT6GO6HRJEFGNU4VIS62QTHHTLJL6JRVAVBBODWWT7EDAOK3RLLFUQNG27K5WFNNUJ3W42W7ODTTR6O3352YNGN5ZBODKI4S46OA56X445SLBKQCTHB4J57YRYJUKZFZXCSNJVVYOZIILKO7ZZIS5AVLGD6PAK6PJCLUB5NYLSD3Y2DMAOLF42I5OAHJSOLEMWAXVZB5L6USJGCHJS6NFQ5GNEDQU3Z7KTETRYWRRU57LSHHIP7R3R26RY2AZLTDYDZAYQLNYEN7IIDABMYPFNZ3FUGMBNN7MXWBWLFK5WLC2MVJO4B4NJ6XNU2O7C7SSN3IBQCFL2QTOTFJ526I7U4ZXDMQFAXUNCWINWPDDXSRPXPXP74ODKLQTKGICLJX5F6M2D2SZEL5GPWPSN4XAUMTQ4LNTRPX2H6TUOMGPMJXG3XAUDYAEN3NMDANWB5ZZUYTIYK7R3SWSAWSWENNZ3XSXRG6H3YV35SO5GSDIEE32PKZBGRYMGYTV6SVVUBOXSJIL4HU5BCW6GA7C2UPGKB3R3YXQPEERJADYRALFJIDGFFJIA4I2WASJN44I4XARFYXFCGVIJJOFJKR22E4WCSVQ6NFI3BJEYPHKH6AA',
'B$ZP05044YHEDDPOKBPHMMY3URG6GYXLQ5ZR5A4CLN3UXSKVLAYAQQIQ4BTBKU2LUWOKPXE663ZRWTRXGZTDOF3RY4CQINUEMTJJVM3G5OKCCIF5GRB7O2TPT7OF5W7VQTHDDQ4X5M4ZU67C5E255ZYWWD5NMI5IGIELQIRRP5F6R3PZI42R36XT6GO6HRJEFGNU4VIS62QTHHTLJL6JRVAVBBODWWT7EDAOK3RLLFUQNG27K5WFNNUJ3W42W7ODTTR6O3352YNGN5ZBODKI4S46OA56X445SLBKQCTHB4J57YRYJUKZFZXCSNJVVYOZIILKO7ZZIS5AVLGD6PAK6PJCLUB5NYLSD3Y2DMAOLF42I5OAHJSOLEMWAXVZB5L6USJGCHJS6NFQ5GNEDQU3Z7KTETRYWRRU57LSHHIP7R3R26RY2AZLTDYDZAYQLNYEN7IIDABMYPFNZ3FUGMBNN7MXWBWLFK5WLC2MVJO4B4NJ6XNU2O7C7SSN3IBQCFL2QTOTFJ526I7U4ZXDMQFAXUNCWINWPDDXSRPXPXP74ODKLQTKGICLJX5F6M2D2SZEL5GPWPSN4XAUMTQ4LNTRPX2H6TUOMGPMJXG3XAUDYAEN3NMDANWB5ZZUYTIYK7R3SWSAWSWENNZ3XSXRG6H3YV35SO5GSDIEE32PKZBGRYMGYTV6SVVUBOXSJIL4HU5BCW6GA7C2UPGKB3R3YXQPEERJADYRALFJIDGFFJIA4I2WASJN44I4XARFYXFCGVIJJOFJKR22E4WCSVQ6NFI3BJEYPHKH6AA',
'B$ZP0500QXJHSNCUP4PQP4EZPOGW3CDEZNGMZNKEFBJXNP6UYRCGJCLMMNBFTMUVKD3MVPRHEJNWQIMTFDETEUUWJJ7FJMRGEVMUHJKVVCEHSTHGHD2TZXPHZY4XHTX46F647Z73PV7V5XSHDWHTDUFIAUAA3ICQFDGOTIKJS5LW73YPVGTW3FQ7PFUWAMMVM3R5DWZMVPSRW5BCEZI4GKQQYX6CYMAYBRKLDLVB7TKYZUGV4RFA54VJJ5PX6DUMSKTWUEUCL2VRV5E7GQ4CXOLSSC4DDPPJNTT4NAE23YH6WA4F3WCDJPFW62AIOJ5YXE4X3V2RZZRMOVQOT2YFNYDTXZF6K45JBWR2RD45XHWUPJ6QG7L45MH56SJZEKHIYST2YHHM2H74ZVYJ7GU7LURR22FL3F7CZOVALHI4NRCHILTJWQ4PVDJL22WRYRBLNX7PKGZFRERDIHRE6LNOMBUQQ47SZBWLYRQFLLDFH5S3JEOL43GDFUN3GIYAWN27RDZ2ETGRNRY6LYTM42CE6E3BFAKFAU6LOM6I36XY7DQIKPTCST2VBZWMYBH3OWC7FGPGN7QTBXCXOMFOYDW2UE6XIIJ2MJUE6YPNP3DTMWRXPDAFNR5R3GZJ2DGX7WFW5VZ3NGXAKA4M5E4IIIW73WPSO6U6EMGWSBFBSWJO42IKDSGEEDKEFPR2T6L7QHVRYYPPHQNBD4O7SORVSST77PCQHBWJXRAA2RRZF6AK6XCIIJMFXO2FL6VPPB7FKGKIDRLY53EKBTVHZL56OD5JCYFUAIYRSZQIE2RLVDZZUTQOO5NX',
'B$ZP0501MYQ75A2GHMJQMOZQJEBRSBKUMKHZCS2YMKT2NWKTBX7RCUDLMBXKBKXVLWBJBHMPPVDXXDJ6X7PLVVTPQ6DDWM2KU3FB432NJUITYOMYJOARTMR7AVR4SHGSQKKXP2ELCFUK4U72Y367ZZDUQB626E4H6RD5H3IPZDZM7HVFCYSACX6WCTCRW2J3Q2DFFQ7LBAY4ERZKLLKWI42JQ5X3CSY5SRLGRW36KCYFE6JIDVTIRQZH6ZG4YIM7BQU73ONOSCC6ZI4PF67OEZ3MXQC7P6I2OOW4KXV3PTAN3W3J6EAIBMULRT2GY3ARBE2ND4QT34P6RUQQ3HYUGT6HNFBQPZZ35ZYHHMYYIFIWHDSJTAQ7PISJ53GCCN54NKBLIJ6LYJEBMRIP4QYVC7OGCLEWMUZFTLD5W5O3PKHEQDRZQAMICDHWF6H36Z5IRHGE3ZHAOYMWYDABH7P5Q7NUROXEOC6P3J532RLQ3NHPDRP7D2BEFIYVUZLK3AB44L7LBTN75HZHUOSXJLVCVU54DVFCGEHH3EF6W6PGN3O5YMRJWWTBQDNSUGLU5IRR5ULBBMFO4QLE3GTTW3BU4LW6VHPOPVMZ7D6TNJDNMH3MIBQL6O2PDIRKLYEFIE5Y2D6XUXCEFWODB7HO2LRNXTMFEUTIJYGYEISYE77M6X2OQKIAAI27SKVMPU4HCI5NDLL6JTFDFFXC3OCZLMX2WI62HPR6JTWTIJG6EIOQJMRMPRWV5SYXZBKK7NPJ7K7CVKGMKIHFS4LUF3ZVBHMDFPDHZ43EBIHXM73T257LLY5ZWKR3',
'B$ZP0502N6QQLR6S2WU3KVVIEEGC3427H6WUVXVEFQEEZ5X7M5CKWKE3I5I77YADUXLG3RFZNNSQK7VWUK43HONJQVRQNLSWK2SZF3EIZ7AQ7BPDHT72PP5FZ5D3NJPO3AIYPYFDCWEMT7ZHR72AZ7G7XD7ZMRZKDP7TPSN74WIYVRX7BXUW66NEKXRP72UPSVTTVNGCVQ4LI4IPKY533OR6W2P2MOTW4OIHAVXUUJCQQPOU73F3YUOKO4B2KZ5JP44BJLGGM6EXA24EPCO2CCZ5P64HTHA2DELNPHGRJXK6F2ON4MUY54EGACZNLATHDRHLIIX7K27AWJKKHOWTLRVMYPDTB6ENWVXVSZWUSTCH2CGI2NO4XGGUEZKNWRQFHCGMPSBLNZYB25VNTONJJGNA7XODH45B7MVQJSVLZI2JW3DBUQ36S6ZWGVVQV4BFE4UOCL63G3NFIHNYNV7NQR7EZOJPN4O4C3HDAKYZ2X5BFORVJXYRUVNEPN7NNWQQZSYTU5BIEV2Q4C4B2TI5FUHSAYXDSR2XHXO5S374ZLESDD6YWM6HKLQB34FHQLLS2XCH4OKEPIHKZQ2BQC4QPRGHYI5GJZMRVKAHLOE4I6WADVRBFOHVINFMINLB5KLELCD4YPGT4GTNKKYO4P3K4UR7S2CNFSXSOBAE7SWI34MTRHVXTAMCDNZIHIOGMX3QUZT64D4HAT7STN2GCVZARI6M2JIMVY24AR35IVXKUTQ2JU4AAX7735YCPE5BBMDDWBQJYS3NM22UBKMR5IQTS42KNKKAIN5F5OFIDBV5CFDP3JHF',
]
d = DecodeQR()
for i in parts:
if d.add_data(i) == DecodeQRStatus.COMPLETE:
break
assert d.qr_type == QRType.PSBT__BBQR
#complete should be true
assert d.is_complete
tx = d.get_psbt()
assert str(tx) == base64_psbt
assert tx.inputs[0].witness_utxo.value == 3826 # input 1 amount in psbt
assert tx.inputs[1].witness_utxo.value == 1366 # input 2 amount in psbt
assert tx.inputs[2].witness_utxo.value == 4398 # input 3 amount in psbt
assert tx.inputs[3].witness_utxo.value == 3716 # input 4 amount in psbt
assert tx.inputs[4].witness_utxo.value == 2811 # input 5 amount in psbt
assert len(tx.outputs) == 1