1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use crate::dao::generated::token_accounts;
use sea_orm::{DatabaseConnection, EntityTrait, QueryFilter, QuerySelect};
use serde::{Deserialize, Serialize};

use utoipa::ToSchema;

use super::super::error::PhotonApiError;
use super::utils::{parse_decimal, AccountDataTable};
use super::utils::{BalanceModel, CompressedAccountRequest, Context};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
// This is a struct because in the future we might add other fields here like decimals or uiAmount,
// which is a string representation with decimals in the form of "10.00"
pub struct TokenAccountBalance {
    pub amount: u64,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
// We do not use generics to simplify documentation generation.
pub struct GetCompressedTokenAccountBalanceResponse {
    pub context: Context,
    pub value: TokenAccountBalance,
}

pub async fn get_compressed_token_account_balance(
    conn: &DatabaseConnection,
    request: CompressedAccountRequest,
) -> Result<GetCompressedTokenAccountBalanceResponse, PhotonApiError> {
    let context = Context::extract(conn).await?;
    let id = request.parse_id()?;
    let balance = token_accounts::Entity::find()
        .select_only()
        .column(token_accounts::Column::Amount)
        .filter(id.filter(AccountDataTable::TokenAccounts))
        .into_model::<BalanceModel>()
        .one(conn)
        .await?
        .ok_or(id.not_found_error())?;

    Ok(GetCompressedTokenAccountBalanceResponse {
        value: TokenAccountBalance {
            amount: parse_decimal(balance.amount)?,
        },
        context,
    })
}