near_api/account/
mod.rs

1use near_api_types::{
2    json::U64,
3    transaction::actions::{AccessKey, AddKeyAction, DeleteAccountAction, DeleteKeyAction},
4    AccessKeyPermission, AccountId, Action, PublicKey, Reference,
5};
6
7use crate::advanced::{query_request::QueryRequest, query_rpc::SimpleQueryRpc};
8use crate::common::query::{
9    AccessKeyHandler, AccessKeyListHandler, AccountViewHandler, RequestBuilder, RpcBuilder,
10};
11use crate::transactions::ConstructTransaction;
12
13use self::create::CreateAccountBuilder;
14
15mod create;
16
17/// Account management related interactions with the NEAR Protocol
18///
19/// The [`Account`] struct provides methods to interact with NEAR accounts, including querying account information, managing access keys, and creating new accounts.
20///
21/// # Examples
22///
23/// ```rust,no_run
24/// use near_api::*;
25///
26/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
27/// let account_info = Account("alice.testnet".parse()?).view().fetch_from_testnet().await?;
28/// println!("Account: {:?}", account_info);
29/// # Ok(())
30/// # }
31/// ```
32#[derive(Clone, Debug)]
33pub struct Account(pub AccountId);
34
35impl Account {
36    /// Returns the underlying account ID for this account.
37    ///
38    /// # Example
39    /// ```rust,no_run
40    /// use near_api::*;
41    ///
42    /// # fn example() -> Result<(), Box<dyn std::error::Error>> {
43    /// let account = Account("alice.testnet".parse()?);
44    /// let account_id = account.account_id();
45    /// println!("Account ID: {}", account_id);
46    /// # Ok(())
47    /// # }
48    /// ```
49    pub const fn account_id(&self) -> &AccountId {
50        &self.0
51    }
52
53    /// Converts this account to a Contract for contract-related operations.
54    ///
55    /// # Example
56    /// ```rust,no_run
57    /// use near_api::*;
58    /// use serde_json::json;
59    ///
60    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
61    /// let account = Account("contract.testnet".parse()?);
62    /// let contract = account.as_contract();
63    /// let result: String = contract.call_function("get_value", ())?.read_only().fetch_from_testnet().await?.data;
64    /// println!("Contract value: {:?}", result);
65    /// # Ok(())
66    /// # }
67    /// ```
68    pub fn as_contract(&self) -> crate::contract::Contract {
69        crate::contract::Contract(self.0.clone())
70    }
71
72    /// Creates a Tokens wrapper for token-related operations on this account.
73    ///
74    /// # Example
75    /// ```rust,no_run
76    /// use near_api::*;
77    ///
78    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
79    /// let account = Account("alice.testnet".parse()?);
80    /// let tokens = account.tokens();
81    /// let balance = tokens.near_balance().fetch_from_testnet().await?;
82    /// println!("NEAR balance: {}", balance.total);
83    /// # Ok(())
84    /// # }
85    /// ```
86    pub fn tokens(&self) -> crate::tokens::Tokens {
87        crate::tokens::Tokens::account(self.0.clone())
88    }
89
90    /// Creates a Delegation wrapper for staking-related operations on this account.
91    ///
92    /// # Example
93    /// ```rust,no_run
94    /// use near_api::*;
95    ///
96    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
97    /// let account = Account("alice.testnet".parse()?);
98    /// let delegation = account.delegation();
99    /// let staked = delegation.view_staked_balance("pool.testnet".parse()?)?.fetch_from_testnet().await?;
100    /// println!("Staked balance: {:?}", staked);
101    /// # Ok(())
102    /// # }
103    /// ```
104    pub fn delegation(&self) -> crate::stake::Delegation {
105        crate::stake::Delegation(self.0.clone())
106    }
107
108    /// Prepares a query to fetch the [Data](crate::Data)<[AccountView](near_api_types::AccountView)> with the account information for the given account ID.
109    ///
110    /// ## Example
111    /// ```rust,no_run
112    /// use near_api::*;
113    ///
114    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
115    /// let account_info = Account("alice.testnet".parse()?).view().fetch_from_testnet().await?;
116    /// println!("Account: {:?}", account_info);
117    /// # Ok(())
118    /// # }
119    /// ```
120    pub fn view(&self) -> RequestBuilder<AccountViewHandler> {
121        let request = QueryRequest::ViewAccount {
122            account_id: self.0.clone(),
123        };
124        RequestBuilder::new(
125            SimpleQueryRpc { request },
126            Reference::Optimistic,
127            Default::default(),
128        )
129    }
130
131    /// Prepares a query to fetch the [Data](crate::Data)<[AccessKey]> with the access key information for the given account public key.
132    ///
133    /// ## Example
134    /// ```rust,no_run
135    /// use near_api::*;
136    /// use std::str::FromStr;
137    ///
138    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
139    /// let access_key = Account("alice.testnet".parse()?)
140    ///     .access_key(PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?)
141    ///     .fetch_from_testnet()
142    ///     .await?;
143    /// println!("Access key: {:?}", access_key);
144    /// # Ok(())
145    /// # }
146    /// ```
147    pub fn access_key(
148        &self,
149        signer_public_key: impl Into<PublicKey>,
150    ) -> RequestBuilder<AccessKeyHandler> {
151        let request = QueryRequest::ViewAccessKey {
152            account_id: self.0.clone(),
153            public_key: signer_public_key.into().into(),
154        };
155        RpcBuilder::new(
156            SimpleQueryRpc { request },
157            Reference::Optimistic,
158            Default::default(),
159        )
160    }
161
162    /// Prepares a query to fetch the Vec<([`PublicKey`], [`AccessKey`])> list of access keys for the given account ID.
163    ///
164    /// ## Example
165    /// ```rust,no_run
166    /// use near_api::*;
167    ///
168    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
169    /// let access_keys = Account("alice.testnet".parse()?).list_keys().fetch_from_testnet().await?;
170    /// println!("Access keys: {:?}", access_keys);
171    /// # Ok(())
172    /// # }
173    /// ```
174    pub fn list_keys(&self) -> RequestBuilder<AccessKeyListHandler> {
175        let request = QueryRequest::ViewAccessKeyList {
176            account_id: self.0.clone(),
177        };
178        RpcBuilder::new(
179            SimpleQueryRpc { request },
180            Reference::Optimistic,
181            Default::default(),
182        )
183    }
184
185    /// Adds a new access key to the given account ID.
186    ///
187    /// ## Example
188    /// ```rust,no_run
189    /// use near_api::{*, types::AccessKeyPermission};
190    /// use std::str::FromStr;
191    ///
192    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
193    /// let pk = PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?;
194    /// let result = Account("alice.testnet".parse()?)
195    ///     .add_key(AccessKeyPermission::FullAccess, pk)
196    ///     .with_signer(Signer::new(Signer::from_ledger())?)
197    ///     .send_to_testnet()
198    ///     .await?;
199    /// # Ok(())
200    /// # }
201    /// ```
202    pub fn add_key(
203        &self,
204        permission: AccessKeyPermission,
205        public_key: impl Into<PublicKey>,
206    ) -> ConstructTransaction {
207        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_action(Action::AddKey(
208            Box::new(AddKeyAction {
209                access_key: AccessKey {
210                    nonce: U64::from(0),
211                    permission,
212                },
213                public_key: public_key.into(),
214            }),
215        ))
216    }
217
218    /// Deletes an access key from the given account ID.
219    ///
220    /// ## Example
221    /// ```rust,no_run
222    /// use near_api::*;
223    /// use std::str::FromStr;
224    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
225    /// let result = Account("alice.testnet".parse()?)
226    ///     .delete_key(PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?)
227    ///     .with_signer(Signer::new(Signer::from_ledger())?)
228    ///     .send_to_testnet()
229    ///     .await?;
230    /// # Ok(())
231    /// # }
232    /// ```
233    pub fn delete_key(&self, public_key: impl Into<PublicKey>) -> ConstructTransaction {
234        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_action(Action::DeleteKey(
235            Box::new(DeleteKeyAction {
236                public_key: public_key.into(),
237            }),
238        ))
239    }
240
241    /// Deletes multiple access keys from the given account ID.
242    ///
243    /// ## Example
244    /// ```rust,no_run
245    /// use near_api::*;
246    /// use std::str::FromStr;
247    ///
248    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
249    /// let result = Account("alice.testnet".parse()?)
250    ///     .delete_keys(vec![PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?])
251    ///     .with_signer(Signer::new(Signer::from_ledger())?)
252    ///     .send_to_testnet()
253    ///     .await?;
254    /// # Ok(())
255    /// # }
256    /// ```
257    pub fn delete_keys(&self, public_keys: Vec<PublicKey>) -> ConstructTransaction {
258        let actions = public_keys
259            .into_iter()
260            .map(|public_key| Action::DeleteKey(Box::new(DeleteKeyAction { public_key })))
261            .collect();
262
263        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_actions(actions)
264    }
265
266    /// Deletes the account with the given beneficiary ID. The account balance will be transferred to the beneficiary.
267    ///
268    /// Please note that this action is irreversible. Also, you have to understand that another person could potentially
269    /// re-create the account with the same name and pretend to be you on other websites that use your account ID as a unique identifier.
270    /// (near.social, devhub proposal, etc)
271    ///
272    /// Do not use it unless you understand the consequences.
273    ///
274    /// ## Example
275    /// ```rust,no_run
276    /// use near_api::*;
277    ///
278    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
279    /// let result = Account("alice.testnet".parse()?)
280    ///     .delete_account_with_beneficiary("bob.testnet".parse()?)
281    ///     .with_signer(Signer::new(Signer::from_ledger())?)
282    ///     .send_to_testnet()
283    ///     .await?;
284    /// # Ok(())
285    /// # }
286    /// ```
287    pub fn delete_account_with_beneficiary(
288        &self,
289        beneficiary_id: AccountId,
290    ) -> ConstructTransaction {
291        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_action(Action::DeleteAccount(
292            DeleteAccountAction { beneficiary_id },
293        ))
294    }
295
296    /// Creates a new account builder for the given account ID.
297    ///
298    /// ## Creating account sponsored by faucet service
299    ///
300    /// This is a way to create an account without having to fund it. It works only on testnet.
301    /// The account should be created as a sub-account of the [testnet](https://testnet.nearblocks.io/address/testnet) account
302    ///
303    /// ```rust,no_run
304    /// use near_api::*;
305    ///
306    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
307    /// let secret = near_api::signer::generate_secret_key()?;
308    /// let result: reqwest::Response = Account::create_account("alice.testnet".parse()?)
309    ///     .sponsor_by_faucet_service()
310    ///     .public_key(secret.public_key())?
311    ///     .send_to_testnet_faucet()
312    ///     .await?;
313    /// // You have to save the secret key somewhere safe
314    /// std::fs::write("secret.key", secret.to_string())?;
315    /// # Ok(())
316    /// # }
317    /// ```
318    ///
319    /// ## Creating sub-account of the linkdrop root account funded by your own NEAR and signed by your account
320    ///
321    /// There is a few linkdrop root accounts that you can use to create sub-accounts.
322    /// * For mainnet, you can use the [near](https://explorer.near.org/accounts/near) account.
323    /// * For testnet, you can use the [testnet](https://testnet.nearblocks.io/address/testnet) account.
324    ///
325    /// ```rust,no_run
326    /// use near_api::*;
327    ///
328    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
329    /// let secret = near_api::signer::generate_secret_key()?;
330    /// let bob_signer = Signer::new(Signer::from_seed_phrase("lucky barrel fall come bottom can rib join rough around subway cloth ", None)?)?;
331    /// let result = Account::create_account("alice.testnet".parse()?)
332    ///     .fund_myself("bob.testnet".parse()?, NearToken::from_near(1))
333    ///     .public_key(secret.public_key())?
334    ///     .with_signer(bob_signer)
335    ///     .send_to_testnet()
336    ///     .await?;
337    /// # Ok(())
338    /// # }
339    /// ```
340    ///
341    /// ## Creating sub-account of your own account funded by your NEAR
342    ///
343    /// You can create only one level deep of sub-accounts.
344    ///
345    /// E.g you are `alice.testnet`, you can't create `sub.sub.alice.testnet`, but you can create `sub.alice.testnet`.
346    /// Though, 'sub.alice.testnet' can create sub-accounts of its own.
347    /// ```rust,no_run
348    /// use near_api::*;
349    ///
350    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
351    /// let secret = near_api::signer::generate_secret_key()?;
352    /// let bob_signer = Signer::new(Signer::from_seed_phrase("lucky barrel fall come bottom can rib join rough around subway cloth ", None)?)?;
353    /// let result = Account::create_account("sub.bob.testnet".parse()?)
354    ///     .fund_myself("bob.testnet".parse()?, NearToken::from_near(1))
355    ///     .public_key(secret.public_key())?
356    ///     .with_signer(bob_signer)
357    ///     .send_to_testnet()
358    ///     .await?;
359    /// # Ok(())
360    /// # }
361    /// ```
362    pub const fn create_account(account_id: AccountId) -> CreateAccountBuilder {
363        CreateAccountBuilder { account_id }
364    }
365}