Skip to main content

aptos_sdk/types/
resources.rs

1//! Common resource types from the Aptos framework.
2//!
3//! These types represent the most commonly accessed on-chain resources and
4//! deserialize the JSON shape returned by the Aptos REST (fullnode) API. In
5//! particular, the API encodes every `u64` / `u128` value as a JSON string
6//! (e.g. `"42"`); the numeric fields here parse that shape (and also accept a
7//! plain JSON number for convenience) and serialize back to a string.
8//!
9//! Some structs are intentionally *partial* views of the underlying on-chain
10//! resource: they declare only the fields callers commonly need. Because serde
11//! ignores unknown fields by default, they still deserialize cleanly from the
12//! full API object.
13
14use crate::types::AccountAddress;
15use crate::types::events::EventHandle;
16use serde::{Deserialize, Serialize};
17
18/// The account resource stored at every account address (`0x1::account::Account`).
19///
20/// This resource contains basic account information including
21/// the sequence number used for replay protection.
22///
23/// This is a **partial view**: the full on-chain `Account` also carries the
24/// `coin_register_events` / `key_rotation_events` handles and the rotation /
25/// signer capability offers. Those fields are ignored during deserialization
26/// (serde skips unknown fields), so this type still parses the full API object.
27#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
28pub struct AccountResource {
29    /// The sequence number of the next transaction to be submitted.
30    #[serde(with = "crate::types::string_num")]
31    pub sequence_number: u64,
32    /// The authentication key, as the hex string returned by the REST API
33    /// (a `0x`-prefixed encoding of the on-chain `vector<u8>`).
34    pub authentication_key: String,
35    /// The next GUID creation number for this account.
36    #[serde(default, with = "crate::types::string_num")]
37    pub guid_creation_num: u64,
38}
39
40impl AccountResource {
41    /// The type string for this resource.
42    pub const TYPE: &'static str = "0x1::account::Account";
43}
44
45/// A coin store resource that holds a specific coin type.
46///
47/// This is the generic structure; use `CoinStore<AptosCoin>` for APT.
48#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
49pub struct CoinStoreResource {
50    /// The current balance.
51    pub coin: CoinInfo,
52    /// Whether deposits are frozen.
53    pub frozen: bool,
54    /// Event handle for deposit events.
55    pub deposit_events: EventHandle,
56    /// Event handle for withdraw events.
57    pub withdraw_events: EventHandle,
58}
59
60/// Coin information containing the balance.
61#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
62pub struct CoinInfo {
63    /// The coin value/balance.
64    #[serde(with = "crate::types::string_num")]
65    pub value: u64,
66}
67
68impl CoinStoreResource {
69    /// Returns the coin balance.
70    pub fn balance(&self) -> u64 {
71        self.coin.value
72    }
73}
74
75/// The APT coin store type string.
76#[allow(dead_code)]
77pub const APT_COIN_STORE_TYPE: &str = "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>";
78
79/// Fungible asset balance (for the new fungible asset standard).
80#[allow(dead_code)] // Public API for users
81#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
82pub struct FungibleAssetBalance {
83    /// The balance amount.
84    #[serde(with = "crate::types::string_num")]
85    pub balance: u64,
86    /// Whether the balance is frozen.
87    pub frozen: bool,
88}
89
90/// Fungible asset metadata.
91#[allow(dead_code)] // Public API for users
92#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
93pub struct FungibleAssetMetadata {
94    /// The name of the asset.
95    pub name: String,
96    /// The symbol of the asset.
97    pub symbol: String,
98    /// The number of decimals.
99    pub decimals: u8,
100}
101
102/// Collection data for NFTs (v2).
103#[allow(dead_code)] // Public API for users
104#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
105pub struct CollectionData {
106    /// The name of the collection.
107    pub name: String,
108    /// The description of the collection.
109    pub description: String,
110    /// The URI for collection metadata.
111    pub uri: String,
112    /// The current supply.
113    #[serde(with = "crate::types::string_num")]
114    pub current_supply: u64,
115    /// The maximum supply (0 for unlimited).
116    #[serde(with = "crate::types::string_num")]
117    pub maximum_supply: u64,
118}
119
120/// Token data for NFTs (v2).
121#[allow(dead_code)] // Public API for users
122#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
123pub struct TokenData {
124    /// The name of the token.
125    pub name: String,
126    /// The description of the token.
127    pub description: String,
128    /// The URI for token metadata.
129    pub uri: String,
130    /// The collection this token belongs to.
131    pub collection: AccountAddress,
132}
133
134/// Stake pool resource.
135#[allow(dead_code)] // Public API for users
136#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
137pub struct StakePool {
138    /// Active stake amount.
139    #[serde(with = "crate::types::string_num")]
140    pub active: u64,
141    /// Inactive stake amount.
142    #[serde(with = "crate::types::string_num")]
143    pub inactive: u64,
144    /// Pending active stake.
145    #[serde(with = "crate::types::string_num")]
146    pub pending_active: u64,
147    /// Pending inactive stake.
148    #[serde(with = "crate::types::string_num")]
149    pub pending_inactive: u64,
150    /// The operator address.
151    pub operator_address: AccountAddress,
152    /// The delegated voter address.
153    pub delegated_voter: AccountAddress,
154}
155
156/// Staking config resource.
157#[allow(dead_code)] // Public API for users
158#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
159pub struct StakingConfig {
160    /// Minimum stake required.
161    #[serde(with = "crate::types::string_num")]
162    pub minimum_stake: u64,
163    /// Maximum stake allowed.
164    #[serde(with = "crate::types::string_num")]
165    pub maximum_stake: u64,
166    /// Recurring lockup duration in seconds.
167    #[serde(with = "crate::types::string_num")]
168    pub recurring_lockup_duration_secs: u64,
169    /// Whether rewards are enabled.
170    #[serde(with = "crate::types::string_num")]
171    pub rewards_rate: u64,
172    /// The rewards rate denominator.
173    #[serde(with = "crate::types::string_num")]
174    pub rewards_rate_denominator: u64,
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    #[test]
182    fn test_account_resource_type() {
183        assert_eq!(AccountResource::TYPE, "0x1::account::Account");
184    }
185
186    #[test]
187    fn test_coin_store_balance() {
188        use crate::types::events::{EventHandleGuid, EventHandleGuidId};
189        let handle = |creation_num| EventHandle {
190            counter: 0,
191            guid: EventHandleGuid {
192                id: EventHandleGuidId {
193                    addr: AccountAddress::ONE,
194                    creation_num,
195                },
196            },
197        };
198        let coin_store = CoinStoreResource {
199            coin: CoinInfo { value: 1000 },
200            frozen: false,
201            deposit_events: handle(0),
202            withdraw_events: handle(1),
203        };
204        assert_eq!(coin_store.balance(), 1000);
205    }
206
207    #[test]
208    fn test_account_resource_api_json() {
209        // Realistic fullnode `0x1::account::Account` data: all integers are
210        // JSON strings, and there are extra fields this partial view ignores.
211        let json = r#"{
212            "authentication_key": "0x0000000000000000000000000000000000000000000000000000000000000001",
213            "coin_register_events": {
214                "counter": "1",
215                "guid": {"id": {"addr": "0x1", "creation_num": "0"}}
216            },
217            "guid_creation_num": "4",
218            "key_rotation_events": {
219                "counter": "0",
220                "guid": {"id": {"addr": "0x1", "creation_num": "1"}}
221            },
222            "rotation_capability_offer": {"for": {"vec": []}},
223            "sequence_number": "42",
224            "signer_capability_offer": {"for": {"vec": []}}
225        }"#;
226
227        let account: AccountResource = serde_json::from_str(json).unwrap();
228        assert_eq!(account.sequence_number, 42);
229        assert_eq!(account.guid_creation_num, 4);
230        assert_eq!(
231            account.authentication_key,
232            "0x0000000000000000000000000000000000000000000000000000000000000001"
233        );
234    }
235
236    #[test]
237    fn test_coin_store_resource_api_json() {
238        // Realistic fullnode `0x1::coin::CoinStore<...>` data.
239        let json = r#"{
240            "coin": {"value": "999999"},
241            "deposit_events": {
242                "counter": "3",
243                "guid": {"id": {"addr": "0x1", "creation_num": "2"}}
244            },
245            "frozen": false,
246            "withdraw_events": {
247                "counter": "0",
248                "guid": {"id": {"addr": "0x1", "creation_num": "3"}}
249            }
250        }"#;
251
252        let store: CoinStoreResource = serde_json::from_str(json).unwrap();
253        assert_eq!(store.balance(), 999_999);
254        assert!(!store.frozen);
255        assert_eq!(store.deposit_events.counter, 3);
256        assert_eq!(store.deposit_events.guid.id.creation_num, 2);
257        assert_eq!(store.deposit_events.guid.id.addr, AccountAddress::ONE);
258    }
259}