Skip to content

Commit 332b92f

Browse files
authored
Add CreateAccountAllowPrefund instruction (SIMD-0312) (#81)
* Add CreateAccountAllowPrefund instruction (SIMD-0312) Adds the new System Program instruction CreateAccountAllowPrefund (discriminator 13) per [SIMD-0312](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0312-create-account-allow-prefund.md), which allows account creation when the new account already holds lamports. The payer account is optional and only required when lamports > 0. * Make lamports optional in CreateAccountAllowPrefund
1 parent b8aca7a commit 332b92f

6 files changed

Lines changed: 716 additions & 1 deletion

File tree

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/**
2+
* This code was AUTOGENERATED using the Codama library.
3+
* Please DO NOT EDIT THIS FILE, instead use visitors
4+
* to add features, then rerun Codama to update it.
5+
*
6+
* @see https://github.com/codama-idl/codama
7+
*/
8+
9+
import {
10+
BASE_ACCOUNT_SIZE,
11+
combineCodec,
12+
getAddressDecoder,
13+
getAddressEncoder,
14+
getStructDecoder,
15+
getStructEncoder,
16+
getU32Decoder,
17+
getU32Encoder,
18+
getU64Decoder,
19+
getU64Encoder,
20+
SOLANA_ERROR__PROGRAM_CLIENTS__INSUFFICIENT_ACCOUNT_METAS,
21+
SolanaError,
22+
transformEncoder,
23+
type AccountMeta,
24+
type AccountSignerMeta,
25+
type Address,
26+
type FixedSizeCodec,
27+
type FixedSizeDecoder,
28+
type FixedSizeEncoder,
29+
type Instruction,
30+
type InstructionWithAccounts,
31+
type InstructionWithData,
32+
type ReadonlyUint8Array,
33+
type TransactionSigner,
34+
type WritableSignerAccount,
35+
} from '@solana/kit';
36+
import {
37+
getAccountMetaFactory,
38+
type InstructionWithByteDelta,
39+
type ResolvedInstructionAccount,
40+
} from '@solana/kit/program-client-core';
41+
import { SYSTEM_PROGRAM_ADDRESS } from '../programs';
42+
43+
export const CREATE_ACCOUNT_ALLOW_PREFUND_DISCRIMINATOR = 13;
44+
45+
export function getCreateAccountAllowPrefundDiscriminatorBytes(): ReadonlyUint8Array {
46+
return getU32Encoder().encode(CREATE_ACCOUNT_ALLOW_PREFUND_DISCRIMINATOR);
47+
}
48+
49+
export type CreateAccountAllowPrefundInstruction<
50+
TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
51+
TAccountNewAccount extends string | AccountMeta<string> = string,
52+
TAccountPayer extends string | AccountMeta<string> | undefined = undefined,
53+
TRemainingAccounts extends readonly AccountMeta<string>[] = [],
54+
> = Instruction<TProgram> &
55+
InstructionWithData<ReadonlyUint8Array> &
56+
InstructionWithAccounts<
57+
[
58+
TAccountNewAccount extends string
59+
? WritableSignerAccount<TAccountNewAccount> & AccountSignerMeta<TAccountNewAccount>
60+
: TAccountNewAccount,
61+
...(TAccountPayer extends undefined
62+
? []
63+
: [
64+
TAccountPayer extends string
65+
? WritableSignerAccount<TAccountPayer> & AccountSignerMeta<TAccountPayer>
66+
: TAccountPayer,
67+
]),
68+
...TRemainingAccounts,
69+
]
70+
>;
71+
72+
export type CreateAccountAllowPrefundInstructionData = {
73+
discriminator: number;
74+
lamports: bigint;
75+
space: bigint;
76+
programAddress: Address;
77+
};
78+
79+
export type CreateAccountAllowPrefundInstructionDataArgs = {
80+
lamports?: number | bigint;
81+
space: number | bigint;
82+
programAddress: Address;
83+
};
84+
85+
export function getCreateAccountAllowPrefundInstructionDataEncoder(): FixedSizeEncoder<CreateAccountAllowPrefundInstructionDataArgs> {
86+
return transformEncoder(
87+
getStructEncoder([
88+
['discriminator', getU32Encoder()],
89+
['lamports', getU64Encoder()],
90+
['space', getU64Encoder()],
91+
['programAddress', getAddressEncoder()],
92+
]),
93+
value => ({
94+
...value,
95+
discriminator: CREATE_ACCOUNT_ALLOW_PREFUND_DISCRIMINATOR,
96+
lamports: value.lamports ?? 0,
97+
}),
98+
);
99+
}
100+
101+
export function getCreateAccountAllowPrefundInstructionDataDecoder(): FixedSizeDecoder<CreateAccountAllowPrefundInstructionData> {
102+
return getStructDecoder([
103+
['discriminator', getU32Decoder()],
104+
['lamports', getU64Decoder()],
105+
['space', getU64Decoder()],
106+
['programAddress', getAddressDecoder()],
107+
]);
108+
}
109+
110+
export function getCreateAccountAllowPrefundInstructionDataCodec(): FixedSizeCodec<
111+
CreateAccountAllowPrefundInstructionDataArgs,
112+
CreateAccountAllowPrefundInstructionData
113+
> {
114+
return combineCodec(
115+
getCreateAccountAllowPrefundInstructionDataEncoder(),
116+
getCreateAccountAllowPrefundInstructionDataDecoder(),
117+
);
118+
}
119+
120+
export type CreateAccountAllowPrefundInput<
121+
TAccountNewAccount extends string = string,
122+
TAccountPayer extends string = string,
123+
> = {
124+
newAccount: TransactionSigner<TAccountNewAccount>;
125+
payer?: TransactionSigner<TAccountPayer>;
126+
lamports?: CreateAccountAllowPrefundInstructionDataArgs['lamports'];
127+
space: CreateAccountAllowPrefundInstructionDataArgs['space'];
128+
programAddress: CreateAccountAllowPrefundInstructionDataArgs['programAddress'];
129+
};
130+
131+
export function getCreateAccountAllowPrefundInstruction<
132+
TAccountNewAccount extends string,
133+
TAccountPayer extends string,
134+
TProgramAddress extends Address = typeof SYSTEM_PROGRAM_ADDRESS,
135+
>(
136+
input: CreateAccountAllowPrefundInput<TAccountNewAccount, TAccountPayer>,
137+
config?: { programAddress?: TProgramAddress },
138+
): CreateAccountAllowPrefundInstruction<TProgramAddress, TAccountNewAccount, TAccountPayer> & InstructionWithByteDelta {
139+
// Program address.
140+
const programAddress = config?.programAddress ?? SYSTEM_PROGRAM_ADDRESS;
141+
142+
// Original accounts.
143+
const originalAccounts = {
144+
newAccount: { value: input.newAccount ?? null, isWritable: true },
145+
payer: { value: input.payer ?? null, isWritable: true },
146+
};
147+
const accounts = originalAccounts as Record<keyof typeof originalAccounts, ResolvedInstructionAccount>;
148+
149+
// Original args.
150+
const args = { ...input };
151+
152+
// Bytes created or reallocated by the instruction.
153+
const byteDelta: number = [Number(args.space) + BASE_ACCOUNT_SIZE].reduce((a, b) => a + b, 0);
154+
155+
const getAccountMeta = getAccountMetaFactory(programAddress, 'omitted');
156+
return Object.freeze({
157+
accounts: [getAccountMeta('newAccount', accounts.newAccount), getAccountMeta('payer', accounts.payer)].filter(
158+
<T>(x: T | undefined): x is T => x !== undefined,
159+
),
160+
byteDelta,
161+
data: getCreateAccountAllowPrefundInstructionDataEncoder().encode(
162+
args as CreateAccountAllowPrefundInstructionDataArgs,
163+
),
164+
programAddress,
165+
} as CreateAccountAllowPrefundInstruction<TProgramAddress, TAccountNewAccount, TAccountPayer> &
166+
InstructionWithByteDelta);
167+
}
168+
169+
export type ParsedCreateAccountAllowPrefundInstruction<
170+
TProgram extends string = typeof SYSTEM_PROGRAM_ADDRESS,
171+
TAccountMetas extends readonly AccountMeta[] = readonly AccountMeta[],
172+
> = {
173+
programAddress: Address<TProgram>;
174+
accounts: {
175+
newAccount: TAccountMetas[0];
176+
payer?: TAccountMetas[1] | undefined;
177+
};
178+
data: CreateAccountAllowPrefundInstructionData;
179+
};
180+
181+
export function parseCreateAccountAllowPrefundInstruction<
182+
TProgram extends string,
183+
TAccountMetas extends readonly AccountMeta[],
184+
>(
185+
instruction: Instruction<TProgram> &
186+
InstructionWithAccounts<TAccountMetas> &
187+
InstructionWithData<ReadonlyUint8Array>,
188+
): ParsedCreateAccountAllowPrefundInstruction<TProgram, TAccountMetas> {
189+
if (instruction.accounts.length < 1) {
190+
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__INSUFFICIENT_ACCOUNT_METAS, {
191+
actualAccountMetas: instruction.accounts.length,
192+
expectedAccountMetas: 1,
193+
});
194+
}
195+
let accountIndex = 0;
196+
const getNextAccount = () => {
197+
const accountMeta = (instruction.accounts as TAccountMetas)[accountIndex]!;
198+
accountIndex += 1;
199+
return accountMeta;
200+
};
201+
let optionalAccountsRemaining = instruction.accounts.length - 1;
202+
const getNextOptionalAccount = () => {
203+
if (optionalAccountsRemaining === 0) return undefined;
204+
optionalAccountsRemaining -= 1;
205+
return getNextAccount();
206+
};
207+
return {
208+
programAddress: instruction.programAddress,
209+
accounts: { newAccount: getNextAccount(), payer: getNextOptionalAccount() },
210+
data: getCreateAccountAllowPrefundInstructionDataDecoder().decode(instruction.data),
211+
};
212+
}

clients/js/src/generated/instructions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export * from './assign';
1313
export * from './assignWithSeed';
1414
export * from './authorizeNonceAccount';
1515
export * from './createAccount';
16+
export * from './createAccountAllowPrefund';
1617
export * from './createAccountWithSeed';
1718
export * from './initializeNonceAccount';
1819
export * from './transferSol';

clients/js/src/generated/programs/system.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
getAssignInstruction,
4040
getAssignWithSeedInstruction,
4141
getAuthorizeNonceAccountInstruction,
42+
getCreateAccountAllowPrefundInstruction,
4243
getCreateAccountInstruction,
4344
getCreateAccountWithSeedInstruction,
4445
getInitializeNonceAccountInstruction,
@@ -52,6 +53,7 @@ import {
5253
parseAssignInstruction,
5354
parseAssignWithSeedInstruction,
5455
parseAuthorizeNonceAccountInstruction,
56+
parseCreateAccountAllowPrefundInstruction,
5557
parseCreateAccountInstruction,
5658
parseCreateAccountWithSeedInstruction,
5759
parseInitializeNonceAccountInstruction,
@@ -65,6 +67,7 @@ import {
6567
type AssignInput,
6668
type AssignWithSeedInput,
6769
type AuthorizeNonceAccountInput,
70+
type CreateAccountAllowPrefundInput,
6871
type CreateAccountInput,
6972
type CreateAccountWithSeedInput,
7073
type InitializeNonceAccountInput,
@@ -74,6 +77,7 @@ import {
7477
type ParsedAssignInstruction,
7578
type ParsedAssignWithSeedInstruction,
7679
type ParsedAuthorizeNonceAccountInstruction,
80+
type ParsedCreateAccountAllowPrefundInstruction,
7781
type ParsedCreateAccountInstruction,
7882
type ParsedCreateAccountWithSeedInstruction,
7983
type ParsedInitializeNonceAccountInstruction,
@@ -107,6 +111,7 @@ export enum SystemInstruction {
107111
AssignWithSeed,
108112
TransferSolWithSeed,
109113
UpgradeNonceAccount,
114+
CreateAccountAllowPrefund,
110115
}
111116

112117
export function identifySystemInstruction(
@@ -152,6 +157,9 @@ export function identifySystemInstruction(
152157
if (containsBytes(data, getU32Encoder().encode(12), 0)) {
153158
return SystemInstruction.UpgradeNonceAccount;
154159
}
160+
if (containsBytes(data, getU32Encoder().encode(13), 0)) {
161+
return SystemInstruction.CreateAccountAllowPrefund;
162+
}
155163
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__FAILED_TO_IDENTIFY_INSTRUCTION, {
156164
instructionData: data,
157165
programName: 'system',
@@ -173,7 +181,10 @@ export type ParsedSystemInstruction<TProgram extends string = '11111111111111111
173181
| ({ instructionType: SystemInstruction.AllocateWithSeed } & ParsedAllocateWithSeedInstruction<TProgram>)
174182
| ({ instructionType: SystemInstruction.AssignWithSeed } & ParsedAssignWithSeedInstruction<TProgram>)
175183
| ({ instructionType: SystemInstruction.TransferSolWithSeed } & ParsedTransferSolWithSeedInstruction<TProgram>)
176-
| ({ instructionType: SystemInstruction.UpgradeNonceAccount } & ParsedUpgradeNonceAccountInstruction<TProgram>);
184+
| ({ instructionType: SystemInstruction.UpgradeNonceAccount } & ParsedUpgradeNonceAccountInstruction<TProgram>)
185+
| ({
186+
instructionType: SystemInstruction.CreateAccountAllowPrefund;
187+
} & ParsedCreateAccountAllowPrefundInstruction<TProgram>);
177188

178189
export function parseSystemInstruction<TProgram extends string>(
179190
instruction: Instruction<TProgram> & InstructionWithData<ReadonlyUint8Array>,
@@ -259,6 +270,13 @@ export function parseSystemInstruction<TProgram extends string>(
259270
...parseUpgradeNonceAccountInstruction(instruction),
260271
};
261272
}
273+
case SystemInstruction.CreateAccountAllowPrefund: {
274+
assertIsInstructionWithAccounts(instruction);
275+
return {
276+
instructionType: SystemInstruction.CreateAccountAllowPrefund,
277+
...parseCreateAccountAllowPrefundInstruction(instruction),
278+
};
279+
}
262280
default:
263281
throw new SolanaError(SOLANA_ERROR__PROGRAM_CLIENTS__UNRECOGNIZED_INSTRUCTION_TYPE, {
264282
instructionType: instructionType as string,
@@ -305,6 +323,9 @@ export type SystemPluginInstructions = {
305323
upgradeNonceAccount: (
306324
input: UpgradeNonceAccountInput,
307325
) => ReturnType<typeof getUpgradeNonceAccountInstruction> & SelfPlanAndSendFunctions;
326+
createAccountAllowPrefund: (
327+
input: CreateAccountAllowPrefundInput,
328+
) => ReturnType<typeof getCreateAccountAllowPrefundInstruction> & SelfPlanAndSendFunctions;
308329
};
309330

310331
export type SystemPluginRequirements = ClientWithRpc<GetAccountInfoApi & GetMultipleAccountsApi> &
@@ -346,6 +367,8 @@ export function systemProgram() {
346367
addSelfPlanAndSendFunctions(client, getTransferSolWithSeedInstruction(input)),
347368
upgradeNonceAccount: input =>
348369
addSelfPlanAndSendFunctions(client, getUpgradeNonceAccountInstruction(input)),
370+
createAccountAllowPrefund: input =>
371+
addSelfPlanAndSendFunctions(client, getCreateAccountAllowPrefundInstruction(input)),
349372
},
350373
},
351374
});

0 commit comments

Comments
 (0)