Skip to content

Commit 4ab8a22

Browse files
committed
Create system account instead of PDA
1 parent e013d66 commit 4ab8a22

File tree

8 files changed

+54
-103
lines changed

8 files changed

+54
-103
lines changed

basics/create-account/steel/api/src/consts.rs

Lines changed: 0 additions & 2 deletions
This file was deleted.

basics/create-account/steel/api/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use steel::*;
22

3-
/// Declare custom error enum
3+
/// Declare custom error enum
44
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, IntoPrimitive)]
55
#[repr(u32)]
66
pub enum CreateAccountError {

basics/create-account/steel/api/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
pub mod consts;
21
pub mod error;
32
pub mod instruction;
43
pub mod sdk;
54
pub mod state;
65

76
pub mod prelude {
8-
pub use crate::consts::*;
97
pub use crate::error::*;
108
pub use crate::instruction::*;
119
pub use crate::sdk::*;

basics/create-account/steel/api/src/sdk.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ use steel::*;
22

33
use crate::prelude::*;
44

5-
6-
/// Creates an instruction to create an account
7-
pub fn initialize_account(signer: Pubkey) -> Instruction {
5+
pub fn initialize_account(signer: Pubkey, new_account_key: Pubkey) -> Instruction {
86
Instruction {
97
program_id: crate::ID,
108
accounts: vec![
119
AccountMeta::new(signer, true),
12-
AccountMeta::new(new_account_pda().unwrap().0, false),
10+
AccountMeta::new(new_account_key, false),
1311
AccountMeta::new_readonly(system_program::ID, false),
1412
],
1513
data: InitializeAccount {}.to_bytes(),
Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
use crate::consts::*;
21
use steel::*;
32

4-
/// Fetch PDA of the account.
5-
pub fn new_account_pda() -> Option<(Pubkey, u8)> {
6-
Pubkey::try_find_program_address(&[CREATE_ACCOUNT], &crate::id())
7-
}
8-
93
/// This enum is used to get a discriminator
104
/// for the new account.
115
#[repr(u8)]
@@ -14,11 +8,10 @@ pub enum CreateAccountDiscriminator {
148
NewAccount = 0,
159
}
1610

17-
/// This empty struct represents the account type
11+
/// This empty struct represents the system account
12+
/// It contains no data and is used to create a new account
1813
#[repr(C)]
1914
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
20-
pub struct NewAccount {
21-
pub user_id: u8,
22-
}
15+
pub struct NewAccount {}
2316

2417
account!(CreateAccountDiscriminator, NewAccount);

basics/create-account/steel/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
"build": "cargo build-sbf --manifest-path=./program/Cargo.toml --sbf-out-dir=./program/target/so",
1111
"deploy": "solana program deploy ./program/target/so/create_account_program.so"
1212
},
13-
"keywords": [
14-
"solana"
15-
],
13+
"keywords": ["solana"],
1614
"author": "",
1715
"license": "MIT",
1816
"dependencies": {
Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,45 @@
11
use create_account_api::prelude::*;
22
use solana_program::msg;
3+
use steel::sysvar::rent::Rent;
34
use steel::*;
45

56
pub fn process_initialize(accounts: &[AccountInfo<'_>]) -> ProgramResult {
6-
7-
// Validate accounts
7+
// Load accounts
88
let [payer, new_account, system_program] = accounts else {
9+
msg!("Not enough accounts provided");
910
return Err(ProgramError::NotEnoughAccountKeys);
1011
};
11-
payer.is_signer()?;
12-
new_account
13-
.is_empty()?
14-
.is_writable()?
15-
.has_seeds(&[CREATE_ACCOUNT, payer.key.as_ref()], &create_account_api::ID)?;
12+
13+
// Validate accounts
14+
payer
15+
.is_signer()
16+
.map_err(|_| ProgramError::MissingRequiredSignature)?;
17+
18+
new_account.is_signer()?.is_empty()?.is_writable()?;
19+
1620
system_program.is_program(&system_program::ID)?;
1721

18-
// Initialize the account.
19-
create_account::<NewAccount>(
20-
new_account,
21-
system_program,
22-
payer,
23-
&create_account_api::ID,
24-
&[CREATE_ACCOUNT, payer.key.as_ref()],
25-
)?;
22+
// The helper "create_account" will create an account
23+
// owned by our program and not the system program
2624

27-
// Fetch the newly created account and give it
28-
// an arbitrary user id
29-
let created_account = new_account.as_account_mut::<NewAccount>(&create_account_api::ID)?;
30-
created_account.user_id = 1;
25+
// Calculate the minimum balance needed for the account
26+
// Space required is the size of our NewAccount struct
27+
let space_required = std::mem::size_of::<NewAccount>() as u64;
28+
let lamports_required = (Rent::get()?).minimum_balance(space_required as usize);
29+
30+
// Create the account by invoking a create_account system instruction
31+
solana_program::program::invoke(
32+
&solana_program::system_instruction::create_account(
33+
payer.key,
34+
new_account.key,
35+
lamports_required,
36+
space_required,
37+
&system_program::ID,
38+
),
39+
&[payer.clone(), new_account.clone(), system_program.clone()],
40+
)?;
3141

3242
msg!("A new account has been created and initialized!");
33-
msg!("Your user id is: {}", created_account.user_id);
3443

3544
Ok(())
3645
}
Lines changed: 18 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,46 @@
1-
import {
2-
type Blockhash,
3-
Keypair,
4-
LAMPORTS_PER_SOL,
5-
PublicKey,
6-
SystemProgram,
7-
Transaction,
8-
TransactionInstruction,
9-
} from "@solana/web3.js";
10-
import { assert } from "chai";
11-
import { before, describe, it } from "mocha";
12-
import {
13-
type BanksClient,
14-
type ProgramTestContext,
15-
start,
16-
} from "solana-bankrun";
1+
import { type Blockhash, Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, Transaction, TransactionInstruction } from '@solana/web3.js';
2+
import { assert } from 'chai';
3+
import { before, describe, it } from 'mocha';
4+
import { type BanksClient, type ProgramTestContext, start } from 'solana-bankrun';
175

18-
const PROGRAM_ID = new PublicKey(
19-
"12rpZ18eGj7BeKvSFRZ45cni97HctTbKziBnW3MsH3NG",
20-
);
21-
const SEED = Buffer.from("createaccount"); // Convert to binary (bytes)
6+
const PROGRAM_ID = new PublicKey('12rpZ18eGj7BeKvSFRZ45cni97HctTbKziBnW3MsH3NG');
227

23-
describe("Create a system account", () => {
8+
const instructionDiscriminators = {
9+
InitializeAccount: Buffer.from([0]),
10+
};
11+
12+
describe('Create a system account', () => {
2413
let context: ProgramTestContext;
2514
let lastBlock: Blockhash;
2615
let client: BanksClient;
2716
let payer: Keypair;
2817

2918
before(async () => {
30-
context = await start(
31-
[{ name: "create_account_program", programId: PROGRAM_ID }],
32-
[],
33-
);
19+
context = await start([{ name: 'create_account_program', programId: PROGRAM_ID }], []);
3420
client = context.banksClient;
3521
payer = context.payer;
3622
lastBlock = context.lastBlockhash;
3723
});
3824

39-
it("Create the account via a cross program invocation", async () => {
40-
const [PDA, _] = await PublicKey.findProgramAddressSync(
41-
[SEED, payer.publicKey.toBuffer()],
42-
PROGRAM_ID,
43-
);
25+
it('should create the account via a cross program invocation', async () => {
26+
const newAccount = Keypair.generate();
4427

4528
const ix = new TransactionInstruction({
4629
keys: [
4730
{ pubkey: payer.publicKey, isSigner: true, isWritable: true },
48-
{ pubkey: PDA, isSigner: false, isWritable: true },
31+
{ pubkey: newAccount.publicKey, isSigner: true, isWritable: true },
4932
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
5033
],
5134
programId: PROGRAM_ID,
52-
data: Buffer.from([0]),
53-
});
54-
55-
const tx = new Transaction();
56-
tx.recentBlockhash = lastBlock;
57-
tx.add(ix).sign(payer);
58-
59-
// Process Transaction with all the instructions
60-
const transaction = await client.processTransaction(tx);
61-
62-
assert(
63-
transaction.logMessages[3].startsWith(
64-
"Program log: A new account has been created and initialized!",
65-
),
66-
);
67-
});
68-
69-
it("Create the account via direct call to system program", async () => {
70-
const newKeypair = Keypair.generate();
71-
72-
const ix = SystemProgram.createAccount({
73-
fromPubkey: payer.publicKey,
74-
newAccountPubkey: newKeypair.publicKey,
75-
lamports: LAMPORTS_PER_SOL,
76-
space: 0,
77-
programId: SystemProgram.programId,
35+
data: Buffer.concat([instructionDiscriminators.InitializeAccount]),
7836
});
7937

8038
const tx = new Transaction();
8139
tx.recentBlockhash = lastBlock;
82-
tx.add(ix).sign(payer, newKeypair);
40+
tx.add(ix).sign(payer, newAccount);
8341

42+
// No other tests required besides confirming if the transaction is processed
43+
// Since transactions are atomic, we can be certain the account was created
8444
await client.processTransaction(tx);
85-
console.log(
86-
`Account with public key ${newKeypair.publicKey} successfully created`,
87-
);
8845
});
8946
});

0 commit comments

Comments
 (0)