Skip to main content

circles_rpc/methods/
token.rs

1use crate::client::RpcClient;
2use crate::error::Result;
3use alloy_primitives::U256;
4use circles_types::{Address, TokenBalanceResponse, TokenHolder};
5use std::str::FromStr;
6
7/// Methods for token balance and holder lookups.
8///
9/// `get_token_balances` selects v1/v2 via `use_v2`; holders come back as
10/// demurraged totals and are normalized to `U256`.
11#[derive(Clone, Debug)]
12pub struct TokenMethods {
13    client: RpcClient,
14}
15
16/// Normalized token holder with numeric balance.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct TokenHolderNormalized {
19    /// Account that owns the token balance.
20    pub account: Address,
21    /// The token address.
22    pub token_address: Address,
23    /// Balance as `U256` (demurraged).
24    pub balance: U256,
25}
26
27impl From<TokenHolder> for TokenHolderNormalized {
28    fn from(holder: TokenHolder) -> Self {
29        let balance = U256::from_str(&holder.demurraged_total_balance).unwrap_or_default();
30        Self {
31            account: holder.account,
32            token_address: holder.token_address,
33            balance,
34        }
35    }
36}
37
38impl TokenMethods {
39    /// Create a new accessor for token-related RPCs.
40    pub fn new(client: RpcClient) -> Self {
41        Self { client }
42    }
43
44    /// circles_getTokenBalances (v1/v2, selected via `use_v2`)
45    pub async fn get_token_balances(
46        &self,
47        address: Address,
48        as_time_circles: bool,
49        use_v2: bool,
50    ) -> Result<Vec<TokenBalanceResponse>> {
51        let method = if use_v2 {
52            "circlesV2_getTokenBalances"
53        } else {
54            "circles_getTokenBalances"
55        };
56        self.client.call(method, (address, as_time_circles)).await
57    }
58
59    /// circles_getTokenHolders (currently assumed v2) returning normalized balances by default.
60    pub async fn get_token_holders(&self, token: Address) -> Result<Vec<TokenHolderNormalized>> {
61        let holders: Vec<TokenHolder> = self
62            .client
63            .call("circles_getTokenHolders", (token,))
64            .await?;
65        Ok(holders
66            .into_iter()
67            .map(TokenHolderNormalized::from)
68            .collect())
69    }
70
71    /// Raw token holders (string balances) if needed.
72    pub async fn get_token_holders_raw(&self, token: Address) -> Result<Vec<TokenHolder>> {
73        self.client.call("circles_getTokenHolders", (token,)).await
74    }
75}