decdn_incentive/origin_assignment.rs
1//! `OriginAssignment` contract ABI bindings (ADR 011 § Origin Assignment
2//! Authority, ADR 022 § FIND\_VALUE Flow "Origin discovery").
3//!
4//! Generated by the `alloy::sol!` macro from the Solidity surface in
5//! `contracts/src/OriginAssignment.sol`. Only the read path, the publisher
6//! control-plane writes the CLI submits, and the membership-mutating events the
7//! node's chain-backed origin directory ([`crate`] consumer
8//! `decdn-node::dht::chain_origin_directory`) consumes are mirrored. The
9//! directory keeps a `namespaceId → authorized-operator` cache current from
10//! these events, falling back to `getOrigins` for the bootstrap snapshot.
11//!
12//! The contract has two planes. Whether a **publisher wallet** may seat origins
13//! is decided by a swappable `IVettingPolicy` (governance re-points it with
14//! `setVettingPolicy`); a vetted publisher then seats and unseats origins for
15//! its own namespaces instantly, one operator at a time. So every event here is
16//! a single-operator delta — `OriginAdded` seats one, `OriginRemoved` /
17//! `InactiveOriginPruned` remove one — and the directory treats each as a
18//! signal to re-read `getOrigins`, not as history. Namespace 0 has no publisher
19//! and no authorized origins, so `getOrigins(0)` is always empty.
20//!
21//! Vetting is not a CLI flow: a `VETTER_ROLE` holder on the installed policy
22//! (an operator, multisig, or governance) vets a wallet out-of-band, after
23//! which it may seat origins immediately. `OriginAssignment::vettingPolicy`
24//! exposes the installed policy address for tooling that wants to read it.
25
26// The `sol!`-generated bindings include macro-emitted code that uses
27// patterns workspace clippy denies (raw indexing into ABI fixed-size
28// byte arrays, `unwrap` on infallible conversions). These allows scope
29// the relaxation to this module only.
30#[allow(
31 clippy::expect_used,
32 clippy::indexing_slicing,
33 clippy::panic,
34 clippy::unwrap_used,
35 clippy::pub_underscore_fields,
36 clippy::missing_docs_in_private_items,
37 clippy::too_many_arguments,
38 missing_debug_implementations,
39 missing_docs,
40 non_snake_case,
41 non_camel_case_types
42)]
43mod sol_types {
44 alloy::sol! {
45 #[sol(rpc)]
46 contract OriginAssignment {
47 // -----------------------------------------------------------------
48 // View functions (only those consumed by the node runtime + CLI)
49 // -----------------------------------------------------------------
50
51 /// Current authorized-origin operator addresses for a namespace.
52 /// `namespaceId == 0` has no set and always returns empty. Returns
53 /// the live `EnumerableSet` values.
54 function getOrigins(uint256 namespaceId) external view returns (address[] memory);
55
56 /// How many namespaces currently have a non-empty authorized set.
57 function assignedNamespaceCount() external view returns (uint256);
58
59 /// A page of the namespaces that currently have origins. Membership
60 /// within a namespace was always readable via `getOrigins`; this is
61 /// the key set, whose absence was the sole reason a bootstrap had to
62 /// replay the seating events from the deploy block.
63 ///
64 /// Order is NOT stable across mutations (swap-and-pop removal), so
65 /// every page and the count it is checked against MUST be read at one
66 /// pinned block height.
67 function assignedNamespaces(uint256 offset, uint256 limit)
68 external
69 view
70 returns (uint256[] memory);
71
72 /// Whether the installed policy vets `publisher` to seat origins for
73 /// its own namespaces. `addOrigin` reverts `PublisherNotVetted` while
74 /// false. A passthrough to `vettingPolicy().isVetted(publisher)`.
75 function isVettedPublisher(address publisher) external view returns (bool);
76
77 /// The installed vetting authority (an `IVettingPolicy`). Exposed for
78 /// tooling that wants to read the policy address; vetting itself is a
79 /// `VETTER_ROLE` action on that policy, not a CLI flow.
80 function vettingPolicy() external view returns (address);
81
82 // -----------------------------------------------------------------
83 // Write functions (publisher control plane, issues #1029 / #1491)
84 // -----------------------------------------------------------------
85
86 /// Vetted namespace owner seats one more authorized origin. Instant:
87 /// there is no pending state and no governance step. Reverts if the
88 /// caller does not own the namespace, is not vetted, or the operator
89 /// is not an active bonded node, is already seated, or would exceed
90 /// `maxOriginsPerNamespace`.
91 function addOrigin(uint256 namespaceId, address operator) external;
92
93 /// Namespace owner (own namespace) or governance (any) unseats one
94 /// authorized origin. Instant; reverts if the operator is not seated.
95 function removeOrigin(uint256 namespaceId, address operator) external;
96
97 // -----------------------------------------------------------------
98 // Per-namespace origin-membership events
99 // -----------------------------------------------------------------
100
101 /// One `operator` was seated as an authorized origin for
102 /// `namespaceId` by its vetted publisher. The single "origin seated"
103 /// event: there is no wholesale set replacement.
104 event OriginAdded(
105 uint256 indexed namespaceId,
106 address indexed operator,
107 address indexed by
108 );
109
110 /// A single `operator` was unseated from `namespaceId`'s authorized
111 /// set (by the namespace owner or governance).
112 event OriginRemoved(
113 uint256 indexed namespaceId,
114 address indexed operator,
115 address indexed by
116 );
117
118 /// An `operator` that left the active set (unbonded, deregistered,
119 /// or ejected) was permissionlessly pruned from `namespaceId`'s
120 /// authorized set. Same cache effect as a removal (remove one).
121 event InactiveOriginPruned(
122 uint256 indexed namespaceId,
123 address indexed operator,
124 address indexed pruner
125 );
126 }
127 }
128}
129
130pub use sol_types::OriginAssignment;