Skip to main content

libid_contracts/bindings/
identity.rs

1//! Bindings for the identity registry (`solidity/contracts/identity/`):
2//! `IdentityRegistry`.
3
4/// Bindings for `identity/IdentityRegistry.sol`.
5///
6/// `Rules` mirrors `HandleNormalizer.Rules` — the normalization rules the
7/// contract stores per platform. Platform ids are `keccak256` of the
8/// platform key.
9#[allow(clippy::too_many_arguments, unused_attributes)]
10mod registry_inner {
11    use alloy::sol;
12
13    sol! {
14        #[sol(rpc, abi)]
15        interface IdentityRegistry {
16            #[derive(Debug, serde::Serialize, serde::Deserialize)]
17            struct Rules {
18                uint16 maxLength;
19                bool stripLeadingAt;
20                bool isEmail;
21                bool allowUnderscore;
22                bool allowHyphen;
23            }
24
25            /// One identity a holder proved, as its list reports it. `handle`
26            /// is the one the identity proved most recently, and
27            /// `handleCurrent` says whether the handle node still points back
28            /// at this identity: it stops doing so when another identity
29            /// proves the same handle, and the string stays as the last thing
30            /// the identity was known as.
31            #[derive(Debug, serde::Serialize, serde::Deserialize)]
32            struct Identity {
33                bytes32 platformId;
34                string id;
35                string handle;
36                bool handleCurrent;
37            }
38
39            function initialize(address owner_) external;
40
41            /// The holder that proved an id, and when.
42            function idBinding(bytes32 idNode) external view returns (address holder, uint64 observedAt);
43            /// The holder that last proved a handle node, and when. A zero
44            /// holder: nobody proved it, or it was retired.
45            function handleBinding(bytes32 handleNode) external view returns (address holder, uint64 observedAt);
46            /// The operation domain a binding's authorization names.
47            function OPERATION_DOMAIN() external view returns (bytes32);
48
49            function owner() external view returns (address);
50            function pendingOwner() external view returns (address);
51            function transferOwnership(address newOwner) external;
52            function acceptOwnership() external;
53            /// Always reverts; the contract declares it `pure`.
54            function renounceOwnership() external pure;
55
56            /// The rules half: what a handle on this platform means. It
57            /// does not vary by proof version — two versions normalizing
58            /// differently would put one handle on two nodes.
59            function setPlatform(bytes32 platformId, Rules calldata rules) external;
60
61            /// Which contract holds the Supported Version Set. Registering a
62            /// version is that contract's call, not this one's.
63            function setProofVerifier(address verifier) external;
64            function proofVerifier() external view returns (address);
65
66            /// The one write. The contract does not know what `payload` is:
67            /// it names a platform and this chain's verifier version for it,
68            /// and the Proof Verifier routes the bytes to the one contract
69            /// that decodes them. The value attached must equal `quoteBind`
70            /// for the same pair exactly.
71            function bind(bytes32 platformId, uint16 verifierVersion, bytes calldata payload, bool publish) external payable;
72            function quoteBind(bytes32 platformId, uint16 verifierVersion) external view returns (uint256);
73            function digestSpent(bytes32 digest) external view returns (bool);
74            function unpublish(bytes32 platformId) external;
75            function resolveId(bytes32 platformId, string calldata id) external view returns (address);
76            function resolveHandle(bytes32 platformId, string calldata handle) external view returns (address);
77            /// The handle's holder, and whether `id` resolves to that same
78            /// holder.
79            function resolveHandleAndId(bytes32 platformId, string calldata handle, string calldata id) external view returns (address holder, bool idAgrees);
80            /// The handle a holder published, while it still resolves back to
81            /// that holder; empty otherwise.
82            function publishedHandleOf(address holder, bytes32 platformId) external view returns (string memory);
83            /// The platform's rules as configured now, for local normalization.
84            function rulesOf(bytes32 platformId) external view returns (Rules memory);
85            /// Whether `bind` can bind a holder on this platform
86            /// now: rules, and a Proof Verifier that verifies it.
87            function acceptsBindings(bytes32 platformId) external view returns (bool);
88            /// `keccak256` of the normalized handle: what `HandleEscrow.deposit`
89            /// takes. Reverts `UnknownPlatform` or `UnusableHandle`.
90            function handleHashOf(bytes32 platformId, string calldata handle) external view returns (bytes32 handleHash);
91            /// The node a handle hashes to now; reverts as `handleHashOf` does.
92            function handleNodeOf(bytes32 platformId, string calldata handle) external view returns (bytes32 handleNode);
93            /// The node of a handle given as its hash, as `bind` binds it.
94            function handleNodeOfHash(bytes32 platformId, bytes32 handleHash) external pure returns (bytes32);
95
96            /// How many identities a holder has, on every platform together.
97            function identityCount(address holder) external view returns (uint256);
98            /// A page of a holder's identities, on every platform
99            /// together: the indices `[from, from + limit)`, counted from
100            /// zero and clipped to the list. Order is arbitrary and changes
101            /// when an identity leaves the list, so a reader that needs every
102            /// identity reads `identityCount` and the pages in one block.
103            function identitiesOf(address holder, uint256 from, uint256 limit) external view returns (Identity[] memory);
104
105            /// Carries the ceremony version that proved the binding -- logged,
106            /// never stored, because nothing on chain acts on it and an
107            /// operator asking which bindings a version touched reads the log.
108            /// What the ceremony authenticated beyond the binding rides on
109            /// `CeremonyBound` instead.
110            event IdentityBound(
111                address indexed holder,
112                bytes32 indexed idNode,
113                bytes32 indexed handleNode,
114                bytes32 platformId,
115                string id,
116                string handle,
117                uint64 observedAt,
118                bool published,
119                uint16 ceremonyVersion
120            );
121            /// A platform not configured, or one nothing verifies and on
122            /// which nothing was ever bound.
123            error UnknownPlatform(bytes32 platformId);
124            /// Text the platform's rules refuse; `problem` is a
125            /// `HandleNormalizer.Problem`.
126            error UnusableHandle(uint8 problem);
127
128            event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
129            event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
130
131            // What `bind` can revert with: its own refusals, and the
132            // normalizer's, for a proved handle the rules refuse.
133            error ZeroAddress();
134            error ForeignOperationDomain(bytes32 operationDomain);
135            error DigestAlreadySpent(bytes32 digest);
136            error BadTransactionData(uint256 length);
137            error WrongBindValue(uint256 required, uint256 provided);
138            error WrongFeeValue(uint256 required, uint256 provided);
139            error NoncanonicalFee(uint256 amount, address receiver);
140            error FeeTransferFailed(address receiver, uint256 amount);
141            error NotProofTarget(address proved, address caller);
142            error NoObservationTime();
143            error NoId();
144            error StaleProof(uint64 observedAt, uint64 known);
145            error EmptyHandle();
146            error HandleTooLong();
147            error BadCharacter();
148            error BadShape();
149            error OwnableUnauthorizedAccount(address account);
150            error OwnableInvalidOwner(address owner);
151            error ReentrancyGuardReentrantCall();
152
153            event HandleRetired(bytes32 indexed platformId, bytes32 indexed handleNode, address indexed holder);
154            event PlatformConfigured(bytes32 indexed platformId);
155            event ProofVerifierConfigured(address verifier);
156            /// The service fee a binding's own Authorized Transaction Data named
157            /// was delivered. Emitted only when there is one.
158            event BindFeePaid(bytes32 indexed authorizationDigest, address indexed receiver, uint256 amount);
159            event HandleUnpublished(address indexed holder, bytes32 indexed platformId);
160            /// The OAuth client a ceremony authenticated. Nothing stores it, so
161            /// "which application produced these bindings" is answerable only
162            /// from this log.
163            event CeremonyBound(
164                bytes32 indexed authorizationDigest,
165                address indexed holder,
166                bytes32 indexed platformId,
167                bytes clientIdentifier
168            );
169        }
170    }
171}
172
173pub use registry_inner::IdentityRegistry;
174
175#[cfg(test)]
176mod tests {
177    use super::registry_inner::IdentityRegistry;
178    use crate::bindings::drift::assert_binding_matches_artifact;
179
180    /// Inherited upgrade and initializer ABI, left to `proxy::IUUPSUpgradeable`.
181    const OMITTED: &[&str] = &[
182        "error AddressEmptyCode(address)",
183        "error ERC1967InvalidImplementation(address)",
184        "error ERC1967NonPayable()",
185        "error FailedCall()",
186        "error InvalidInitialization()",
187        "error NotInitializing()",
188        "error UUPSUnauthorizedCallContext()",
189        "error UUPSUnsupportedProxiableUUID(bytes32)",
190        "event Initialized(uint64)",
191        "event Upgraded(address)",
192        "function UPGRADE_INTERFACE_VERSION()",
193        "function proxiableUUID()",
194        "function upgradeToAndCall(address,bytes)",
195    ];
196
197    #[test]
198    fn the_binding_matches_the_artifact_abi() {
199        assert_binding_matches_artifact(
200            "IdentityRegistry",
201            "IdentityRegistry",
202            &IdentityRegistry::abi::contract(),
203            OMITTED,
204        );
205    }
206}