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, "chain_id", " = ", 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("id", Uuid::new_v4().to_string());
59 active.set("user_id", owner.id().into_owned());
60 active.set("address", data.address);
61 active.set(
62 "chain_id",
63 WalletChainId::from(data.chain_id).into_sql_value(),
64 );
65 active.set("is_primary", data.is_primary);
66 active.set("created_at", Utc::now());
67 let created = model::insert::<wallet_address::Model>(exec, &active).await?;
68 Ok(created.into())
69 })
70 .await
71 }
72}
73
74pub(super) async fn remove_owned_wallets(tx: &SqlxTransaction, user_id: &str) -> AuthResult<()> {
75 let exec = Exec::Tx(tx);
76 if !super::migrator::has_table(exec, "wallet_address").await? {
77 return Ok(());
78 }
79 let mut sql = Sql::with(exec.engine(), "DELETE FROM ");
80 sql.ident(wallet_address::Model::TABLE);
81 sql.push(" WHERE ");
82 sql.compare(wallet_address::Model::TABLE, "user_id", " = ", user_id);
83 _ = exec.execute(sql).await?;
84 Ok(())
85}