1use alloy::primitives::Address;
4use eddsa_babyjubjub::EdDSAPublicKey;
5use ruint::aliases::U256;
6
7use crate::{
8 api_types::{
9 GatewayRequestId, GatewayRequestState, GatewayStatusResponse, InsertAuthenticatorRequest,
10 RemoveAuthenticatorRequest, UpdateAuthenticatorRequest,
11 },
12 authenticator::Authenticator,
13 error::AuthenticatorError,
14 registry::{
15 domain, sign_insert_authenticator, sign_remove_authenticator, sign_update_authenticator,
16 },
17 traits::OnchainKeyRepresentable,
18};
19
20impl Authenticator {
21 pub async fn insert_authenticator(
30 &self,
31 new_authenticator_pubkey: EdDSAPublicKey,
32 new_authenticator_address: Address,
33 ) -> Result<GatewayRequestId, AuthenticatorError> {
34 let leaf_index = self.leaf_index();
35 let nonce = self.signing_nonce().await?;
36 let mut key_set = self.fetch_authenticator_pubkeys().await?;
37 let old_offchain_signer_commitment = key_set.leaf_hash();
38 let encoded_offchain_pubkey = new_authenticator_pubkey.to_ethereum_representation()?;
39 let index =
40 Self::insert_or_reuse_authenticator_key(&mut key_set, new_authenticator_pubkey)?;
41 let new_offchain_signer_commitment = key_set.leaf_hash();
42
43 let eip712_domain = domain(self.config.chain_id(), *self.config.registry_address());
44
45 #[allow(clippy::cast_possible_truncation)]
46 let signature = sign_insert_authenticator(
48 &self.signer.onchain_signer(),
49 leaf_index,
50 new_authenticator_address,
51 index as u32,
52 encoded_offchain_pubkey,
53 new_offchain_signer_commitment.into(),
54 nonce,
55 &eip712_domain,
56 )
57 .map_err(|e| {
58 AuthenticatorError::Generic(format!("Failed to sign insert authenticator: {e}"))
59 })?;
60
61 #[allow(clippy::cast_possible_truncation)]
62 let req = InsertAuthenticatorRequest {
64 leaf_index,
65 new_authenticator_address,
66 pubkey_id: index as u32,
67 new_authenticator_pubkey: encoded_offchain_pubkey,
68 old_offchain_signer_commitment: old_offchain_signer_commitment.into(),
69 new_offchain_signer_commitment: new_offchain_signer_commitment.into(),
70 signature,
71 nonce,
72 };
73
74 let body: GatewayStatusResponse = self
75 .gateway_client
76 .post_json(self.config.gateway_url(), "/insert-authenticator", &req)
77 .await?;
78 Ok(body.request_id)
79 }
80
81 pub async fn update_authenticator(
90 &self,
91 old_authenticator_address: Address,
92 new_authenticator_address: Address,
93 new_authenticator_pubkey: EdDSAPublicKey,
94 index: u32,
95 ) -> Result<GatewayRequestId, AuthenticatorError> {
96 let leaf_index = self.leaf_index();
97 let nonce = self.signing_nonce().await?;
98 let mut key_set = self.fetch_authenticator_pubkeys().await?;
99 let old_commitment: U256 = key_set.leaf_hash().into();
100 let encoded_offchain_pubkey = new_authenticator_pubkey.to_ethereum_representation()?;
101 key_set.try_set_at_index(index as usize, new_authenticator_pubkey)?;
102 let new_commitment: U256 = key_set.leaf_hash().into();
103
104 let eip712_domain = domain(self.config.chain_id(), *self.config.registry_address());
105
106 let signature = sign_update_authenticator(
107 &self.signer.onchain_signer(),
108 leaf_index,
109 old_authenticator_address,
110 new_authenticator_address,
111 index,
112 encoded_offchain_pubkey,
113 new_commitment,
114 nonce,
115 &eip712_domain,
116 )
117 .map_err(|e| {
118 AuthenticatorError::Generic(format!("Failed to sign update authenticator: {e}"))
119 })?;
120
121 let req = UpdateAuthenticatorRequest {
122 leaf_index,
123 old_authenticator_address,
124 new_authenticator_address,
125 old_offchain_signer_commitment: old_commitment,
126 new_offchain_signer_commitment: new_commitment,
127 signature,
128 nonce,
129 pubkey_id: index,
130 new_authenticator_pubkey: encoded_offchain_pubkey,
131 };
132
133 let gateway_resp: GatewayStatusResponse = self
134 .gateway_client
135 .post_json(self.config.gateway_url(), "/update-authenticator", &req)
136 .await?;
137 Ok(gateway_resp.request_id)
138 }
139
140 pub async fn remove_authenticator(
149 &self,
150 authenticator_address: Address,
151 index: u32,
152 ) -> Result<GatewayRequestId, AuthenticatorError> {
153 let leaf_index = self.leaf_index();
154 let nonce = self.signing_nonce().await?;
155 let mut key_set = self.fetch_authenticator_pubkeys().await?;
156 let old_commitment: U256 = key_set.leaf_hash().into();
157 let existing_pubkey = key_set
158 .get(index as usize)
159 .ok_or(AuthenticatorError::PublicKeyNotFound)?;
160
161 let encoded_old_offchain_pubkey = existing_pubkey.to_ethereum_representation()?;
162
163 key_set.try_clear_at_index(index as usize)?;
164 let new_commitment: U256 = key_set.leaf_hash().into();
165
166 let eip712_domain = domain(self.config.chain_id(), *self.config.registry_address());
167
168 let signature = sign_remove_authenticator(
169 &self.signer.onchain_signer(),
170 leaf_index,
171 authenticator_address,
172 index,
173 encoded_old_offchain_pubkey,
174 new_commitment,
175 nonce,
176 &eip712_domain,
177 )
178 .map_err(|e| {
179 AuthenticatorError::Generic(format!("Failed to sign remove authenticator: {e}"))
180 })?;
181
182 let req = RemoveAuthenticatorRequest {
183 leaf_index,
184 authenticator_address,
185 old_offchain_signer_commitment: old_commitment,
186 new_offchain_signer_commitment: new_commitment,
187 signature,
188 nonce,
189 pubkey_id: Some(index),
190 authenticator_pubkey: Some(encoded_old_offchain_pubkey),
191 };
192
193 let gateway_resp: GatewayStatusResponse = self
194 .gateway_client
195 .post_json(self.config.gateway_url(), "/remove-authenticator", &req)
196 .await?;
197 Ok(gateway_resp.request_id)
198 }
199
200 pub async fn poll_status(
210 &self,
211 request_id: &GatewayRequestId,
212 ) -> Result<GatewayRequestState, AuthenticatorError> {
213 let path = format!("/status/{request_id}");
214 let body: GatewayStatusResponse = self
215 .gateway_client
216 .get_json(self.config.gateway_url(), &path)
217 .await?;
218 Ok(body.status)
219 }
220}