decdn_incentive/lib.rs
1//! The deCDN payment layer: USDC payment pools, the off-chain vouchers that pay
2//! them down, and the signatures and contract bindings that tie them to the
3//! chain.
4//!
5//! A client pays a node per megabyte from a `PaymentPool` deposit ([ADR 003]).
6//! The pool owner opens a pool on chain and authorizes spenders off chain with
7//! a signed [`Capability`]. Each spender pays each node on its own lane, a
8//! `(pool, signer, provider)` triple, with cumulative EIP-712 [`Voucher`]s. A
9//! `PayWord` hash chain advances a voucher between signatures, one preimage per
10//! delivered chunk ([ADR 003 § Hash-chain metering]). The node redeems the
11//! highest voucher on each lane with `redeem` or `redeemMany`.
12//!
13//! # Modules
14//!
15//! | Area | Modules |
16//! |---|---|
17//! | Vouchers and metering | [`voucher`] (sign and verify), [`chain`] (hash chains), [`rate`] (rate checks), [`credit`] (credit window), [`client_bridge`] (to and from the wire [`decdn_protocol::Voucher`]) |
18//! | Spend delegation | [`capability`] (the signed capability), [`capability_grant`] (its transferable `dcap1:` form) |
19//! | Lane state | [`lane`] (the seller's per-lane watermark), [`store`] (persistence traits and in-memory stores), [`deployment`] (which `PaymentPool` a state belongs to) |
20//! | Buyer bookkeeping | [`buyer_pool`] (the buyer's pools and lanes), `buyer_pool_table` and `buyer_pool_redb` (an on-disk `redb` store, behind the `buyer-store-core` and `redb` features) |
21//! | Response signatures | [`probe_sig`] and [`stream_sig`] (the `slash_sig` on probe and stream responses), [`bind_sig`] (client bindings), [`sig_canon`] (canonical `s`) |
22//! | Keys | [`eth_identity`] (Web3 Secret Storage keystores and the `PrivateKeySigner` they load) |
23//! | Contract bindings | [`payment_pool`], [`capacity_bond`], [`node_register`], [`erc20`], [`slash_judge`], [`slash_appeal`], [`origin_assignment`], [`publisher_registry`], [`content_blacklist`] |
24//! | Transactions | [`tx`] (send, await the receipt, fail on a revert), [`pool_open_error`] (`PaymentPool` revert decoding) |
25//!
26//! # Sign and verify a voucher
27//!
28//! ```
29//! use alloy::primitives::{Address, B256, U256};
30//! use alloy::signers::local::PrivateKeySigner;
31//! use decdn_incentive::{Voucher, voucher_domain};
32//!
33//! let payer = PrivateKeySigner::random();
34//! let domain = voucher_domain(421_614, Address::repeat_byte(0x11));
35//! let voucher = Voucher {
36//! pool_id: B256::repeat_byte(0x22),
37//! signer: payer.address(),
38//! provider: Address::repeat_byte(0x33),
39//! amount: U256::from(1_000),
40//! bytes_delivered: U256::from(1_048_576),
41//! chain_root: B256::ZERO,
42//! chunk_price: U256::ZERO,
43//! };
44//! let signed = voucher.sign(&payer, &domain)?;
45//! signed.verify_signer(payer.address(), &domain)?;
46//! # Ok::<(), Box<dyn std::error::Error>>(())
47//! ```
48//!
49//! # Who drives settlement
50//!
51//! This crate holds the primitives. The `decdn-node` daemon drives both sides
52//! of settlement with them. As a seller, it records each lane's watermark from
53//! the `PoolOpened` and `Redeemed` events, redeems every lane worth the gas on a
54//! sweep that runs well inside a closing pool's grace window, and forgets a
55//! reclaimed pool. As a buyer on a cache miss,
56//! it approves USDC once, opens or tops up a pool, signs the vouchers, and
57//! closes and reclaims a pool it no longer uses.
58//!
59//! [ADR 003]: https://github.com/decdn/decdn/blob/main/adr/003-payments.md
60//! [ADR 003 § Hash-chain metering]: https://github.com/decdn/decdn/blob/main/adr/003-payments.md#hash-chain-metering-payword
61#![cfg_attr(docsrs, feature(doc_cfg))]
62
63pub mod bind_sig;
64pub mod buyer_pool;
65pub mod credit;
66pub mod deployment;
67// NOTE: no outer `///` docs on these two — each module's `//!` header is its
68// documentation. An outer doc here would be a second copy free to drift, and
69// rustdoc merges it with the `//!` block and resolves the result in *this*
70// module's scope, silently breaking the module's own intra-doc links.
71#[cfg(feature = "redb")]
72pub mod buyer_pool_redb;
73#[cfg(feature = "buyer-store-core")]
74pub mod buyer_pool_table;
75pub mod capability;
76pub mod capability_grant;
77pub mod capacity_bond;
78pub mod chain;
79pub mod client_bridge;
80pub mod content_blacklist;
81pub mod erc20;
82pub mod eth_identity;
83pub mod lane;
84pub mod lane_signer;
85pub mod node_register;
86pub mod origin_assignment;
87pub mod payment_pool;
88pub mod pool_open_error;
89pub mod probe_sig;
90pub mod publisher_registry;
91pub mod rate;
92pub mod sig_canon;
93pub mod slash_appeal;
94pub mod slash_judge;
95pub mod store;
96pub mod stream_sig;
97#[cfg(feature = "test-util")]
98pub mod test_rpc;
99pub mod tx;
100pub mod voucher;
101
102pub use bind_sig::{
103 BindError, CAPACITY_BOND_DOMAIN_NAME, CAPACITY_BOND_DOMAIN_VERSION, EPHEMERAL_BINDING_NONCE,
104 bind_node_id_domain, binding_signing_hash, register_node_signing_hash, verify_binding,
105};
106pub use buyer_pool::{
107 AdvanceOutcome, BuyerLaneProgress, BuyerLoad, BuyerPoolState, BuyerPoolStore,
108 BuyerProgressError, DepositOutcome, MemoryBuyerPoolStore,
109};
110pub use capability::{Capability, CapabilityError, SignedCapability};
111pub use capability_grant::{CapabilityGrant, GrantError, GrantOwnerError};
112pub use chain::{
113 CHUNK_BYTES, ChainMeterError, MAX_CHAIN_LENGTH, pack_chain_meter, preimage_at, random_seed,
114 root_from_seed, verify_forward,
115};
116pub use client_bridge::{
117 RetrySignal, WireVoucherError, signed_to_wire_voucher, voucher_reject_reason,
118 wire_voucher_to_signed,
119};
120pub use credit::ramped_credit_window;
121pub use deployment::Deployment;
122pub use erc20::Erc20;
123pub use lane::{
124 FoldAxis, LaneChain, LaneKey, LaneState, PoolError, PoolId, PreimageApplied, RedeemClaim,
125 VoucherApplied,
126};
127pub use pool_open_error::{
128 PoolLifecycleRevert, PoolOpenFailureReason, is_erc20_allowance_shortfall, is_pool_not_open,
129};
130pub use probe_sig::{
131 PROBE_RESPONSE_TYPEHASH, ProbeSlashData, ProbeSlashError, SLASH_JUDGE_DOMAIN_NAME,
132 SLASH_JUDGE_DOMAIN_VERSION, slash_judge_domain,
133};
134pub use rate::{
135 BYTES_PER_MB, DEFAULT_TOLERANCE_BPS, RateError, min_payment, pool_budget_covers, verify_rate,
136};
137pub use store::{
138 CheckpointKey, KeyedCheckpointStore, MemoryPoolStateStore, PendingSettle, PendingSettleStore,
139 PoolStateStore, StoreError,
140};
141pub use stream_sig::{STREAM_RESPONSE_TYPEHASH, StreamSlashData, StreamSlashError};
142pub use voucher::{
143 DOMAIN_NAME, DOMAIN_VERSION, SignedVoucher, Voucher, VoucherError, voucher_domain,
144};