world_id_authenticator/
recovery.rs1use alloy::{primitives::Address, signers::Signature};
2use ruint::aliases::U256;
3
4use crate::{
5 api_types::{
6 CancelRecoveryAgentUpdateRequest, ExecuteRecoveryAgentUpdateRequest, GatewayRequestId,
7 GatewayStatusResponse, UpdateRecoveryAgentRequest,
8 },
9 authenticator::Authenticator,
10 error::AuthenticatorError,
11};
12use world_id_registries::world_id::{
13 domain, sign_cancel_recovery_agent_update, sign_initiate_recovery_agent_update,
14};
15
16impl Authenticator {
17 #[deprecated(
26 note = "WIP-102: use `update_recovery_agent`. The legacy URL still works against a V2-upgraded gateway, but the V2 contract changes the agent immediately (with a revert window) instead of starting a cooldown."
27 )]
28 pub async fn initiate_recovery_agent_update(
29 &self,
30 new_recovery_agent: Address,
31 ) -> Result<GatewayRequestId, AuthenticatorError> {
32 let leaf_index = self.leaf_index();
33 let (sig, nonce) = self
34 .danger_sign_initiate_recovery_agent_update(new_recovery_agent)
35 .await?;
36
37 let req = UpdateRecoveryAgentRequest {
38 leaf_index,
39 new_recovery_agent,
40 signature: sig,
41 nonce,
42 };
43
44 let gateway_resp: GatewayStatusResponse = self
45 .gateway_client
46 .post_json(
47 self.config.gateway_url(),
48 "/initiate-recovery-agent-update",
49 &req,
50 )
51 .await?;
52 Ok(gateway_resp.request_id)
53 }
54
55 pub async fn danger_sign_initiate_recovery_agent_update(
73 &self,
74 new_recovery_agent: Address,
75 ) -> Result<(Signature, U256), AuthenticatorError> {
76 let leaf_index = self.leaf_index();
77 let nonce = self.signing_nonce().await?;
78 let eip712_domain = domain(self.config.chain_id(), *self.config.registry_address());
79
80 let signature = sign_initiate_recovery_agent_update(
81 &self.signer.onchain_signer(),
82 leaf_index,
83 new_recovery_agent,
84 nonce,
85 &eip712_domain,
86 )
87 .map_err(|e| {
88 AuthenticatorError::Generic(format!(
89 "Failed to sign initiate recovery agent update: {e}"
90 ))
91 })?;
92
93 Ok((signature, nonce))
94 }
95
96 pub async fn update_recovery_agent(
108 &self,
109 new_recovery_agent: Address,
110 ) -> Result<GatewayRequestId, AuthenticatorError> {
111 let leaf_index = self.leaf_index();
112 let (sig, nonce) = self
113 .danger_sign_initiate_recovery_agent_update(new_recovery_agent)
114 .await?;
115
116 let req = UpdateRecoveryAgentRequest {
117 leaf_index,
118 new_recovery_agent,
119 signature: sig,
120 nonce,
121 };
122
123 let gateway_resp: GatewayStatusResponse = self
124 .gateway_client
125 .post_json(self.config.gateway_url(), "/update-recovery-agent", &req)
126 .await?;
127 Ok(gateway_resp.request_id)
128 }
129
130 #[deprecated(
138 note = "WIP-102: this operation no longer exists. On a V2-upgraded gateway the call is a no-op (returns Finalized without touching chain). Remove the call from your flow."
139 )]
140 pub async fn execute_recovery_agent_update(
141 &self,
142 ) -> Result<GatewayRequestId, AuthenticatorError> {
143 let req = ExecuteRecoveryAgentUpdateRequest {
144 leaf_index: self.leaf_index(),
145 };
146
147 let gateway_resp: GatewayStatusResponse = self
148 .gateway_client
149 .post_json(
150 self.config.gateway_url(),
151 "/execute-recovery-agent-update",
152 &req,
153 )
154 .await?;
155 Ok(gateway_resp.request_id)
156 }
157
158 #[deprecated(
163 note = "WIP-102: use `revert_recovery_agent_update`. The legacy URL still works against a V2-upgraded gateway, but the new method name reflects WIP-102 semantics: the operation can only succeed within the revert window after `update_recovery_agent`."
164 )]
165 pub async fn cancel_recovery_agent_update(
166 &self,
167 ) -> Result<GatewayRequestId, AuthenticatorError> {
168 let leaf_index = self.leaf_index();
169 let nonce = self.signing_nonce().await?;
170 let eip712_domain = domain(self.config.chain_id(), *self.config.registry_address());
171
172 let sig = sign_cancel_recovery_agent_update(
173 &self.signer.onchain_signer(),
174 leaf_index,
175 nonce,
176 &eip712_domain,
177 )
178 .map_err(|e| {
179 AuthenticatorError::Generic(format!("Failed to sign cancel recovery agent update: {e}"))
180 })?;
181
182 let req = CancelRecoveryAgentUpdateRequest {
183 leaf_index,
184 signature: sig,
185 nonce,
186 };
187
188 let gateway_resp: GatewayStatusResponse = self
189 .gateway_client
190 .post_json(
191 self.config.gateway_url(),
192 "/cancel-recovery-agent-update",
193 &req,
194 )
195 .await?;
196 Ok(gateway_resp.request_id)
197 }
198
199 pub async fn revert_recovery_agent_update(
204 &self,
205 ) -> Result<GatewayRequestId, AuthenticatorError> {
206 let leaf_index = self.leaf_index();
207 let nonce = self.signing_nonce().await?;
208 let eip712_domain = domain(self.config.chain_id(), *self.config.registry_address());
209
210 let sig = sign_cancel_recovery_agent_update(
211 &self.signer.onchain_signer(),
212 leaf_index,
213 nonce,
214 &eip712_domain,
215 )
216 .map_err(|e| {
217 AuthenticatorError::Generic(format!("Failed to sign revert recovery agent update: {e}"))
218 })?;
219
220 let req = CancelRecoveryAgentUpdateRequest {
221 leaf_index,
222 signature: sig,
223 nonce,
224 };
225
226 let gateway_resp: GatewayStatusResponse = self
227 .gateway_client
228 .post_json(
229 self.config.gateway_url(),
230 "/revert-recovery-agent-update",
231 &req,
232 )
233 .await?;
234 Ok(gateway_resp.request_id)
235 }
236}