@solana/program-client-core 0.0.0 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +14 -0
- package/dist/index.browser.cjs +117 -0
- package/dist/index.browser.cjs.map +1 -0
- package/dist/index.browser.mjs +109 -0
- package/dist/index.browser.mjs.map +1 -0
- package/dist/index.native.mjs +109 -0
- package/dist/index.native.mjs.map +1 -0
- package/dist/index.node.cjs +117 -0
- package/dist/index.node.cjs.map +1 -0
- package/dist/index.node.mjs +109 -0
- package/dist/index.node.mjs.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/instruction-input-resolution.d.ts +133 -0
- package/dist/types/instruction-input-resolution.d.ts.map +1 -0
- package/dist/types/instructions.d.ts +12 -0
- package/dist/types/instructions.d.ts.map +1 -0
- package/dist/types/self-fetch-functions.d.ts +109 -0
- package/dist/types/self-fetch-functions.d.ts.map +1 -0
- package/dist/types/self-plan-and-send-functions.d.ts +85 -0
- package/dist/types/self-plan-and-send-functions.d.ts.map +1 -0
- package/package.json +91 -7
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2023 Solana Labs, Inc
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[![npm][npm-image]][npm-url]
|
|
2
|
+
[![npm-downloads][npm-downloads-image]][npm-url]
|
|
3
|
+
<br />
|
|
4
|
+
[![code-style-prettier][code-style-prettier-image]][code-style-prettier-url]
|
|
5
|
+
|
|
6
|
+
[code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
|
|
7
|
+
[code-style-prettier-url]: https://github.com/prettier/prettier
|
|
8
|
+
[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/program-client-core?style=flat
|
|
9
|
+
[npm-image]: https://img.shields.io/npm/v/@solana/program-client-core?style=flat
|
|
10
|
+
[npm-url]: https://www.npmjs.com/package/@solana/program-client-core
|
|
11
|
+
|
|
12
|
+
# @solana/program-client-core
|
|
13
|
+
|
|
14
|
+
This package contains types and utilities for building Solana program clients. This is mainly used by the JavaScript Codama renderer to generate Kit-compatible program clients.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var addresses = require('@solana/addresses');
|
|
4
|
+
var errors = require('@solana/errors');
|
|
5
|
+
var instructions = require('@solana/instructions');
|
|
6
|
+
var signers = require('@solana/signers');
|
|
7
|
+
var accounts = require('@solana/accounts');
|
|
8
|
+
|
|
9
|
+
// src/instruction-input-resolution.ts
|
|
10
|
+
function getNonNullResolvedInstructionInput(inputName, value) {
|
|
11
|
+
if (value === null || value === void 0) {
|
|
12
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, {
|
|
13
|
+
inputName
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function getAddressFromResolvedInstructionAccount(inputName, value) {
|
|
19
|
+
const nonNullValue = getNonNullResolvedInstructionInput(inputName, value);
|
|
20
|
+
if (typeof value === "object" && "address" in nonNullValue) {
|
|
21
|
+
return nonNullValue.address;
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(nonNullValue)) {
|
|
24
|
+
return nonNullValue[0];
|
|
25
|
+
}
|
|
26
|
+
return nonNullValue;
|
|
27
|
+
}
|
|
28
|
+
function getResolvedInstructionAccountAsProgramDerivedAddress(inputName, value) {
|
|
29
|
+
if (!addresses.isProgramDerivedAddress(value)) {
|
|
30
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {
|
|
31
|
+
expectedType: "ProgramDerivedAddress",
|
|
32
|
+
inputName
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
function getResolvedInstructionAccountAsTransactionSigner(inputName, value) {
|
|
38
|
+
if (!isResolvedInstructionAccountSigner(value)) {
|
|
39
|
+
throw new errors.SolanaError(errors.SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {
|
|
40
|
+
expectedType: "TransactionSigner",
|
|
41
|
+
inputName
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
function getAccountMetaFactory(programAddress, optionalAccountStrategy) {
|
|
47
|
+
return (inputName, account) => {
|
|
48
|
+
if (!account.value) {
|
|
49
|
+
if (optionalAccountStrategy === "omitted") return;
|
|
50
|
+
return Object.freeze({ address: programAddress, role: instructions.AccountRole.READONLY });
|
|
51
|
+
}
|
|
52
|
+
const writableRole = account.isWritable ? instructions.AccountRole.WRITABLE : instructions.AccountRole.READONLY;
|
|
53
|
+
const isSigner = isResolvedInstructionAccountSigner(account.value);
|
|
54
|
+
return Object.freeze({
|
|
55
|
+
address: getAddressFromResolvedInstructionAccount(inputName, account.value),
|
|
56
|
+
role: isSigner ? instructions.upgradeRoleToSigner(writableRole) : writableRole,
|
|
57
|
+
...isSigner ? { signer: account.value } : {}
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function isResolvedInstructionAccountSigner(value) {
|
|
62
|
+
return !!value && typeof value === "object" && "address" in value && typeof value.address === "string" && signers.isTransactionSigner(value);
|
|
63
|
+
}
|
|
64
|
+
function addSelfFetchFunctions(client, codec) {
|
|
65
|
+
const fetchMaybe = async (address, config) => {
|
|
66
|
+
const maybeAccount = await accounts.fetchEncodedAccount(client.rpc, address, config);
|
|
67
|
+
return accounts.decodeAccount(maybeAccount, codec);
|
|
68
|
+
};
|
|
69
|
+
const fetchAllMaybe = async (addresses, config) => {
|
|
70
|
+
const maybeAccounts = await accounts.fetchEncodedAccounts(client.rpc, addresses, config);
|
|
71
|
+
return maybeAccounts.map((maybeAccount) => accounts.decodeAccount(maybeAccount, codec));
|
|
72
|
+
};
|
|
73
|
+
const fetch = async (address, config) => {
|
|
74
|
+
const maybeAccount = await fetchMaybe(address, config);
|
|
75
|
+
accounts.assertAccountExists(maybeAccount);
|
|
76
|
+
return maybeAccount;
|
|
77
|
+
};
|
|
78
|
+
const fetchAll = async (addresses, config) => {
|
|
79
|
+
const maybeAccounts = await fetchAllMaybe(addresses, config);
|
|
80
|
+
accounts.assertAccountsExist(maybeAccounts);
|
|
81
|
+
return maybeAccounts;
|
|
82
|
+
};
|
|
83
|
+
const out = { ...codec, fetch, fetchAll, fetchAllMaybe, fetchMaybe };
|
|
84
|
+
return Object.freeze(out);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/self-plan-and-send-functions.ts
|
|
88
|
+
function addSelfPlanAndSendFunctions(client, input) {
|
|
89
|
+
if (isPromiseLike(input)) {
|
|
90
|
+
const newInput = input;
|
|
91
|
+
newInput.planTransaction = async (config) => await client.planTransaction(await input, config);
|
|
92
|
+
newInput.planTransactions = async (config) => await client.planTransactions(await input, config);
|
|
93
|
+
newInput.sendTransaction = async (config) => await client.sendTransaction(await input, config);
|
|
94
|
+
newInput.sendTransactions = async (config) => await client.sendTransactions(await input, config);
|
|
95
|
+
return newInput;
|
|
96
|
+
}
|
|
97
|
+
return Object.freeze({
|
|
98
|
+
...input,
|
|
99
|
+
planTransaction: (config) => client.planTransaction(input, config),
|
|
100
|
+
planTransactions: (config) => client.planTransactions(input, config),
|
|
101
|
+
sendTransaction: (config) => client.sendTransaction(input, config),
|
|
102
|
+
sendTransactions: (config) => client.sendTransactions(input, config)
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function isPromiseLike(item) {
|
|
106
|
+
return !!item && (typeof item === "object" || typeof item === "function") && typeof item.then === "function";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
exports.addSelfFetchFunctions = addSelfFetchFunctions;
|
|
110
|
+
exports.addSelfPlanAndSendFunctions = addSelfPlanAndSendFunctions;
|
|
111
|
+
exports.getAccountMetaFactory = getAccountMetaFactory;
|
|
112
|
+
exports.getAddressFromResolvedInstructionAccount = getAddressFromResolvedInstructionAccount;
|
|
113
|
+
exports.getNonNullResolvedInstructionInput = getNonNullResolvedInstructionInput;
|
|
114
|
+
exports.getResolvedInstructionAccountAsProgramDerivedAddress = getResolvedInstructionAccountAsProgramDerivedAddress;
|
|
115
|
+
exports.getResolvedInstructionAccountAsTransactionSigner = getResolvedInstructionAccountAsTransactionSigner;
|
|
116
|
+
//# sourceMappingURL=index.browser.cjs.map
|
|
117
|
+
//# sourceMappingURL=index.browser.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/instruction-input-resolution.ts","../src/self-fetch-functions.ts","../src/self-plan-and-send-functions.ts"],"names":["SolanaError","SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL","isProgramDerivedAddress","SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE","AccountRole","upgradeRoleToSigner","isTransactionSigner","fetchEncodedAccount","decodeAccount","fetchEncodedAccounts","assertAccountExists","assertAccountsExist"],"mappings":"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","file":"index.browser.cjs","sourcesContent":["import { type Address, isProgramDerivedAddress, type ProgramDerivedAddress } from '@solana/addresses';\nimport {\n SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL,\n SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE,\n SolanaError,\n} from '@solana/errors';\nimport { type AccountMeta, AccountRole, upgradeRoleToSigner } from '@solana/instructions';\nimport { type AccountSignerMeta, isTransactionSigner, type TransactionSigner } from '@solana/signers';\n\n/**\n * Ensures a resolved instruction input is not null or undefined.\n *\n * This function is used during instruction resolution to validate that\n * required inputs have been properly resolved to a non-null value.\n *\n * @typeParam T - The expected type of the resolved input value.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved value to validate.\n * @returns The validated non-null value.\n *\n * @throws Throws a {@link SolanaError} if the value is null or undefined.\n *\n * @example\n * ```ts\n * const resolvedAuthority = getNonNullResolvedInstructionInput(\n * 'authority',\n * maybeAuthority\n * );\n * // resolvedAuthority is guaranteed to be non-null here.\n * ```\n */\nexport function getNonNullResolvedInstructionInput<T>(inputName: string, value: T | null | undefined): T {\n if (value === null || value === undefined) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, {\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Extracts the address from a resolved instruction account.\n *\n * A resolved instruction account can be an {@link Address}, a {@link ProgramDerivedAddress},\n * or a {@link TransactionSigner}. This function extracts the underlying address from\n * any of these types.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value to extract the address from.\n * @returns The extracted address.\n *\n * @throws Throws a {@link SolanaError} if the value is null or undefined.\n *\n * @example\n * ```ts\n * const address = getAddressFromResolvedInstructionAccount('mint', resolvedMint);\n * ```\n */\nexport function getAddressFromResolvedInstructionAccount<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): Address<T> {\n const nonNullValue = getNonNullResolvedInstructionInput(inputName, value);\n if (typeof value === 'object' && 'address' in nonNullValue) {\n return nonNullValue.address;\n }\n if (Array.isArray(nonNullValue)) {\n return nonNullValue[0] as Address<T>;\n }\n return nonNullValue as Address<T>;\n}\n\n/**\n * Extracts a {@link ProgramDerivedAddress} from a resolved instruction account.\n *\n * This function validates that the resolved account is a PDA and returns it.\n * Use this when you need access to both the address and the bump seed of a PDA.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value expected to be a PDA.\n * @returns The program-derived address.\n *\n * @throws Throws a {@link SolanaError} if the value is not a {@link ProgramDerivedAddress}.\n *\n * @example\n * ```ts\n * const pda = getResolvedInstructionAccountAsProgramDerivedAddress('metadata', resolvedMetadata);\n * const [address, bump] = pda;\n * ```\n */\nexport function getResolvedInstructionAccountAsProgramDerivedAddress<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): ProgramDerivedAddress<T> {\n if (!isProgramDerivedAddress(value)) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {\n expectedType: 'ProgramDerivedAddress',\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Extracts a {@link TransactionSigner} from a resolved instruction account.\n *\n * This function validates that the resolved account is a transaction signer and returns it.\n * Use this when you need the resolved account to be a signer.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value expected to be a signer.\n * @returns The transaction signer.\n *\n * @throws Throws a {@link SolanaError} if the value is not a {@link TransactionSigner}.\n *\n * @example\n * ```ts\n * const signer = getResolvedInstructionAccountAsTransactionSigner('authority', resolvedAuthority);\n * ```\n */\nexport function getResolvedInstructionAccountAsTransactionSigner<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): TransactionSigner<T> {\n if (!isResolvedInstructionAccountSigner(value)) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {\n expectedType: 'TransactionSigner',\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Represents a resolved account input for an instruction.\n *\n * During instruction building, account inputs are resolved to this type which\n * captures both the account value and whether it should be marked as writable.\n * The value can be an {@link Address}, a {@link ProgramDerivedAddress}, a\n * {@link TransactionSigner}, or `null` for optional accounts.\n *\n * @typeParam TAddress - The address type, defaults to `string`.\n * @typeParam TValue - The type of the resolved value.\n *\n * @example\n * ```ts\n * const mintAccount: ResolvedInstructionAccount = {\n * value: mintAddress,\n * isWritable: true,\n * };\n * ```\n */\nexport type ResolvedInstructionAccount<\n TAddress extends string = string,\n TValue extends Address<TAddress> | ProgramDerivedAddress<TAddress> | TransactionSigner<TAddress> | null =\n | Address<TAddress>\n | ProgramDerivedAddress<TAddress>\n | TransactionSigner<TAddress>\n | null,\n> = {\n isWritable: boolean;\n value: TValue;\n};\n\n/**\n * Creates a factory function that converts resolved instruction accounts to account metas.\n *\n * The factory handles the conversion of {@link ResolvedInstructionAccount} objects into\n * {@link AccountMeta} or {@link AccountSignerMeta} objects suitable for building instructions.\n * It also determines how to handle optional accounts based on the provided strategy.\n *\n * @param programAddress - The program address, used when optional accounts use the `programId` strategy.\n * @param optionalAccountStrategy - How to handle null account values:\n * - `'omitted'`: Optional accounts are excluded from the instruction entirely.\n * - `'programId'`: Optional accounts are replaced with the program address as a read-only account.\n * @returns A factory function that converts a resolved account to an account meta.\n *\n * @example\n * ```ts\n * const toAccountMeta = getAccountMetaFactory(programAddress, 'programId');\n * const mintMeta = toAccountMeta('mint', resolvedMint);\n * ```\n */\nexport function getAccountMetaFactory(programAddress: Address, optionalAccountStrategy: 'omitted' | 'programId') {\n return (inputName: string, account: ResolvedInstructionAccount): AccountMeta | AccountSignerMeta | undefined => {\n if (!account.value) {\n if (optionalAccountStrategy === 'omitted') return;\n return Object.freeze({ address: programAddress, role: AccountRole.READONLY });\n }\n\n const writableRole = account.isWritable ? AccountRole.WRITABLE : AccountRole.READONLY;\n const isSigner = isResolvedInstructionAccountSigner(account.value);\n return Object.freeze({\n address: getAddressFromResolvedInstructionAccount(inputName, account.value),\n role: isSigner ? upgradeRoleToSigner(writableRole) : writableRole,\n ...(isSigner ? { signer: account.value } : {}),\n });\n };\n}\n\nfunction isResolvedInstructionAccountSigner(value: unknown): value is TransactionSigner {\n return (\n !!value &&\n typeof value === 'object' &&\n 'address' in value &&\n typeof value.address === 'string' &&\n isTransactionSigner(value as { address: Address })\n );\n}\n","import {\n type Account,\n assertAccountExists,\n assertAccountsExist,\n decodeAccount,\n type FetchAccountConfig,\n type FetchAccountsConfig,\n fetchEncodedAccount,\n fetchEncodedAccounts,\n type MaybeAccount,\n} from '@solana/accounts';\nimport type { Address } from '@solana/addresses';\nimport type { Codec } from '@solana/codecs-core';\nimport type { ClientWithRpc } from '@solana/plugin-interfaces';\nimport type { GetAccountInfoApi, GetMultipleAccountsApi } from '@solana/rpc-api';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyObjectCodec = Codec<any, object>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferTFrom<T> = T extends Codec<infer TFrom, any> ? TFrom : never;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferTTo<T> = T extends Codec<any, infer TTo> ? TTo : never;\n\n/**\n * Methods that allow a codec to fetch and decode accounts directly.\n *\n * These methods are added to codec objects via {@link addSelfFetchFunctions},\n * enabling a fluent API where you can call `.fetch()` directly on a codec\n * to retrieve and decode accounts in one step.\n *\n * @typeParam TFrom - The type that the codec encodes from.\n * @typeParam TTo - The type that the codec decodes to.\n *\n * @example\n * Fetching a single account and asserting it exists.\n * ```ts\n * const account = await myAccountCodec.fetch(address);\n * // account.data is of type TTo.\n * ```\n *\n * @example\n * Fetching a single account that may not exist.\n * ```ts\n * const maybeAccount = await myAccountCodec.fetchMaybe(address);\n * if (maybeAccount.exists) {\n * // maybeAccount.data is of type TTo.\n * }\n * ```\n *\n * @example\n * Fetching multiple accounts at once.\n * ```ts\n * const accounts = await myAccountCodec.fetchAll([addressA, addressB]);\n * // All accounts exist.\n * ```\n *\n * @see {@link addSelfFetchFunctions}\n */\nexport type SelfFetchFunctions<TFrom extends object, TTo extends TFrom> = {\n /** Fetches and decodes a single account, throwing if it does not exist. */\n readonly fetch: <TAddress extends string>(\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n ) => Promise<Account<TTo, TAddress>>;\n /** Fetches and decodes multiple accounts, throwing if any do not exist. */\n readonly fetchAll: (addresses: Address[], config?: FetchAccountsConfig) => Promise<Account<TTo>[]>;\n /** Fetches and decodes multiple accounts, returning {@link MaybeAccount} for each. */\n readonly fetchAllMaybe: (addresses: Address[], config?: FetchAccountsConfig) => Promise<MaybeAccount<TTo>[]>;\n /** Fetches and decodes a single account, returning a {@link MaybeAccount}. */\n readonly fetchMaybe: <TAddress extends string>(\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n ) => Promise<MaybeAccount<TTo, TAddress>>;\n};\n\n/**\n * Adds self-fetching methods to a codec for retrieving and decoding accounts.\n *\n * This function augments the provided codec with methods that allow it to fetch\n * accounts from the network and decode them in one step. It enables a fluent API\n * where you can call methods like `.fetch()` directly on the codec.\n *\n * @typeParam TFrom - The type that the codec encodes from.\n * @typeParam TTo - The type that the codec decodes to.\n * @typeParam TCodec - The codec type being augmented.\n *\n * @param client - A client that provides RPC access for fetching accounts.\n * @param codec - The codec to augment with self-fetch methods.\n * @returns The codec augmented with {@link SelfFetchFunctions} methods.\n *\n * @example\n * Adding self-fetch functions to an account codec.\n * ```ts\n * import { addSelfFetchFunctions } from '@solana/program-client-core';\n *\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * // Fetch and decode an account in one step.\n * const account = await myAccountCodec.fetch(accountAddress);\n * ```\n *\n * @example\n * Handling accounts that may not exist.\n * ```ts\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * const maybeAccount = await myAccountCodec.fetchMaybe(accountAddress);\n * if (maybeAccount.exists) {\n * console.log('Account data:', maybeAccount.data);\n * } else {\n * console.log(`Account ${maybeAccount.address} does not exist`);\n * }\n * ```\n *\n * @example\n * Fetching multiple accounts at once.\n * ```ts\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * // Throws if any account does not exist.\n * const accounts = await myAccountCodec.fetchAll([addressA, addressB, addressC]);\n *\n * // Returns MaybeAccount for each, allowing some to not exist.\n * const maybeAccounts = await myAccountCodec.fetchAllMaybe([addressA, addressB]);\n * ```\n *\n * @see {@link SelfFetchFunctions}\n */\nexport function addSelfFetchFunctions<TCodec extends AnyObjectCodec>(\n client: ClientWithRpc<GetAccountInfoApi & GetMultipleAccountsApi>,\n codec: TCodec,\n): SelfFetchFunctions<InferTFrom<TCodec>, InferTTo<TCodec>> & TCodec {\n type Functions = SelfFetchFunctions<InferTFrom<TCodec>, InferTTo<TCodec>>;\n type InferredCodec = Codec<InferTFrom<TCodec>, InferTTo<TCodec>>;\n const fetchMaybe: Functions['fetchMaybe'] = async (address, config?) => {\n const maybeAccount = await fetchEncodedAccount(client.rpc, address, config);\n return decodeAccount(maybeAccount, codec as InferredCodec);\n };\n const fetchAllMaybe: Functions['fetchAllMaybe'] = async (addresses, config?) => {\n const maybeAccounts = await fetchEncodedAccounts(client.rpc, addresses, config);\n return maybeAccounts.map(maybeAccount => decodeAccount(maybeAccount, codec as InferredCodec));\n };\n const fetch: Functions['fetch'] = async (address, config?) => {\n const maybeAccount = await fetchMaybe(address, config);\n assertAccountExists(maybeAccount);\n return maybeAccount;\n };\n const fetchAll: Functions['fetchAll'] = async (addresses, config?) => {\n const maybeAccounts = await fetchAllMaybe(addresses, config);\n assertAccountsExist(maybeAccounts);\n return maybeAccounts;\n };\n\n const out = { ...codec, fetch, fetchAll, fetchAllMaybe, fetchMaybe };\n return Object.freeze<typeof out>(out);\n}\n","import type { InstructionPlan } from '@solana/instruction-plans';\nimport type { Instruction } from '@solana/instructions';\nimport type { ClientWithTransactionPlanning, ClientWithTransactionSending } from '@solana/plugin-interfaces';\n\ntype PlanTransaction = ClientWithTransactionPlanning['planTransaction'];\ntype PlanTransactions = ClientWithTransactionPlanning['planTransactions'];\ntype SendTransaction = ClientWithTransactionSending['sendTransaction'];\ntype SendTransactions = ClientWithTransactionSending['sendTransactions'];\n\n/**\n * Methods that allow an instruction or instruction plan to plan and send itself.\n *\n * These methods are added to instruction or instruction plan objects via\n * {@link addSelfPlanAndSendFunctions}, enabling a fluent API where you can call\n * `.sendTransaction()` directly on an instruction without passing it to a separate function.\n *\n * @example\n * Sending a transfer instruction directly.\n * ```ts\n * const result = await getTransferInstruction({ source, destination, amount }).sendTransaction();\n * ```\n *\n * @example\n * Planning multiple transactions from an instruction plan.\n * ```ts\n * const plan = await getComplexInstructionPlan(/* ... *\\/).planTransactions();\n * ```\n *\n * @see {@link addSelfPlanAndSendFunctions}\n */\nexport type SelfPlanAndSendFunctions = {\n /** Plans a single transaction. */\n planTransaction: (config?: Parameters<PlanTransaction>[1]) => ReturnType<PlanTransaction>;\n /** Plans one or more transactions. */\n planTransactions: (config?: Parameters<PlanTransactions>[1]) => ReturnType<PlanTransactions>;\n /** Sends a single transaction. */\n sendTransaction: (config?: Parameters<SendTransaction>[1]) => ReturnType<SendTransaction>;\n /** Sends one or more transactions. */\n sendTransactions: (config?: Parameters<SendTransactions>[1]) => ReturnType<SendTransactions>;\n};\n\n/**\n * Adds self-planning and self-sending methods to an instruction or instruction plan.\n *\n * This function augments the provided instruction or instruction plan with methods\n * that allow it to plan and send itself using the provided client. It enables a fluent API\n * where you can call methods like `.sendTransaction()` directly on the instruction.\n *\n * The function supports both synchronous inputs (instructions, instruction plans) and\n * promise-like inputs, making it suitable for use with async instruction builders.\n *\n * @typeParam TItem - The type of the instruction, instruction plan, or a promise resolving to one.\n *\n * @param client - A client that provides transaction planning and sending capabilities.\n * @param input - The instruction, instruction plan, or promise to augment with self-plan/send methods.\n * @returns The input augmented with {@link SelfPlanAndSendFunctions} methods.\n *\n * @example\n * Adding self-plan and send to a transfer instruction.\n * ```ts\n * import { addSelfPlanAndSendFunctions } from '@solana/program-client-core';\n *\n * const transferInstruction = addSelfPlanAndSendFunctions(\n * client,\n * getTransferInstruction({ payer, source, destination, amount })\n * );\n *\n * // Now you can send directly from the instruction.\n * const result = await transferInstruction.sendTransaction();\n * ```\n *\n * @example\n * Using with an async instruction builder.\n * ```ts\n * const asyncInstruction = addSelfPlanAndSendFunctions(\n * client,\n * fetchAndBuildInstruction(/* ... *\\/)\n * );\n *\n * // The promise is augmented with self-plan/send methods.\n * const result = await asyncInstruction.sendTransaction();\n * ```\n *\n * @see {@link SelfPlanAndSendFunctions}\n */\nexport function addSelfPlanAndSendFunctions<\n TItem extends Instruction | InstructionPlan | PromiseLike<Instruction> | PromiseLike<InstructionPlan>,\n>(\n client: ClientWithTransactionPlanning & ClientWithTransactionSending,\n input: TItem,\n): SelfPlanAndSendFunctions & TItem {\n if (isPromiseLike(input)) {\n const newInput = input as SelfPlanAndSendFunctions & TItem;\n newInput.planTransaction = async config => await client.planTransaction(await input, config);\n newInput.planTransactions = async config => await client.planTransactions(await input, config);\n newInput.sendTransaction = async config => await client.sendTransaction(await input, config);\n newInput.sendTransactions = async config => await client.sendTransactions(await input, config);\n return newInput;\n }\n\n return Object.freeze(<SelfPlanAndSendFunctions & (Instruction | InstructionPlan)>{\n ...input,\n planTransaction: config => client.planTransaction(input, config),\n planTransactions: config => client.planTransactions(input, config),\n sendTransaction: config => client.sendTransaction(input, config),\n sendTransactions: config => client.sendTransactions(input, config),\n }) as unknown as SelfPlanAndSendFunctions & TItem;\n}\n\nfunction isPromiseLike(\n item: Instruction | InstructionPlan | PromiseLike<Instruction> | PromiseLike<InstructionPlan>,\n): item is PromiseLike<Instruction> | PromiseLike<InstructionPlan> {\n return (\n !!item &&\n (typeof item === 'object' || typeof item === 'function') &&\n typeof (item as PromiseLike<unknown>).then === 'function'\n );\n}\n"]}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { isProgramDerivedAddress } from '@solana/addresses';
|
|
2
|
+
import { SolanaError, SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE } from '@solana/errors';
|
|
3
|
+
import { AccountRole, upgradeRoleToSigner } from '@solana/instructions';
|
|
4
|
+
import { isTransactionSigner } from '@solana/signers';
|
|
5
|
+
import { fetchEncodedAccount, decodeAccount, fetchEncodedAccounts, assertAccountExists, assertAccountsExist } from '@solana/accounts';
|
|
6
|
+
|
|
7
|
+
// src/instruction-input-resolution.ts
|
|
8
|
+
function getNonNullResolvedInstructionInput(inputName, value) {
|
|
9
|
+
if (value === null || value === void 0) {
|
|
10
|
+
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, {
|
|
11
|
+
inputName
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function getAddressFromResolvedInstructionAccount(inputName, value) {
|
|
17
|
+
const nonNullValue = getNonNullResolvedInstructionInput(inputName, value);
|
|
18
|
+
if (typeof value === "object" && "address" in nonNullValue) {
|
|
19
|
+
return nonNullValue.address;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(nonNullValue)) {
|
|
22
|
+
return nonNullValue[0];
|
|
23
|
+
}
|
|
24
|
+
return nonNullValue;
|
|
25
|
+
}
|
|
26
|
+
function getResolvedInstructionAccountAsProgramDerivedAddress(inputName, value) {
|
|
27
|
+
if (!isProgramDerivedAddress(value)) {
|
|
28
|
+
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {
|
|
29
|
+
expectedType: "ProgramDerivedAddress",
|
|
30
|
+
inputName
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function getResolvedInstructionAccountAsTransactionSigner(inputName, value) {
|
|
36
|
+
if (!isResolvedInstructionAccountSigner(value)) {
|
|
37
|
+
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {
|
|
38
|
+
expectedType: "TransactionSigner",
|
|
39
|
+
inputName
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function getAccountMetaFactory(programAddress, optionalAccountStrategy) {
|
|
45
|
+
return (inputName, account) => {
|
|
46
|
+
if (!account.value) {
|
|
47
|
+
if (optionalAccountStrategy === "omitted") return;
|
|
48
|
+
return Object.freeze({ address: programAddress, role: AccountRole.READONLY });
|
|
49
|
+
}
|
|
50
|
+
const writableRole = account.isWritable ? AccountRole.WRITABLE : AccountRole.READONLY;
|
|
51
|
+
const isSigner = isResolvedInstructionAccountSigner(account.value);
|
|
52
|
+
return Object.freeze({
|
|
53
|
+
address: getAddressFromResolvedInstructionAccount(inputName, account.value),
|
|
54
|
+
role: isSigner ? upgradeRoleToSigner(writableRole) : writableRole,
|
|
55
|
+
...isSigner ? { signer: account.value } : {}
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function isResolvedInstructionAccountSigner(value) {
|
|
60
|
+
return !!value && typeof value === "object" && "address" in value && typeof value.address === "string" && isTransactionSigner(value);
|
|
61
|
+
}
|
|
62
|
+
function addSelfFetchFunctions(client, codec) {
|
|
63
|
+
const fetchMaybe = async (address, config) => {
|
|
64
|
+
const maybeAccount = await fetchEncodedAccount(client.rpc, address, config);
|
|
65
|
+
return decodeAccount(maybeAccount, codec);
|
|
66
|
+
};
|
|
67
|
+
const fetchAllMaybe = async (addresses, config) => {
|
|
68
|
+
const maybeAccounts = await fetchEncodedAccounts(client.rpc, addresses, config);
|
|
69
|
+
return maybeAccounts.map((maybeAccount) => decodeAccount(maybeAccount, codec));
|
|
70
|
+
};
|
|
71
|
+
const fetch = async (address, config) => {
|
|
72
|
+
const maybeAccount = await fetchMaybe(address, config);
|
|
73
|
+
assertAccountExists(maybeAccount);
|
|
74
|
+
return maybeAccount;
|
|
75
|
+
};
|
|
76
|
+
const fetchAll = async (addresses, config) => {
|
|
77
|
+
const maybeAccounts = await fetchAllMaybe(addresses, config);
|
|
78
|
+
assertAccountsExist(maybeAccounts);
|
|
79
|
+
return maybeAccounts;
|
|
80
|
+
};
|
|
81
|
+
const out = { ...codec, fetch, fetchAll, fetchAllMaybe, fetchMaybe };
|
|
82
|
+
return Object.freeze(out);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/self-plan-and-send-functions.ts
|
|
86
|
+
function addSelfPlanAndSendFunctions(client, input) {
|
|
87
|
+
if (isPromiseLike(input)) {
|
|
88
|
+
const newInput = input;
|
|
89
|
+
newInput.planTransaction = async (config) => await client.planTransaction(await input, config);
|
|
90
|
+
newInput.planTransactions = async (config) => await client.planTransactions(await input, config);
|
|
91
|
+
newInput.sendTransaction = async (config) => await client.sendTransaction(await input, config);
|
|
92
|
+
newInput.sendTransactions = async (config) => await client.sendTransactions(await input, config);
|
|
93
|
+
return newInput;
|
|
94
|
+
}
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
...input,
|
|
97
|
+
planTransaction: (config) => client.planTransaction(input, config),
|
|
98
|
+
planTransactions: (config) => client.planTransactions(input, config),
|
|
99
|
+
sendTransaction: (config) => client.sendTransaction(input, config),
|
|
100
|
+
sendTransactions: (config) => client.sendTransactions(input, config)
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function isPromiseLike(item) {
|
|
104
|
+
return !!item && (typeof item === "object" || typeof item === "function") && typeof item.then === "function";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { addSelfFetchFunctions, addSelfPlanAndSendFunctions, getAccountMetaFactory, getAddressFromResolvedInstructionAccount, getNonNullResolvedInstructionInput, getResolvedInstructionAccountAsProgramDerivedAddress, getResolvedInstructionAccountAsTransactionSigner };
|
|
108
|
+
//# sourceMappingURL=index.browser.mjs.map
|
|
109
|
+
//# sourceMappingURL=index.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/instruction-input-resolution.ts","../src/self-fetch-functions.ts","../src/self-plan-and-send-functions.ts"],"names":[],"mappings":"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","file":"index.browser.mjs","sourcesContent":["import { type Address, isProgramDerivedAddress, type ProgramDerivedAddress } from '@solana/addresses';\nimport {\n SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL,\n SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE,\n SolanaError,\n} from '@solana/errors';\nimport { type AccountMeta, AccountRole, upgradeRoleToSigner } from '@solana/instructions';\nimport { type AccountSignerMeta, isTransactionSigner, type TransactionSigner } from '@solana/signers';\n\n/**\n * Ensures a resolved instruction input is not null or undefined.\n *\n * This function is used during instruction resolution to validate that\n * required inputs have been properly resolved to a non-null value.\n *\n * @typeParam T - The expected type of the resolved input value.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved value to validate.\n * @returns The validated non-null value.\n *\n * @throws Throws a {@link SolanaError} if the value is null or undefined.\n *\n * @example\n * ```ts\n * const resolvedAuthority = getNonNullResolvedInstructionInput(\n * 'authority',\n * maybeAuthority\n * );\n * // resolvedAuthority is guaranteed to be non-null here.\n * ```\n */\nexport function getNonNullResolvedInstructionInput<T>(inputName: string, value: T | null | undefined): T {\n if (value === null || value === undefined) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, {\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Extracts the address from a resolved instruction account.\n *\n * A resolved instruction account can be an {@link Address}, a {@link ProgramDerivedAddress},\n * or a {@link TransactionSigner}. This function extracts the underlying address from\n * any of these types.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value to extract the address from.\n * @returns The extracted address.\n *\n * @throws Throws a {@link SolanaError} if the value is null or undefined.\n *\n * @example\n * ```ts\n * const address = getAddressFromResolvedInstructionAccount('mint', resolvedMint);\n * ```\n */\nexport function getAddressFromResolvedInstructionAccount<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): Address<T> {\n const nonNullValue = getNonNullResolvedInstructionInput(inputName, value);\n if (typeof value === 'object' && 'address' in nonNullValue) {\n return nonNullValue.address;\n }\n if (Array.isArray(nonNullValue)) {\n return nonNullValue[0] as Address<T>;\n }\n return nonNullValue as Address<T>;\n}\n\n/**\n * Extracts a {@link ProgramDerivedAddress} from a resolved instruction account.\n *\n * This function validates that the resolved account is a PDA and returns it.\n * Use this when you need access to both the address and the bump seed of a PDA.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value expected to be a PDA.\n * @returns The program-derived address.\n *\n * @throws Throws a {@link SolanaError} if the value is not a {@link ProgramDerivedAddress}.\n *\n * @example\n * ```ts\n * const pda = getResolvedInstructionAccountAsProgramDerivedAddress('metadata', resolvedMetadata);\n * const [address, bump] = pda;\n * ```\n */\nexport function getResolvedInstructionAccountAsProgramDerivedAddress<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): ProgramDerivedAddress<T> {\n if (!isProgramDerivedAddress(value)) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {\n expectedType: 'ProgramDerivedAddress',\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Extracts a {@link TransactionSigner} from a resolved instruction account.\n *\n * This function validates that the resolved account is a transaction signer and returns it.\n * Use this when you need the resolved account to be a signer.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value expected to be a signer.\n * @returns The transaction signer.\n *\n * @throws Throws a {@link SolanaError} if the value is not a {@link TransactionSigner}.\n *\n * @example\n * ```ts\n * const signer = getResolvedInstructionAccountAsTransactionSigner('authority', resolvedAuthority);\n * ```\n */\nexport function getResolvedInstructionAccountAsTransactionSigner<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): TransactionSigner<T> {\n if (!isResolvedInstructionAccountSigner(value)) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {\n expectedType: 'TransactionSigner',\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Represents a resolved account input for an instruction.\n *\n * During instruction building, account inputs are resolved to this type which\n * captures both the account value and whether it should be marked as writable.\n * The value can be an {@link Address}, a {@link ProgramDerivedAddress}, a\n * {@link TransactionSigner}, or `null` for optional accounts.\n *\n * @typeParam TAddress - The address type, defaults to `string`.\n * @typeParam TValue - The type of the resolved value.\n *\n * @example\n * ```ts\n * const mintAccount: ResolvedInstructionAccount = {\n * value: mintAddress,\n * isWritable: true,\n * };\n * ```\n */\nexport type ResolvedInstructionAccount<\n TAddress extends string = string,\n TValue extends Address<TAddress> | ProgramDerivedAddress<TAddress> | TransactionSigner<TAddress> | null =\n | Address<TAddress>\n | ProgramDerivedAddress<TAddress>\n | TransactionSigner<TAddress>\n | null,\n> = {\n isWritable: boolean;\n value: TValue;\n};\n\n/**\n * Creates a factory function that converts resolved instruction accounts to account metas.\n *\n * The factory handles the conversion of {@link ResolvedInstructionAccount} objects into\n * {@link AccountMeta} or {@link AccountSignerMeta} objects suitable for building instructions.\n * It also determines how to handle optional accounts based on the provided strategy.\n *\n * @param programAddress - The program address, used when optional accounts use the `programId` strategy.\n * @param optionalAccountStrategy - How to handle null account values:\n * - `'omitted'`: Optional accounts are excluded from the instruction entirely.\n * - `'programId'`: Optional accounts are replaced with the program address as a read-only account.\n * @returns A factory function that converts a resolved account to an account meta.\n *\n * @example\n * ```ts\n * const toAccountMeta = getAccountMetaFactory(programAddress, 'programId');\n * const mintMeta = toAccountMeta('mint', resolvedMint);\n * ```\n */\nexport function getAccountMetaFactory(programAddress: Address, optionalAccountStrategy: 'omitted' | 'programId') {\n return (inputName: string, account: ResolvedInstructionAccount): AccountMeta | AccountSignerMeta | undefined => {\n if (!account.value) {\n if (optionalAccountStrategy === 'omitted') return;\n return Object.freeze({ address: programAddress, role: AccountRole.READONLY });\n }\n\n const writableRole = account.isWritable ? AccountRole.WRITABLE : AccountRole.READONLY;\n const isSigner = isResolvedInstructionAccountSigner(account.value);\n return Object.freeze({\n address: getAddressFromResolvedInstructionAccount(inputName, account.value),\n role: isSigner ? upgradeRoleToSigner(writableRole) : writableRole,\n ...(isSigner ? { signer: account.value } : {}),\n });\n };\n}\n\nfunction isResolvedInstructionAccountSigner(value: unknown): value is TransactionSigner {\n return (\n !!value &&\n typeof value === 'object' &&\n 'address' in value &&\n typeof value.address === 'string' &&\n isTransactionSigner(value as { address: Address })\n );\n}\n","import {\n type Account,\n assertAccountExists,\n assertAccountsExist,\n decodeAccount,\n type FetchAccountConfig,\n type FetchAccountsConfig,\n fetchEncodedAccount,\n fetchEncodedAccounts,\n type MaybeAccount,\n} from '@solana/accounts';\nimport type { Address } from '@solana/addresses';\nimport type { Codec } from '@solana/codecs-core';\nimport type { ClientWithRpc } from '@solana/plugin-interfaces';\nimport type { GetAccountInfoApi, GetMultipleAccountsApi } from '@solana/rpc-api';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyObjectCodec = Codec<any, object>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferTFrom<T> = T extends Codec<infer TFrom, any> ? TFrom : never;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferTTo<T> = T extends Codec<any, infer TTo> ? TTo : never;\n\n/**\n * Methods that allow a codec to fetch and decode accounts directly.\n *\n * These methods are added to codec objects via {@link addSelfFetchFunctions},\n * enabling a fluent API where you can call `.fetch()` directly on a codec\n * to retrieve and decode accounts in one step.\n *\n * @typeParam TFrom - The type that the codec encodes from.\n * @typeParam TTo - The type that the codec decodes to.\n *\n * @example\n * Fetching a single account and asserting it exists.\n * ```ts\n * const account = await myAccountCodec.fetch(address);\n * // account.data is of type TTo.\n * ```\n *\n * @example\n * Fetching a single account that may not exist.\n * ```ts\n * const maybeAccount = await myAccountCodec.fetchMaybe(address);\n * if (maybeAccount.exists) {\n * // maybeAccount.data is of type TTo.\n * }\n * ```\n *\n * @example\n * Fetching multiple accounts at once.\n * ```ts\n * const accounts = await myAccountCodec.fetchAll([addressA, addressB]);\n * // All accounts exist.\n * ```\n *\n * @see {@link addSelfFetchFunctions}\n */\nexport type SelfFetchFunctions<TFrom extends object, TTo extends TFrom> = {\n /** Fetches and decodes a single account, throwing if it does not exist. */\n readonly fetch: <TAddress extends string>(\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n ) => Promise<Account<TTo, TAddress>>;\n /** Fetches and decodes multiple accounts, throwing if any do not exist. */\n readonly fetchAll: (addresses: Address[], config?: FetchAccountsConfig) => Promise<Account<TTo>[]>;\n /** Fetches and decodes multiple accounts, returning {@link MaybeAccount} for each. */\n readonly fetchAllMaybe: (addresses: Address[], config?: FetchAccountsConfig) => Promise<MaybeAccount<TTo>[]>;\n /** Fetches and decodes a single account, returning a {@link MaybeAccount}. */\n readonly fetchMaybe: <TAddress extends string>(\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n ) => Promise<MaybeAccount<TTo, TAddress>>;\n};\n\n/**\n * Adds self-fetching methods to a codec for retrieving and decoding accounts.\n *\n * This function augments the provided codec with methods that allow it to fetch\n * accounts from the network and decode them in one step. It enables a fluent API\n * where you can call methods like `.fetch()` directly on the codec.\n *\n * @typeParam TFrom - The type that the codec encodes from.\n * @typeParam TTo - The type that the codec decodes to.\n * @typeParam TCodec - The codec type being augmented.\n *\n * @param client - A client that provides RPC access for fetching accounts.\n * @param codec - The codec to augment with self-fetch methods.\n * @returns The codec augmented with {@link SelfFetchFunctions} methods.\n *\n * @example\n * Adding self-fetch functions to an account codec.\n * ```ts\n * import { addSelfFetchFunctions } from '@solana/program-client-core';\n *\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * // Fetch and decode an account in one step.\n * const account = await myAccountCodec.fetch(accountAddress);\n * ```\n *\n * @example\n * Handling accounts that may not exist.\n * ```ts\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * const maybeAccount = await myAccountCodec.fetchMaybe(accountAddress);\n * if (maybeAccount.exists) {\n * console.log('Account data:', maybeAccount.data);\n * } else {\n * console.log(`Account ${maybeAccount.address} does not exist`);\n * }\n * ```\n *\n * @example\n * Fetching multiple accounts at once.\n * ```ts\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * // Throws if any account does not exist.\n * const accounts = await myAccountCodec.fetchAll([addressA, addressB, addressC]);\n *\n * // Returns MaybeAccount for each, allowing some to not exist.\n * const maybeAccounts = await myAccountCodec.fetchAllMaybe([addressA, addressB]);\n * ```\n *\n * @see {@link SelfFetchFunctions}\n */\nexport function addSelfFetchFunctions<TCodec extends AnyObjectCodec>(\n client: ClientWithRpc<GetAccountInfoApi & GetMultipleAccountsApi>,\n codec: TCodec,\n): SelfFetchFunctions<InferTFrom<TCodec>, InferTTo<TCodec>> & TCodec {\n type Functions = SelfFetchFunctions<InferTFrom<TCodec>, InferTTo<TCodec>>;\n type InferredCodec = Codec<InferTFrom<TCodec>, InferTTo<TCodec>>;\n const fetchMaybe: Functions['fetchMaybe'] = async (address, config?) => {\n const maybeAccount = await fetchEncodedAccount(client.rpc, address, config);\n return decodeAccount(maybeAccount, codec as InferredCodec);\n };\n const fetchAllMaybe: Functions['fetchAllMaybe'] = async (addresses, config?) => {\n const maybeAccounts = await fetchEncodedAccounts(client.rpc, addresses, config);\n return maybeAccounts.map(maybeAccount => decodeAccount(maybeAccount, codec as InferredCodec));\n };\n const fetch: Functions['fetch'] = async (address, config?) => {\n const maybeAccount = await fetchMaybe(address, config);\n assertAccountExists(maybeAccount);\n return maybeAccount;\n };\n const fetchAll: Functions['fetchAll'] = async (addresses, config?) => {\n const maybeAccounts = await fetchAllMaybe(addresses, config);\n assertAccountsExist(maybeAccounts);\n return maybeAccounts;\n };\n\n const out = { ...codec, fetch, fetchAll, fetchAllMaybe, fetchMaybe };\n return Object.freeze<typeof out>(out);\n}\n","import type { InstructionPlan } from '@solana/instruction-plans';\nimport type { Instruction } from '@solana/instructions';\nimport type { ClientWithTransactionPlanning, ClientWithTransactionSending } from '@solana/plugin-interfaces';\n\ntype PlanTransaction = ClientWithTransactionPlanning['planTransaction'];\ntype PlanTransactions = ClientWithTransactionPlanning['planTransactions'];\ntype SendTransaction = ClientWithTransactionSending['sendTransaction'];\ntype SendTransactions = ClientWithTransactionSending['sendTransactions'];\n\n/**\n * Methods that allow an instruction or instruction plan to plan and send itself.\n *\n * These methods are added to instruction or instruction plan objects via\n * {@link addSelfPlanAndSendFunctions}, enabling a fluent API where you can call\n * `.sendTransaction()` directly on an instruction without passing it to a separate function.\n *\n * @example\n * Sending a transfer instruction directly.\n * ```ts\n * const result = await getTransferInstruction({ source, destination, amount }).sendTransaction();\n * ```\n *\n * @example\n * Planning multiple transactions from an instruction plan.\n * ```ts\n * const plan = await getComplexInstructionPlan(/* ... *\\/).planTransactions();\n * ```\n *\n * @see {@link addSelfPlanAndSendFunctions}\n */\nexport type SelfPlanAndSendFunctions = {\n /** Plans a single transaction. */\n planTransaction: (config?: Parameters<PlanTransaction>[1]) => ReturnType<PlanTransaction>;\n /** Plans one or more transactions. */\n planTransactions: (config?: Parameters<PlanTransactions>[1]) => ReturnType<PlanTransactions>;\n /** Sends a single transaction. */\n sendTransaction: (config?: Parameters<SendTransaction>[1]) => ReturnType<SendTransaction>;\n /** Sends one or more transactions. */\n sendTransactions: (config?: Parameters<SendTransactions>[1]) => ReturnType<SendTransactions>;\n};\n\n/**\n * Adds self-planning and self-sending methods to an instruction or instruction plan.\n *\n * This function augments the provided instruction or instruction plan with methods\n * that allow it to plan and send itself using the provided client. It enables a fluent API\n * where you can call methods like `.sendTransaction()` directly on the instruction.\n *\n * The function supports both synchronous inputs (instructions, instruction plans) and\n * promise-like inputs, making it suitable for use with async instruction builders.\n *\n * @typeParam TItem - The type of the instruction, instruction plan, or a promise resolving to one.\n *\n * @param client - A client that provides transaction planning and sending capabilities.\n * @param input - The instruction, instruction plan, or promise to augment with self-plan/send methods.\n * @returns The input augmented with {@link SelfPlanAndSendFunctions} methods.\n *\n * @example\n * Adding self-plan and send to a transfer instruction.\n * ```ts\n * import { addSelfPlanAndSendFunctions } from '@solana/program-client-core';\n *\n * const transferInstruction = addSelfPlanAndSendFunctions(\n * client,\n * getTransferInstruction({ payer, source, destination, amount })\n * );\n *\n * // Now you can send directly from the instruction.\n * const result = await transferInstruction.sendTransaction();\n * ```\n *\n * @example\n * Using with an async instruction builder.\n * ```ts\n * const asyncInstruction = addSelfPlanAndSendFunctions(\n * client,\n * fetchAndBuildInstruction(/* ... *\\/)\n * );\n *\n * // The promise is augmented with self-plan/send methods.\n * const result = await asyncInstruction.sendTransaction();\n * ```\n *\n * @see {@link SelfPlanAndSendFunctions}\n */\nexport function addSelfPlanAndSendFunctions<\n TItem extends Instruction | InstructionPlan | PromiseLike<Instruction> | PromiseLike<InstructionPlan>,\n>(\n client: ClientWithTransactionPlanning & ClientWithTransactionSending,\n input: TItem,\n): SelfPlanAndSendFunctions & TItem {\n if (isPromiseLike(input)) {\n const newInput = input as SelfPlanAndSendFunctions & TItem;\n newInput.planTransaction = async config => await client.planTransaction(await input, config);\n newInput.planTransactions = async config => await client.planTransactions(await input, config);\n newInput.sendTransaction = async config => await client.sendTransaction(await input, config);\n newInput.sendTransactions = async config => await client.sendTransactions(await input, config);\n return newInput;\n }\n\n return Object.freeze(<SelfPlanAndSendFunctions & (Instruction | InstructionPlan)>{\n ...input,\n planTransaction: config => client.planTransaction(input, config),\n planTransactions: config => client.planTransactions(input, config),\n sendTransaction: config => client.sendTransaction(input, config),\n sendTransactions: config => client.sendTransactions(input, config),\n }) as unknown as SelfPlanAndSendFunctions & TItem;\n}\n\nfunction isPromiseLike(\n item: Instruction | InstructionPlan | PromiseLike<Instruction> | PromiseLike<InstructionPlan>,\n): item is PromiseLike<Instruction> | PromiseLike<InstructionPlan> {\n return (\n !!item &&\n (typeof item === 'object' || typeof item === 'function') &&\n typeof (item as PromiseLike<unknown>).then === 'function'\n );\n}\n"]}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { isProgramDerivedAddress } from '@solana/addresses';
|
|
2
|
+
import { SolanaError, SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE } from '@solana/errors';
|
|
3
|
+
import { AccountRole, upgradeRoleToSigner } from '@solana/instructions';
|
|
4
|
+
import { isTransactionSigner } from '@solana/signers';
|
|
5
|
+
import { fetchEncodedAccount, decodeAccount, fetchEncodedAccounts, assertAccountExists, assertAccountsExist } from '@solana/accounts';
|
|
6
|
+
|
|
7
|
+
// src/instruction-input-resolution.ts
|
|
8
|
+
function getNonNullResolvedInstructionInput(inputName, value) {
|
|
9
|
+
if (value === null || value === void 0) {
|
|
10
|
+
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, {
|
|
11
|
+
inputName
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function getAddressFromResolvedInstructionAccount(inputName, value) {
|
|
17
|
+
const nonNullValue = getNonNullResolvedInstructionInput(inputName, value);
|
|
18
|
+
if (typeof value === "object" && "address" in nonNullValue) {
|
|
19
|
+
return nonNullValue.address;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(nonNullValue)) {
|
|
22
|
+
return nonNullValue[0];
|
|
23
|
+
}
|
|
24
|
+
return nonNullValue;
|
|
25
|
+
}
|
|
26
|
+
function getResolvedInstructionAccountAsProgramDerivedAddress(inputName, value) {
|
|
27
|
+
if (!isProgramDerivedAddress(value)) {
|
|
28
|
+
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {
|
|
29
|
+
expectedType: "ProgramDerivedAddress",
|
|
30
|
+
inputName
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function getResolvedInstructionAccountAsTransactionSigner(inputName, value) {
|
|
36
|
+
if (!isResolvedInstructionAccountSigner(value)) {
|
|
37
|
+
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {
|
|
38
|
+
expectedType: "TransactionSigner",
|
|
39
|
+
inputName
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function getAccountMetaFactory(programAddress, optionalAccountStrategy) {
|
|
45
|
+
return (inputName, account) => {
|
|
46
|
+
if (!account.value) {
|
|
47
|
+
if (optionalAccountStrategy === "omitted") return;
|
|
48
|
+
return Object.freeze({ address: programAddress, role: AccountRole.READONLY });
|
|
49
|
+
}
|
|
50
|
+
const writableRole = account.isWritable ? AccountRole.WRITABLE : AccountRole.READONLY;
|
|
51
|
+
const isSigner = isResolvedInstructionAccountSigner(account.value);
|
|
52
|
+
return Object.freeze({
|
|
53
|
+
address: getAddressFromResolvedInstructionAccount(inputName, account.value),
|
|
54
|
+
role: isSigner ? upgradeRoleToSigner(writableRole) : writableRole,
|
|
55
|
+
...isSigner ? { signer: account.value } : {}
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function isResolvedInstructionAccountSigner(value) {
|
|
60
|
+
return !!value && typeof value === "object" && "address" in value && typeof value.address === "string" && isTransactionSigner(value);
|
|
61
|
+
}
|
|
62
|
+
function addSelfFetchFunctions(client, codec) {
|
|
63
|
+
const fetchMaybe = async (address, config) => {
|
|
64
|
+
const maybeAccount = await fetchEncodedAccount(client.rpc, address, config);
|
|
65
|
+
return decodeAccount(maybeAccount, codec);
|
|
66
|
+
};
|
|
67
|
+
const fetchAllMaybe = async (addresses, config) => {
|
|
68
|
+
const maybeAccounts = await fetchEncodedAccounts(client.rpc, addresses, config);
|
|
69
|
+
return maybeAccounts.map((maybeAccount) => decodeAccount(maybeAccount, codec));
|
|
70
|
+
};
|
|
71
|
+
const fetch = async (address, config) => {
|
|
72
|
+
const maybeAccount = await fetchMaybe(address, config);
|
|
73
|
+
assertAccountExists(maybeAccount);
|
|
74
|
+
return maybeAccount;
|
|
75
|
+
};
|
|
76
|
+
const fetchAll = async (addresses, config) => {
|
|
77
|
+
const maybeAccounts = await fetchAllMaybe(addresses, config);
|
|
78
|
+
assertAccountsExist(maybeAccounts);
|
|
79
|
+
return maybeAccounts;
|
|
80
|
+
};
|
|
81
|
+
const out = { ...codec, fetch, fetchAll, fetchAllMaybe, fetchMaybe };
|
|
82
|
+
return Object.freeze(out);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/self-plan-and-send-functions.ts
|
|
86
|
+
function addSelfPlanAndSendFunctions(client, input) {
|
|
87
|
+
if (isPromiseLike(input)) {
|
|
88
|
+
const newInput = input;
|
|
89
|
+
newInput.planTransaction = async (config) => await client.planTransaction(await input, config);
|
|
90
|
+
newInput.planTransactions = async (config) => await client.planTransactions(await input, config);
|
|
91
|
+
newInput.sendTransaction = async (config) => await client.sendTransaction(await input, config);
|
|
92
|
+
newInput.sendTransactions = async (config) => await client.sendTransactions(await input, config);
|
|
93
|
+
return newInput;
|
|
94
|
+
}
|
|
95
|
+
return Object.freeze({
|
|
96
|
+
...input,
|
|
97
|
+
planTransaction: (config) => client.planTransaction(input, config),
|
|
98
|
+
planTransactions: (config) => client.planTransactions(input, config),
|
|
99
|
+
sendTransaction: (config) => client.sendTransaction(input, config),
|
|
100
|
+
sendTransactions: (config) => client.sendTransactions(input, config)
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function isPromiseLike(item) {
|
|
104
|
+
return !!item && (typeof item === "object" || typeof item === "function") && typeof item.then === "function";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export { addSelfFetchFunctions, addSelfPlanAndSendFunctions, getAccountMetaFactory, getAddressFromResolvedInstructionAccount, getNonNullResolvedInstructionInput, getResolvedInstructionAccountAsProgramDerivedAddress, getResolvedInstructionAccountAsTransactionSigner };
|
|
108
|
+
//# sourceMappingURL=index.native.mjs.map
|
|
109
|
+
//# sourceMappingURL=index.native.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/instruction-input-resolution.ts","../src/self-fetch-functions.ts","../src/self-plan-and-send-functions.ts"],"names":[],"mappings":"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","file":"index.native.mjs","sourcesContent":["import { type Address, isProgramDerivedAddress, type ProgramDerivedAddress } from '@solana/addresses';\nimport {\n SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL,\n SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE,\n SolanaError,\n} from '@solana/errors';\nimport { type AccountMeta, AccountRole, upgradeRoleToSigner } from '@solana/instructions';\nimport { type AccountSignerMeta, isTransactionSigner, type TransactionSigner } from '@solana/signers';\n\n/**\n * Ensures a resolved instruction input is not null or undefined.\n *\n * This function is used during instruction resolution to validate that\n * required inputs have been properly resolved to a non-null value.\n *\n * @typeParam T - The expected type of the resolved input value.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved value to validate.\n * @returns The validated non-null value.\n *\n * @throws Throws a {@link SolanaError} if the value is null or undefined.\n *\n * @example\n * ```ts\n * const resolvedAuthority = getNonNullResolvedInstructionInput(\n * 'authority',\n * maybeAuthority\n * );\n * // resolvedAuthority is guaranteed to be non-null here.\n * ```\n */\nexport function getNonNullResolvedInstructionInput<T>(inputName: string, value: T | null | undefined): T {\n if (value === null || value === undefined) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__RESOLVED_INSTRUCTION_INPUT_MUST_BE_NON_NULL, {\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Extracts the address from a resolved instruction account.\n *\n * A resolved instruction account can be an {@link Address}, a {@link ProgramDerivedAddress},\n * or a {@link TransactionSigner}. This function extracts the underlying address from\n * any of these types.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value to extract the address from.\n * @returns The extracted address.\n *\n * @throws Throws a {@link SolanaError} if the value is null or undefined.\n *\n * @example\n * ```ts\n * const address = getAddressFromResolvedInstructionAccount('mint', resolvedMint);\n * ```\n */\nexport function getAddressFromResolvedInstructionAccount<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): Address<T> {\n const nonNullValue = getNonNullResolvedInstructionInput(inputName, value);\n if (typeof value === 'object' && 'address' in nonNullValue) {\n return nonNullValue.address;\n }\n if (Array.isArray(nonNullValue)) {\n return nonNullValue[0] as Address<T>;\n }\n return nonNullValue as Address<T>;\n}\n\n/**\n * Extracts a {@link ProgramDerivedAddress} from a resolved instruction account.\n *\n * This function validates that the resolved account is a PDA and returns it.\n * Use this when you need access to both the address and the bump seed of a PDA.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value expected to be a PDA.\n * @returns The program-derived address.\n *\n * @throws Throws a {@link SolanaError} if the value is not a {@link ProgramDerivedAddress}.\n *\n * @example\n * ```ts\n * const pda = getResolvedInstructionAccountAsProgramDerivedAddress('metadata', resolvedMetadata);\n * const [address, bump] = pda;\n * ```\n */\nexport function getResolvedInstructionAccountAsProgramDerivedAddress<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): ProgramDerivedAddress<T> {\n if (!isProgramDerivedAddress(value)) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {\n expectedType: 'ProgramDerivedAddress',\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Extracts a {@link TransactionSigner} from a resolved instruction account.\n *\n * This function validates that the resolved account is a transaction signer and returns it.\n * Use this when you need the resolved account to be a signer.\n *\n * @typeParam T - The address type, defaults to `string`.\n *\n * @param inputName - The name of the instruction input, used in error messages.\n * @param value - The resolved account value expected to be a signer.\n * @returns The transaction signer.\n *\n * @throws Throws a {@link SolanaError} if the value is not a {@link TransactionSigner}.\n *\n * @example\n * ```ts\n * const signer = getResolvedInstructionAccountAsTransactionSigner('authority', resolvedAuthority);\n * ```\n */\nexport function getResolvedInstructionAccountAsTransactionSigner<T extends string = string>(\n inputName: string,\n value: ResolvedInstructionAccount<T>['value'] | undefined,\n): TransactionSigner<T> {\n if (!isResolvedInstructionAccountSigner(value)) {\n throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNEXPECTED_RESOLVED_INSTRUCTION_INPUT_TYPE, {\n expectedType: 'TransactionSigner',\n inputName,\n });\n }\n return value;\n}\n\n/**\n * Represents a resolved account input for an instruction.\n *\n * During instruction building, account inputs are resolved to this type which\n * captures both the account value and whether it should be marked as writable.\n * The value can be an {@link Address}, a {@link ProgramDerivedAddress}, a\n * {@link TransactionSigner}, or `null` for optional accounts.\n *\n * @typeParam TAddress - The address type, defaults to `string`.\n * @typeParam TValue - The type of the resolved value.\n *\n * @example\n * ```ts\n * const mintAccount: ResolvedInstructionAccount = {\n * value: mintAddress,\n * isWritable: true,\n * };\n * ```\n */\nexport type ResolvedInstructionAccount<\n TAddress extends string = string,\n TValue extends Address<TAddress> | ProgramDerivedAddress<TAddress> | TransactionSigner<TAddress> | null =\n | Address<TAddress>\n | ProgramDerivedAddress<TAddress>\n | TransactionSigner<TAddress>\n | null,\n> = {\n isWritable: boolean;\n value: TValue;\n};\n\n/**\n * Creates a factory function that converts resolved instruction accounts to account metas.\n *\n * The factory handles the conversion of {@link ResolvedInstructionAccount} objects into\n * {@link AccountMeta} or {@link AccountSignerMeta} objects suitable for building instructions.\n * It also determines how to handle optional accounts based on the provided strategy.\n *\n * @param programAddress - The program address, used when optional accounts use the `programId` strategy.\n * @param optionalAccountStrategy - How to handle null account values:\n * - `'omitted'`: Optional accounts are excluded from the instruction entirely.\n * - `'programId'`: Optional accounts are replaced with the program address as a read-only account.\n * @returns A factory function that converts a resolved account to an account meta.\n *\n * @example\n * ```ts\n * const toAccountMeta = getAccountMetaFactory(programAddress, 'programId');\n * const mintMeta = toAccountMeta('mint', resolvedMint);\n * ```\n */\nexport function getAccountMetaFactory(programAddress: Address, optionalAccountStrategy: 'omitted' | 'programId') {\n return (inputName: string, account: ResolvedInstructionAccount): AccountMeta | AccountSignerMeta | undefined => {\n if (!account.value) {\n if (optionalAccountStrategy === 'omitted') return;\n return Object.freeze({ address: programAddress, role: AccountRole.READONLY });\n }\n\n const writableRole = account.isWritable ? AccountRole.WRITABLE : AccountRole.READONLY;\n const isSigner = isResolvedInstructionAccountSigner(account.value);\n return Object.freeze({\n address: getAddressFromResolvedInstructionAccount(inputName, account.value),\n role: isSigner ? upgradeRoleToSigner(writableRole) : writableRole,\n ...(isSigner ? { signer: account.value } : {}),\n });\n };\n}\n\nfunction isResolvedInstructionAccountSigner(value: unknown): value is TransactionSigner {\n return (\n !!value &&\n typeof value === 'object' &&\n 'address' in value &&\n typeof value.address === 'string' &&\n isTransactionSigner(value as { address: Address })\n );\n}\n","import {\n type Account,\n assertAccountExists,\n assertAccountsExist,\n decodeAccount,\n type FetchAccountConfig,\n type FetchAccountsConfig,\n fetchEncodedAccount,\n fetchEncodedAccounts,\n type MaybeAccount,\n} from '@solana/accounts';\nimport type { Address } from '@solana/addresses';\nimport type { Codec } from '@solana/codecs-core';\nimport type { ClientWithRpc } from '@solana/plugin-interfaces';\nimport type { GetAccountInfoApi, GetMultipleAccountsApi } from '@solana/rpc-api';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyObjectCodec = Codec<any, object>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferTFrom<T> = T extends Codec<infer TFrom, any> ? TFrom : never;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InferTTo<T> = T extends Codec<any, infer TTo> ? TTo : never;\n\n/**\n * Methods that allow a codec to fetch and decode accounts directly.\n *\n * These methods are added to codec objects via {@link addSelfFetchFunctions},\n * enabling a fluent API where you can call `.fetch()` directly on a codec\n * to retrieve and decode accounts in one step.\n *\n * @typeParam TFrom - The type that the codec encodes from.\n * @typeParam TTo - The type that the codec decodes to.\n *\n * @example\n * Fetching a single account and asserting it exists.\n * ```ts\n * const account = await myAccountCodec.fetch(address);\n * // account.data is of type TTo.\n * ```\n *\n * @example\n * Fetching a single account that may not exist.\n * ```ts\n * const maybeAccount = await myAccountCodec.fetchMaybe(address);\n * if (maybeAccount.exists) {\n * // maybeAccount.data is of type TTo.\n * }\n * ```\n *\n * @example\n * Fetching multiple accounts at once.\n * ```ts\n * const accounts = await myAccountCodec.fetchAll([addressA, addressB]);\n * // All accounts exist.\n * ```\n *\n * @see {@link addSelfFetchFunctions}\n */\nexport type SelfFetchFunctions<TFrom extends object, TTo extends TFrom> = {\n /** Fetches and decodes a single account, throwing if it does not exist. */\n readonly fetch: <TAddress extends string>(\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n ) => Promise<Account<TTo, TAddress>>;\n /** Fetches and decodes multiple accounts, throwing if any do not exist. */\n readonly fetchAll: (addresses: Address[], config?: FetchAccountsConfig) => Promise<Account<TTo>[]>;\n /** Fetches and decodes multiple accounts, returning {@link MaybeAccount} for each. */\n readonly fetchAllMaybe: (addresses: Address[], config?: FetchAccountsConfig) => Promise<MaybeAccount<TTo>[]>;\n /** Fetches and decodes a single account, returning a {@link MaybeAccount}. */\n readonly fetchMaybe: <TAddress extends string>(\n address: Address<TAddress>,\n config?: FetchAccountConfig,\n ) => Promise<MaybeAccount<TTo, TAddress>>;\n};\n\n/**\n * Adds self-fetching methods to a codec for retrieving and decoding accounts.\n *\n * This function augments the provided codec with methods that allow it to fetch\n * accounts from the network and decode them in one step. It enables a fluent API\n * where you can call methods like `.fetch()` directly on the codec.\n *\n * @typeParam TFrom - The type that the codec encodes from.\n * @typeParam TTo - The type that the codec decodes to.\n * @typeParam TCodec - The codec type being augmented.\n *\n * @param client - A client that provides RPC access for fetching accounts.\n * @param codec - The codec to augment with self-fetch methods.\n * @returns The codec augmented with {@link SelfFetchFunctions} methods.\n *\n * @example\n * Adding self-fetch functions to an account codec.\n * ```ts\n * import { addSelfFetchFunctions } from '@solana/program-client-core';\n *\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * // Fetch and decode an account in one step.\n * const account = await myAccountCodec.fetch(accountAddress);\n * ```\n *\n * @example\n * Handling accounts that may not exist.\n * ```ts\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * const maybeAccount = await myAccountCodec.fetchMaybe(accountAddress);\n * if (maybeAccount.exists) {\n * console.log('Account data:', maybeAccount.data);\n * } else {\n * console.log(`Account ${maybeAccount.address} does not exist`);\n * }\n * ```\n *\n * @example\n * Fetching multiple accounts at once.\n * ```ts\n * const myAccountCodec = addSelfFetchFunctions(client, getMyAccountCodec());\n *\n * // Throws if any account does not exist.\n * const accounts = await myAccountCodec.fetchAll([addressA, addressB, addressC]);\n *\n * // Returns MaybeAccount for each, allowing some to not exist.\n * const maybeAccounts = await myAccountCodec.fetchAllMaybe([addressA, addressB]);\n * ```\n *\n * @see {@link SelfFetchFunctions}\n */\nexport function addSelfFetchFunctions<TCodec extends AnyObjectCodec>(\n client: ClientWithRpc<GetAccountInfoApi & GetMultipleAccountsApi>,\n codec: TCodec,\n): SelfFetchFunctions<InferTFrom<TCodec>, InferTTo<TCodec>> & TCodec {\n type Functions = SelfFetchFunctions<InferTFrom<TCodec>, InferTTo<TCodec>>;\n type InferredCodec = Codec<InferTFrom<TCodec>, InferTTo<TCodec>>;\n const fetchMaybe: Functions['fetchMaybe'] = async (address, config?) => {\n const maybeAccount = await fetchEncodedAccount(client.rpc, address, config);\n return decodeAccount(maybeAccount, codec as InferredCodec);\n };\n const fetchAllMaybe: Functions['fetchAllMaybe'] = async (addresses, config?) => {\n const maybeAccounts = await fetchEncodedAccounts(client.rpc, addresses, config);\n return maybeAccounts.map(maybeAccount => decodeAccount(maybeAccount, codec as InferredCodec));\n };\n const fetch: Functions['fetch'] = async (address, config?) => {\n const maybeAccount = await fetchMaybe(address, config);\n assertAccountExists(maybeAccount);\n return maybeAccount;\n };\n const fetchAll: Functions['fetchAll'] = async (addresses, config?) => {\n const maybeAccounts = await fetchAllMaybe(addresses, config);\n assertAccountsExist(maybeAccounts);\n return maybeAccounts;\n };\n\n const out = { ...codec, fetch, fetchAll, fetchAllMaybe, fetchMaybe };\n return Object.freeze<typeof out>(out);\n}\n","import type { InstructionPlan } from '@solana/instruction-plans';\nimport type { Instruction } from '@solana/instructions';\nimport type { ClientWithTransactionPlanning, ClientWithTransactionSending } from '@solana/plugin-interfaces';\n\ntype PlanTransaction = ClientWithTransactionPlanning['planTransaction'];\ntype PlanTransactions = ClientWithTransactionPlanning['planTransactions'];\ntype SendTransaction = ClientWithTransactionSending['sendTransaction'];\ntype SendTransactions = ClientWithTransactionSending['sendTransactions'];\n\n/**\n * Methods that allow an instruction or instruction plan to plan and send itself.\n *\n * These methods are added to instruction or instruction plan objects via\n * {@link addSelfPlanAndSendFunctions}, enabling a fluent API where you can call\n * `.sendTransaction()` directly on an instruction without passing it to a separate function.\n *\n * @example\n * Sending a transfer instruction directly.\n * ```ts\n * const result = await getTransferInstruction({ source, destination, amount }).sendTransaction();\n * ```\n *\n * @example\n * Planning multiple transactions from an instruction plan.\n * ```ts\n * const plan = await getComplexInstructionPlan(/* ... *\\/).planTransactions();\n * ```\n *\n * @see {@link addSelfPlanAndSendFunctions}\n */\nexport type SelfPlanAndSendFunctions = {\n /** Plans a single transaction. */\n planTransaction: (config?: Parameters<PlanTransaction>[1]) => ReturnType<PlanTransaction>;\n /** Plans one or more transactions. */\n planTransactions: (config?: Parameters<PlanTransactions>[1]) => ReturnType<PlanTransactions>;\n /** Sends a single transaction. */\n sendTransaction: (config?: Parameters<SendTransaction>[1]) => ReturnType<SendTransaction>;\n /** Sends one or more transactions. */\n sendTransactions: (config?: Parameters<SendTransactions>[1]) => ReturnType<SendTransactions>;\n};\n\n/**\n * Adds self-planning and self-sending methods to an instruction or instruction plan.\n *\n * This function augments the provided instruction or instruction plan with methods\n * that allow it to plan and send itself using the provided client. It enables a fluent API\n * where you can call methods like `.sendTransaction()` directly on the instruction.\n *\n * The function supports both synchronous inputs (instructions, instruction plans) and\n * promise-like inputs, making it suitable for use with async instruction builders.\n *\n * @typeParam TItem - The type of the instruction, instruction plan, or a promise resolving to one.\n *\n * @param client - A client that provides transaction planning and sending capabilities.\n * @param input - The instruction, instruction plan, or promise to augment with self-plan/send methods.\n * @returns The input augmented with {@link SelfPlanAndSendFunctions} methods.\n *\n * @example\n * Adding self-plan and send to a transfer instruction.\n * ```ts\n * import { addSelfPlanAndSendFunctions } from '@solana/program-client-core';\n *\n * const transferInstruction = addSelfPlanAndSendFunctions(\n * client,\n * getTransferInstruction({ payer, source, destination, amount })\n * );\n *\n * // Now you can send directly from the instruction.\n * const result = await transferInstruction.sendTransaction();\n * ```\n *\n * @example\n * Using with an async instruction builder.\n * ```ts\n * const asyncInstruction = addSelfPlanAndSendFunctions(\n * client,\n * fetchAndBuildInstruction(/* ... *\\/)\n * );\n *\n * // The promise is augmented with self-plan/send methods.\n * const result = await asyncInstruction.sendTransaction();\n * ```\n *\n * @see {@link SelfPlanAndSendFunctions}\n */\nexport function addSelfPlanAndSendFunctions<\n TItem extends Instruction | InstructionPlan | PromiseLike<Instruction> | PromiseLike<InstructionPlan>,\n>(\n client: ClientWithTransactionPlanning & ClientWithTransactionSending,\n input: TItem,\n): SelfPlanAndSendFunctions & TItem {\n if (isPromiseLike(input)) {\n const newInput = input as SelfPlanAndSendFunctions & TItem;\n newInput.planTransaction = async config => await client.planTransaction(await input, config);\n newInput.planTransactions = async config => await client.planTransactions(await input, config);\n newInput.sendTransaction = async config => await client.sendTransaction(await input, config);\n newInput.sendTransactions = async config => await client.sendTransactions(await input, config);\n return newInput;\n }\n\n return Object.freeze(<SelfPlanAndSendFunctions & (Instruction | InstructionPlan)>{\n ...input,\n planTransaction: config => client.planTransaction(input, config),\n planTransactions: config => client.planTransactions(input, config),\n sendTransaction: config => client.sendTransaction(input, config),\n sendTransactions: config => client.sendTransactions(input, config),\n }) as unknown as SelfPlanAndSendFunctions & TItem;\n}\n\nfunction isPromiseLike(\n item: Instruction | InstructionPlan | PromiseLike<Instruction> | PromiseLike<InstructionPlan>,\n): item is PromiseLike<Instruction> | PromiseLike<InstructionPlan> {\n return (\n !!item &&\n (typeof item === 'object' || typeof item === 'function') &&\n typeof (item as PromiseLike<unknown>).then === 'function'\n );\n}\n"]}
|