1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! The DIG-CAT per-capsule payment — the canonical store-payment spend builder.
//!
//! ## Pricing model: mint is FREE of $DIG; a CAPSULE (commit) is paid
//! Creating (minting) a data **store** does NOT cost $DIG — minting only launches the on-chain
//! DataLayer singleton with an empty/initial root and pays the XCH network fee. $DIG is paid ONLY
//! when a **capsule** is created: every commit / root-advance (a new `(storeId, rootHash)` generation)
//! pays the per-capsule price in $DIG to the DIG treasury. So `mint_store` (the launch) carries NO DIG
//! payment, and the COMMIT path concatenates a [`build_dig_store_payment`] CAT spend with the
//! root-advance ([`crate::update_store_metadata`]) into one atomic bundle.
//!
//! ## Dynamic, USD-pegged amount — the caller passes it in
//! The per-capsule price is **dynamic and USD-pegged** (SYSTEM.md → Core concept → Pricing):
//! `dig_amount = target_usd ÷ live DIG price`, uniform per fixed-size capsule. This builder is
//! offline + deterministic and NEVER fetches a price — the live `amount` (base units) is an input
//! param computed by the caller (the hub in-browser, the CLI from `--dig-amount`). There is
//! intentionally NO hardcoded amount constant here.
//!
//! ## Shared contract — byte-identical across the ecosystem
//! The DIG CAT asset id, the treasury inner puzzle hash, and the treasury-output memo layout
//! (`[treasury_inner_ph (hint), store_id]`) are a cross-system shared contract (SYSTEM.md →
//! Shared contracts → "DIG CAT payment"). They MUST be byte-identical to the digstore-chain mirror
//! (`crates/digstore-chain/src/{dig,cat}.rs`). A drift here breaks payment atomicity / anchor-watcher
//! gating. chip35 is the canonical spend builder, so this is the source the mirror follows.
//!
//! Boundary discipline (the same as every builder here): no networking, no signing, no key
//! derivation, no coin selection. The caller supplies the buyer's reconstructed DIG [`Cat`] coins and
//! the launcher id; this builds the (unsigned) CAT coin spends. The caller concatenates them with the
//! commit's singleton spend and signs the whole bundle.
use PublicKey;
use ;
use StandardArgs;
use ;
use Conditions;
use hex;
use crateWalletError;
/// DIG CAT asset id (TAIL hash) on Chia **mainnet**. The single token a capsule (commit) is paid in.
///
/// CONTRACT: byte-identical to digstore-chain's `DIG_ASSET_ID` and DataLayer-Driver's. Do not change
/// without changing every consumer in lockstep (SYSTEM.md → Shared contracts → DIG CAT payment).
/// Re-exported from `dig-constants` — the canonical source of truth.
pub use DIG_ASSET_ID;
/// The DIG treasury's INNER (standard) puzzle hash — the recipient of every per-capsule DIG payment.
///
/// This is the inner puzzle hash decoded from the treasury address
/// `xch1a37rq3cgcl2ecpudttsf35x75qzdan68lgw2l6ajvmqs44jxdn5qv6pk3y`; the CAT layer (curried with
/// [`DIG_ASSET_ID`]) wraps it so the on-chain coin lands at the treasury's DIG CAT puzzle hash.
///
/// CONTRACT: byte-identical to the digstore-chain mirror (`treasury_inner_puzzle_hash()` decodes the
/// SAME address) and the hub's `DIG_TREASURY_*` constants. The anchor-watcher gates confirmed payments
/// on a coin landing at the DIG-CAT wrap of THIS hash, so a drift silently rejects valid payments.
pub const DIG_TREASURY_INNER_PUZZLE_HASH: Bytes32 = new;
/// Build the (UNSIGNED) DIG-CAT coin spends that pay `amount` base units of $DIG to the DIG treasury
/// for a capsule (commit) — the canonical per-capsule store payment.
///
/// This is the ONLY place a store payment is constructed (chip35 is the canonical spend builder). The
/// COMMIT path concatenates the returned coin spends with the root-advance singleton spend
/// ([`crate::update_store_metadata`]) into ONE bundle and signs them together, so the payment and the
/// new capsule are admitted atomically. The MINT path does NOT call this — minting a store is free of
/// $DIG.
///
/// Behaviour (byte-mirror of digstore-chain's `build_dig_payment`):
/// - ring-spends the buyer's `dig_cats` (all of [`DIG_ASSET_ID`]),
/// - creates ONE DIG CAT coin of `amount` to [`DIG_TREASURY_INNER_PUZZLE_HASH`], carrying memos
/// `[treasury_inner_ph (hint), store_id]` so the treasury wallet discovers it and the payment is
/// tied to the capsule's store,
/// - returns the DIG change to the buyer (hinted to their own inner puzzle hash),
/// - reserves NO XCH (the CAT ring nets to zero; an XCH network fee rides on a separate coin via the
/// commit's [`crate::update_store_metadata`] + [`crate::add_fee`]).
///
/// `amount` is the dynamic, USD-pegged per-capsule price in DIG base units — an INPUT, never a
/// hardcoded constant (see the module docs). `store_id` is the capsule's launcher id (= store id).
///
/// # Errors
/// [`WalletError::Parse`] if `dig_cats` is empty, mixes asset ids, is not the DIG asset, or totals
/// below `amount`; [`WalletError::Driver`] on spend-construction failure.
/// The DIG CAT payment coin a capsule (commit) pays to the treasury — what
/// [`build_dig_store_payment`] emits.
///
/// `parent` is the lead DIG CAT coin's id; the returned coin is the treasury's DIG CAT coin (the CAT
/// outer puzzle wrapping the treasury inner puzzle hash). Lets a caller pin the exact expected coin
/// (e.g. for a payment receipt / verification) without re-deriving the CAT wrap by hand.