Commit graph

8 commits

Author SHA1 Message Date
c592a58148 Public-flip audit: drop audit-ticket prefixes + topology refs + AI scaffolding
cardano-api: strip 'Fix #N:' audit-ticket prefixes from inline comments (was
50+ in main.py), drop hardening-pass changelog blocks from module docstring,
rewrite README to drop deploy paths + marketing sections, keep tier/auth/TTL
+ policy IDs.

cardano-checkout-py: drop TradeCraft lineage refs, swap chromaticcraft/tradecraft
test fixtures for acme/globex, repository URL → git.sulkta.com.
2026-05-27 11:15:03 -07:00
af41f945b1 v1.0.0-dev: slim to the real product — merchant state machine only
Drop everything that duplicates PyCardano. The landscape scan done
2026-04-23 confirmed: no ecosystem gap for wallet/chain/tx-build —
pycardano 0.19.x covers all of it cleanly. The gap is the merchant
state machine, so that's all we ship.

Deleted:
- addresses.py  → consumers call pycardano.HDWallet directly
- txbuild.py    → consumers use pycardano.OgmiosChainContext directly
- oracles.py    → consumers supply a price_fn callable
- mint.py       → consumers build mint txs with pycardano;
                  CIP-25 v2 metadata builder shipped as a copy-paste
                  snippet in the README
- ipfs.py       → py-ipfs-http-client covers it
- tradecraft_compat.py → no one was importing it; kill
- docs/minting-workflow.md → redundant with README pairing guidance

Refactored:
- monitor.evaluate_utxos: ADA-only. The DexHunter token-equivalent
  block came out. Consumers who want stablecoin support wrap the
  function with their own asset-to-lovelace converter.
- monitor.reprice_expired_invoices: takes a new required kwarg
  price_fn: Callable[[float], Awaitable[int]]. No more ADA/USD
  oracle shipped in the SDK.
- scheduler.InvoiceScheduler: takes an optional price_fn field;
  if None, the reprice job is a no-op (works for fixed-ADA invoices).

Tests (26/26 passing, all offline):
- test_invoice.py — state-machine helpers, 3 tests
- test_store_protocol.py — Protocol conformance + InMemoryStore round-trips, 13 tests
- test_monitor_with_inmemory_store.py — all status transitions + reprice,
  rewired to pass price_fn fixtures instead of monkeypatching oracle funcs

Deps dropped: pycardano (consumer pairing, not our dep).
Deps kept: httpx (Koios), apscheduler (background scheduler).

Package shape (1.0.0-dev, ~700 LOC src):

  cardano_checkout/
    invoice.py    —  Invoice + InvoiceStatus
    store.py      —  InvoiceStore Protocol + InMemoryStore
    monitor.py    —  Koios poll + UTxO matching + reprice driver
    scheduler.py  —  APScheduler wrapper

README rewritten top-to-bottom: "what we ship", "what we don't ship",
why the niche exists, pycardano-directly examples for the delete-list,
CIP-25 builder as a 20-line copy-paste, InvoiceStore implementation
example. Apache-2.0 license unchanged.
2026-04-23 21:58:26 -07:00
68cb535c0f v0.2: README rewrite + docs/minting-workflow.md cold-signer runbook
README status table moves everything green except the TradeCraft compat
shim (still yellow, documented sunset path). Adds a migration guide
section mapping every old services/cardano_*.py import to its new
cardano_checkout.* equivalent so TradeCraft can adopt in one atomic
diff once the SQLAlchemyInvoiceStore adapter lands.

docs/minting-workflow.md: step-by-step runbook for the cold-signer
pattern — hot host builds UnsignedMint, operator ships three CBOR hex
files to Lucy, offline signer produces a signed tx, hot host submits
via submit_signed_tx. Covers the tx-id sanity check, skey hygiene
rules, time-locked-policy TTL clamp, and the preprod dry-run
requirement for every new policy.
2026-04-23 20:00:49 -07:00
dd435a5e2d v0.2: add store, mint, and monitor integration tests
Three new modules land in tests/ alongside the v0.1 pure-module
tests:

- test_store_protocol.py: InMemoryStore round-trips + Protocol
  conformance. Covers create / get / update / list_by_status /
  next_derivation_index / record_tx idempotency + defensive-copy
  semantics.
- test_mint_metadata.py: mint_nft_cert end-to-end against a stubbed
  ChainContext (no live Ogmios). Exercises the 2-of-2 native-script
  policy shape, tx body construction, CIP-25 envelope CBOR
  round-trip, and the oversize-asset-name guard.
- test_monitor_with_inmemory_store.py: monitor loop driven against
  InMemoryStore with Koios + the oracle monkeypatched. Covers every
  status transition the scheduler cares about (confirm, overpay,
  underpay, stay-pending, record_tx, expiry skip) and the two
  reprice code paths (successful reprice bumps expected_lovelace +
  expires_at; max_repricings flips to EXPIRED).

All 42 tests pass on pycardano 0.16 with pytest-asyncio auto mode.
2026-04-23 19:58:46 -07:00
27b119bbe1 v0.2: wire mint + txbuild end-to-end against local Ogmios
txbuild.py gets real: make_ogmios_context builds an
OgmiosChainContext pointed at 127.0.0.1:1337 by default (matches the
Rackham stack), get_protocol_parameters peeks at live params,
get_address_utxos powers the eventual refund path, submit_signed_tx
ships a cold-signed blob to the chain.

mint.py's mint_nft_cert now constructs the real tx body:
  - mints exactly 1 of {policy_id}.{asset_name}
  - sends it to recipient_address in its own UTxO padded with min-ADA
  - attaches CIP-25 v2 metadata + the native script as aux data
  - clamps TTL to policy.locked_after_slot when the policy is time-locked

Does NOT sign — matches the ADAMaps cold-signing pattern. Returns an
UnsignedMint bundle carrying body CBOR, aux CBOR, native-script CBOR,
required-signer hashes, and a human-readable summary. Operator moves
the bundle to the cold host (Lucy in Sulkta's pattern — 2-of-2
native-script under Cobb + Kayos skeys), signs offline, ships the
signed CBOR back. submit_signed_tx finishes the round-trip.
2026-04-23 19:55:45 -07:00
a6d4ac8521 v0.2: refactor monitor + scheduler around InvoiceStore Protocol
Rewrite monitor.py so it operates entirely through the
cardano_checkout.store.InvoiceStore Protocol — no more SQLAlchemy
imports, no more CardanoPayment / PlatformConfig coupling. Same
behavioural shape: same Koios URL, same 15s check cadence, same 2%
confirm / overpay tolerances, same 3-reprice cap.

Rewrite scheduler.py as a reusable InvoiceScheduler dataclass that
wires two APScheduler jobs (check_pending every 15s, reprice_expired
every 60s) against a consumer-supplied store. The subscription +
grace-period jobs are TradeCraft-specific and get lifted into
tradecraft_compat.py verbatim so TradeCraft can still import them
during the migration window without any code change.

Add InMemoryStore reference implementation to store.py — used by the
test suite and handy for local dev / ephemeral workflows.

Bump version to 0.2.0-dev.
2026-04-23 19:55:28 -07:00
eef22dc5cd addresses: swap nonexistent HDPublicKey for HDWallet soft derivation
pycardano >=0.11 doesn't ship HDPublicKey — the v0.1 extraction
imported a symbol that never existed in the installed version, which
meant every address-derivation test failed at import time.

Use HDWallet rooted at the account level with public-only fields set,
then soft-derive receive chain (0) and staking chain (2). Hash the
resulting verification keys through PaymentVerificationKey /
StakeVerificationKey to compose the Shelley base address.

Refresh the test-vector xpub with a real, deterministic CIP-1852
account xpub derived from the well-known "test ... junk" mnemonic so
validate_xpub + derive_address actually exercise the BIP32 math.

Drop the "random hex should be rejected" assertion — BIP32-ED25519
soft derivation doesn't enforce that the 32-byte pubkey half is a
point on the curve, so arbitrary well-shaped hex is accepted by the
underlying crypto.
2026-04-23 19:55:16 -07:00
dc6378eda6 v0.1.0-dev: initial extraction from TradeCraft + new abstractions
Sulkta Coop's Python SDK for merchant-side Cardano payments +
NFT certificate-of-authenticity minting. Zero-custody by design.

Extracted from TradeCraft's services/cardano_*.py (2,400+ lines of
production Cardano-mainnet code) and restructured as an installable
Python package.

Package layout (cardano_checkout/):
- addresses.py   — lifted verbatim: CIP-1852 HD derivation, pure pycardano
- oracles.py     — lifted from cardano_price.py: Koios ADA/USD feed w/ 5m cache
- monitor.py     — lifted verbatim (SQLAlchemy-coupled; v0.2 refactors to Store)
- scheduler.py   — lifted verbatim (same refactor note)
- invoice.py     — NEW: framework-agnostic Invoice dataclass + lifecycle enum
- store.py       — NEW: InvoiceStore Protocol for pluggable persistence
- mint.py        — NEW: CIP-25 v2 metadata builder (works); tx submission stub for v0.2
- ipfs.py        — NEW: kubo HTTP client with primary-pin + mirror-pin pattern
- txbuild.py     — NEW: v0.2 stub for PyCardano / Ogmios tx construction

Design:
- Consumers provide xpub + InvoiceStore impl. SDK provides everything else.
- IPFS: local kubo for upload + serve, optional mirror pins for archival.
  Chromaticcraft pattern: Rackham kubo primary, Lucy kubo mirror.
- NFT: single native-script policy per merchant studio (CIP-25 v2, not CIP-68
  — full wallet coverage, no mutability needed for static certs). Policy skey
  stays under Sulkta cold-custody (Lucy pattern); signing is an external
  hand-off like ADAMaps payouts.

Tests: pure-module smoke tests pass for invoice, store-protocol, CIP-25
metadata envelope, IPFS client import, txbuild stub module. Address
derivation tests ship but require pycardano + will exercise in CI.

LICENSE: Apache-2.0 (matches upstream Cardano tooling).

Next (v0.2 scope):
- Refactor monitor + scheduler around InvoiceStore (drop SQLAlchemy coupling)
- Wire mint.mint_nft_cert to PyCardano + local Ogmios on Rackham
- txbuild: Ogmios chain-context + cold-signer hand-off shape
- chromaticcraft Phase 2 imports the SDK as its first external consumer
2026-04-23 18:04:00 -07:00