near_api/storage.rs
1use near_api_types::{AccountId, Data, NearToken, StorageBalance, StorageBalanceInternal};
2use serde_json::json;
3
4use crate::{
5 common::query::{CallResultHandler, PostprocessHandler, RequestBuilder},
6 contract::{Contract, ContractTransactBuilder},
7 errors::BuilderError,
8 transactions::ConstructTransaction,
9};
10
11///A wrapper struct that simplifies interactions with the [Storage Management](https://github.com/near/NEPs/blob/master/neps/nep-0145.md) standard
12///
13/// Contracts on NEAR Protocol often implement a [NEP-145](https://github.com/near/NEPs/blob/master/neps/nep-0145.md) for managing storage deposits,
14/// which are required for storing data on the blockchain. This struct provides convenient methods
15/// to interact with these storage-related functions on the contract.
16///
17/// # Example
18/// ```
19/// use near_api::*;
20///
21/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
22/// let storage = StorageDeposit::on_contract("contract.testnet".parse()?);
23///
24/// // Check storage balance
25/// let balance = storage.view_account_storage("alice.testnet".parse()?)?.fetch_from_testnet().await?;
26/// println!("Storage balance: {:?}", balance);
27///
28/// // Bob pays for Alice's storage on the contract contract.testnet
29/// let deposit_tx = storage.deposit("alice.testnet".parse()?, NearToken::from_near(1))?
30/// .with_signer("bob.testnet".parse()?, Signer::new(Signer::from_ledger())?)
31/// .send_to_testnet()
32/// .await
33/// .unwrap();
34/// # Ok(())
35/// # }
36/// ```
37#[derive(Clone, Debug)]
38pub struct StorageDeposit(AccountId);
39
40impl StorageDeposit {
41 pub const fn on_contract(contract_id: AccountId) -> Self {
42 Self(contract_id)
43 }
44
45 /// Prepares a new contract query (`storage_balance_of`) for fetching the storage balance (Option<[StorageBalance]>) of the account on the contract.
46 ///
47 /// ## Example
48 /// ```rust,no_run
49 /// use near_api::*;
50 ///
51 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
52 /// let balance = StorageDeposit::on_contract("contract.testnet".parse()?)
53 /// .view_account_storage("alice.testnet".parse()?)?
54 /// .fetch_from_testnet()
55 /// .await?;
56 /// println!("Storage balance: {:?}", balance);
57 /// # Ok(())
58 /// # }
59 /// ```
60 #[allow(clippy::type_complexity)]
61 pub fn view_account_storage(
62 &self,
63 account_id: AccountId,
64 ) -> Result<
65 RequestBuilder<
66 PostprocessHandler<
67 Data<Option<StorageBalance>>,
68 CallResultHandler<Option<StorageBalanceInternal>>,
69 >,
70 >,
71 BuilderError,
72 > {
73 Ok(Contract(self.0.clone())
74 .call_function(
75 "storage_balance_of",
76 json!({
77 "account_id": account_id,
78 }),
79 )?
80 .read_only()
81 .map(|storage: Data<Option<StorageBalanceInternal>>| {
82 storage.map(|option_storage| {
83 option_storage.map(|data| StorageBalance {
84 available: data.available,
85 total: data.total,
86 locked: NearToken::from_yoctonear(
87 data.total.as_yoctonear() - data.available.as_yoctonear(),
88 ),
89 })
90 })
91 }))
92 }
93
94 /// Prepares a new transaction contract call (`storage_deposit`) for depositing storage on the contract.
95 ///
96 /// ## Example
97 /// ```rust,no_run
98 /// use near_api::*;
99 ///
100 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
101 /// let tx = StorageDeposit::on_contract("contract.testnet".parse()?)
102 /// .deposit("alice.testnet".parse()?, NearToken::from_near(1))?
103 /// .with_signer("bob.testnet".parse()?, Signer::new(Signer::from_ledger())?)
104 /// .send_to_testnet()
105 /// .await?;
106 /// # Ok(())
107 /// # }
108 /// ```
109 pub fn deposit(
110 &self,
111 receiver_account_id: AccountId,
112 amount: NearToken,
113 ) -> Result<ContractTransactBuilder, BuilderError> {
114 Ok(Contract(self.0.clone())
115 .call_function(
116 "storage_deposit",
117 json!({
118 "account_id": receiver_account_id.to_string(),
119 }),
120 )?
121 .transaction()
122 .deposit(amount))
123 }
124
125 /// Prepares a new transaction contract call (`storage_withdraw`) for withdrawing storage from the contract.
126 ///
127 /// ## Example
128 /// ```rust,no_run
129 /// use near_api::*;
130 ///
131 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
132 /// let tx = StorageDeposit::on_contract("contract.testnet".parse()?)
133 /// .withdraw("alice.testnet".parse()?, NearToken::from_near(1))?
134 /// .with_signer(Signer::new(Signer::from_ledger())?)
135 /// .send_to_testnet()
136 /// .await?;
137 /// # Ok(())
138 /// # }
139 /// ```
140 pub fn withdraw(
141 &self,
142 account_id: AccountId,
143 amount: NearToken,
144 ) -> Result<ConstructTransaction, BuilderError> {
145 Ok(Contract(self.0.clone())
146 .call_function(
147 "storage_withdraw",
148 json!({
149 "amount": amount.as_yoctonear()
150 }),
151 )?
152 .transaction()
153 .deposit(NearToken::from_yoctonear(1))
154 .with_signer_account(account_id))
155 }
156}