Skip to content

Conversation

@tadeubas
Copy link
Member

@tadeubas tadeubas commented Feb 1, 2026

This PR introduces breaking changes and should be released as v2.0.0.

It achieves: firmware size reduction, and sometimes less RAM usage

Removed ~100 lines of code (in the end almost no reduction because of black and comments left from "deleted" code. Don't consider new lines from tests, poetry.lock, README.md and .pylintrc)

Summary of Changes

  • Code cleanup and simplification:

    • Removed __eq__ as it is used only by tests
    • Removed import * from init files to void unnecessary imports and reduce RAM usage
    • Removed other unnecessary code
    • Make use of lazy imports to reduce RAM usage
    • Code reuse on src/urtypes/cbor/decoder.py decode_bytestring / decode_textstring
    • Other small changes that conform to pylint
  • Testing and documentation:

    • New test_output.py case to show fixed bug on HDKey bip32_key when key has 32-bytes
    • Added new tests and increased test coverage.
    • Updated README.md with develop instructions.
  • Tooling additions:

    • Added development dependencies:

      • pylint
      • vulture
      • black

Changes needed on Krux (imports need to be specific):

  • src/krux/pages/datum_tool.py:
def urobj_to_data(ur_obj):
    """returns flatened data from a UR object. belongs in qr or qr_capture???"""
    from urtypes.crypto.bip39 import BIP39
    from urtypes.crypto.account import Account
    from urtypes.crypto.output import Output
    from urtypes.crypto.psbt import PSBT
    from urtypes.bytes import Bytes

    if ur_obj.type == "CRYPTO-BIP39":
        data = BIP39.from_cbor(ur_obj.cbor).words
        data = " ".join(data)
    elif ur_obj.type == "CRYPTO-ACCOUNT":
        data = (
            Account.from_cbor(ur_obj.cbor)
            .output_descriptors[0]
            .descriptor()
        )
    elif ur_obj.type == "CRYPTO-OUTPUT":
        data = Output.from_cbor(ur_obj.cbor).descriptor()
    elif ur_obj.type == "CRYPTO-PSBT":
        data = PSBT.from_cbor(ur_obj.cbor).data
    elif ur_obj.type == "BYTES":
        data = Bytes.from_cbor(ur_obj.cbor).data
    else:
        data = None
    return data

...

def view_qr(self):
...
# change line:
import urtypes

# to:
from urtypes.bytes import Bytes
from urtypes.crypto.psbt import PSBT

# change lines:
if ur_type == "bytes":
    encoded = UR(ur_type, urtypes.Bytes(encoded).to_cbor())
elif ur_type == "crypto-psbt":
    encoded = UR(ur_type, urtypes.PSBT(encoded).to_cbor())

# to:
if ur_type == "bytes":
    encoded = UR(ur_type, Bytes(encoded).to_cbor())
elif ur_type == "crypto-psbt":
    encoded = UR(ur_type, PSBT(encoded).to_cbor())

  • src/krux/psbt.py:
# change lines:
import urtypes
from urtypes.crypto import CRYPTO_PSBT

# to:
from urtypes.crypto.psbt import PSBT as URTYPE_PSBT, CRYPTO_PSBT

# change lines:
self.psbt = PSBT.parse(
    urtypes.crypto.PSBT.from_cbor(psbt_data.cbor).data
)

# to:
self.psbt = PSBT.parse(
    URTYPE_PSBT.from_cbor(psbt_data.cbor).data
)

# from:
return (
    UR(
        CRYPTO_PSBT.type,
        urtypes.crypto.PSBT(psbt_data).to_cbor(),
    ),
    self.qr_format,
)

# to:
return (
    UR(
        CRYPTO_PSBT.type,
        URTYPE_PSBT(psbt_data).to_cbor(),
    ),
    self.qr_format,
)

  • src/krux/wallet.py:
def parse_wallet(wallet_data):
    """Exhaustively tries to parse the wallet data from a known format, returning
    a descriptor and label if possible.

    If the descriptor cannot be derived, an exception is raised.
    """
    # pylint: disable=R0912

    # Check if wallet_data is a UR object without loading the UR module
    if wallet_data.__class__.__name__ == "UR":
        # Try to parse as a Crypto-Output type
        try:
            from urtypes.crypto.output import Output

            output = Output.from_cbor(wallet_data.cbor)
            return Descriptor.from_string(output.descriptor()), None
        except:
            pass

        # Try to parse as a Crypto-Account type
        try:
            from urtypes.crypto.account import Account

            account = Account.from_cbor(
                wallet_data.cbor
            ).output_descriptors[0]
            return Descriptor.from_string(account.descriptor()), None
        except:
            pass

        # Treat the UR as a generic UR bytes object and extract the data for further processing
        from urtypes.bytes import Bytes
        
        wallet_data = Bytes.from_cbor(wallet_data.cbor).data

...

  • tests/pages/test_datum_tool.py:

Change line from urtypes import Bytes to:

from urtypes.bytes import Bytes

@tadeubas
Copy link
Member Author

It is worth mentioning that this lib ur-types implements CBOR encode / decode in /src/urtypes/cbor/decoder.py and /src/urtypes/cbor/encoder.py. The other lib foundation-ur-py also implements CBOR encode / decode in /src/ur/cbor_lite.py. It would be good to integrate the CBOR implementation and reuse on both libs for even more firmware size reduction.

@tadeubas tadeubas force-pushed the min-lib branch 2 times, most recently from 34295ff to f183e95 Compare February 11, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant