Skip to main content

wallet_adapter/wallet_ser_der/standard_features/
signin.rs

1use wallet_adapter_common::{signin_standard::SignInOutput, WalletCommonUtils};
2use web_sys::{js_sys, wasm_bindgen::JsValue};
3
4use crate::{
5    Reflection, SemverVersion, SigninInput, StandardFunction, WalletAccount, WalletError,
6    WalletResult,
7};
8
9/// A `solana:signin` struct containing the `version` and `callback`
10/// within [StandardFunction]
11#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
12pub struct SignIn(StandardFunction);
13
14impl SignIn {
15    /// Parse the `solana:signin` callback function from the [JsValue]
16    pub(crate) fn new(reflection: &Reflection, version: SemverVersion) -> WalletResult<Self> {
17        Ok(Self(StandardFunction::new(
18            reflection, version, "signIn", "solana",
19        )?))
20    }
21
22    pub(crate) async fn call_signin(
23        &self,
24        signin_input: &SigninInput,
25        public_key: [u8; 32],
26    ) -> WalletResult<SignInOutput> {
27        let outcome = self
28            .0
29            .callback
30            .call1(&JsValue::null(), &signin_input.get_object()?)?;
31
32        let outcome = js_sys::Promise::resolve(&outcome);
33
34        let value = wasm_bindgen_futures::JsFuture::from(outcome).await?;
35        let output_array = Reflection::new(value)?.get_array()?;
36
37        let first_index = Reflection::new(output_array.get(0))?;
38        let wallet_account = first_index.reflect_inner("account")?;
39        let wallet_account = WalletAccount::parse(Reflection::new(wallet_account)?)?;
40
41        let message_value = first_index.reflect_inner("signedMessage")?;
42        let message_bytes = Reflection::new(message_value)?.into_bytes()?;
43        let message =
44            core::str::from_utf8(&message_bytes).map_err(|error| WalletError::JsError {
45                name: "Invalid UTF-8 Message".to_string(),
46                message: error.to_string(),
47                stack: "INTERNAL_ERROR".to_string(),
48            })?;
49
50        signin_input.0.check_eq(message)?;
51
52        let signature_value = first_index.reflect_inner("signature")?;
53        let signature_bytes: [u8; 64] = Reflection::new(signature_value)?
54            .into_bytes()?
55            .try_into()
56            .or(Err(WalletError::InvalidEd25519SignatureBytes))?;
57
58        WalletCommonUtils::verify(&public_key, &message_bytes, &signature_bytes)?;
59
60        Ok(SignInOutput {
61            account: wallet_account.account,
62            message: message.to_string(),
63            signature: signature_bytes,
64            public_key,
65        })
66    }
67}