Skip to main content

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 node_register;
85pub mod origin_assignment;
86pub mod payment_pool;
87pub mod pool_open_error;
88pub mod probe_sig;
89pub mod publisher_registry;
90pub mod rate;
91pub mod sig_canon;
92pub mod slash_appeal;
93pub mod slash_judge;
94pub mod store;
95pub mod stream_sig;
96pub mod tx;
97pub mod voucher;
98
99pub use bind_sig::{
100    BindError, CAPACITY_BOND_DOMAIN_NAME, CAPACITY_BOND_DOMAIN_VERSION, EPHEMERAL_BINDING_NONCE,
101    bind_node_id_domain, binding_signing_hash, register_node_signing_hash, verify_binding,
102};
103pub use buyer_pool::{
104    AdvanceOutcome, BuyerLaneProgress, BuyerLoad, BuyerPoolState, BuyerPoolStore,
105    BuyerProgressError, DepositOutcome, MemoryBuyerPoolStore,
106};
107pub use capability::{Capability, CapabilityError, SignedCapability};
108pub use capability_grant::{CapabilityGrant, GrantError, GrantOwnerError};
109pub use chain::{
110    CHUNK_BYTES, ChainMeterError, MAX_CHAIN_LENGTH, pack_chain_meter, preimage_at, random_seed,
111    root_from_seed, verify_forward,
112};
113pub use client_bridge::{
114    RetrySignal, WireVoucherError, signed_to_wire_voucher, voucher_reject_reason,
115    wire_voucher_to_signed,
116};
117pub use credit::ramped_credit_window;
118pub use deployment::Deployment;
119pub use erc20::Erc20;
120pub use lane::{
121    FoldAxis, LaneChain, LaneKey, LaneState, PoolError, PoolId, PreimageApplied, RedeemClaim,
122    VoucherApplied,
123};
124pub use pool_open_error::{
125    PoolLifecycleRevert, PoolOpenFailureReason, is_erc20_allowance_shortfall, is_pool_not_open,
126};
127pub use probe_sig::{
128    PROBE_RESPONSE_TYPEHASH, ProbeSlashData, ProbeSlashError, SLASH_JUDGE_DOMAIN_NAME,
129    SLASH_JUDGE_DOMAIN_VERSION, slash_judge_domain,
130};
131pub use rate::{
132    BYTES_PER_MB, DEFAULT_TOLERANCE_BPS, RateError, min_payment, pool_budget_covers, verify_rate,
133};
134pub use store::{
135    CheckpointKey, KeyedCheckpointStore, MemoryPoolStateStore, PendingSettle, PendingSettleStore,
136    PoolStateStore, StoreError,
137};
138pub use stream_sig::{STREAM_RESPONSE_TYPEHASH, StreamSlashData, StreamSlashError};
139pub use voucher::{
140    DOMAIN_NAME, DOMAIN_VERSION, SignedVoucher, Voucher, VoucherError, voucher_domain,
141};