fuel_core/schema/
balance.rs1use crate::{
2 database::database_description::IndexationKind,
3 fuel_core_graphql_api::{
4 api_service::ChainInfoProvider,
5 query_costs,
6 },
7 schema::{
8 ReadViewProvider,
9 scalars::{
10 Address,
11 AssetId,
12 U128,
13 },
14 },
15};
16use anyhow::anyhow;
17use async_graphql::{
18 Context,
19 InputObject,
20 Object,
21 connection::{
22 Connection,
23 EmptyFields,
24 },
25};
26use fuel_core_types::services::graphql_api;
27use futures::StreamExt;
28
29use super::scalars::U64;
30
31pub struct Balance(graphql_api::AddressBalance);
32
33#[Object]
34impl Balance {
35 async fn owner(&self) -> Address {
36 self.0.owner.into()
37 }
38
39 async fn amount(&self) -> U64 {
40 let amount: u64 = self.0.amount.try_into().unwrap_or(u64::MAX);
41 amount.into()
42 }
43
44 async fn amount_u128(&self) -> U128 {
45 self.0.amount.into()
46 }
47
48 async fn asset_id(&self) -> AssetId {
49 self.0.asset_id.into()
50 }
51}
52
53#[derive(InputObject)]
54struct BalanceFilterInput {
55 owner: Address,
57}
58
59#[derive(Default)]
60pub struct BalanceQuery;
61
62#[Object]
63impl BalanceQuery {
64 #[graphql(complexity = "query_costs().balance_query")]
65 async fn balance(
66 &self,
67 ctx: &Context<'_>,
68 #[graphql(desc = "address of the owner")] owner: Address,
69 #[graphql(desc = "asset_id of the coin")] asset_id: AssetId,
70 ) -> async_graphql::Result<Balance> {
71 let query = ctx.read_view()?;
72 let base_asset_id = *ctx
73 .data_unchecked::<ChainInfoProvider>()
74 .current_consensus_params()
75 .base_asset_id();
76 let balance = query
77 .balance(owner.0, asset_id.0, base_asset_id)
78 .await?
79 .into();
80 Ok(balance)
81 }
82
83 #[graphql(complexity = "if query_costs().balance_query == 0 { \
103 (child_complexity as f32 * first.unwrap_or_default() as f32 * 0.66) as usize + \
104 (child_complexity as f32 * last.unwrap_or_default() as f32 * 0.66) as usize
105 } else { query_costs().balance_query }")]
106 async fn balances(
107 &self,
108 ctx: &Context<'_>,
109 filter: BalanceFilterInput,
110 first: Option<i32>,
111 after: Option<String>,
112 last: Option<i32>,
113 before: Option<String>,
114 ) -> async_graphql::Result<Connection<AssetId, Balance, EmptyFields, EmptyFields>>
115 {
116 let query = ctx.read_view()?;
117 if !query.indexation_flags.contains(&IndexationKind::Balances)
118 && (before.is_some() || after.is_some())
119 {
120 return Err(anyhow!(
121 "Can not use pagination when balances indexation is not available"
122 )
123 .into())
124 }
125 let base_asset_id = *ctx
126 .data_unchecked::<ChainInfoProvider>()
127 .current_consensus_params()
128 .base_asset_id();
129 let owner = filter.owner.into();
130 crate::schema::query_pagination(after, before, first, last, |start, direction| {
131 Ok(query
132 .balances(&owner, (*start).map(Into::into), direction, &base_asset_id)
133 .map(|result| {
134 result.map(|balance| (balance.asset_id.into(), balance.into()))
135 }))
136 })
137 .await
138 }
139}
140
141impl From<graphql_api::AddressBalance> for Balance {
142 fn from(balance: graphql_api::AddressBalance) -> Self {
143 Balance(balance)
144 }
145}