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    /// Prepares a query to fetch the [Data](crate::Data)<[AccountView](near_api_types::AccountView)> with the account information for the given account ID.
37    ///
38    /// ## Example
39    /// ```rust,no_run
40    /// use near_api::*;
41    ///
42    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
43    /// let account_info = Account("alice.testnet".parse()?).view().fetch_from_testnet().await?;
44    /// println!("Account: {:?}", account_info);
45    /// # Ok(())
46    /// # }
47    /// ```
48    pub fn view(&self) -> RequestBuilder<AccountViewHandler> {
49        let request = QueryRequest::ViewAccount {
50            account_id: self.0.clone(),
51        };
52        RequestBuilder::new(
53            SimpleQueryRpc { request },
54            Reference::Optimistic,
55            Default::default(),
56        )
57    }
58
59    /// Prepares a query to fetch the [Data](crate::Data)<[AccessKey]> with the access key information for the given account public key.
60    ///
61    /// ## Example
62    /// ```rust,no_run
63    /// use near_api::*;
64    /// use std::str::FromStr;
65    ///
66    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
67    /// let access_key = Account("alice.testnet".parse()?)
68    ///     .access_key(PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?)
69    ///     .fetch_from_testnet()
70    ///     .await?;
71    /// println!("Access key: {:?}", access_key);
72    /// # Ok(())
73    /// # }
74    /// ```
75    pub fn access_key(
76        &self,
77        signer_public_key: impl Into<PublicKey>,
78    ) -> RequestBuilder<AccessKeyHandler> {
79        let request = QueryRequest::ViewAccessKey {
80            account_id: self.0.clone(),
81            public_key: signer_public_key.into().into(),
82        };
83        RpcBuilder::new(
84            SimpleQueryRpc { request },
85            Reference::Optimistic,
86            Default::default(),
87        )
88    }
89
90    /// Prepares a query to fetch the Vec<([`PublicKey`], [`AccessKey`])> list of access keys for the given account ID.
91    ///
92    /// ## Example
93    /// ```rust,no_run
94    /// use near_api::*;
95    ///
96    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
97    /// let access_keys = Account("alice.testnet".parse()?).list_keys().fetch_from_testnet().await?;
98    /// println!("Access keys: {:?}", access_keys);
99    /// # Ok(())
100    /// # }
101    /// ```
102    pub fn list_keys(&self) -> RequestBuilder<AccessKeyListHandler> {
103        let request = QueryRequest::ViewAccessKeyList {
104            account_id: self.0.clone(),
105        };
106        RpcBuilder::new(
107            SimpleQueryRpc { request },
108            Reference::Optimistic,
109            Default::default(),
110        )
111    }
112
113    /// Adds a new access key to the given account ID.
114    ///
115    /// ## Example
116    /// ```rust,no_run
117    /// use near_api::{*, types::AccessKeyPermission};
118    /// use std::str::FromStr;
119    ///
120    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
121    /// let pk = PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?;
122    /// let result = Account("alice.testnet".parse()?)
123    ///     .add_key(AccessKeyPermission::FullAccess, pk)
124    ///     .with_signer(Signer::new(Signer::from_ledger())?)
125    ///     .send_to_testnet()
126    ///     .await?;
127    /// # Ok(())
128    /// # }
129    /// ```
130    pub fn add_key(
131        &self,
132        permission: AccessKeyPermission,
133        public_key: impl Into<PublicKey>,
134    ) -> ConstructTransaction {
135        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_action(Action::AddKey(
136            Box::new(AddKeyAction {
137                access_key: AccessKey {
138                    nonce: U64::from(0),
139                    permission,
140                },
141                public_key: public_key.into(),
142            }),
143        ))
144    }
145
146    /// Deletes an access key from the given account ID.
147    ///
148    /// ## Example
149    /// ```rust,no_run
150    /// use near_api::*;
151    /// use std::str::FromStr;
152    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
153    /// let result = Account("alice.testnet".parse()?)
154    ///     .delete_key(PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?)
155    ///     .with_signer(Signer::new(Signer::from_ledger())?)
156    ///     .send_to_testnet()
157    ///     .await?;
158    /// # Ok(())
159    /// # }
160    /// ```
161    pub fn delete_key(&self, public_key: impl Into<PublicKey>) -> ConstructTransaction {
162        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_action(Action::DeleteKey(
163            Box::new(DeleteKeyAction {
164                public_key: public_key.into(),
165            }),
166        ))
167    }
168
169    /// Deletes multiple access keys from the given account ID.
170    ///
171    /// ## Example
172    /// ```rust,no_run
173    /// use near_api::*;
174    /// use std::str::FromStr;
175    ///
176    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
177    /// let result = Account("alice.testnet".parse()?)
178    ///     .delete_keys(vec![PublicKey::from_str("ed25519:H4sIAAAAAAAAA+2X0Q6CMBAAtVlJQgYAAAA=")?])
179    ///     .with_signer(Signer::new(Signer::from_ledger())?)
180    ///     .send_to_testnet()
181    ///     .await?;
182    /// # Ok(())
183    /// # }
184    /// ```
185    pub fn delete_keys(&self, public_keys: Vec<PublicKey>) -> ConstructTransaction {
186        let actions = public_keys
187            .into_iter()
188            .map(|public_key| Action::DeleteKey(Box::new(DeleteKeyAction { public_key })))
189            .collect();
190
191        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_actions(actions)
192    }
193
194    /// Deletes the account with the given beneficiary ID. The account balance will be transferred to the beneficiary.
195    ///
196    /// Please note that this action is irreversible. Also, you have to understand that another person could potentially
197    /// 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.
198    /// (near.social, devhub proposal, etc)
199    ///
200    /// Do not use it unless you understand the consequences.
201    ///
202    /// ## Example
203    /// ```rust,no_run
204    /// use near_api::*;
205    ///
206    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
207    /// let result = Account("alice.testnet".parse()?)
208    ///     .delete_account_with_beneficiary("bob.testnet".parse()?)
209    ///     .with_signer(Signer::new(Signer::from_ledger())?)
210    ///     .send_to_testnet()
211    ///     .await?;
212    /// # Ok(())
213    /// # }
214    /// ```
215    pub fn delete_account_with_beneficiary(
216        &self,
217        beneficiary_id: AccountId,
218    ) -> ConstructTransaction {
219        ConstructTransaction::new(self.0.clone(), self.0.clone()).add_action(Action::DeleteAccount(
220            DeleteAccountAction { beneficiary_id },
221        ))
222    }
223
224    /// Creates a new account builder for the given account ID.
225    ///
226    /// ## Creating account sponsored by faucet service
227    ///
228    /// This is a way to create an account without having to fund it. It works only on testnet.
229    /// The account should be created as a sub-account of the [testnet](https://testnet.nearblocks.io/address/testnet) account
230    ///
231    /// ```rust,no_run
232    /// use near_api::*;
233    ///
234    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
235    /// let secret = near_api::signer::generate_secret_key()?;
236    /// let result: reqwest::Response = Account::create_account("alice.testnet".parse()?)
237    ///     .sponsor_by_faucet_service()
238    ///     .public_key(secret.public_key())?
239    ///     .send_to_testnet_faucet()
240    ///     .await?;
241    /// // You have to save the secret key somewhere safe
242    /// std::fs::write("secret.key", secret.to_string())?;
243    /// # Ok(())
244    /// # }
245    /// ```
246    ///
247    /// ## Creating sub-account of the linkdrop root account funded by your own NEAR and signed by your account
248    ///
249    /// There is a few linkdrop root accounts that you can use to create sub-accounts.
250    /// * For mainnet, you can use the [near](https://explorer.near.org/accounts/near) account.
251    /// * For testnet, you can use the [testnet](https://testnet.nearblocks.io/address/testnet) account.
252    ///
253    /// ```rust,no_run
254    /// use near_api::*;
255    ///
256    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
257    /// let secret = near_api::signer::generate_secret_key()?;
258    /// let bob_signer = Signer::new(Signer::from_seed_phrase("lucky barrel fall come bottom can rib join rough around subway cloth ", None)?)?;
259    /// let result = Account::create_account("alice.testnet".parse()?)
260    ///     .fund_myself("bob.testnet".parse()?, NearToken::from_near(1))
261    ///     .public_key(secret.public_key())?
262    ///     .with_signer(bob_signer)
263    ///     .send_to_testnet()
264    ///     .await?;
265    /// # Ok(())
266    /// # }
267    /// ```
268    ///
269    /// ## Creating sub-account of your own account funded by your NEAR
270    ///
271    /// You can create only one level deep of sub-accounts.
272    ///
273    /// E.g you are `alice.testnet`, you can't create `sub.sub.alice.testnet`, but you can create `sub.alice.testnet`.
274    /// Though, 'sub.alice.testnet' can create sub-accounts of its own.
275    /// ```rust,no_run
276    /// use near_api::*;
277    ///
278    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
279    /// let secret = near_api::signer::generate_secret_key()?;
280    /// let bob_signer = Signer::new(Signer::from_seed_phrase("lucky barrel fall come bottom can rib join rough around subway cloth ", None)?)?;
281    /// let result = Account::create_account("sub.bob.testnet".parse()?)
282    ///     .fund_myself("bob.testnet".parse()?, NearToken::from_near(1))
283    ///     .public_key(secret.public_key())?
284    ///     .with_signer(bob_signer)
285    ///     .send_to_testnet()
286    ///     .await?;
287    /// # Ok(())
288    /// # }
289    /// ```
290    pub const fn create_account(account_id: AccountId) -> CreateAccountBuilder {
291        CreateAccountBuilder { account_id }
292    }
293}