use super::entities::wallet_address;
use super::{ScopedTransaction, SeaOrmStore, map_db_err};
use crate::schema::{AuthSchema, SeaOrmUserModel};
use alibi_core::error::{AuthError, AuthResult};
use alibi_core::store::WalletAddressStore;
use alibi_core::{AuthUser, CreateWalletAddress, WalletAddress};
use async_trait::async_trait;
use chrono::Utc;
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QuerySelect, Set};
use uuid::Uuid;
#[async_trait]
impl<S> WalletAddressStore for SeaOrmStore<S>
where
S: AuthSchema + Send + Sync,
S::User: SeaOrmUserModel,
{
async fn get_wallet_address(
&self,
address: &str,
chain_id: Option<f64>,
) -> AuthResult<Option<WalletAddress>> {
let mut query =
wallet_address::Entity::find().filter(wallet_address::Column::Address.eq(address));
if let Some(chain_id) = chain_id {
query = query.filter(wallet_address::Column::ChainId.eq(chain_id));
}
Ok(query
.one(self.scoped_connection())
.await
.map_err(map_db_err)?
.map(Into::into))
}
async fn create_wallet_address(&self, data: CreateWalletAddress) -> AuthResult<WalletAddress> {
if !data.chain_id.is_finite() {
return Err(AuthError::bad_request("Wallet chain ID must be finite"));
}
let transaction = self.scoped_connection().begin_immediate().await?;
let owner_id = S::User::parse_id(&data.user_id)?;
let owner = super::users::user_query::<S::User>(
sea_orm::ConnectionTrait::get_database_backend(&transaction),
)
.filter(S::User::id_column().eq(owner_id))
.lock_shared()
.one(&transaction)
.await
.map_err(map_db_err)?
.ok_or(AuthError::UserNotFound)?;
let created = wallet_address::ActiveModel {
id: Set(self
.generated_id(&self.db, "walletAddress", "walletAddress", "id")
.await?
.unwrap_or_else(|| Uuid::new_v4().to_string())),
user_id: Set(owner.id().into_owned()),
address: Set(data.address),
chain_id: Set(data.chain_id.into()),
is_primary: Set(data.is_primary),
created_at: Set(Utc::now()),
}
.insert(&transaction)
.await
.map_err(map_db_err)?;
transaction.commit().await.map_err(map_db_err)?;
Ok(created.into())
}
}
pub(super) async fn remove_owned_wallets(
transaction: &ScopedTransaction,
user_id: &str,
) -> AuthResult<()> {
if !transaction
.has_table("walletAddress")
.await
.map_err(map_db_err)?
{
return Ok(());
}
_ = wallet_address::Entity::delete_many()
.filter(wallet_address::Column::UserId.eq(user_id))
.exec(transaction)
.await
.map_err(map_db_err)?;
Ok(())
}