Skip to main content

world_id_authenticator/
registry.rs

1//! Minimal World ID Registry contract bindings.
2//!
3//! This crate provides only the contract bindings and EIP-712 signing utilities.
4//! It has no dependencies on other world-id crates to avoid circular dependencies.
5
6use alloy::{
7    primitives::{Address, Signature, U256},
8    signers::SignerSync,
9    sol,
10    sol_types::{Eip712Domain, SolStruct, eip712_domain},
11};
12
13sol!(
14    /// The registry of World IDs. Each World ID is represented as a leaf in the Merkle tree.
15    #[allow(clippy::too_many_arguments)]
16    #[sol(rpc, ignore_unlinked)]
17    WorldIdRegistry,
18    "abi/WorldIDRegistryAbi.json"
19);
20
21/// These structs are created in a private module to avoid confusion with their exports.
22///
23/// They are only used to compute the EIP-712 typed data for signature.
24mod sol_types {
25    use alloy::sol;
26
27    sol! {
28        /// EIP-712 typed-data payload for `updateAuthenticator`.
29        ///
30        /// This is used only for signature hashing/recovery, not as the Solidity call signature.
31        struct UpdateAuthenticator {
32            uint64 leafIndex;
33            address oldAuthenticatorAddress;
34            address newAuthenticatorAddress;
35            uint32 pubkeyId;
36            uint256 newAuthenticatorPubkey;
37            uint256 newOffchainSignerCommitment;
38            uint256 nonce;
39        }
40
41        /// EIP-712 typed-data payload for `insertAuthenticator`.
42        ///
43        /// This is used only for signature hashing/recovery, not as the Solidity call signature.
44        struct InsertAuthenticator {
45            uint64 leafIndex;
46            address newAuthenticatorAddress;
47            uint32 pubkeyId;
48            uint256 newAuthenticatorPubkey;
49            uint256 newOffchainSignerCommitment;
50            uint256 nonce;
51        }
52
53        /// EIP-712 typed-data payload for `removeAuthenticator`.
54        ///
55        /// This is used only for signature hashing/recovery, not as the Solidity call signature.
56        struct RemoveAuthenticator {
57            uint64 leafIndex;
58            address authenticatorAddress;
59            uint32 pubkeyId;
60            uint256 authenticatorPubkey;
61            uint256 newOffchainSignerCommitment;
62            uint256 nonce;
63        }
64
65        /// EIP-712 typed-data payload for `recoverAccount`.
66        ///
67        /// This is used only for signature hashing/recovery, not as the Solidity call signature.
68        struct RecoverAccount {
69            uint64 leafIndex;
70            address newAuthenticatorAddress;
71            uint256 newAuthenticatorPubkey;
72            uint256 newOffchainSignerCommitment;
73            uint256 nonce;
74        }
75    }
76}
77
78/// EIP-712 typed-data signature payload for `updateAuthenticator`.
79pub type UpdateAuthenticatorTypedData = sol_types::UpdateAuthenticator;
80/// EIP-712 typed-data signature payload for `insertAuthenticator`.
81pub type InsertAuthenticatorTypedData = sol_types::InsertAuthenticator;
82/// EIP-712 typed-data signature payload for `removeAuthenticator`.
83pub type RemoveAuthenticatorTypedData = sol_types::RemoveAuthenticator;
84/// EIP-712 typed-data signature payload for `recoverAccount`.
85pub type RecoverAccountTypedData = sol_types::RecoverAccount;
86
87/// Returns the EIP-712 domain used by the `[WorldIdRegistry]` contract
88/// for a given `chain_id` and `verifying_contract` address.
89#[must_use]
90pub const fn domain(chain_id: u64, verifying_contract: Address) -> Eip712Domain {
91    eip712_domain!(
92        name: "WorldIDRegistry",
93        version: "1.0",
94        chain_id: chain_id,
95        verifying_contract: verifying_contract,
96    )
97}
98
99/// Signs the EIP-712 payload for an `updateAuthenticator` contract call.
100///
101/// # Errors
102/// Will error if the signer unexpectedly fails to sign the hash.
103#[allow(clippy::too_many_arguments)]
104pub fn sign_update_authenticator<S: SignerSync + Sync>(
105    signer: &S,
106    leaf_index: u64,
107    old_authenticator_address: Address,
108    new_authenticator_address: Address,
109    pubkey_id: u32,
110    new_authenticator_pubkey: U256,
111    new_offchain_signer_commitment: U256,
112    nonce: U256,
113    domain: &Eip712Domain,
114) -> anyhow::Result<Signature> {
115    let payload = UpdateAuthenticatorTypedData {
116        leafIndex: leaf_index,
117        oldAuthenticatorAddress: old_authenticator_address,
118        newAuthenticatorAddress: new_authenticator_address,
119        pubkeyId: pubkey_id,
120        newAuthenticatorPubkey: new_authenticator_pubkey,
121        newOffchainSignerCommitment: new_offchain_signer_commitment,
122        nonce,
123    };
124    let digest = payload.eip712_signing_hash(domain);
125    Ok(signer.sign_hash_sync(&digest)?)
126}
127
128/// Signs the EIP-712 payload for an `insertAuthenticator` contract call.
129///
130/// # Errors
131/// Will error if the signer unexpectedly fails to sign the hash.
132#[allow(clippy::too_many_arguments)]
133pub fn sign_insert_authenticator<S: SignerSync + Sync>(
134    signer: &S,
135    leaf_index: u64,
136    new_authenticator_address: Address,
137    pubkey_id: u32,
138    new_authenticator_pubkey: U256,
139    new_offchain_signer_commitment: U256,
140    nonce: U256,
141    domain: &Eip712Domain,
142) -> anyhow::Result<Signature> {
143    let payload = InsertAuthenticatorTypedData {
144        leafIndex: leaf_index,
145        newAuthenticatorAddress: new_authenticator_address,
146        pubkeyId: pubkey_id,
147        newAuthenticatorPubkey: new_authenticator_pubkey,
148        newOffchainSignerCommitment: new_offchain_signer_commitment,
149        nonce,
150    };
151    let digest = payload.eip712_signing_hash(domain);
152    Ok(signer.sign_hash_sync(&digest)?)
153}
154
155/// Signs the EIP-712 payload for a `removeAuthenticator` contract call.
156///
157/// # Errors
158/// Will error if the signer unexpectedly fails to sign the hash.
159#[allow(clippy::too_many_arguments)]
160pub fn sign_remove_authenticator<S: SignerSync + Sync>(
161    signer: &S,
162    leaf_index: u64,
163    authenticator_address: Address,
164    pubkey_id: u32,
165    authenticator_pubkey: U256,
166    new_offchain_signer_commitment: U256,
167    nonce: U256,
168    domain: &Eip712Domain,
169) -> anyhow::Result<Signature> {
170    let payload = RemoveAuthenticatorTypedData {
171        leafIndex: leaf_index,
172        authenticatorAddress: authenticator_address,
173        pubkeyId: pubkey_id,
174        authenticatorPubkey: authenticator_pubkey,
175        newOffchainSignerCommitment: new_offchain_signer_commitment,
176        nonce,
177    };
178    let digest = payload.eip712_signing_hash(domain);
179    Ok(signer.sign_hash_sync(&digest)?)
180}
181
182/// Signs the EIP-712 payload for a `recoverAccount` contract call.
183///
184/// # Errors
185/// Will error if the signer unexpectedly fails to sign the hash.
186pub fn sign_recover_account<S: SignerSync + Sync>(
187    signer: &S,
188    leaf_index: u64,
189    new_authenticator_address: Address,
190    new_authenticator_pubkey: U256,
191    new_offchain_signer_commitment: U256,
192    nonce: U256,
193    domain: &Eip712Domain,
194) -> anyhow::Result<Signature> {
195    let payload = RecoverAccountTypedData {
196        leafIndex: leaf_index,
197        newAuthenticatorAddress: new_authenticator_address,
198        newAuthenticatorPubkey: new_authenticator_pubkey,
199        newOffchainSignerCommitment: new_offchain_signer_commitment,
200        nonce,
201    };
202    let digest = payload.eip712_signing_hash(domain);
203    Ok(signer.sign_hash_sync(&digest)?)
204}