# State Lookup

> Reading the smart-accounts-related states from the Flare chain using Viem.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

Source: https://dev.flare.network/smart-accounts/guides/typescript-viem/state-lookup-ts

In this guide, you will learn how to get the following using the Viem TypeScript library:

-   the Flare address that corresponds to an XRPL account
-   whether a Flare address is a smart account
-   the total value of FXRP that belongs to a personal account tied to an XRPL address
-   a list of all the registered vaults
-   the total value of FXRP of a personal account, in each of the registered vaults
-   a list of all the registered agent vaults

The code example is available on the [Flare Foundation GitHub](https://github.com/flare-foundation/flare-viem-starter).

src/state-lookup.ts

```
import { Wallet } from "xrpl";import {  getAgentVaults,  getOperatorXrplAddresses,  getPersonalAccountAddress,  getVaults,} from "./utils/smart-accounts";import { getFxrpBalance } from "./utils/fassets";import { publicClient } from "./utils/client";import { erc4626Abi } from "viem";import type { Address } from "viem";async function getVaultBalance(vaultAddress: Address, accountAddress: Address) {  const vaultBalance = await publicClient.readContract({    address: vaultAddress,    abi: erc4626Abi,    functionName: "balanceOf",    args: [accountAddress],  });  return vaultBalance;}async function main() {  const xrplWallet = Wallet.fromSeed(process.env.XRPL_SEED!);  const operatorXrplAddress = await getOperatorXrplAddresses();  console.log("Operator XRPL addresses:", operatorXrplAddress, "\n");  const personalAccountAddress = await getPersonalAccountAddress(    xrplWallet.address,  );  console.log("Personal account address:", personalAccountAddress, "\n");  const fxrpBalance = await getFxrpBalance(personalAccountAddress);  console.log("Personal account FXRP balance:", fxrpBalance, "\n");  const vaults = await getVaults();  console.log("Vaults:", vaults, "\n");  for (const vault of vaults) {    const vaultBalance = await getVaultBalance(      vault.address,      personalAccountAddress,    );    console.log(`Vault ${vault.id} balance:`, vaultBalance, "\n");  }  const agentVaults = await getAgentVaults();  console.log("Agent vaults:", agentVaults, "\n");}void main()  .then(() => process.exit(0))  .catch((error) => {    console.error(error);    process.exit(1);  });
```

<details>
<summary>Details</summary>

Details

Expected output The following is an example of the expected output. The values will differ slightly, but the output should follow the same general format. The personal account address is tied to the XRPL address obtained from the XRPL secret value in the `.env` file.

```
Operator XRPL addresses: [ 'rEyj8nsHLdgt79KJWzXR5BgF7ZbaohbXwq' ]Personal account address: 0xFd2f0eb6b9fA4FE5bb1F7B26fEE3c647ed103d9FPersonal account FXRP balance: 0nVaults: [  {    id: 2n,    address: '0x2C5f203CAd22f3d351912e634dDd0f93C6D503d9',    type: 2  },  {    id: 1n,    address: '0x9BbE85a672Dd2fE2197516656FB2dC76c974954d',    type: 1  }]Vault 2 balance: 20000000nVault 1 balance: 0nAgent vaults: [ { id: 1n, address: '0x55c815260cBE6c45Fe5bFe5FF32E3C7D746f14dC' } ]
```

</details>

Let us examine each of the helper functions in more detail. First of all, we need to define a [Viem public client](https://viem.sh/docs/clients/public). Since the two Flare mainnets and the two testnets are already registered with Viem, we simply need to import them. Then, we create a basic public client with the HTTP transporter.

```
import { createPublicClient, http } from "viem";import { flareTestnet } from "viem/chains";export const publicClient = createPublicClient({  chain: flareTestnet,  transport: http(),});
```

With that, we can look at the actual functions. All of them rely primarily on the `readContract` function of the Viem `publicClient` to call read functions of contracts on the Flare chain.

## Operator's XRPL addresses[​](#operators-xrpl-addresses "Direct link to Operator's XRPL addresses")

The `getOperatorXrplAddresses` calls the `getXrplProviderWallets` function of the `MasterAccountController` contract. The function returns an array of XRPL addresses; these are all the registered operator XRPL addresses.

```
export async function getOperatorXrplAddresses() {  const result = await publicClient.readContract({    address: await getMasterAccountControllerAddress(),    abi: coston2.iMasterAccountControllerAbi,    functionName: "getXrplProviderWallets",    args: [],  });  return result as string[];}
```

We define a helper function for retrieving the address of the `MasterAccountController` contract from the `FlareContractsRegistry`.

```
export async function getMasterAccountControllerAddress(): Promise<Address> {  return getContractAddressByName("MasterAccountController");}
```

With the mainnet launch of the Flare smart accounts, the `MasterAccountController` has been added to the list of official Flare contracts. Its address can be obtained from the `FlareContractRegistry` contract by calling its `getContractAddressByName` function.

```
export async function getContractAddressByName(name: string) {  const contractAddress = await publicClient.readContract({    address: FLARE_CONTRACT_REGISTRY_ADDRESS,    abi: coston2.iFlareContractRegistryAbi,    functionName: "getContractAddressByName",    args: [name],  });  return contractAddress;}
```

## Checking if a Flare address is a smart account[​](#checking-if-a-flare-address-is-a-smart-account "Direct link to Checking if a Flare address is a smart account")

A Flare address is a smart account (PersonalAccount) if calling the `xrplOwner()` function on it returns an XRPL account using the [`IPersonalAccount`](/smart-accounts/reference/IPersonalAccount) interface. The `PersonalAccount` contract exposes the `xrplOwner()` function — the XRPL address that controls it. If the call succeeds and returns a non-empty and valid XRPL address, the address is a smart account.

```
export async function getXrplAccountForAddress(  evmAddress: Address,): Promise<`0x${string}`> {  const xrplOwner = await publicClient.readContract({    address: evmAddress,    abi: coston2.iPersonalAccountAbi,    functionName: "xrplOwner",    args: [],  });  return xrplOwner && xrplOwner.length > 0    ? evmAddress    : "0x0000000000000000000000000000000000000000";}export async function isSmartAccount(evmAddress: Address): Promise<boolean> {  const smartAccountAddress = await getXrplAccountForAddress(evmAddress);  return smartAccountAddress !== "0x0000000000000000000000000000000000000000";}
```

## Personal account of an XRPL address[​](#personal-account-of-an-xrpl-address "Direct link to Personal account of an XRPL address")

There are many situations when it is important or even necessary to know the address of the `PersonalAccount` of an XRPL address; like monitoring different emitted events and retrieving user balances. The `getPersonalAccountAddress` function retrieves the address of the `PersonalAccount` contract, belonging to the given XRPL address. It calls the `getPersonalAccount` function of the `MasterAccountController` contract, with the XRPL address as the function argument.

```
export async function getPersonalAccountAddress(xrplAddress: string) {  const personalAccountAddress = await publicClient.readContract({    address: await getMasterAccountControllerAddress(),    abi: coston2.iMasterAccountControllerAbi,    functionName: "getPersonalAccount",    args: [xrplAddress],  });  return personalAccountAddress;}
```

## Account's FXRP balance[​](#accounts-fxrp-balance "Direct link to Account's FXRP balance")

The `getFxrpBalance` function looks up the current FXRP balance of the given address. It calls the `balanceOf` function, which is a generic ERC-20 function of the FXRP token.

```
export async function getFxrpBalance(address: Address) {  const fxrpAddress = await getFxrpAddress();  const fxrpBalance = await publicClient.readContract({    address: fxrpAddress,    abi: erc20Abi,    functionName: "balanceOf",    args: [address],  });  return fxrpBalance;}
```

The FXRP token address is obtained from the `AssetManagerFXRP` contract by calling its `fAsset` function.

```
export async function getFxrpAddress(): Promise<Address> {  const assetManagerAddress = await getAssetManagerFXRPAddress();  const fxrpAddress = await publicClient.readContract({    address: assetManagerAddress,    abi: coston2.iAssetManagerAbi,    functionName: "fAsset",  });  return fxrpAddress;}
```

The `AssetManagerFXRP` contract is one of the contracts registered with the `FlareContractRegistry` contract. This allows us to read the `AssetManagerFXRP` contract's address from the latter.

```
export async function getAssetManagerFXRPAddress(): Promise<Address> {  const assetManagerAddress =    await getContractAddressByName("AssetManagerFXRP");  return assetManagerAddress;}
```

## Vaults and vault balances[​](#vaults-and-vault-balances "Direct link to Vaults and vault balances")

Certain instructions require the user to specify a vault ID. The user should also be able to check their share of each vault to which they have committed their funds. That is why it is important that we know how to retrieve those values.

To get the array of registered vaults, we define two helper types. The `getVaults` function of the `MasterAccountController` contract returns an array of three arrays; the first one represents the vault IDs, the second their addresses, and the third their types. The vaults are either of the Firelight (`1`) or the Upshift (`2`) type. The `GetVaultsReturnType` type allows us to properly interpret that data.

The `getVaults` function calls the function of the `MasterAccountController` contract with the same name. It iterates over the three sub-arrays and constructs a new array of the `Vault` type.

```
export type Vault = {  id: bigint;  address: Address;  type: number;};export type GetVaultsReturnType = [bigint[], string[], number[]];export async function getVaults(): Promise<Vault[]> {  const _vaults = (await publicClient.readContract({    address: await getMasterAccountControllerAddress(),    abi: coston2.iMasterAccountControllerAbi,    functionName: "getVaults",    args: [],  })) as GetVaultsReturnType;  const length = _vaults[0].length;  if (length === 0) {    return [];  }  const vaults = new Array(length) as Vault[];  _vaults[0].forEach((id, index) => {    vaults[index] = {      id,      address: _vaults[1][index]! as Address,      type: _vaults[2][index]!,    };  });  return vaults;}
```

On the testnet, the vaults are mocks. They are straightforward ERC-4626 implementations. To get the vault balance of a Flare address, we call the ERC-46426 `balanceOf` function on the selected vault, with the account address as the argument.

```
async function getVaultBalance(vaultAddress: Address, accountAddress: Address) {  const vaultBalance = await publicClient.readContract({    address: vaultAddress,    abi: erc4626Abi,    functionName: "balanceOf",    args: [accountAddress],  });  return vaultBalance;}
```

## Agent vaults[​](#agent-vaults "Direct link to Agent vaults")

Smart account instructions, which include a minting step (`FXRPCollateralReservation`, `FirelightCollateralReservationAndDeposit`, and `UpshiftCollateralReservationAndDeposit`), require the user to specify the ID of the agent vault they wish to use. We obtain the list of all the registered agent vaults in a similar way to how we do for the deposit vaults.

```
export type AgentVault = {  id: bigint;  address: Address;};export type GetAgentVaultsReturnType = [bigint[], string[]];export async function getAgentVaults(): Promise<AgentVault[]> {  const _vaults = await publicClient.readContract({    address: await getMasterAccountControllerAddress(),    abi: coston2.iMasterAccountControllerAbi,    functionName: "getAgentVaults",    args: [],  });  const length = _vaults[0].length;  if (length === 0) {    return [];  }  const vaults = new Array(length) as AgentVault[];  _vaults[0].forEach((id, index) => {    vaults[index] = {      id,      address: _vaults[1][index]!,    };  });  return vaults;}
```

## Video Tutorial[​](#video-tutorial "Direct link to Video Tutorial")
