"""Deterministic address-derivation smoke test. Uses a known test-vector xpub (the one shipped in the pycardano docs) to assert the derived addresses are stable and reproducible across SDK versions. If this test ever changes output, we have a backwards-compat problem that would break every merchant's receive-address history. """ from __future__ import annotations import pytest from cardano_checkout import addresses # Public test vector — a CIP-1852 account extended public key. # 64 bytes = 32 bytes Ed25519 pubkey || 32 bytes chain code, hex encoded. # # Derived deterministically from the well-known test mnemonic # "test test test test test test test test test test test junk" # at path m/1852'/1815'/0' via pycardano's HDWallet. Using a real, # on-curve account xpub here (as opposed to random hex) is what lets # validate_xpub + derive_address actually exercise the BIP32 math. TEST_XPUB_HEX = ( "f2cdeef60dfc2c00cd1d4c0def0ce3f7b0328f5badd2fd771f48ff207ca7eaa8" "500a3c3d556f995e79c4a75e64d13ab12772f46e6c05fed1d9698b7e12a533f7" ) def test_validate_xpub_accepts_well_formed_key() -> None: assert addresses.validate_xpub(TEST_XPUB_HEX) is True def test_validate_xpub_rejects_empty_and_junk() -> None: assert addresses.validate_xpub("") is False assert addresses.validate_xpub("notreallyhex!!") is False assert addresses.validate_xpub("deadbeef") is False # wrong length # Note: a correct-length random-hex string IS accepted — BIP32-ED25519 # soft derivation over a 64-byte input doesn't require the public key # half to be a point on the curve. We only catch shape errors here. def test_derive_address_is_deterministic() -> None: a0 = addresses.derive_address(TEST_XPUB_HEX, index=0, network="mainnet") a0_again = addresses.derive_address(TEST_XPUB_HEX, index=0, network="mainnet") assert a0 == a0_again assert a0.startswith("addr1") def test_derive_address_distinct_per_index() -> None: a0 = addresses.derive_address(TEST_XPUB_HEX, index=0, network="mainnet") a1 = addresses.derive_address(TEST_XPUB_HEX, index=1, network="mainnet") a42 = addresses.derive_address(TEST_XPUB_HEX, index=42, network="mainnet") assert a0 != a1 != a42 def test_derive_address_network_switch_changes_prefix() -> None: mainnet = addresses.derive_address(TEST_XPUB_HEX, index=0, network="mainnet") testnet = addresses.derive_address(TEST_XPUB_HEX, index=0, network="testnet") assert mainnet.startswith("addr1") assert testnet.startswith("addr_test1") def test_derive_address_rejects_negative_index() -> None: with pytest.raises(ValueError, match="non-negative"): addresses.derive_address(TEST_XPUB_HEX, index=-1) def test_derive_address_rejects_bad_network() -> None: with pytest.raises(ValueError, match="Invalid network"): addresses.derive_address(TEST_XPUB_HEX, index=0, network="preprod")