diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index 2ddab6dfb4..42c91bec31 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -6067,6 +6067,7 @@ pub mod args { owner: chain_ctx.get_cached(&self.owner), token: chain_ctx.get(&self.token), no_conversions: self.no_conversions, + height: self.height, }) } } @@ -6077,11 +6078,13 @@ pub mod args { let owner = BALANCE_OWNER.parse(matches); let token = TOKEN.parse(matches); let no_conversions = NO_CONVERSIONS.parse(matches); + let height = BLOCK_HEIGHT_OPT.parse(matches); Self { query, owner, token, no_conversions, + height, } } @@ -6100,6 +6103,10 @@ pub mod args { .arg(NO_CONVERSIONS.def().help(wrap!( "Whether not to automatically perform conversions." ))) + .arg(BLOCK_HEIGHT_OPT.def().help(wrap!( + "The block height at which to query the balance. \ + (Optional)" + ))) } } @@ -6957,6 +6964,7 @@ pub mod args { type AddrOrNativeToken = WalletAddrOrNativeToken; type Address = WalletAddress; type BalanceOwner = WalletBalanceOwner; + type BlockHeight = BlockHeight; type BpConversionTable = PathBuf; type ConfigRpcTendermintAddress = ConfigRpcAddress; type Data = PathBuf; diff --git a/crates/apps_lib/src/client/rpc.rs b/crates/apps_lib/src/client/rpc.rs index d078b0367a..8a4f9a1b35 100644 --- a/crates/apps_lib/src/client/rpc.rs +++ b/crates/apps_lib/src/client/rpc.rs @@ -207,6 +207,8 @@ async fn query_transparent_balance( owner, // The token to query token, + // Optional block height + height, .. } = args; @@ -215,9 +217,13 @@ async fn query_transparent_balance( .expect("Balance owner should have been a transparent address"); let token_alias = lookup_token_alias(context, &token, &owner).await; - let token_balance_result = - namada_sdk::rpc::get_token_balance(context.client(), &token, &owner) - .await; + let token_balance_result = namada_sdk::rpc::get_token_balance( + context.client(), + &token, + &owner, + height, + ) + .await; match token_balance_result { Ok(balance) => { diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index 083076a28f..54c493ab93 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -936,6 +936,7 @@ where namada.client(), &namada.native_token(), &proposal.proposal.author, + None, ) .await .unwrap(); @@ -965,6 +966,7 @@ where namada.client(), &namada.native_token(), &proposal.proposal.author, + None, ) .await .unwrap(); diff --git a/crates/light_sdk/src/reading/asynchronous/account.rs b/crates/light_sdk/src/reading/asynchronous/account.rs index 24b1c34e13..eda5fd7464 100644 --- a/crates/light_sdk/src/reading/asynchronous/account.rs +++ b/crates/light_sdk/src/reading/asynchronous/account.rs @@ -1,5 +1,6 @@ use namada_sdk::account::Account; use namada_sdk::key::common; +use namada_sdk::storage::BlockHeight; use super::*; @@ -8,13 +9,14 @@ pub async fn get_token_balance( tendermint_addr: &str, token: &Address, owner: &Address, + height: Option, // Specify block height or None for latest ) -> Result { let client = HttpClient::new( TendermintAddress::from_str(tendermint_addr) .map_err(|e| Error::Other(e.to_string()))?, ) .map_err(|e| Error::Other(e.to_string()))?; - rpc::get_token_balance(&client, token, owner).await + rpc::get_token_balance(&client, token, owner, height).await } /// Check if the address exists on chain. Established address exists if it diff --git a/crates/sdk/src/args.rs b/crates/sdk/src/args.rs index 8bdf73202c..74683f973e 100644 --- a/crates/sdk/src/args.rs +++ b/crates/sdk/src/args.rs @@ -79,6 +79,8 @@ pub trait NamadaTypes: Clone + std::fmt::Debug { type Data: Clone + std::fmt::Debug; /// Bridge pool recommendations conversion rates table. type BpConversionTable: Clone + std::fmt::Debug; + /// Represents a block height + type BlockHeight: Clone + std::fmt::Debug; } /// The concrete types being used in Namada SDK @@ -100,6 +102,7 @@ impl NamadaTypes for SdkTypes { type AddrOrNativeToken = Address; type Address = Address; type BalanceOwner = namada_core::masp::BalanceOwner; + type BlockHeight = namada_core::storage::BlockHeight; type BpConversionTable = HashMap; type ConfigRpcTendermintAddress = tendermint_rpc::Url; type Data = Vec; @@ -652,6 +655,7 @@ impl InitProposal { context.client(), &nam_address, &proposal.proposal.author, + None, ) .await?; let proposal = proposal @@ -680,6 +684,7 @@ impl InitProposal { context.client(), &nam_address, &proposal.proposal.author, + None, ) .await?; let proposal = proposal @@ -1538,6 +1543,8 @@ pub struct QueryBalance { pub token: C::Address, /// Whether not to convert balances pub no_conversions: bool, + /// Optional height to query balances at + pub height: Option, } /// Query historical transfer(s) diff --git a/crates/sdk/src/queries/vp/token.rs b/crates/sdk/src/queries/vp/token.rs index 89d8a15e55..5b7fb8e502 100644 --- a/crates/sdk/src/queries/vp/token.rs +++ b/crates/sdk/src/queries/vp/token.rs @@ -48,6 +48,7 @@ where pub mod client_only_methods { use borsh::BorshDeserialize; use namada_core::address::Address; + use namada_core::storage::BlockHeight; use namada_core::token; use namada_token::storage_key::{balance_key, masp_total_rewards}; @@ -55,12 +56,14 @@ pub mod client_only_methods { use crate::queries::{Client, RPC}; impl Token { - /// Get the balance of the given `token` belonging to the given `owner`. + /// Get the balance of the given `token` belonging to the given `owner`, + /// optionally at the given `height`. pub async fn balance( &self, client: &CLIENT, token: &Address, owner: &Address, + height: Option, ) -> Result::Error> where CLIENT: Client + Sync, @@ -68,7 +71,7 @@ pub mod client_only_methods { let balance_key = balance_key(token, owner); let response = RPC .shell() - .storage_value(client, None, None, false, &balance_key) + .storage_value(client, None, height, false, &balance_key) .await?; let balance = if response.data.is_empty() { diff --git a/crates/sdk/src/rpc.rs b/crates/sdk/src/rpc.rs index 4856ef12a2..dd0547b688 100644 --- a/crates/sdk/src/rpc.rs +++ b/crates/sdk/src/rpc.rs @@ -211,9 +211,10 @@ pub async fn get_token_balance( client: &C, token: &Address, owner: &Address, + height: Option, ) -> Result { convert_response::( - RPC.vp().token().balance(client, token, owner).await, + RPC.vp().token().balance(client, token, owner, height).await, ) }