Skip to content

Commit 34b5d78

Browse files
author
Adrian Nagy
committed
fix(graphql): Use correct and complete account balances
1 parent 81b2fd7 commit 34b5d78

File tree

2 files changed

+54
-18
lines changed

2 files changed

+54
-18
lines changed

node/native/src/graphql/account.rs

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use std::{collections::HashMap, sync::Arc};
22

33
use dataloader::non_cached::Loader;
44
use juniper::{graphql_object, FieldResult, GraphQLInputObject, GraphQLObject};
5-
use ledger::{Account, AccountId, FpExt};
5+
use ledger::{
6+
scan_state::currency::{Balance, Magnitude, Slot},
7+
Account, AccountId, FpExt, Timing,
8+
};
69
use mina_p2p_messages::{
710
string::{TokenSymbol, ZkAppUri},
811
v2::{
@@ -49,11 +52,12 @@ pub(crate) fn create_account_loader(rpc_sender: RpcSender) -> AccountLoader {
4952

5053
#[derive(Debug, Clone)]
5154
pub(crate) struct GraphQLAccount {
55+
inner: Account,
5256
public_key: String,
5357
token_id: String,
5458
token: String,
5559
token_symbol: String,
56-
balance: GraphQLBalance,
60+
// balance: GraphQLBalance,
5761
nonce: String,
5862
receipt_chain_hash: String,
5963
// Storing the key for later
@@ -70,6 +74,27 @@ pub(crate) struct GraphQLAccount {
7074
zkapp_uri: Option<String>,
7175
}
7276

77+
impl GraphQLAccount {
78+
fn min_balance(&self, global_slot: Option<u32>) -> Option<Balance> {
79+
global_slot.map(|slot| match self.inner.timing {
80+
Timing::Untimed => Balance::zero(),
81+
Timing::Timed { .. } => self.inner.min_balance_at_slot(Slot::from_u32(slot)),
82+
})
83+
}
84+
85+
fn liquid_balance(&self, global_slot: Option<u32>) -> Option<Balance> {
86+
let min_balance = self.min_balance(global_slot);
87+
let total = self.inner.balance;
88+
min_balance.map(|mb| {
89+
if total > mb {
90+
total.checked_sub(&mb).expect("overflow")
91+
} else {
92+
Balance::zero()
93+
}
94+
})
95+
}
96+
}
97+
7398
#[graphql_object(context = Context)]
7499
#[graphql(description = "A Mina account")]
75100
impl GraphQLAccount {
@@ -89,8 +114,26 @@ impl GraphQLAccount {
89114
&self.token_symbol
90115
}
91116

92-
fn balance(&self) -> &GraphQLBalance {
93-
&self.balance
117+
async fn balance(&self, context: &Context) -> GraphQLBalance {
118+
let best_tip = context.get_or_fetch_best_tip().await;
119+
let global_slot = best_tip.as_ref().map(|bt| bt.global_slot());
120+
121+
GraphQLBalance {
122+
total: self.inner.balance.as_u64().to_string(),
123+
block_height: best_tip
124+
.as_ref()
125+
.map(|bt| bt.height())
126+
.unwrap_or_default()
127+
.to_string(),
128+
state_hash: best_tip.as_ref().map(|bt| bt.hash().to_string()),
129+
liquid: self
130+
.liquid_balance(global_slot)
131+
.map(|b| b.as_u64().to_string()),
132+
locked: self
133+
.min_balance(global_slot)
134+
.map(|b| b.as_u64().to_string()),
135+
unknown: self.inner.balance.as_u64().to_string(),
136+
}
94137
}
95138

96139
fn nonce(&self) -> &str {
@@ -232,6 +275,11 @@ pub struct GraphQLSetVerificationKey {
232275
#[derive(GraphQLObject, Debug, Clone)]
233276
pub struct GraphQLBalance {
234277
pub total: String,
278+
pub block_height: String,
279+
pub state_hash: Option<String>,
280+
pub liquid: Option<String>,
281+
pub locked: Option<String>,
282+
pub unknown: String,
235283
}
236284

237285
// #[derive(GraphQLObject, Debug)]
@@ -310,15 +358,6 @@ impl From<ledger::Timing> for GraphQLTiming {
310358
}
311359
}
312360

313-
// TODO(adonagy)
314-
impl From<ledger::scan_state::currency::Balance> for GraphQLBalance {
315-
fn from(value: ledger::scan_state::currency::Balance) -> Self {
316-
Self {
317-
total: value.as_u64().to_string(),
318-
}
319-
}
320-
}
321-
322361
impl TryFrom<ledger::Account> for GraphQLAccount {
323362
type Error = ConversionError;
324363

@@ -340,11 +379,12 @@ impl TryFrom<ledger::Account> for GraphQLAccount {
340379
.transpose()?; // Transpose Option<Result<...>> to Result<Option<...>>
341380

342381
Ok(Self {
382+
inner: value.clone(),
343383
public_key: value.public_key.into_address(),
344384
token_id: TokenIdKeyHash::from(value.token_id.clone()).to_string(),
345385
token: TokenIdKeyHash::from(value.token_id).to_string(),
346386
token_symbol: TokenSymbol::from(&value.token_symbol).to_string(),
347-
balance: GraphQLBalance::from(value.balance),
387+
// balance: GraphQLBalance::from(value.balance),
348388
nonce: value.nonce.as_u32().to_string(),
349389
receipt_chain_hash: ReceiptChainHash::from(value.receipt_chain_hash).to_string(),
350390
delegate_key: value.delegate,

node/native/src/graphql/block.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ impl GraphQLBlock {
4141
}
4242

4343
async fn creator_account(&self, context: &Context) -> FieldResult<Box<GraphQLAccount>> {
44-
// TODO(adonagy): cleanup
4544
let account_id = AccountId::new_with_default_token(self.creator_account_key.clone());
46-
// Use the loader to fetch the delegate account
4745
let account_result = context
4846
.account_loader
4947
.try_load(account_id)
@@ -66,9 +64,7 @@ impl GraphQLBlock {
6664
}
6765

6866
async fn winner_account(&self, context: &Context) -> FieldResult<Box<GraphQLAccount>> {
69-
// TODO(adonagy): cleanup
7067
let account_id = AccountId::new_with_default_token(self.winner_account_key.clone());
71-
// Use the loader to fetch the delegate account
7268
let account_result = context
7369
.account_loader
7470
.try_load(account_id)

0 commit comments

Comments
 (0)