Skip to main content

dig_offers/
lib.rs

1//! # dig-offers — the DIG Network canonical Chia offers expert crate
2//!
3//! `dig-offers` is a **pure, key-free, network-free** SpendBundle-builder for Chia offers
4//! (settlement per CHIP-0023/CHIP-0024). It constructs the exact
5//! [`CoinSpend`](chia_protocol::CoinSpend)s for every offer operation — make, take, combine,
6//! cancel, and summarize/inspect — over any asset (XCH / CAT / NFT), and reports the exact
7//! signatures a caller must produce.
8//!
9//! ## The custody model (HARD invariants)
10//!
11//! dig-offers **never holds a secret key, never signs, and never touches the network.** Every
12//! builder takes only public inputs (puzzle hashes, asset ids, public keys, and coins with their
13//! lineage proofs) and appends unsigned coin spends to a caller-owned
14//! [`chia_wallet_sdk::driver::SpendContext`]. The consumer signs the messages
15//! reported by [`required_signatures`], assembles/combines the `SpendBundle`, and broadcasts. This
16//! keeps the signing decision — and the secret key — entirely on the caller's side of the identity
17//! boundary (#908).
18//!
19//! ## The make/take two-phase flow
20//!
21//! Building and assembling are split so the caller signs BETWEEN them, in ONE shared context:
22//!
23//! - **make:** [`make_build`] → [`required_signatures`] → caller signs → [`make_assemble`].
24//! - **take:** [`take_build`] → [`required_signatures`] → caller signs → [`take_combine`].
25//!
26//! The two phases of each flow MUST share the same [`SpendContext`], because a parsed/requested
27//! NFT carries an allocator-relative metadata pointer that only survives in that context.
28//!
29//! ## The requested-side rule (no self-fund)
30//!
31//! A make's requested side is an assertion plus a phantom carrier — never a settle action — so the
32//! maker never funds both sides of its own offer. Settle actions appear only when taking. See
33//! `SPEC.md` for the normative contract.
34
35#![forbid(unsafe_code)]
36
37mod cancel;
38mod combine;
39mod error;
40mod hydrate;
41mod make;
42mod offer_id;
43mod sign;
44mod summarize;
45mod take;
46mod types;
47
48#[cfg(test)]
49mod test_support;
50
51pub use cancel::cancel_build;
52pub use combine::combine;
53pub use error::{Error, Result};
54pub use hydrate::{decode, parse};
55pub use make::{make_assemble, make_build};
56pub use offer_id::offer_id;
57pub use sign::required_signatures;
58pub use summarize::summarize;
59pub use take::{take_build, take_combine};
60pub use types::{
61    OfferAsset, OfferCost, OfferSummary, OfferedSide, RequestedSide, TakerFunds, UnsignedCancel,
62    UnsignedMake, UnsignedTake,
63};
64
65// Re-exports so a consumer need not depend on the SDK directly for the common surface.
66pub use chia_wallet_sdk::driver::{
67    decode_offer, encode_offer, AssetInfo, Cat, CatAssetInfo, Nft, NftAssetInfo, Offer,
68    RequestedPayments, SpendContext,
69};
70pub use chia_wallet_sdk::signer::RequiredSignature;
71
72/// The crate's semantic version, surfaced so a consumer can record which builder version produced
73/// a spend.
74#[must_use]
75pub fn version() -> &'static str {
76    env!("CARGO_PKG_VERSION")
77}
78
79#[cfg(test)]
80mod tests {
81    #[test]
82    fn version_is_reported() {
83        assert!(!super::version().is_empty());
84    }
85}