alibi_sqlx/store/
wallets.rs1use super::SqlxStore;
2use super::entities::wallet_address::{self, WalletChainId};
3use crate::model::{self, ActiveRow, SqlxModel};
4use crate::pool::{Exec, SqlxTransaction};
5use crate::schema::{AuthSchema, SqlxUserModel};
6use crate::sql::Sql;
7use crate::value::SqlxValue;
8use alibi_core::error::{AuthError, AuthResult};
9use alibi_core::store::WalletAddressStore;
10use alibi_core::{AuthUser, CreateWalletAddress, WalletAddress};
11use async_trait::async_trait;
12use chrono::Utc;
13use uuid::Uuid;
14
15#[async_trait]
16impl<S> WalletAddressStore for SqlxStore<S>
17where
18 S: AuthSchema + Send + Sync,
19 S::User: SqlxUserModel,
20{
21 async fn get_wallet_address(
22 &self,
23 address: &str,
24 chain_id: Option<f64>,
25 ) -> AuthResult<Option<WalletAddress>> {
26 let mut sql = model::select_model::<wallet_address::Model>(self.exec());
27 sql.push(" WHERE ");
28 sql.compare(wallet_address::Model::TABLE, "address", " = ", address);
29 if let Some(chain_id) = chain_id {
30 sql.push(" AND ");
31 sql.compare(wallet_address::Model::TABLE, "chainId", " = ", chain_id);
32 }
33 model::limit_one(&mut sql);
34 Ok(self
38 .exec()
39 .fetch_optional::<wallet_address::Model>(sql)
40 .await?
41 .map(Into::into))
42 }
43
44 async fn create_wallet_address(&self, data: CreateWalletAddress) -> AuthResult<WalletAddress> {
45 if !data.chain_id.is_finite() {
46 return Err(AuthError::bad_request("Wallet chain ID must be finite"));
47 }
48 self.in_transaction(true, async move |tx| {
49 let exec = Exec::tx(tx);
50 let owner = super::users::find_user_by_id::<S::User>(
51 exec,
52 &data.user_id,
53 super::users::Lock::Shared,
54 )
55 .await?
56 .ok_or(AuthError::UserNotFound)?;
57 let mut active = ActiveRow::new();
58 active.set(
59 "id",
60 self.generated_id(self.exec(), "walletAddress", "walletAddress", "id")
61 .await?
62 .unwrap_or_else(|| Uuid::new_v4().to_string()),
63 );
64 active.set("userId", owner.id().into_owned());
65 active.set("address", data.address);
66 active.set(
67 "chainId",
68 WalletChainId::from(data.chain_id).into_sql_value(),
69 );
70 active.set("isPrimary", data.is_primary);
71 active.set("createdAt", Utc::now());
72 let created = model::insert::<wallet_address::Model>(exec, &active).await?;
73 Ok(created.into())
74 })
75 .await
76 }
77}
78
79pub(super) async fn remove_owned_wallets(tx: &SqlxTransaction, user_id: &str) -> AuthResult<()> {
80 let exec = Exec::tx(tx);
81 if !super::migrator::has_table(exec, "walletAddress").await? {
82 return Ok(());
83 }
84 let mut sql = Sql::with(exec.engine(), "DELETE FROM ");
85 sql.ident(wallet_address::Model::TABLE);
86 sql.push(" WHERE ");
87 sql.compare(wallet_address::Model::TABLE, "userId", " = ", user_id);
88 _ = exec.execute(sql).await?;
89 Ok(())
90}