UNPKG

@solana/accounts

Version:

Helpers for representing, fetching and decoding Solana accounts

1 lines • 33.8 kB
{"version":3,"sources":["../src/account.ts","../src/decode-account.ts","../src/parse-account.ts","../src/fetch-account.ts","../src/maybe-account.ts"],"names":["SolanaError"],"mappings":"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","file":"index.native.mjs","sourcesContent":["import type { Address } from '@solana/addresses';\nimport { ReadonlyUint8Array } from '@solana/codecs-core';\nimport type { Lamports } from '@solana/rpc-types';\n\n/**\n * The number of bytes required to store the {@link BaseAccount} information without its data.\n *\n * @example\n * ```ts\n * const myTotalAccountSize = myAccountDataSize + BASE_ACCOUNT_SIZE;\n * ```\n */\nexport const BASE_ACCOUNT_SIZE = 128;\n\n/**\n * Defines the attributes common to all Solana accounts. Namely, it contains everything stored\n * on-chain except the account data itself.\n *\n * @interface\n *\n * @example\n * ```ts\n * const BaseAccount: BaseAccount = {\n * executable: false,\n * lamports: lamports(1_000_000_000n),\n * programAddress: address('1111..1111'),\n * space: 42n,\n * };\n * ```\n */\nexport type BaseAccount = {\n readonly executable: boolean;\n readonly lamports: Lamports;\n readonly programAddress: Address;\n readonly space: bigint;\n};\n\n/**\n * Contains all the information relevant to a Solana account. It includes the account's address and\n * data, as well as the properties of {@link BaseAccount}.\n *\n * @interface\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The nature of this account's data. It can be represented as either a\n * `Uint8Array` &ndash; meaning the account is encoded &ndash; or a custom data type &ndash; meaning\n * the account is decoded.\n *\n * @example\n * ```ts\n * // Encoded\n * const myEncodedAccount: Account<Uint8Array, '1234..5678'> = {\n * address: address('1234..5678'),\n * data: new Uint8Array([1, 2, 3]),\n * executable: false,\n * lamports: lamports(1_000_000_000n),\n * programAddress: address('1111..1111'),\n * space: 42n,\n * };\n *\n * // Decoded\n * type MyAccountData = { name: string; age: number };\n * const myDecodedAccount: Account<MyAccountData, '1234..5678'> = {\n * address: address('1234..5678'),\n * data: { name: 'Alice', age: 30 },\n * executable: false,\n * lamports: lamports(1_000_000_000n),\n * programAddress: address('1111..1111'),\n * space: 42n,\n * };\n * ```\n */\nexport type Account<TData extends Uint8Array | object, TAddress extends string = string> = BaseAccount & {\n readonly address: Address<TAddress>;\n readonly data: TData;\n};\n\n/**\n * Represents an encoded account and is equivalent to an {@link Account} with `Uint8Array` account\n * data.\n *\n * @interface\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n *\n * @example\n * ```ts\n * {\n * address: address('1234..5678'),\n * data: new Uint8Array([1, 2, 3]),\n * executable: false,\n * lamports: lamports(1_000_000_000n),\n * programAddress: address('1111..1111'),\n * space: 42n,\n * } satisfies EncodedAccount<'1234..5678'>;\n * ```\n */\nexport type EncodedAccount<TAddress extends string = string> = Account<ReadonlyUint8Array, TAddress>;\n","import type { Decoder, ReadonlyUint8Array } from '@solana/codecs-core';\nimport {\n SOLANA_ERROR__ACCOUNTS__EXPECTED_ALL_ACCOUNTS_TO_BE_DECODED,\n SOLANA_ERROR__ACCOUNTS__EXPECTED_DECODED_ACCOUNT,\n SOLANA_ERROR__ACCOUNTS__FAILED_TO_DECODE_ACCOUNT,\n SolanaError,\n} from '@solana/errors';\n\nimport type { Account, EncodedAccount } from './account';\nimport type { MaybeAccount, MaybeEncodedAccount } from './maybe-account';\n\n/**\n * Transforms an {@link EncodedAccount} into an {@link Account} (or a {@link MaybeEncodedAccount}\n * into a {@link MaybeAccount}) by decoding the account data using the provided {@link Decoder}\n * instance.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The type of this account's data.\n *\n * @example\n * ```ts\n * type MyAccountData = { name: string; age: number };\n *\n * const myAccount: EncodedAccount<'1234..5678'>;\n * const myDecoder: Decoder<MyAccountData> = getStructDecoder([\n * ['name', addDecoderSizePrefix(getUtf8Decoder(), getU32Decoder())],\n * ['age', getU32Decoder()],\n * ]);\n *\n * const myDecodedAccount = decodeAccount(myAccount, myDecoder);\n * myDecodedAccount satisfies Account<MyAccountData, '1234..5678'>;\n * ```\n */\nexport function decodeAccount<TData extends object, TAddress extends string = string>(\n encodedAccount: EncodedAccount<TAddress>,\n decoder: Decoder<TData>,\n): Account<TData, TAddress>;\nexport function decodeAccount<TData extends object, TAddress extends string = string>(\n encodedAccount: MaybeEncodedAccount<TAddress>,\n decoder: Decoder<TData>,\n): MaybeAccount<TData, TAddress>;\nexport function decodeAccount<TData extends object, TAddress extends string = string>(\n encodedAccount: EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress>,\n decoder: Decoder<TData>,\n): Account<TData, TAddress> | MaybeAccount<TData, TAddress> {\n try {\n if ('exists' in encodedAccount && !encodedAccount.exists) {\n return encodedAccount;\n }\n return Object.freeze({ ...encodedAccount, data: decoder.decode(encodedAccount.data) });\n } catch {\n throw new SolanaError(SOLANA_ERROR__ACCOUNTS__FAILED_TO_DECODE_ACCOUNT, {\n address: encodedAccount.address,\n });\n }\n}\n\nfunction accountExists<TData extends object>(account: Account<TData> | MaybeAccount<TData>): account is Account<TData> {\n return !('exists' in account) || ('exists' in account && account.exists);\n}\n\n/**\n * Asserts that an account stores decoded data, ie. not a `Uint8Array`.\n *\n * Note that it does not check the shape of the data matches the decoded type, only that it is not a\n * `Uint8Array`.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The type of this account's data.\n *\n * @example\n * ```ts\n * type MyAccountData = { name: string; age: number };\n *\n * const myAccount: Account<MyAccountData | Uint8Array, '1234..5678'>;\n * assertAccountDecoded(myAccount);\n *\n * // now the account data can be used as MyAccountData\n * account.data satisfies MyAccountData;\n * ```\n *\n * This is particularly useful for narrowing the result of fetching a JSON parsed account.\n *\n * ```ts\n * const account: MaybeAccount<MockData | Uint8Array> = await fetchJsonParsedAccount<MockData>(\n * rpc,\n * '1234..5678' as Address,\n * );\n *\n * assertAccountDecoded(account);\n * // now we have a MaybeAccount<MockData>\n * account satisfies MaybeAccount<MockData>;\n * ```\n */\nexport function assertAccountDecoded<TData extends object, TAddress extends string = string>(\n account: Account<TData | Uint8Array, TAddress>,\n): asserts account is Account<TData, TAddress>;\nexport function assertAccountDecoded<TData extends object, TAddress extends string = string>(\n account: MaybeAccount<TData | Uint8Array, TAddress>,\n): asserts account is MaybeAccount<TData, TAddress>;\nexport function assertAccountDecoded<TData extends object, TAddress extends string = string>(\n account: Account<TData | Uint8Array, TAddress> | MaybeAccount<TData | Uint8Array, TAddress>,\n): asserts account is Account<TData, TAddress> | MaybeAccount<TData, TAddress> {\n if (accountExists(account) && account.data instanceof Uint8Array) {\n throw new SolanaError(SOLANA_ERROR__ACCOUNTS__EXPECTED_DECODED_ACCOUNT, {\n address: account.address,\n });\n }\n}\n\n/**\n * Asserts that all input accounts store decoded data, ie. not a `Uint8Array`.\n *\n * As with {@link assertAccountDecoded} it does not check the shape of the data matches the decoded\n * type, only that it is not a `Uint8Array`.\n *\n * @example\n * ```ts\n * type MyAccountData = { name: string; age: number };\n *\n * const myAccounts: Account<MyAccountData | Uint8Array, Address>[];\n * assertAccountsDecoded(myAccounts);\n *\n * // now the account data can be used as MyAccountData\n * for (const a of account) {\n * account.data satisfies MyAccountData;\n * }\n * ```\n */\nexport function assertAccountsDecoded<TData extends object, TAddress extends string = string>(\n accounts: Account<ReadonlyUint8Array | TData, TAddress>[],\n): asserts accounts is Account<TData, TAddress>[];\nexport function assertAccountsDecoded<TData extends object, TAddress extends string = string>(\n accounts: MaybeAccount<ReadonlyUint8Array | TData, TAddress>[],\n): asserts accounts is MaybeAccount<TData, TAddress>[];\nexport function assertAccountsDecoded<TData extends object, TAddress extends string = string>(\n accounts: (Account<ReadonlyUint8Array | TData, TAddress> | MaybeAccount<ReadonlyUint8Array | TData, TAddress>)[],\n): asserts accounts is (Account<TData, TAddress> | MaybeAccount<TData, TAddress>)[] {\n const encoded = accounts.filter(a => accountExists(a) && a.data instanceof Uint8Array);\n if (encoded.length > 0) {\n const encodedAddresses = encoded.map(a => a.address);\n throw new SolanaError(SOLANA_ERROR__ACCOUNTS__EXPECTED_ALL_ACCOUNTS_TO_BE_DECODED, {\n addresses: encodedAddresses,\n });\n }\n}\n","import type { Address } from '@solana/addresses';\nimport { getBase58Encoder, getBase64Encoder } from '@solana/codecs-strings';\nimport type {\n AccountInfoBase,\n AccountInfoWithBase58Bytes,\n AccountInfoWithBase58EncodedData,\n AccountInfoWithBase64EncodedData,\n} from '@solana/rpc-types';\n\nimport type { Account, BaseAccount, EncodedAccount } from './account';\nimport type { MaybeAccount, MaybeEncodedAccount } from './maybe-account';\nimport type { JsonParsedDataResponse } from './rpc-api';\n\ntype Base64EncodedRpcAccount = AccountInfoBase & AccountInfoWithBase64EncodedData;\n\n/**\n * Parses a base64-encoded account provided by the RPC client into an {@link EncodedAccount} type or\n * a {@link MaybeEncodedAccount} type if the raw data can be set to `null`.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n *\n * @example\n * ```ts\n * const myAddress = address('1234..5678');\n * const myRpcAccount = await rpc.getAccountInfo(myAddress, { encoding: 'base64' }).send();\n * const myAccount: MaybeEncodedAccount<'1234..5678'> = parseBase64RpcAccount(myRpcAccount);\n * ```\n */\nexport function parseBase64RpcAccount<TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: Base64EncodedRpcAccount,\n): EncodedAccount<TAddress>;\nexport function parseBase64RpcAccount<TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: Base64EncodedRpcAccount | null,\n): MaybeEncodedAccount<TAddress>;\nexport function parseBase64RpcAccount<TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: Base64EncodedRpcAccount | null,\n): EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress> {\n if (!rpcAccount) return Object.freeze({ address, exists: false });\n const data = getBase64Encoder().encode(rpcAccount.data[0]);\n return Object.freeze({ ...parseBaseAccount(rpcAccount), address, data, exists: true });\n}\n\ntype Base58EncodedRpcAccount = AccountInfoBase & (AccountInfoWithBase58Bytes | AccountInfoWithBase58EncodedData);\n\n/**\n * Parses a base58-encoded account provided by the RPC client into an {@link EncodedAccount} type or\n * a {@link MaybeEncodedAccount} type if the raw data can be set to `null`.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n *\n * @example\n * ```ts\n * const myAddress = address('1234..5678');\n * const myRpcAccount = await rpc.getAccountInfo(myAddress, { encoding: 'base58' }).send();\n * const myAccount: MaybeEncodedAccount<'1234..5678'> = parseBase58RpcAccount(myRpcAccount);\n * ```\n */\nexport function parseBase58RpcAccount<TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: Base58EncodedRpcAccount,\n): EncodedAccount<TAddress>;\nexport function parseBase58RpcAccount<TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: Base58EncodedRpcAccount | null,\n): MaybeEncodedAccount<TAddress>;\nexport function parseBase58RpcAccount<TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: Base58EncodedRpcAccount | null,\n): EncodedAccount<TAddress> | MaybeEncodedAccount<TAddress> {\n if (!rpcAccount) return Object.freeze({ address, exists: false });\n const data = getBase58Encoder().encode(typeof rpcAccount.data === 'string' ? rpcAccount.data : rpcAccount.data[0]);\n return Object.freeze({ ...parseBaseAccount(rpcAccount), address, data, exists: true });\n}\n\ntype JsonParsedRpcAccount = AccountInfoBase & { readonly data: JsonParsedDataResponse<unknown> };\n\n/**\n * Parses an arbitrary `jsonParsed` account provided by the RPC client into an {@link Account} type\n * or a {@link MaybeAccount} type if the raw data can be set to `null`.\n *\n * The expected data type should be explicitly provided as the first type parameter.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The expected type of this account's data.\n *\n * @example\n * ```ts\n * const myAccount: Account<MyData> = parseJsonRpcAccount<MyData>(myJsonRpcAccount);\n * ```\n */\nexport function parseJsonRpcAccount<TData extends object, TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: JsonParsedRpcAccount,\n): Account<TData, TAddress>;\nexport function parseJsonRpcAccount<TData extends object, TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: JsonParsedRpcAccount | null,\n): MaybeAccount<TData, TAddress>;\nexport function parseJsonRpcAccount<TData extends object, TAddress extends string = string>(\n address: Address<TAddress>,\n rpcAccount: JsonParsedRpcAccount | null,\n): Account<TData, TAddress> | MaybeAccount<TData, TAddress> {\n if (!rpcAccount) return Object.freeze({ address, exists: false });\n const data = rpcAccount.data.parsed.info as TData;\n return Object.freeze({ ...parseBaseAccount(rpcAccount), address, data, exists: true });\n}\n\nfunction parseBaseAccount(rpcAccount: AccountInfoBase): BaseAccount {\n return Object.freeze({\n executable: rpcAccount.executable,\n lamports: rpcAccount.lamports,\n programAddress: rpcAccount.owner,\n space: rpcAccount.space,\n });\n}\n","import type { Address } from '@solana/addresses';\nimport type { Rpc } from '@solana/rpc-spec';\nimport type { Commitment, Slot } from '@solana/rpc-types';\n\nimport type { MaybeAccount, MaybeEncodedAccount } from './maybe-account';\nimport { parseBase64RpcAccount, parseJsonRpcAccount } from './parse-account';\nimport type { GetAccountInfoApi, GetMultipleAccountsApi } from './rpc-api';\n\n/**\n * Optional configuration for fetching a singular account.\n *\n * @interface\n */\nexport type FetchAccountConfig = {\n abortSignal?: AbortSignal;\n /**\n * Fetch the details of the account as of the highest slot that has reached this level of\n * commitment.\n *\n * @defaultValue Whichever default is applied by the underlying {@link RpcApi} in use. For\n * example, when using an API created by a `createSolanaRpc*()` helper, the default commitment\n * is `\"confirmed\"` unless configured otherwise. Unmitigated by an API layer on the client, the\n * default commitment applied by the server is `\"finalized\"`.\n */\n commitment?: Commitment;\n /**\n * Prevents accessing stale data by enforcing that the RPC node has processed transactions up to\n * this slot\n */\n minContextSlot?: Slot;\n};\n\n/**\n * Fetches a {@link MaybeEncodedAccount} from the provided RPC client and address.\n *\n * It uses the {@link GetAccountInfoApi.getAccountInfo | getAccountInfo} RPC method under the hood\n * with base64 encoding and an additional configuration object can be provided to customize the\n * behavior of the RPC call.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n *\n * @example\n * ```ts\n * const myAddress = address('1234..5678');\n * const myAccount: MaybeEncodedAccount<'1234..5678'> = await fetchEncodedAccount(rpc, myAddress);\n *\n * // With custom configuration.\n * const myAccount: MaybeEncodedAccount<'1234..5678'> = await fetchEncodedAccount(rpc, myAddress, {\n * abortSignal: myAbortController.signal,\n * commitment: 'confirmed',\n * });\n * ```\n */\nexport async function fetchEncodedAccount<TAddress extends string = string>(\n rpc: Rpc<GetAccountInfoApi>,\n address: Address<TAddress>,\n config: FetchAccountConfig = {},\n): Promise<MaybeEncodedAccount<TAddress>> {\n const { abortSignal, ...rpcConfig } = config;\n const response = await rpc.getAccountInfo(address, { ...rpcConfig, encoding: 'base64' }).send({ abortSignal });\n return parseBase64RpcAccount(address, response.value);\n}\n\n/**\n * Fetches a {@link MaybeAccount} from the provided RPC client and address by using\n * {@link GetAccountInfoApi.getAccountInfo | getAccountInfo} under the hood with the `jsonParsed`\n * encoding.\n *\n * It may also return a {@link MaybeEncodedAccount} if the RPC client does not know how to parse the\n * account at the requested address. In any case, the expected data type should be explicitly\n * provided as the first type parameter.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The expected type of this account's data.\n *\n * @example\n * ```ts\n * type TokenData = { mint: Address; owner: Address };\n * const myAccount = await fetchJsonParsedAccount<TokenData>(rpc, myAddress);\n * myAccount satisfies MaybeAccount<TokenData> | MaybeEncodedAccount;\n *\n * // With custom configuration.\n * const myAccount = await fetchJsonParsedAccount<TokenData>(rpc, myAddress, {\n * abortSignal: myAbortController.signal,\n * commitment: 'confirmed',\n * });\n * ```\n */\nexport async function fetchJsonParsedAccount<TData extends object, TAddress extends string = string>(\n rpc: Rpc<GetAccountInfoApi>,\n address: Address<TAddress>,\n config: FetchAccountConfig = {},\n): Promise<MaybeAccount<TData, TAddress> | MaybeEncodedAccount<TAddress>> {\n const { abortSignal, ...rpcConfig } = config;\n const { value: account } = await rpc\n .getAccountInfo(address, { ...rpcConfig, encoding: 'jsonParsed' })\n .send({ abortSignal });\n return !!account && typeof account === 'object' && 'parsed' in account.data\n ? parseJsonRpcAccount<TData, TAddress>(address, account as Parameters<typeof parseJsonRpcAccount>[1])\n : parseBase64RpcAccount<TAddress>(address, account as Parameters<typeof parseBase64RpcAccount>[1]);\n}\n\n/**\n * Optional configuration for fetching multiple accounts.\n *\n * @interface\n */\nexport type FetchAccountsConfig = {\n abortSignal?: AbortSignal;\n /**\n * Fetch the details of the accounts as of the highest slot that has reached this level of\n * commitment.\n *\n * @defaultValue Whichever default is applied by the underlying {@link RpcApi} in use. For\n * example, when using an API created by a `createSolanaRpc*()` helper, the default commitment\n * is `\"confirmed\"` unless configured otherwise. Unmitigated by an API layer on the client, the\n * default commitment applied by the server is `\"finalized\"`.\n */\n commitment?: Commitment;\n /**\n * Prevents accessing stale data by enforcing that the RPC node has processed transactions up to\n * this slot\n */\n minContextSlot?: Slot;\n};\n\n/**\n * Fetches an array of {@link MaybeEncodedAccount | MaybeEncodedAccounts} from the provided RPC\n * client and an array of addresses.\n *\n * It uses the {@link GetMultipleAccountsApi#getMultipleAccounts | getMultipleAccounts} RPC method\n * under the hood with base64 encodings and an additional configuration object can be provided to\n * customize the behavior of the RPC call.\n *\n * @typeParam TAddresses - Supply an array of string literals to define accounts having particular\n * addresses.\n *\n * @example\n * ```ts\n * const myAddressA = address('1234..5678');\n * const myAddressB = address('8765..4321');\n * const [myAccountA, myAccountB] = await fetchEncodedAccounts(rpc, [myAddressA, myAddressB]);\n * myAccountA satisfies MaybeEncodedAccount<'1234..5678'>;\n * myAccountB satisfies MaybeEncodedAccount<'8765..4321'>;\n *\n * // With custom configuration.\n * const [myAccountA, myAccountB] = await fetchEncodedAccounts(rpc, [myAddressA, myAddressB], {\n * abortSignal: myAbortController.signal,\n * commitment: 'confirmed',\n * });\n * ```\n */\nexport async function fetchEncodedAccounts<\n TAddresses extends string[] = string[],\n TWrappedAddresses extends { [P in keyof TAddresses]: Address<TAddresses[P]> } = {\n [P in keyof TAddresses]: Address<TAddresses[P]>;\n },\n>(rpc: Rpc<GetMultipleAccountsApi>, addresses: TWrappedAddresses, config: FetchAccountsConfig = {}) {\n const { abortSignal, ...rpcConfig } = config;\n const response = await rpc\n .getMultipleAccounts(addresses, { ...rpcConfig, encoding: 'base64' })\n .send({ abortSignal });\n return response.value.map((account, index) => parseBase64RpcAccount(addresses[index], account)) as {\n [P in keyof TAddresses]: MaybeEncodedAccount<TAddresses[P]>;\n };\n}\n\n/**\n * Fetches an array of {@link MaybeAccount | MaybeAccounts} from a provided RPC client and an array\n * of addresses.\n *\n * It uses the {@link GetMultipleAccountsApi#getMultipleAccounts | getMultipleAccounts} RPC method\n * under the hood with the `jsonParsed` encoding. It may also return a\n * {@link MaybeEncodedAccount} instead of the expected {@link MaybeAccount} if the RPC client does\n * not know how to parse some of the requested accounts. In any case, the array of expected data\n * types should be explicitly provided as the first type parameter.\n *\n * @typeParam TAddresses - Supply an array of string literals to define accounts having particular\n * addresses.\n * @typeParam TData - The expected types of these accounts' data.\n \n * @example\n * ```ts\n * type TokenData = { mint: Address; owner: Address };\n * type MintData = { supply: bigint };\n * const [myAccountA, myAccountB] = await fetchJsonParsedAccounts<[TokenData, MintData]>(rpc, [myAddressA, myAddressB]);\n * myAccountA satisfies MaybeAccount<TokenData> | MaybeEncodedAccount;\n * myAccountB satisfies MaybeAccount<MintData> | MaybeEncodedAccount;\n * ```\n */\nexport async function fetchJsonParsedAccounts<\n TData extends object[],\n TAddresses extends string[] = string[],\n TWrappedAddresses extends { [P in keyof TAddresses]: Address<TAddresses[P]> } = {\n [P in keyof TAddresses]: Address<TAddresses[P]>;\n },\n>(rpc: Rpc<GetMultipleAccountsApi>, addresses: TWrappedAddresses, config: FetchAccountsConfig = {}) {\n const { abortSignal, ...rpcConfig } = config;\n const response = await rpc\n .getMultipleAccounts(addresses, { ...rpcConfig, encoding: 'jsonParsed' })\n .send({ abortSignal });\n return response.value.map((account, index) => {\n return !!account && typeof account === 'object' && 'parsed' in account.data\n ? parseJsonRpcAccount(addresses[index], account as Parameters<typeof parseJsonRpcAccount>[1])\n : parseBase64RpcAccount(addresses[index], account as Parameters<typeof parseBase64RpcAccount>[1]);\n }) as {\n [P in keyof TAddresses]:\n | MaybeAccount<TData[P & keyof TData], TAddresses[P]>\n | MaybeEncodedAccount<TAddresses[P]>;\n } & {\n [P in keyof TData]:\n | MaybeAccount<TData[P], TAddresses[P & keyof TAddresses]>\n | MaybeEncodedAccount<TAddresses[P & keyof TAddresses]>;\n };\n}\n","import { Address } from '@solana/addresses';\nimport {\n SOLANA_ERROR__ACCOUNTS__ACCOUNT_NOT_FOUND,\n SOLANA_ERROR__ACCOUNTS__ONE_OR_MORE_ACCOUNTS_NOT_FOUND,\n SolanaError,\n} from '@solana/errors';\n\nimport { Account } from './account';\n\n/**\n * Represents an account that may or may not exist on-chain.\n *\n * When the account exists, it is represented as an {@link Account} type with an additional `exists`\n * attribute set to `true`. When it does not exist, it is represented by an object containing only\n * the address of the account and an `exists` attribute set to `false`.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The nature of this account's data. It can be represented as either a\n * `Uint8Array` &ndash; meaning the account is encoded &ndash; or a custom data type &ndash; meaning\n * the account is decoded.\n *\n * @example\n * ```ts\n * // Account exists\n * const myExistingAccount: MaybeAccount<MyAccountData, '1234..5678'> = {\n * exists: true,\n * address: address('1234..5678'),\n * data: { name: 'Alice', age: 30 },\n * // ...\n * };\n *\n * // Account does not exist\n * const myMissingAccount: MaybeAccount<MyAccountData, '8765..4321'> = {\n * exists: false,\n * address: address('8765..4321'),\n * };\n * ```\n */\nexport type MaybeAccount<TData extends Uint8Array | object, TAddress extends string = string> =\n | { readonly address: Address<TAddress>; readonly exists: false }\n | (Account<TData, TAddress> & { readonly exists: true });\n\n/**\n * Represents an encoded account that may or may not exist on-chain.\n *\n * When the account exists, it is represented as an {@link Account} type having its `TData` type\n * parameter set to `Uint8Array` with an additional `exists` attribute set to `true`. When it does\n * not exist, it is represented by an object containing only the address of the account and an\n * `exists` attribute set to `false`.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n *\n * @example\n * ```ts\n * // Encoded account exists\n * const myExistingAccount: MaybeEncodedAccount<'1234..5678'> = {\n * exists: true,\n * address: address('1234..5678'),\n * data: new Uint8Array([1, 2, 3]),\n * // ...\n * };\n *\n * // Encoded account does not exist\n * const myMissingAccount: MaybeEncodedAccount<'8765..4321'> = {\n * exists: false,\n * address: address('8765..4321'),\n * };\n * ```\n */\nexport type MaybeEncodedAccount<TAddress extends string = string> = MaybeAccount<Uint8Array, TAddress>;\n\n/**\n * Given a {@link MaybeAccount}, asserts that the account exists and allows it to be used as an\n * {@link Account} type going forward.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The nature of this account's data. It can be represented as either a\n * `Uint8Array` &ndash; meaning the account is encoded &ndash; or a custom data type &ndash; meaning\n * the account is decoded.\n *\n * @example\n * ```ts\n * const myAccount: MaybeEncodedAccount<'1234..5678'>;\n * assertAccountExists(myAccount);\n *\n * // Now we can use myAccount as an `EncodedAccount`\n * myAccount satisfies EncodedAccount<'1234..5678'>;\n * ```\n */\nexport function assertAccountExists<TData extends Uint8Array | object, TAddress extends string = string>(\n account: MaybeAccount<TData, TAddress>,\n): asserts account is Account<TData, TAddress> & { exists: true } {\n if (!account.exists) {\n throw new SolanaError(SOLANA_ERROR__ACCOUNTS__ACCOUNT_NOT_FOUND, { address: account.address });\n }\n}\n\n/**\n * Given an array of {@link MaybeAccount | MaybeAccounts}, asserts that all the accounts exist and\n * allows them to be used as an array of {@link Account | Accounts} going forward.\n *\n * @typeParam TAddress - Supply a string literal to define an account having a particular address.\n * @typeParam TData - The nature of this account's data. It can be represented as either a\n * `Uint8Array` &ndash; meaning the account is encoded &ndash; or a custom data type &ndash; meaning\n * the account is decoded.\n *\n * @example\n * ```ts\n * const myAccounts: MaybeEncodedAccount<Address>[];\n * assertAccountsExist(myAccounts);\n *\n * // Now we can use them as an array of `EncodedAccounts`\n * for (const a of myAccounts) {\n * a satisfies EncodedAccount<Address>;\n * }\n * ```\n */\nexport function assertAccountsExist<TData extends Uint8Array | object, TAddress extends string = string>(\n accounts: MaybeAccount<TData, TAddress>[],\n): asserts accounts is (Account<TData, TAddress> & { exists: true })[] {\n const missingAccounts = accounts.filter(a => !a.exists);\n if (missingAccounts.length > 0) {\n const missingAddresses = missingAccounts.map(a => a.address);\n throw new SolanaError(SOLANA_ERROR__ACCOUNTS__ONE_OR_MORE_ACCOUNTS_NOT_FOUND, { addresses: missingAddresses });\n }\n}\n"]}