Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* Incremented the limits for various RPC calls to accommodate larger data sets ([#1621](https://github.com/0xMiden/miden-client/pull/1621)).
* [BREAKING] Introduced named storage slots, changed `FilesystemKeystore` to not be generic over RNG ([#1626](https://github.com/0xMiden/miden-client/pull/1626)).
* Added `submit_new_transaction_with_prover` to the Rust client and `submitNewTransactionWithProver` to the WebClient([#1622](https://github.com/0xMiden/miden-client/pull/1622)).
* Added `getAccountDetails` to WebClient's `RpcClient` ([#1628](https://github.com/0xMiden/miden-client/pull/1628))

## 0.12.5 (2025-12-01)

Expand Down
1 change: 1 addition & 0 deletions crates/web-client/js/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export {
FeltArray,
FetchedNote,
FlattenedU8Vec,
FetchedAccount,
ForeignAccount,
ForeignAccountArray,
FungibleAsset,
Expand Down
62 changes: 62 additions & 0 deletions crates/web-client/src/models/fetched_account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use miden_client::rpc::domain::account::FetchedAccount as NativeFetchedAccount;
use wasm_bindgen::prelude::wasm_bindgen;

use crate::models::account::Account;
use crate::models::account_id::AccountId;
use crate::models::word::Word;

/// Describes the response from the `GetAccountDetails` endpoint.
///
/// The content varies based on account visibility:
/// - **Public or Network accounts**: Contains the complete [`Account`] details, as these are stored
/// on-chain
/// - **Private accounts**: Contains only the state commitment, since full account data is stored
/// off-chain
#[wasm_bindgen]
pub struct FetchedAccount(NativeFetchedAccount);

#[wasm_bindgen]
impl FetchedAccount {
/// Returns true if the fetched account is private
#[wasm_bindgen(js_name = "isPrivate")]
pub fn is_private(&self) -> bool {
matches!(&self.0, NativeFetchedAccount::Private(_, _))
}

/// Returns true if the fetched account is public
#[wasm_bindgen(js_name = "isPublic")]
pub fn is_public(&self) -> bool {
matches!(&self.0, NativeFetchedAccount::Public(_, _))
}

/// Returns the associated [`Account`] if the account is public, otherwise none
pub fn account(&self) -> Option<Account> {
self.0.account().map(Into::into)
}

/// Returns the account identifier
#[wasm_bindgen(js_name = "accountId")]
pub fn account_id(&self) -> AccountId {
self.0.account_id().into()
}

/// Returns the account update summary commitment
pub fn commitment(&self) -> Word {
self.0.commitment().into()
}
}

// CONVERSIONS
// ================================================================================================

impl From<NativeFetchedAccount> for FetchedAccount {
fn from(native_account: NativeFetchedAccount) -> Self {
FetchedAccount(native_account)
}
}

impl From<FetchedAccount> for NativeFetchedAccount {
fn from(fetched_account: FetchedAccount) -> Self {
fetched_account.0
}
}
1 change: 1 addition & 0 deletions crates/web-client/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub mod consumable_note_record;
pub mod endpoint;
pub mod executed_transaction;
pub mod felt;
pub mod fetched_account;
pub mod foreign_account;
pub mod fungible_asset;
pub mod input_note;
Expand Down
22 changes: 22 additions & 0 deletions crates/web-client/src/rpc_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use note::FetchedNote;
use wasm_bindgen::prelude::*;

use crate::js_error_with_context;
use crate::models::account_id::AccountId;
use crate::models::endpoint::Endpoint;
use crate::models::fetched_account::FetchedAccount;
use crate::models::note_id::NoteId;
use crate::models::note_script::NoteScript;
use crate::models::word::Word;
Expand Down Expand Up @@ -92,4 +94,24 @@ impl RpcClient {

Ok(note_script.into())
}

/// Fetches the current state of an account from the node using the `/GetAccountDetails` RPC
/// endpoint.
///
/// @param `account_id` - the ID of the wanted account.
/// @returns Promise that resolves to the [`FetchedAccount`].
#[wasm_bindgen(js_name = "getAccountDetails")]
pub async fn get_account_details(
&self,
account_id: AccountId,
) -> Result<FetchedAccount, JsValue> {
let native_account_id = account_id.into();

let fetched_account =
self.inner.get_account_details(native_account_id).await.map_err(|err| {
js_error_with_context(err, "failed to get account for the given account id")
})?;

Ok(fetched_account.into())
}
}
94 changes: 94 additions & 0 deletions crates/web-client/test/account.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { Page, expect } from "@playwright/test";
import test from "./playwright.global.setup";
import {
createNewFaucet,
createNewWallet,
fundAccountFromFaucet,
getAccount,
StorageMode,
} from "./webClientTestUtils";

// GET_ACCOUNT TESTS
// =======================================================================================================
Expand Down Expand Up @@ -159,3 +166,90 @@ test.describe("getAccounts tests", () => {
expect(result.resultTypes.length).toEqual(0);
});
});

test.describe("fetch account tests", () => {
test("retrieves a public account", async ({ page }) => {
const walletSeed = new Uint8Array(32);
crypto.getRandomValues(walletSeed);

const mutable = false;
const storageMode = StorageMode.PUBLIC;
const authSchemeId = 0;
const initialWallet = await createNewWallet(page, {
storageMode,
mutable,
authSchemeId,
walletSeed,
});
const faucet = await createNewFaucet(page);

const { targetAccountBalance: initialBalance } =
await fundAccountFromFaucet(page, initialWallet.id, faucet.id);
const { commitment } = await getAccount(page, initialWallet.id);

const { isPublic, accountIsDefined, fetchedCommitment, balance } =
await page.evaluate(async (accountId: string) => {
const endpoint = new window.Endpoint(window.rpcUrl);
const rpcClient = new window.RpcClient(endpoint);

const fetchedAccount = await rpcClient.getAccountDetails(
window.AccountId.fromHex(accountId)
);
return {
isPublic: fetchedAccount.isPublic(),
accountIsDefined: !!fetchedAccount.account(),
fetchedCommitment: fetchedAccount.commitment().toHex(),
balance: fetchedAccount.account()
? fetchedAccount
.account()!
.vault()
.fungibleAssets()[0]
.amount()
.toString()
: undefined,
};
}, initialWallet.id);
expect(isPublic).toBe(true);
expect(accountIsDefined).toBe(true);
expect(fetchedCommitment).toBe(commitment);
expect(balance).toBe(initialBalance);
});

test("retrieves a private account", async ({ page }) => {
const walletSeed = new Uint8Array(32);
crypto.getRandomValues(walletSeed);

const mutable = false;
const storageMode = StorageMode.PRIVATE;
const authSchemeId = 0;
const initialWallet = await createNewWallet(page, {
storageMode,
mutable,
authSchemeId,
walletSeed,
});
const faucet = await createNewFaucet(page);

await fundAccountFromFaucet(page, initialWallet.id, faucet.id);

const { commitment } = await getAccount(page, initialWallet.id);

const { isPrivate, accountIsDefined, fetchedCommitment } =
await page.evaluate(async (accountId: string) => {
const endpoint = new window.Endpoint(window.rpcUrl);
const rpcClient = new window.RpcClient(endpoint);

const fetchedAccount = await rpcClient.getAccountDetails(
window.AccountId.fromHex(accountId)
);
return {
isPrivate: fetchedAccount.isPrivate(),
accountIsDefined: !!fetchedAccount.account(),
fetchedCommitment: fetchedAccount.commitment().toHex(),
};
}, initialWallet.id);
expect(isPrivate).toBe(true);
expect(accountIsDefined).toBe(false);
expect(fetchedCommitment).toBe(commitment);
});
});
1 change: 1 addition & 0 deletions docs/typedoc/web-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
- [ExecutedTransaction](classes/ExecutedTransaction.md)
- [Felt](classes/Felt.md)
- [FeltArray](classes/FeltArray.md)
- [FetchedAccount](classes/FetchedAccount.md)
- [FetchedNote](classes/FetchedNote.md)
- [FlattenedU8Vec](classes/FlattenedU8Vec.md)
- [ForeignAccount](classes/ForeignAccount.md)
Expand Down
95 changes: 95 additions & 0 deletions docs/typedoc/web-client/classes/FetchedAccount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
[**@demox-labs/miden-sdk**](../README.md)

***

[@demox-labs/miden-sdk](../README.md) / FetchedAccount

# Class: FetchedAccount

Describes the response from the `GetAccountDetails` endpoint.

The content varies based on account visibility:
- **Public or Network accounts**: Contains the complete [`Account`] details, as these are stored
on-chain
- **Private accounts**: Contains only the state commitment, since full account data is stored
off-chain

## Methods

### \[dispose\]()

> **\[dispose\]**(): `void`

#### Returns

`void`

***

### account()

> **account**(): [`Account`](Account.md)

Returns the associated [`Account`] if the account is public, otherwise none

#### Returns

[`Account`](Account.md)

***

### accountId()

> **accountId**(): [`AccountId`](AccountId.md)

Returns the account identifier

#### Returns

[`AccountId`](AccountId.md)

***

### commitment()

> **commitment**(): [`Word`](Word.md)

Returns the account update summary commitment

#### Returns

[`Word`](Word.md)

***

### free()

> **free**(): `void`

#### Returns

`void`

***

### isPrivate()

> **isPrivate**(): `boolean`

Returns true if the fetched account is private

#### Returns

`boolean`

***

### isPublic()

> **isPublic**(): `boolean`

Returns true if the fetched account is public

#### Returns

`boolean`
21 changes: 21 additions & 0 deletions docs/typedoc/web-client/classes/RpcClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ Endpoint to connect to.

***

### getAccountDetails()

> **getAccountDetails**(`account_id`): `Promise`\<[`FetchedAccount`](FetchedAccount.md)\>

Fetches the current state of an account from the node using the `/GetAccountDetails` RPC
endpoint.

#### Parameters

##### account\_id

[`AccountId`](AccountId.md)

#### Returns

`Promise`\<[`FetchedAccount`](FetchedAccount.md)\>

Promise that resolves to the [`FetchedAccount`].

***

### getNotesById()

> **getNotesById**(`note_ids`): `Promise`\<[`FetchedNote`](FetchedNote.md)[]\>
Expand Down