@solana/instructions 6.3.1 → 6.3.2-canary-20260313112147

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/instructions",
3
- "version": "6.3.1",
3
+ "version": "6.3.2-canary-20260313112147",
4
4
  "description": "Helpers for creating transaction instructions",
5
5
  "homepage": "https://www.solanakit.com/api#solanainstructions",
6
6
  "exports": {
@@ -33,7 +33,8 @@
33
33
  "types": "./dist/types/index.d.ts",
34
34
  "type": "commonjs",
35
35
  "files": [
36
- "./dist/"
36
+ "./dist/",
37
+ "./src/"
37
38
  ],
38
39
  "sideEffects": false,
39
40
  "keywords": [
@@ -55,8 +56,8 @@
55
56
  "maintained node versions"
56
57
  ],
57
58
  "dependencies": {
58
- "@solana/codecs-core": "6.3.1",
59
- "@solana/errors": "6.3.1"
59
+ "@solana/codecs-core": "6.3.2-canary-20260313112147",
60
+ "@solana/errors": "6.3.2-canary-20260313112147"
60
61
  },
61
62
  "peerDependencies": {
62
63
  "typescript": "^5.0.0"
@@ -0,0 +1,92 @@
1
+ import { Address } from '@solana/addresses';
2
+
3
+ import { AccountRole } from './roles';
4
+
5
+ /**
6
+ * Represents an account's address and metadata about its mutability and whether it must be a signer
7
+ * of the transaction.
8
+ *
9
+ * Typically, you will use one of its subtypes.
10
+ *
11
+ * | | `role` | `isSigner` | `isWritable` |
12
+ * | --------------------------------- | ----------------------------- | ---------- | ------------ |
13
+ * | `ReadonlyAccount<TAddress>` | `AccountRole.READONLY` | No | No |
14
+ * | `WritableAccount<TAddress>` | `AccountRole.WRITABLE` | No | Yes |
15
+ * | `ReadonlySignerAccount<TAddress>` | `AccountRole.READONLY_SIGNER` | Yes | No |
16
+ * | `WritableSignerAccount<TAddress>` | `AccountRole.WRITABLE_SIGNER` | Yes | Yes |
17
+ *
18
+ * @example A type for the Rent sysvar account
19
+ * ```ts
20
+ * type RentSysvar = ReadonlyAccount<'SysvarRent111111111111111111111111111111111'>;
21
+ * ```
22
+ */
23
+ export interface AccountMeta<TAddress extends string = string> {
24
+ readonly address: Address<TAddress>;
25
+ readonly role: AccountRole;
26
+ }
27
+
28
+ /**
29
+ * @see {@link AccountMeta}
30
+ */
31
+ export type ReadonlyAccount<TAddress extends string = string> = AccountMeta<TAddress> & {
32
+ readonly role: AccountRole.READONLY;
33
+ };
34
+ /**
35
+ * @see {@link AccountMeta}
36
+ */
37
+ export type WritableAccount<TAddress extends string = string> = AccountMeta<TAddress> & { role: AccountRole.WRITABLE };
38
+ /**
39
+ * @see {@link AccountMeta}
40
+ */
41
+ export type ReadonlySignerAccount<TAddress extends string = string> = AccountMeta<TAddress> & {
42
+ role: AccountRole.READONLY_SIGNER;
43
+ };
44
+ /**
45
+ * @see {@link AccountMeta}
46
+ */
47
+ export type WritableSignerAccount<TAddress extends string = string> = AccountMeta<TAddress> & {
48
+ role: AccountRole.WRITABLE_SIGNER;
49
+ };
50
+
51
+ /**
52
+ * Represents a lookup of the account's address in an address lookup table. It specifies which
53
+ * lookup table account in which to perform the lookup, the index of the desired account address in
54
+ * that table, and metadata about its mutability. Notably, account addresses obtained via lookups
55
+ * may not act as signers.
56
+ *
57
+ * Typically, you will use one of its subtypes.
58
+ *
59
+ * | | `role` | `isSigner` | `isWritable` |
60
+ * | ------------------------------------------------------ | ---------------------- | ---------- | ------------ |
61
+ * | `ReadonlyLookupAccount<TAddress, TLookupTableAddress>` | `AccountRole.READONLY` | No | No |
62
+ * | `WritableLookupAccount<TAddress, TLookupTableAddress>` | `AccountRole.WRITABLE` | No | Yes |
63
+ *
64
+ * @example A type for the Rent sysvar account that you looked up in a lookup table
65
+ * ```ts
66
+ * type RentSysvar = ReadonlyLookupAccount<
67
+ * 'SysvarRent111111111111111111111111111111111',
68
+ * 'MyLookupTable111111111111111111111111111111'
69
+ * >;
70
+ * ```
71
+ */
72
+ export interface AccountLookupMeta<TAddress extends string = string, TLookupTableAddress extends string = string> {
73
+ readonly address: Address<TAddress>;
74
+ readonly addressIndex: number;
75
+ readonly lookupTableAddress: Address<TLookupTableAddress>;
76
+ readonly role: AccountRole.READONLY | AccountRole.WRITABLE;
77
+ }
78
+
79
+ /**
80
+ * @see {@link AccountLookupMeta}
81
+ */
82
+ export type ReadonlyAccountLookup<
83
+ TAddress extends string = string,
84
+ TLookupTableAddress extends string = string,
85
+ > = AccountLookupMeta<TAddress, TLookupTableAddress> & { readonly role: AccountRole.READONLY };
86
+ /**
87
+ * @see {@link AccountLookupMeta}
88
+ */
89
+ export type WritableAccountLookup<
90
+ TAddress extends string = string,
91
+ TLookupTableAddress extends string = string,
92
+ > = AccountLookupMeta<TAddress, TLookupTableAddress> & { readonly role: AccountRole.WRITABLE };
package/src/index.ts ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * This package contains types for creating transaction instructions. It can be used standalone, but it is also exported as part of Kit [`@solana/kit`](https://github.com/anza-xyz/kit/tree/main/packages/kit).
3
+ * @packageDocumentation
4
+ */
5
+ export * from './accounts';
6
+ export * from './instruction';
7
+ export * from './roles';
@@ -0,0 +1,129 @@
1
+ import { Address } from '@solana/addresses';
2
+ import { ReadonlyUint8Array } from '@solana/codecs-core';
3
+ import {
4
+ SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_ACCOUNTS,
5
+ SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_DATA,
6
+ SOLANA_ERROR__INSTRUCTION__PROGRAM_ID_MISMATCH,
7
+ SolanaError,
8
+ } from '@solana/errors';
9
+
10
+ import { AccountLookupMeta, AccountMeta } from './accounts';
11
+
12
+ /**
13
+ * An instruction destined for a given program.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * type StakeProgramInstruction = Instruction<'StakeConfig11111111111111111111111111111111'>;
18
+ * ```
19
+ */
20
+ export interface Instruction<
21
+ TProgramAddress extends string = string,
22
+ TAccounts extends readonly (AccountLookupMeta | AccountMeta)[] = readonly (AccountLookupMeta | AccountMeta)[],
23
+ > {
24
+ readonly accounts?: TAccounts;
25
+ readonly data?: ReadonlyUint8Array;
26
+ readonly programAddress: Address<TProgramAddress>;
27
+ }
28
+
29
+ /**
30
+ * An instruction that loads certain accounts.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * type InstructionWithTwoAccounts = InstructionWithAccounts<
35
+ * [
36
+ * WritableAccount, // First account
37
+ * RentSysvar, // Second account
38
+ * ]
39
+ * >;
40
+ * ```
41
+ */
42
+ export interface InstructionWithAccounts<
43
+ TAccounts extends readonly (AccountLookupMeta | AccountMeta)[],
44
+ > extends Instruction {
45
+ readonly accounts: TAccounts;
46
+ }
47
+
48
+ export function isInstructionForProgram<TProgramAddress extends string, TInstruction extends Instruction>(
49
+ instruction: TInstruction,
50
+ programAddress: Address<TProgramAddress>,
51
+ ): instruction is TInstruction & { programAddress: Address<TProgramAddress> } {
52
+ return instruction.programAddress === programAddress;
53
+ }
54
+
55
+ export function assertIsInstructionForProgram<TProgramAddress extends string, TInstruction extends Instruction>(
56
+ instruction: TInstruction,
57
+ programAddress: Address<TProgramAddress>,
58
+ ): asserts instruction is TInstruction & { programAddress: Address<TProgramAddress> } {
59
+ if (instruction.programAddress !== programAddress) {
60
+ throw new SolanaError(SOLANA_ERROR__INSTRUCTION__PROGRAM_ID_MISMATCH, {
61
+ actualProgramAddress: instruction.programAddress,
62
+ expectedProgramAddress: programAddress,
63
+ });
64
+ }
65
+ }
66
+
67
+ export function isInstructionWithAccounts<
68
+ TAccounts extends readonly (AccountLookupMeta | AccountMeta)[] = readonly (AccountLookupMeta | AccountMeta)[],
69
+ TInstruction extends Instruction = Instruction,
70
+ >(instruction: TInstruction): instruction is InstructionWithAccounts<TAccounts> & TInstruction {
71
+ return instruction.accounts !== undefined;
72
+ }
73
+
74
+ export function assertIsInstructionWithAccounts<
75
+ TAccounts extends readonly (AccountLookupMeta | AccountMeta)[] = readonly (AccountLookupMeta | AccountMeta)[],
76
+ TInstruction extends Instruction = Instruction,
77
+ >(instruction: TInstruction): asserts instruction is InstructionWithAccounts<TAccounts> & TInstruction {
78
+ if (instruction.accounts === undefined) {
79
+ throw new SolanaError(SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_ACCOUNTS, {
80
+ data: instruction.data,
81
+ programAddress: instruction.programAddress,
82
+ });
83
+ }
84
+ }
85
+
86
+ /**
87
+ * An instruction whose data conforms to a certain type.
88
+ *
89
+ * This is most useful when you have a branded `Uint8Array` that represents a particular
90
+ * instruction's data.
91
+ *
92
+ * @example A type for the \`AdvanceNonce\` instruction of the System program
93
+ * ```ts
94
+ * type AdvanceNonceAccountInstruction<
95
+ * TNonceAccountAddress extends string = string,
96
+ * TNonceAuthorityAddress extends string = string,
97
+ * > = Instruction<'11111111111111111111111111111111'> &
98
+ * InstructionWithAccounts<
99
+ * [
100
+ * WritableAccount<TNonceAccountAddress>,
101
+ * ReadonlyAccount<'SysvarRecentB1ockHashes11111111111111111111'>,
102
+ * ReadonlySignerAccount<TNonceAuthorityAddress>,
103
+ * ]
104
+ * > &
105
+ * InstructionWithData<AdvanceNonceAccountInstructionData>;
106
+ * ```
107
+ */
108
+ export interface InstructionWithData<TData extends ReadonlyUint8Array> extends Instruction {
109
+ readonly data: TData;
110
+ }
111
+
112
+ export function isInstructionWithData<
113
+ TData extends ReadonlyUint8Array = ReadonlyUint8Array,
114
+ TInstruction extends Instruction = Instruction,
115
+ >(instruction: TInstruction): instruction is InstructionWithData<TData> & TInstruction {
116
+ return instruction.data !== undefined;
117
+ }
118
+
119
+ export function assertIsInstructionWithData<
120
+ TData extends ReadonlyUint8Array = ReadonlyUint8Array,
121
+ TInstruction extends Instruction = Instruction,
122
+ >(instruction: TInstruction): asserts instruction is InstructionWithData<TData> & TInstruction {
123
+ if (instruction.data === undefined) {
124
+ throw new SolanaError(SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_DATA, {
125
+ accountAddresses: instruction.accounts?.map(a => a.address),
126
+ programAddress: instruction.programAddress,
127
+ });
128
+ }
129
+ }
package/src/roles.ts ADDED
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Describes the purpose for which an account participates in a transaction.
3
+ *
4
+ * Every account that participates in a transaction can be read from, but only ones that you mark as
5
+ * writable may be written to, and only ones that you indicate must sign the transaction will gain
6
+ * the privileges associated with signers at runtime.
7
+ *
8
+ * | | `isSigner` | `isWritable` |
9
+ * | ----------------------------- | ---------- | ------------ |
10
+ * | `AccountRole.READONLY` | &#x274c; | &#x274c; |
11
+ * | `AccountRole.WRITABLE` | &#x274c; | &#x2705; |
12
+ * | `AccountRole.READONLY_SIGNER` | &#x2705; | &#x274c; |
13
+ * | `AccountRole.WRITABLE_SIGNER` | &#x2705; | &#x2705; |
14
+ */
15
+ export enum AccountRole {
16
+ // Bitflag guide: is signer ⌄⌄ is writable
17
+ WRITABLE_SIGNER = /* 3 */ 0b11, // prettier-ignore
18
+ READONLY_SIGNER = /* 2 */ 0b10, // prettier-ignore
19
+ WRITABLE = /* 1 */ 0b01, // prettier-ignore
20
+ READONLY = /* 0 */ 0b00, // prettier-ignore
21
+ }
22
+
23
+ // Quick primer on bitwise operations: https://stackoverflow.com/a/1436448/802047
24
+ const IS_SIGNER_BITMASK = 0b10;
25
+ const IS_WRITABLE_BITMASK = 0b01;
26
+
27
+ /**
28
+ * @returns An {@link AccountRole} representing the non-signer variant of the supplied role.
29
+ */
30
+ export function downgradeRoleToNonSigner(role: AccountRole.READONLY_SIGNER): AccountRole.READONLY;
31
+ export function downgradeRoleToNonSigner(role: AccountRole.WRITABLE_SIGNER): AccountRole.WRITABLE;
32
+ export function downgradeRoleToNonSigner(role: AccountRole): AccountRole;
33
+ export function downgradeRoleToNonSigner(role: AccountRole): AccountRole {
34
+ return role & ~IS_SIGNER_BITMASK;
35
+ }
36
+
37
+ /**
38
+ * @returns An {@link AccountRole} representing the read-only variant of the supplied role.
39
+ */
40
+ export function downgradeRoleToReadonly(role: AccountRole.WRITABLE): AccountRole.READONLY;
41
+ export function downgradeRoleToReadonly(role: AccountRole.WRITABLE_SIGNER): AccountRole.READONLY_SIGNER;
42
+ export function downgradeRoleToReadonly(role: AccountRole): AccountRole;
43
+ export function downgradeRoleToReadonly(role: AccountRole): AccountRole {
44
+ return role & ~IS_WRITABLE_BITMASK;
45
+ }
46
+
47
+ /**
48
+ * Returns `true` if the {@link AccountRole} given represents that of a signer. Also refines the
49
+ * TypeScript type of the supplied role.
50
+ */
51
+ export function isSignerRole(role: AccountRole): role is AccountRole.READONLY_SIGNER | AccountRole.WRITABLE_SIGNER {
52
+ return role >= AccountRole.READONLY_SIGNER;
53
+ }
54
+
55
+ /**
56
+ * Returns `true` if the {@link AccountRole} given represents that of a writable account. Also
57
+ * refines the TypeScript type of the supplied role.
58
+ */
59
+ export function isWritableRole(role: AccountRole): role is AccountRole.WRITABLE | AccountRole.WRITABLE_SIGNER {
60
+ return (role & IS_WRITABLE_BITMASK) !== 0;
61
+ }
62
+
63
+ /**
64
+ * Given two {@link AccountRole | AccountRoles}, will return the {@link AccountRole} that grants the
65
+ * highest privileges of both.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * // Returns `AccountRole.WRITABLE_SIGNER`
70
+ * mergeRoles(AccountRole.READONLY_SIGNER, AccountRole.WRITABLE);
71
+ * ```
72
+ */
73
+ export function mergeRoles(roleA: AccountRole.WRITABLE, roleB: AccountRole.READONLY_SIGNER): AccountRole.WRITABLE_SIGNER; // prettier-ignore
74
+ export function mergeRoles(roleA: AccountRole.READONLY_SIGNER, roleB: AccountRole.WRITABLE): AccountRole.WRITABLE_SIGNER; // prettier-ignore
75
+ export function mergeRoles(roleA: AccountRole, roleB: AccountRole.WRITABLE_SIGNER): AccountRole.WRITABLE_SIGNER; // prettier-ignore
76
+ export function mergeRoles(roleA: AccountRole.WRITABLE_SIGNER, roleB: AccountRole): AccountRole.WRITABLE_SIGNER; // prettier-ignore
77
+ export function mergeRoles(roleA: AccountRole, roleB: AccountRole.READONLY_SIGNER): AccountRole.READONLY_SIGNER; // prettier-ignore
78
+ export function mergeRoles(roleA: AccountRole.READONLY_SIGNER, roleB: AccountRole): AccountRole.READONLY_SIGNER; // prettier-ignore
79
+ export function mergeRoles(roleA: AccountRole, roleB: AccountRole.WRITABLE): AccountRole.WRITABLE; // prettier-ignore
80
+ export function mergeRoles(roleA: AccountRole.WRITABLE, roleB: AccountRole): AccountRole.WRITABLE; // prettier-ignore
81
+ export function mergeRoles(roleA: AccountRole.READONLY, roleB: AccountRole.READONLY): AccountRole.READONLY; // prettier-ignore
82
+ export function mergeRoles(roleA: AccountRole, roleB: AccountRole): AccountRole; // prettier-ignore
83
+ export function mergeRoles(roleA: AccountRole, roleB: AccountRole): AccountRole {
84
+ return roleA | roleB;
85
+ }
86
+
87
+ /**
88
+ * @returns An {@link AccountRole} representing the signer variant of the supplied role.
89
+ */
90
+ export function upgradeRoleToSigner(role: AccountRole.READONLY): AccountRole.READONLY_SIGNER;
91
+ export function upgradeRoleToSigner(role: AccountRole.WRITABLE): AccountRole.WRITABLE_SIGNER;
92
+ export function upgradeRoleToSigner(role: AccountRole): AccountRole;
93
+ export function upgradeRoleToSigner(role: AccountRole): AccountRole {
94
+ return role | IS_SIGNER_BITMASK;
95
+ }
96
+
97
+ /**
98
+ * @returns An {@link AccountRole} representing the writable variant of the supplied role.
99
+ */
100
+ export function upgradeRoleToWritable(role: AccountRole.READONLY): AccountRole.WRITABLE;
101
+ export function upgradeRoleToWritable(role: AccountRole.READONLY_SIGNER): AccountRole.WRITABLE_SIGNER;
102
+ export function upgradeRoleToWritable(role: AccountRole): AccountRole;
103
+ export function upgradeRoleToWritable(role: AccountRole): AccountRole {
104
+ return role | IS_WRITABLE_BITMASK;
105
+ }