Stage C of the create→list arc. The wizard's "Publish for \$1 in DEA"
button (and every other openPublishOverlay entry) now broadcasts a real
KatalogosRegistryV1.register() transaction via the local signer.
src/publish.ts (new)
publishViaLocalSigner(signer, categoryId) builds the four-output
register() tx:
inputs [0] state UTXO (minting NFT) at registry contract,
unlocked via covenant register(targetCategory,
oracleSig, oracleMessage)
[1+] DEA UTXOs from signer (≥ feeDea)
[N+] plain BCH from signer for miner fee + dust
outputs [0] state UTXO re-created (minting NFT preserved)
[1] entry NFT (immutable, commitment = target category)
[2] fee to treasury (≥ 231 atomic DEA at chipnet rate)
[3+] DEA change (if any) + BCH change
Oracle: chipnet dev key (baked, matches shells/app/src/core/
katalogos-oracle-dev.ts). Signs a 16-byte AnyHedge-shape message
with satsPerUsd=200,000. feeDea = ceil(satsPerUsd / deaRateSats)
= 231 (matches the covenant's ceil-div on-chain).
Address helper encodes the treasury LB as p2pkhWithTokens
(bchtest:z…) because cashscript refuses a token output to a
non-token-aware address even when the underlying locking bytecode
is identical.
PublishError typed codes (insufficient-dea/insufficient-bch/
no-state-utxo/invalid-category/other) so main.ts can render
actionable messages.
src/main.ts
wirePublishInterceptor monkey-patches window.openPublishOverlay so
EVERY entry (post-genesis button, Katalogos row, Stoa link) routes
through the real broadcast when a local signer is attached;
falls back to the mockup's illustrative overlay otherwise.
runRealPublish renders a small scrim, calls publishViaLocalSigner,
refreshes the registry read on success so the count updates
immediately. On PublishError('insufficient-dea') it prints the
signer address so the user knows where to send DEA.
contracts/ArtemisionMintFT.cash
Family-doc header refreshed with the three MBA Shares siblings
chipnet-proven this session: DeviantShareMBA + DistributionVault +
TermCouponVault. Enumerates the three Artemision presets that
compose them (rewards / shares+dividends / t-bond).
Bug fixes along the way (verified before publish landed):
• DEA change output uses signer.tokenaddr (was cashaddr → cashscript
"no token support" error).
• register()'s targetCategory arg passed as display-order bytes to
match the commitment cashscript writes into the NFT — NOT the
consensus-LE reversal used for constructor args like
registryCategory. Byte-order mismatch surfaced as
"require(tx.outputs[1].nftCommitment == targetCategory)" failing.
SMOKE-TESTED ON CHIPNET (Wallet D, TST431 from prior genesis smoke)
Attach Wallet D → openPublishOverlay('TST431')
Publish tx: 27017650fa58c4f5635a2293041d82f0c7e184b46b4b1abd0586cfe95e89c134
Category: 2dd5af3fb0660c23d8aa96a44edf8d33eb5ab838f46573e6df543fab94997a49
Fee: 231 atomic DEA (\$1 at chipnet dev-oracle rate)
Registry count after reload: 8 → 9 · window.potidaeaRegistry now
includes TST431's category id.
WHAT WORKS · WHAT REMAINS
✓ Create MBA → swap MBA (same-user, from genesis smoke ed73…)
✓ Publish MBA → Katalogos v1 (cross-user visibility of the id)
• Cross-user metadata for swap: v2 registry with params on-chain
per ADR-0055 Amendment 2026-09-02 (readers see the id today,
but need rate/fee/founderLB to build a claim tx).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>