feat: Setup a coder for SystemProgram (#1920)
This commit is contained in:
parent
f866d073db
commit
707ebf26e7
|
@ -21,6 +21,7 @@ com/project-serum/anchor/pull/1841)).
|
|||
* lang: Add `PartialEq` and `Eq` for `anchor_lang::Error` ([#1544](https://github.com/project-serum/anchor/pull/1544)).
|
||||
* cli: Add `b` and `t` aliases for `build` and `test` respectively ([#1823](https://github.com/project-serum/anchor/pull/1823)).
|
||||
* spl: Add `sync_native` token program CPI wrapper function ([#1833](https://github.com/project-serum/anchor/pull/1833)).
|
||||
* ts: Implement a coder for system program ([#1920](https://github.com/project-serum/anchor/pull/1920)).
|
||||
|
||||
### Fixes
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
[programs.localnet]
|
||||
custom_coder = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
|
||||
spl_token = "FmpfPa1LHEYRbueNMnwNVd2JvyQ89GXGWdyZEXNNKV8w"
|
||||
native_system = "9NxAd91hhJ3ZBTHytYP894y4ESRKG7n8VbLgdyYGJFLB"
|
||||
|
||||
[registry]
|
||||
url = "https://anchor.projectserum.com"
|
||||
|
|
|
@ -15,5 +15,9 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "anchor test"
|
||||
},
|
||||
"dependencies": {
|
||||
"mocha": "^10.0.0",
|
||||
"ts-mocha": "^10.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "native-system"
|
||||
version = "0.1.0"
|
||||
description = "Created with Anchor"
|
||||
rust-version = "1.56"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
name = "native_system"
|
||||
|
||||
[features]
|
||||
no-entrypoint = []
|
||||
no-idl = []
|
||||
no-log-ix-name = []
|
||||
cpi = ["no-entrypoint"]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anchor-lang = { path = "../../../../lang" }
|
|
@ -0,0 +1,2 @@
|
|||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
|
@ -0,0 +1,214 @@
|
|||
use anchor_lang::prelude::*;
|
||||
|
||||
declare_id!("9NxAd91hhJ3ZBTHytYP894y4ESRKG7n8VbLgdyYGJFLB");
|
||||
|
||||
#[program]
|
||||
pub mod native_system {
|
||||
use super::*;
|
||||
|
||||
pub fn create_account(
|
||||
ctx: Context<CreateAccount>,
|
||||
lamports: u64,
|
||||
space: u64,
|
||||
owner: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn assign(ctx: Context<Assign>, owner: Pubkey) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn transfer(ctx: Context<Transfer>, lamports: u64) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_account_with_seed(
|
||||
ctx: Context<CreateAccountWithSeed>,
|
||||
base: Pubkey,
|
||||
seed: String,
|
||||
lamports: u64,
|
||||
space: u64,
|
||||
owner: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn advance_nonce_account(
|
||||
ctx: Context<AdvanceNonceAccount>,
|
||||
authorized: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn withdraw_nonce_account(ctx: Context<WithdrawNonceAccount>, lamports: u64) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn initialize_nonce_account(
|
||||
ctx: Context<InitializeNonceAccount>,
|
||||
authorized: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn authorize_nonce_account(
|
||||
ctx: Context<AuthorizeNonceAccount>,
|
||||
authorized: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn allocate(ctx: Context<Allocate>, space: u64) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn allocate_with_seed(
|
||||
ctx: Context<AllocateWithSeed>,
|
||||
base: Pubkey,
|
||||
seed: String,
|
||||
space: u64,
|
||||
owner: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn assign_with_seed(
|
||||
ctx: Context<AssignWithSeed>,
|
||||
base: Pubkey,
|
||||
seed: String,
|
||||
owner: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn transfer_with_seed(
|
||||
ctx: Context<TransferWithSeed>,
|
||||
lamports: u64,
|
||||
seed: String,
|
||||
owner: Pubkey,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct CreateAccount<'info> {
|
||||
#[account(mut)]
|
||||
from: Signer<'info>,
|
||||
#[account(mut)]
|
||||
to: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Assign<'info> {
|
||||
#[account(mut)]
|
||||
pubkey: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Transfer<'info> {
|
||||
#[account(mut)]
|
||||
from: Signer<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
to: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct CreateAccountWithSeed<'info> {
|
||||
#[account(mut)]
|
||||
from: Signer<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
to: AccountInfo<'info>,
|
||||
base: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AdvanceNonceAccount<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
nonce: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
recent_blockhashes: AccountInfo<'info>,
|
||||
authorized: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct WithdrawNonceAccount<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
nonce: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
to: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
recent_blockhashes: AccountInfo<'info>,
|
||||
rent: Sysvar<'info, Rent>,
|
||||
authorized: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct InitializeNonceAccount<'info> {
|
||||
#[account(mut)]
|
||||
nonce: Signer<'info>,
|
||||
/// CHECK:
|
||||
recent_blockhashes: AccountInfo<'info>,
|
||||
rent: Sysvar<'info, Rent>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AuthorizeNonceAccount<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
nonce: AccountInfo<'info>,
|
||||
authorized: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Allocate<'info> {
|
||||
#[account(mut)]
|
||||
pubkey: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AllocateWithSeed<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
base: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct AssignWithSeed<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
base: Signer<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct TransferWithSeed<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
from: AccountInfo<'info>,
|
||||
base: Signer<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
to: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
|
||||
pub struct FeeCalculator {
|
||||
pub lamports_per_signature: u64,
|
||||
}
|
||||
|
||||
#[account]
|
||||
pub struct Nonce {
|
||||
pub version: u32,
|
||||
pub state: u32,
|
||||
pub authorized_pubkey: Pubkey,
|
||||
pub nonce: Pubkey,
|
||||
pub fee_calculator: FeeCalculator,
|
||||
}
|
|
@ -131,31 +131,41 @@ pub mod spl_token {
|
|||
#[derive(Accounts)]
|
||||
pub struct InitializeMint<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
rent: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct InitializeAccount<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
authority: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
rent: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct InitializeMultisig<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
rent: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct Transfer<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
source: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
destination: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -163,7 +173,9 @@ pub struct Transfer<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Approve<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
source: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
delegate: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -171,6 +183,7 @@ pub struct Approve<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Revoke<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
source: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -178,6 +191,7 @@ pub struct Revoke<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct SetAuthority<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
pub mint: AccountInfo<'info>,
|
||||
pub authority: Signer<'info>,
|
||||
}
|
||||
|
@ -185,8 +199,10 @@ pub struct SetAuthority<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct MintTo<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
pub mint: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
pub to: AccountInfo<'info>,
|
||||
pub authority: Signer<'info>,
|
||||
}
|
||||
|
@ -194,8 +210,10 @@ pub struct MintTo<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct Burn<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
source: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -203,16 +221,21 @@ pub struct Burn<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct CloseAccount<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
destination: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
authority: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct FreezeAccount<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -220,7 +243,9 @@ pub struct FreezeAccount<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct ThawAccount<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -228,9 +253,12 @@ pub struct ThawAccount<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct TransferChecked<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
source: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
destination: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -238,8 +266,11 @@ pub struct TransferChecked<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct ApproveChecked<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
source: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
delegate: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -247,8 +278,10 @@ pub struct ApproveChecked<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct MintToChecked<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
to: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -256,8 +289,10 @@ pub struct MintToChecked<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct BurnChecked<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
source: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
authority: Signer<'info>,
|
||||
}
|
||||
|
@ -265,32 +300,40 @@ pub struct BurnChecked<'info> {
|
|||
#[derive(Accounts)]
|
||||
pub struct InitializeAccount2<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
rent: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct SyncNative<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct InitializeAccount3<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct InitializeMultisig2<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
account: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct InitializeMint2<'info> {
|
||||
#[account(mut)]
|
||||
/// CHECK:
|
||||
mint: AccountInfo<'info>,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
import * as anchor from "@project-serum/anchor";
|
||||
import { Native } from "@project-serum/anchor";
|
||||
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
||||
import {
|
||||
Keypair,
|
||||
LAMPORTS_PER_SOL,
|
||||
NONCE_ACCOUNT_LENGTH,
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
} from "@solana/web3.js";
|
||||
import * as assert from "assert";
|
||||
import BN from "bn.js";
|
||||
|
||||
describe("system-coder", () => {
|
||||
// Configure the client to use the local cluster.
|
||||
const provider = anchor.AnchorProvider.env();
|
||||
anchor.setProvider(provider);
|
||||
|
||||
// Client.
|
||||
const program = Native.system();
|
||||
|
||||
// Constants.
|
||||
const aliceKeypair = Keypair.generate();
|
||||
|
||||
it("Creates an account", async () => {
|
||||
// arrange
|
||||
const space = 100;
|
||||
const lamports =
|
||||
await program.provider.connection.getMinimumBalanceForRentExemption(
|
||||
space
|
||||
);
|
||||
const owner = SystemProgram.programId;
|
||||
// act
|
||||
await program.methods
|
||||
.createAccount(new BN(lamports), new BN(space), owner)
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: aliceKeypair.publicKey,
|
||||
})
|
||||
.signers([aliceKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const aliceAccount = await program.provider.connection.getAccountInfo(
|
||||
aliceKeypair.publicKey
|
||||
);
|
||||
assert.notEqual(aliceAccount, null);
|
||||
assert.ok(owner.equals(aliceAccount.owner));
|
||||
assert.equal(lamports, aliceAccount.lamports);
|
||||
});
|
||||
|
||||
it("Assigns an account to a program", async () => {
|
||||
// arrange
|
||||
const owner = TOKEN_PROGRAM_ID;
|
||||
// act
|
||||
await program.methods
|
||||
.assign(owner)
|
||||
.accounts({
|
||||
pubkey: aliceKeypair.publicKey,
|
||||
})
|
||||
.signers([aliceKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const aliceAccount = await program.provider.connection.getAccountInfo(
|
||||
aliceKeypair.publicKey
|
||||
);
|
||||
assert.notEqual(aliceAccount, null);
|
||||
assert.ok(owner.equals(aliceAccount.owner));
|
||||
});
|
||||
|
||||
it("Allocates space to an account", async () => {
|
||||
// arrange
|
||||
const newKeypair = Keypair.generate();
|
||||
const space = 100;
|
||||
const lamports =
|
||||
await program.provider.connection.getMinimumBalanceForRentExemption(
|
||||
space
|
||||
);
|
||||
// act
|
||||
await program.methods
|
||||
.allocate(new BN(space))
|
||||
.accounts({
|
||||
pubkey: newKeypair.publicKey,
|
||||
})
|
||||
.postInstructions([
|
||||
await program.methods
|
||||
.transfer(new BN(lamports))
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: newKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
.signers([newKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const newAccountAfter = await program.provider.connection.getAccountInfo(
|
||||
newKeypair.publicKey
|
||||
);
|
||||
assert.equal(space, newAccountAfter.data.byteLength);
|
||||
});
|
||||
|
||||
it("Creates an account with seed", async () => {
|
||||
const space = 100;
|
||||
const lamports =
|
||||
await program.provider.connection.getMinimumBalanceForRentExemption(
|
||||
space
|
||||
);
|
||||
const owner = SystemProgram.programId;
|
||||
const seed = "seeds";
|
||||
const bobPublicKey = await PublicKey.createWithSeed(
|
||||
aliceKeypair.publicKey,
|
||||
seed,
|
||||
owner
|
||||
);
|
||||
// act
|
||||
await program.methods
|
||||
.createAccountWithSeed(
|
||||
aliceKeypair.publicKey,
|
||||
seed,
|
||||
new BN(lamports),
|
||||
new BN(space),
|
||||
owner
|
||||
)
|
||||
.accounts({
|
||||
base: aliceKeypair.publicKey,
|
||||
from: provider.wallet.publicKey,
|
||||
to: bobPublicKey,
|
||||
})
|
||||
.signers([aliceKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const bobAccount = await program.provider.connection.getAccountInfo(
|
||||
bobPublicKey
|
||||
);
|
||||
assert.notEqual(bobAccount, null);
|
||||
});
|
||||
|
||||
it("Allocates and assigns an account with seed", async () => {
|
||||
const owner = TOKEN_PROGRAM_ID;
|
||||
const seed = "seeds2";
|
||||
const space = 100;
|
||||
const lamports =
|
||||
await program.provider.connection.getMinimumBalanceForRentExemption(
|
||||
space
|
||||
);
|
||||
const bobPublicKey = await PublicKey.createWithSeed(
|
||||
aliceKeypair.publicKey,
|
||||
seed,
|
||||
owner
|
||||
);
|
||||
// act
|
||||
await program.methods
|
||||
.allocateWithSeed(aliceKeypair.publicKey, seed, new BN(space), owner)
|
||||
.accounts({
|
||||
base: aliceKeypair.publicKey,
|
||||
account: bobPublicKey,
|
||||
})
|
||||
.postInstructions([
|
||||
await program.methods
|
||||
.transfer(new BN(lamports))
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: bobPublicKey,
|
||||
})
|
||||
.instruction(),
|
||||
await program.methods
|
||||
.assignWithSeed(aliceKeypair.publicKey, seed, owner)
|
||||
.accounts({
|
||||
base: aliceKeypair.publicKey,
|
||||
account: bobPublicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
.signers([aliceKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const bobAccount = await program.provider.connection.getAccountInfo(
|
||||
bobPublicKey
|
||||
);
|
||||
assert.notEqual(bobAccount, null);
|
||||
assert.ok(owner.equals(bobAccount.owner));
|
||||
});
|
||||
|
||||
it("Transfers from account with seed", async () => {
|
||||
const lamports = 1 * LAMPORTS_PER_SOL;
|
||||
const owner = SystemProgram.programId;
|
||||
const seed = "seeds3";
|
||||
const bobPublicKey = await PublicKey.createWithSeed(
|
||||
aliceKeypair.publicKey,
|
||||
seed,
|
||||
owner
|
||||
);
|
||||
const aliceAccountBefore = await program.provider.connection.getAccountInfo(
|
||||
aliceKeypair.publicKey
|
||||
);
|
||||
// act
|
||||
await program.methods
|
||||
.transfer(new BN(lamports))
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: bobPublicKey,
|
||||
})
|
||||
.rpc();
|
||||
await program.methods
|
||||
.transferWithSeed(new BN(lamports), seed, owner)
|
||||
.accounts({
|
||||
from: bobPublicKey,
|
||||
base: aliceKeypair.publicKey,
|
||||
to: aliceKeypair.publicKey,
|
||||
})
|
||||
.signers([aliceKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const aliceAccountAfter = await program.provider.connection.getAccountInfo(
|
||||
aliceKeypair.publicKey
|
||||
);
|
||||
assert.equal(
|
||||
aliceAccountBefore.lamports + lamports,
|
||||
aliceAccountAfter.lamports
|
||||
);
|
||||
});
|
||||
|
||||
it("Transfers lamports", async () => {
|
||||
// arrange
|
||||
const receiverKeypair = Keypair.generate();
|
||||
const lamports = 0.1 * LAMPORTS_PER_SOL;
|
||||
// act
|
||||
await program.methods
|
||||
.transfer(new BN(lamports))
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: receiverKeypair.publicKey,
|
||||
})
|
||||
.rpc();
|
||||
// assert
|
||||
const receiverAccount = await program.provider.connection.getAccountInfo(
|
||||
receiverKeypair.publicKey
|
||||
);
|
||||
assert.notEqual(receiverAccount, null);
|
||||
assert.equal(lamports, receiverAccount.lamports);
|
||||
});
|
||||
|
||||
it("Initializes nonce account", async () => {
|
||||
// arrange
|
||||
const nonceKeypair = Keypair.generate();
|
||||
const owner = SystemProgram.programId;
|
||||
const space = NONCE_ACCOUNT_LENGTH;
|
||||
const lamports =
|
||||
await provider.connection.getMinimumBalanceForRentExemption(space);
|
||||
// act
|
||||
await program.methods
|
||||
.initializeNonceAccount(provider.wallet.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
})
|
||||
.preInstructions([
|
||||
await program.methods
|
||||
.createAccount(new BN(lamports), new BN(space), owner)
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: nonceKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
.signers([nonceKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const nonceAccount = await program.account.nonce.fetch(
|
||||
nonceKeypair.publicKey
|
||||
);
|
||||
assert.notEqual(nonceAccount, null);
|
||||
assert.ok(nonceAccount.authorizedPubkey.equals(provider.wallet.publicKey));
|
||||
});
|
||||
|
||||
it("Advances a nonce account", async () => {
|
||||
// arrange
|
||||
const nonceKeypair = Keypair.generate();
|
||||
const owner = SystemProgram.programId;
|
||||
const space = NONCE_ACCOUNT_LENGTH;
|
||||
const lamports =
|
||||
await provider.connection.getMinimumBalanceForRentExemption(space);
|
||||
// act
|
||||
await program.methods
|
||||
.initializeNonceAccount(provider.wallet.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
})
|
||||
.preInstructions([
|
||||
await program.methods
|
||||
.createAccount(new BN(lamports), new BN(space), owner)
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: nonceKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
.signers([nonceKeypair])
|
||||
.rpc();
|
||||
// These have to be separate to make sure advance is in another slot.
|
||||
await program.methods
|
||||
.advanceNonceAccount(provider.wallet.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
})
|
||||
.rpc();
|
||||
// assert
|
||||
const nonceAccount = await program.account.nonce.fetch(
|
||||
nonceKeypair.publicKey
|
||||
);
|
||||
assert.notEqual(nonceAccount, null);
|
||||
});
|
||||
|
||||
it("Authorizes a nonce account", async () => {
|
||||
// arrange
|
||||
const nonceKeypair = Keypair.generate();
|
||||
const owner = SystemProgram.programId;
|
||||
const space = NONCE_ACCOUNT_LENGTH;
|
||||
const lamports =
|
||||
await provider.connection.getMinimumBalanceForRentExemption(space);
|
||||
// act
|
||||
await program.methods
|
||||
.initializeNonceAccount(provider.wallet.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
})
|
||||
.preInstructions([
|
||||
await program.methods
|
||||
.createAccount(new BN(lamports), new BN(space), owner)
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: nonceKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
.signers([nonceKeypair])
|
||||
.rpc();
|
||||
await program.methods
|
||||
.authorizeNonceAccount(aliceKeypair.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
authorized: provider.wallet.publicKey,
|
||||
})
|
||||
.rpc();
|
||||
// assert
|
||||
const nonceAccount = await program.account.nonce.fetch(
|
||||
nonceKeypair.publicKey
|
||||
);
|
||||
assert.notEqual(nonceAccount, null);
|
||||
assert.ok(nonceAccount.authorizedPubkey.equals(aliceKeypair.publicKey));
|
||||
});
|
||||
|
||||
it("Withdraws from nonce account", async () => {
|
||||
// arrange
|
||||
const nonceKeypair = Keypair.generate();
|
||||
const owner = SystemProgram.programId;
|
||||
const space = NONCE_ACCOUNT_LENGTH;
|
||||
const lamports =
|
||||
await provider.connection.getMinimumBalanceForRentExemption(space);
|
||||
const amount = 0.1 * LAMPORTS_PER_SOL;
|
||||
const aliceBalanceBefore = (
|
||||
await program.provider.connection.getAccountInfo(aliceKeypair.publicKey)
|
||||
).lamports;
|
||||
// act
|
||||
await program.methods
|
||||
.initializeNonceAccount(provider.wallet.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
})
|
||||
.preInstructions([
|
||||
await program.methods
|
||||
.createAccount(new BN(lamports), new BN(space), owner)
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: nonceKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
.signers([nonceKeypair])
|
||||
.rpc();
|
||||
await program.methods
|
||||
.advanceNonceAccount(provider.wallet.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
})
|
||||
.postInstructions([
|
||||
await program.methods
|
||||
.transfer(new BN(amount))
|
||||
.accounts({
|
||||
from: provider.wallet.publicKey,
|
||||
to: nonceKeypair.publicKey,
|
||||
})
|
||||
.instruction(),
|
||||
])
|
||||
.rpc();
|
||||
await program.methods
|
||||
.authorizeNonceAccount(aliceKeypair.publicKey)
|
||||
.accounts({
|
||||
nonce: nonceKeypair.publicKey,
|
||||
authorized: provider.wallet.publicKey,
|
||||
})
|
||||
.rpc();
|
||||
await program.methods
|
||||
.withdrawNonceAccount(new BN(amount))
|
||||
.accounts({
|
||||
authorized: aliceKeypair.publicKey,
|
||||
nonce: nonceKeypair.publicKey,
|
||||
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
|
||||
to: aliceKeypair.publicKey,
|
||||
})
|
||||
.signers([aliceKeypair])
|
||||
.rpc();
|
||||
// assert
|
||||
const aliceBalanceAfter = (
|
||||
await program.provider.connection.getAccountInfo(aliceKeypair.publicKey)
|
||||
).lamports;
|
||||
assert.equal(aliceBalanceAfter - aliceBalanceBefore, amount);
|
||||
});
|
||||
});
|
|
@ -3,6 +3,7 @@ import { Event } from "../program/event.js";
|
|||
|
||||
export * from "./borsh/index.js";
|
||||
export * from "./spl-token/index.js";
|
||||
export * from "./system/index.js";
|
||||
|
||||
/**
|
||||
* Coder provides a facade for encoding and decoding all IDL related objects.
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
import { AccountsCoder } from "../index.js";
|
||||
import { Idl, IdlTypeDef } from "../../idl.js";
|
||||
import * as BufferLayout from "buffer-layout";
|
||||
import { NONCE_ACCOUNT_LENGTH, PublicKey } from "@solana/web3.js";
|
||||
import { accountSize } from "../common.js";
|
||||
|
||||
export class SystemAccountsCoder<A extends string = string>
|
||||
implements AccountsCoder
|
||||
{
|
||||
constructor(private idl: Idl) {}
|
||||
|
||||
public async encode<T = any>(accountName: A, account: T): Promise<Buffer> {
|
||||
switch (accountName) {
|
||||
case "nonce": {
|
||||
const buffer = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
|
||||
const len = NONCE_ACCOUNT_LAYOUT.encode(account, buffer);
|
||||
return buffer.slice(0, len);
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid account name: ${accountName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public decode<T = any>(accountName: A, ix: Buffer): T {
|
||||
return this.decodeUnchecked(accountName, ix);
|
||||
}
|
||||
|
||||
public decodeUnchecked<T = any>(accountName: A, ix: Buffer): T {
|
||||
switch (accountName) {
|
||||
case "nonce": {
|
||||
return decodeNonceAccount(ix);
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid account name: ${accountName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this won't use the appendData.
|
||||
public memcmp(accountName: A, _appendData?: Buffer): any {
|
||||
switch (accountName) {
|
||||
case "nonce": {
|
||||
return {
|
||||
dataSize: NONCE_ACCOUNT_LENGTH,
|
||||
};
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid account name: ${accountName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public size(idlAccount: IdlTypeDef): number {
|
||||
return accountSize(this.idl, idlAccount) ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
function decodeNonceAccount<T = any>(ix: Buffer): T {
|
||||
return NONCE_ACCOUNT_LAYOUT.decode(ix) as T;
|
||||
}
|
||||
|
||||
class WrappedLayout<T, U> extends BufferLayout.Layout<U> {
|
||||
layout: BufferLayout.Layout<T>;
|
||||
decoder: (data: T) => U;
|
||||
encoder: (src: U) => T;
|
||||
|
||||
constructor(
|
||||
layout: BufferLayout.Layout<T>,
|
||||
decoder: (data: T) => U,
|
||||
encoder: (src: U) => T,
|
||||
property?: string
|
||||
) {
|
||||
super(layout.span, property);
|
||||
this.layout = layout;
|
||||
this.decoder = decoder;
|
||||
this.encoder = encoder;
|
||||
}
|
||||
|
||||
decode(b: Buffer, offset?: number): U {
|
||||
return this.decoder(this.layout.decode(b, offset));
|
||||
}
|
||||
|
||||
encode(src: U, b: Buffer, offset?: number): number {
|
||||
return this.layout.encode(this.encoder(src), b, offset);
|
||||
}
|
||||
|
||||
getSpan(b: Buffer, offset?: number): number {
|
||||
return this.layout.getSpan(b, offset);
|
||||
}
|
||||
}
|
||||
|
||||
function publicKey(property?: string): BufferLayout.Layout<PublicKey> {
|
||||
return new WrappedLayout(
|
||||
BufferLayout.blob(32),
|
||||
(b: Buffer) => new PublicKey(b),
|
||||
(key: PublicKey) => key.toBuffer(),
|
||||
property
|
||||
);
|
||||
}
|
||||
|
||||
const NONCE_ACCOUNT_LAYOUT = BufferLayout.struct([
|
||||
BufferLayout.u32("version"),
|
||||
BufferLayout.u32("state"),
|
||||
publicKey("authorizedPubkey"),
|
||||
publicKey("nonce"),
|
||||
BufferLayout.struct(
|
||||
[BufferLayout.nu64("lamportsPerSignature")],
|
||||
"feeCalculator"
|
||||
),
|
||||
]);
|
|
@ -0,0 +1,14 @@
|
|||
import { EventCoder } from "../index.js";
|
||||
import { Idl } from "../../idl.js";
|
||||
import { Event } from "../../program/event";
|
||||
import { IdlEvent } from "../../idl";
|
||||
|
||||
export class SystemEventsCoder implements EventCoder {
|
||||
constructor(_idl: Idl) {}
|
||||
|
||||
decode<E extends IdlEvent = IdlEvent, T = Record<string, string>>(
|
||||
_log: string
|
||||
): Event<E, T> | null {
|
||||
throw new Error("System program does not have events");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { Idl } from "../../idl.js";
|
||||
import { Coder } from "../index.js";
|
||||
import { SystemInstructionCoder } from "./instruction.js";
|
||||
import { SystemStateCoder } from "./state.js";
|
||||
import { SystemAccountsCoder } from "./accounts.js";
|
||||
import { SystemEventsCoder } from "./events.js";
|
||||
|
||||
/**
|
||||
* Coder for the System program.
|
||||
*/
|
||||
export class SystemCoder implements Coder {
|
||||
readonly instruction: SystemInstructionCoder;
|
||||
readonly accounts: SystemAccountsCoder;
|
||||
readonly state: SystemStateCoder;
|
||||
readonly events: SystemEventsCoder;
|
||||
|
||||
constructor(idl: Idl) {
|
||||
this.instruction = new SystemInstructionCoder(idl);
|
||||
this.accounts = new SystemAccountsCoder(idl);
|
||||
this.events = new SystemEventsCoder(idl);
|
||||
this.state = new SystemStateCoder(idl);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
import BN from "bn.js";
|
||||
import * as BufferLayout from "buffer-layout";
|
||||
import camelCase from "camelcase";
|
||||
import { Idl } from "../../idl.js";
|
||||
import { InstructionCoder } from "../index.js";
|
||||
|
||||
export class SystemInstructionCoder implements InstructionCoder {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
constructor(_: Idl) {}
|
||||
|
||||
encode(ixName: string, ix: any): Buffer {
|
||||
switch (camelCase(ixName)) {
|
||||
case "createAccount": {
|
||||
return encodeCreateAccount(ix);
|
||||
}
|
||||
case "assign": {
|
||||
return encodeAssign(ix);
|
||||
}
|
||||
case "transfer": {
|
||||
return encodeTransfer(ix);
|
||||
}
|
||||
case "createAccountWithSeed": {
|
||||
return encodeCreateAccountWithSeed(ix);
|
||||
}
|
||||
case "advanceNonceAccount": {
|
||||
return encodeAdvanceNonceAccount(ix);
|
||||
}
|
||||
case "withdrawNonceAccount": {
|
||||
return encodeWithdrawNonceAccount(ix);
|
||||
}
|
||||
case "initializeNonceAccount": {
|
||||
return encodeInitializeNonceAccount(ix);
|
||||
}
|
||||
case "authorizeNonceAccount": {
|
||||
return encodeAuthorizeNonceAccount(ix);
|
||||
}
|
||||
case "allocate": {
|
||||
return encodeAllocate(ix);
|
||||
}
|
||||
case "allocateWithSeed": {
|
||||
return encodeAllocateWithSeed(ix);
|
||||
}
|
||||
case "assignWithSeed": {
|
||||
return encodeAssignWithSeed(ix);
|
||||
}
|
||||
case "transferWithSeed": {
|
||||
return encodeTransferWithSeed(ix);
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Invalid instruction: ${ixName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
encodeState(_ixName: string, _ix: any): Buffer {
|
||||
throw new Error("System does not have state");
|
||||
}
|
||||
}
|
||||
|
||||
class RustStringLayout extends BufferLayout.Layout<string | null> {
|
||||
layout = BufferLayout.struct<
|
||||
Readonly<{
|
||||
length?: number;
|
||||
lengthPadding?: number;
|
||||
chars: Buffer;
|
||||
}>
|
||||
>(
|
||||
[
|
||||
BufferLayout.u32("length"),
|
||||
BufferLayout.u32("lengthPadding"),
|
||||
BufferLayout.blob(BufferLayout.offset(BufferLayout.u32(), -8), "chars"),
|
||||
],
|
||||
this.property
|
||||
);
|
||||
|
||||
constructor(public property?: string) {
|
||||
super(-1, property);
|
||||
}
|
||||
|
||||
encode(src: string | null, b: Buffer, offset = 0): number {
|
||||
if (src === null || src === undefined) {
|
||||
return this.layout.span;
|
||||
}
|
||||
|
||||
const data = {
|
||||
chars: Buffer.from(src, "utf8"),
|
||||
};
|
||||
|
||||
return this.layout.encode(data, b, offset);
|
||||
}
|
||||
|
||||
decode(b: Buffer, offset = 0): string | null {
|
||||
const data = this.layout.decode(b, offset);
|
||||
return data["chars"].toString();
|
||||
}
|
||||
|
||||
getSpan(b: Buffer, offset = 0): number {
|
||||
return (
|
||||
BufferLayout.u32().span +
|
||||
BufferLayout.u32().span +
|
||||
new BN(new Uint8Array(b).slice(offset, offset + 4), 10, "le").toNumber()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function rustStringLayout(property: string) {
|
||||
return new RustStringLayout(property);
|
||||
}
|
||||
|
||||
function publicKey(property: string): any {
|
||||
return BufferLayout.blob(32, property);
|
||||
}
|
||||
|
||||
function encodeCreateAccount({ lamports, space, owner }: any): Buffer {
|
||||
return encodeData({
|
||||
createAccount: { lamports, space, owner: owner.toBuffer() },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeAssign({ owner }: any): Buffer {
|
||||
return encodeData({
|
||||
assign: { owner: owner.toBuffer() },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeTransfer({ lamports }: any): Buffer {
|
||||
return encodeData({
|
||||
transfer: { lamports },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeCreateAccountWithSeed({
|
||||
base,
|
||||
seed,
|
||||
lamports,
|
||||
space,
|
||||
owner,
|
||||
}: any): Buffer {
|
||||
return encodeData(
|
||||
{
|
||||
createAccountWithSeed: {
|
||||
base: base.toBuffer(),
|
||||
seed,
|
||||
lamports,
|
||||
space,
|
||||
owner: owner.toBuffer(),
|
||||
},
|
||||
},
|
||||
LAYOUT.getVariant(3).span + seed.length
|
||||
);
|
||||
}
|
||||
|
||||
function encodeInitializeNonceAccount({ authorized }: any): Buffer {
|
||||
return encodeData({
|
||||
initializeNonceAccount: { authorized: authorized.toBuffer() },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeAdvanceNonceAccount({ authorized }: any): Buffer {
|
||||
return encodeData({
|
||||
advanceNonceAccount: { authorized: authorized.toBuffer() },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeWithdrawNonceAccount({ lamports }: any): Buffer {
|
||||
return encodeData({
|
||||
withdrawNonceAccount: { lamports },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeAuthorizeNonceAccount({ authorized }: any): Buffer {
|
||||
return encodeData({
|
||||
authorizeNonceAccount: { authorized: authorized.toBuffer() },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeAllocate({ space }: any): Buffer {
|
||||
return encodeData({
|
||||
allocate: { space },
|
||||
});
|
||||
}
|
||||
|
||||
function encodeAllocateWithSeed({ base, seed, space, owner }: any): Buffer {
|
||||
return encodeData(
|
||||
{
|
||||
allocateWithSeed: {
|
||||
base: base.toBuffer(),
|
||||
seed,
|
||||
space,
|
||||
owner: owner.toBuffer(),
|
||||
},
|
||||
},
|
||||
LAYOUT.getVariant(9).span + seed.length
|
||||
);
|
||||
}
|
||||
|
||||
function encodeAssignWithSeed({ base, seed, owner }: any): Buffer {
|
||||
return encodeData(
|
||||
{
|
||||
assignWithSeed: {
|
||||
base: base.toBuffer(),
|
||||
seed,
|
||||
owner: owner.toBuffer(),
|
||||
},
|
||||
},
|
||||
LAYOUT.getVariant(10).span + seed.length
|
||||
);
|
||||
}
|
||||
|
||||
function encodeTransferWithSeed({ lamports, seed, owner }: any): Buffer {
|
||||
return encodeData(
|
||||
{
|
||||
transferWithSeed: {
|
||||
lamports,
|
||||
seed,
|
||||
owner: owner.toBuffer(),
|
||||
},
|
||||
},
|
||||
LAYOUT.getVariant(11).span + seed.length
|
||||
);
|
||||
}
|
||||
|
||||
const LAYOUT = BufferLayout.union(BufferLayout.u32("instruction"));
|
||||
LAYOUT.addVariant(
|
||||
0,
|
||||
BufferLayout.struct([
|
||||
BufferLayout.ns64("lamports"),
|
||||
BufferLayout.ns64("space"),
|
||||
publicKey("owner"),
|
||||
]),
|
||||
"createAccount"
|
||||
);
|
||||
LAYOUT.addVariant(1, BufferLayout.struct([publicKey("owner")]), "assign");
|
||||
LAYOUT.addVariant(
|
||||
2,
|
||||
BufferLayout.struct([BufferLayout.ns64("lamports")]),
|
||||
"transfer"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
3,
|
||||
BufferLayout.struct([
|
||||
publicKey("base"),
|
||||
rustStringLayout("seed"),
|
||||
BufferLayout.ns64("lamports"),
|
||||
BufferLayout.ns64("space"),
|
||||
publicKey("owner"),
|
||||
]),
|
||||
"createAccountWithSeed"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
4,
|
||||
BufferLayout.struct([publicKey("authorized")]),
|
||||
"advanceNonceAccount"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
5,
|
||||
BufferLayout.struct([BufferLayout.ns64("lamports")]),
|
||||
"withdrawNonceAccount"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
6,
|
||||
BufferLayout.struct([publicKey("authorized")]),
|
||||
"initializeNonceAccount"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
7,
|
||||
BufferLayout.struct([publicKey("authorized")]),
|
||||
"authorizeNonceAccount"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
8,
|
||||
BufferLayout.struct([BufferLayout.ns64("space")]),
|
||||
"allocate"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
9,
|
||||
BufferLayout.struct([
|
||||
publicKey("base"),
|
||||
rustStringLayout("seed"),
|
||||
BufferLayout.ns64("space"),
|
||||
publicKey("owner"),
|
||||
]),
|
||||
"allocateWithSeed"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
10,
|
||||
BufferLayout.struct([
|
||||
publicKey("base"),
|
||||
rustStringLayout("seed"),
|
||||
publicKey("owner"),
|
||||
]),
|
||||
"assignWithSeed"
|
||||
);
|
||||
LAYOUT.addVariant(
|
||||
11,
|
||||
BufferLayout.struct([
|
||||
BufferLayout.ns64("lamports"),
|
||||
rustStringLayout("seed"),
|
||||
publicKey("owner"),
|
||||
]),
|
||||
"transferWithSeed"
|
||||
);
|
||||
|
||||
function encodeData(instruction: any, maxSpan?: number): Buffer {
|
||||
const b = Buffer.alloc(maxSpan ?? instructionMaxSpan);
|
||||
const span = LAYOUT.encode(instruction, b);
|
||||
|
||||
if (maxSpan === undefined) {
|
||||
return b.slice(0, span);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
const instructionMaxSpan = Math.max(
|
||||
...Object.values(LAYOUT.registry).map((r: any) => r.span)
|
||||
);
|
|
@ -0,0 +1,14 @@
|
|||
import { StateCoder } from "../index.js";
|
||||
import { Idl } from "../../idl";
|
||||
|
||||
export class SystemStateCoder implements StateCoder {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
constructor(_idl: Idl) {}
|
||||
|
||||
encode<T = any>(_name: string, _account: T): Promise<Buffer> {
|
||||
throw new Error("System does not have state");
|
||||
}
|
||||
decode<T = any>(_ix: Buffer): T {
|
||||
throw new Error("System does not have state");
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ export * from "./coder/index.js";
|
|||
export * as utils from "./utils/index.js";
|
||||
export * from "./program/index.js";
|
||||
export * from "./spl/index.js";
|
||||
export * from "./native/index.js";
|
||||
|
||||
export declare const workspace: any;
|
||||
export declare class Wallet extends NodeWallet {}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import { Program, Provider } from "../index.js";
|
||||
import { program as systemProgram, SystemProgram } from "./system.js";
|
||||
|
||||
export { SystemProgram } from "./system.js";
|
||||
|
||||
export class Native {
|
||||
public static system(provider?: Provider): Program<SystemProgram> {
|
||||
return systemProgram(provider);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,781 @@
|
|||
import { PublicKey } from "@solana/web3.js";
|
||||
import { Program } from "../program/index.js";
|
||||
import Provider from "../provider.js";
|
||||
import { SystemCoder } from "../coder/system/index.js";
|
||||
|
||||
const SYSTEM_PROGRAM_ID = new PublicKey("11111111111111111111111111111111");
|
||||
|
||||
export function program(provider?: Provider): Program<SystemProgram> {
|
||||
return new Program<SystemProgram>(IDL, SYSTEM_PROGRAM_ID, provider, coder());
|
||||
}
|
||||
|
||||
export function coder(): SystemCoder {
|
||||
return new SystemCoder(IDL);
|
||||
}
|
||||
|
||||
/**
|
||||
* System IDL.
|
||||
*/
|
||||
export type SystemProgram = {
|
||||
version: "0.1.0";
|
||||
name: "system_program";
|
||||
instructions: [
|
||||
{
|
||||
name: "createAccount";
|
||||
accounts: [
|
||||
{
|
||||
name: "from";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
},
|
||||
{
|
||||
name: "to";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "lamports";
|
||||
type: "u64";
|
||||
},
|
||||
{
|
||||
name: "space";
|
||||
type: "u64";
|
||||
},
|
||||
{
|
||||
name: "owner";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "assign";
|
||||
accounts: [
|
||||
{
|
||||
name: "pubkey";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "owner";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "transfer";
|
||||
accounts: [
|
||||
{
|
||||
name: "from";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
},
|
||||
{
|
||||
name: "to";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "lamports";
|
||||
type: "u64";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "createAccountWithSeed";
|
||||
accounts: [
|
||||
{
|
||||
name: "from";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
},
|
||||
{
|
||||
name: "to";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "base";
|
||||
isMut: false;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "base";
|
||||
type: "publicKey";
|
||||
},
|
||||
{
|
||||
name: "seed";
|
||||
type: "string";
|
||||
},
|
||||
{
|
||||
name: "lamports";
|
||||
type: "u64";
|
||||
},
|
||||
{
|
||||
name: "space";
|
||||
type: "u64";
|
||||
},
|
||||
{
|
||||
name: "owner";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "advanceNonceAccount";
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "recentBlockhashes";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "authorized";
|
||||
isMut: false;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "authorized";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "withdrawNonceAccount";
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "to";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "recentBlockhashes";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "rent";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "authorized";
|
||||
isMut: false;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "lamports";
|
||||
type: "u64";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "initializeNonceAccount";
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
},
|
||||
{
|
||||
name: "recentBlockhashes";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "rent";
|
||||
isMut: false;
|
||||
isSigner: false;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "authorized";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "authorizeNonceAccount";
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "authorized";
|
||||
isMut: false;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "authorized";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "allocate";
|
||||
accounts: [
|
||||
{
|
||||
name: "pubkey";
|
||||
isMut: true;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "space";
|
||||
type: "u64";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "allocateWithSeed";
|
||||
accounts: [
|
||||
{
|
||||
name: "account";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "base";
|
||||
isMut: false;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "base";
|
||||
type: "publicKey";
|
||||
},
|
||||
{
|
||||
name: "seed";
|
||||
type: "string";
|
||||
},
|
||||
{
|
||||
name: "space";
|
||||
type: "u64";
|
||||
},
|
||||
{
|
||||
name: "owner";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "assignWithSeed";
|
||||
accounts: [
|
||||
{
|
||||
name: "account";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "base";
|
||||
isMut: false;
|
||||
isSigner: true;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "base";
|
||||
type: "publicKey";
|
||||
},
|
||||
{
|
||||
name: "seed";
|
||||
type: "string";
|
||||
},
|
||||
{
|
||||
name: "owner";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
},
|
||||
{
|
||||
name: "transferWithSeed";
|
||||
accounts: [
|
||||
{
|
||||
name: "from";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
},
|
||||
{
|
||||
name: "base";
|
||||
isMut: false;
|
||||
isSigner: true;
|
||||
},
|
||||
{
|
||||
name: "to";
|
||||
isMut: true;
|
||||
isSigner: false;
|
||||
}
|
||||
];
|
||||
args: [
|
||||
{
|
||||
name: "lamports";
|
||||
type: "u64";
|
||||
},
|
||||
{
|
||||
name: "seed";
|
||||
type: "string";
|
||||
},
|
||||
{
|
||||
name: "owner";
|
||||
type: "publicKey";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce";
|
||||
type: {
|
||||
kind: "struct";
|
||||
fields: [
|
||||
{
|
||||
name: "version";
|
||||
type: "u32";
|
||||
},
|
||||
{
|
||||
name: "state";
|
||||
type: "u32";
|
||||
},
|
||||
{
|
||||
name: "authorizedPubkey";
|
||||
type: "publicKey";
|
||||
},
|
||||
{
|
||||
name: "nonce";
|
||||
type: "publicKey";
|
||||
},
|
||||
{
|
||||
name: "feeCalculator";
|
||||
type: {
|
||||
defined: "FeeCalculator";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
types: [
|
||||
{
|
||||
name: "FeeCalculator";
|
||||
type: {
|
||||
kind: "struct";
|
||||
fields: [
|
||||
{
|
||||
name: "lamportsPerSignature";
|
||||
type: "u64";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
export const IDL: SystemProgram = {
|
||||
version: "0.1.0",
|
||||
name: "system_program",
|
||||
instructions: [
|
||||
{
|
||||
name: "createAccount",
|
||||
accounts: [
|
||||
{
|
||||
name: "from",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
{
|
||||
name: "to",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "lamports",
|
||||
type: "u64",
|
||||
},
|
||||
{
|
||||
name: "space",
|
||||
type: "u64",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "assign",
|
||||
accounts: [
|
||||
{
|
||||
name: "pubkey",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "owner",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "transfer",
|
||||
accounts: [
|
||||
{
|
||||
name: "from",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
{
|
||||
name: "to",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "lamports",
|
||||
type: "u64",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "createAccountWithSeed",
|
||||
accounts: [
|
||||
{
|
||||
name: "from",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
{
|
||||
name: "to",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "base",
|
||||
isMut: false,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "base",
|
||||
type: "publicKey",
|
||||
},
|
||||
{
|
||||
name: "seed",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "lamports",
|
||||
type: "u64",
|
||||
},
|
||||
{
|
||||
name: "space",
|
||||
type: "u64",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "advanceNonceAccount",
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "recentBlockhashes",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "authorized",
|
||||
isMut: false,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "authorized",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "withdrawNonceAccount",
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "to",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "recentBlockhashes",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "rent",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "authorized",
|
||||
isMut: false,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "lamports",
|
||||
type: "u64",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "initializeNonceAccount",
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
{
|
||||
name: "recentBlockhashes",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "rent",
|
||||
isMut: false,
|
||||
isSigner: false,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "authorized",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "authorizeNonceAccount",
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "authorized",
|
||||
isMut: false,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "authorized",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "allocate",
|
||||
accounts: [
|
||||
{
|
||||
name: "pubkey",
|
||||
isMut: true,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "space",
|
||||
type: "u64",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "allocateWithSeed",
|
||||
accounts: [
|
||||
{
|
||||
name: "account",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "base",
|
||||
isMut: false,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "base",
|
||||
type: "publicKey",
|
||||
},
|
||||
{
|
||||
name: "seed",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "space",
|
||||
type: "u64",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "assignWithSeed",
|
||||
accounts: [
|
||||
{
|
||||
name: "account",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "base",
|
||||
isMut: false,
|
||||
isSigner: true,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "base",
|
||||
type: "publicKey",
|
||||
},
|
||||
{
|
||||
name: "seed",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "transferWithSeed",
|
||||
accounts: [
|
||||
{
|
||||
name: "from",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
{
|
||||
name: "base",
|
||||
isMut: false,
|
||||
isSigner: true,
|
||||
},
|
||||
{
|
||||
name: "to",
|
||||
isMut: true,
|
||||
isSigner: false,
|
||||
},
|
||||
],
|
||||
args: [
|
||||
{
|
||||
name: "lamports",
|
||||
type: "u64",
|
||||
},
|
||||
{
|
||||
name: "seed",
|
||||
type: "string",
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
type: "publicKey",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
accounts: [
|
||||
{
|
||||
name: "nonce",
|
||||
type: {
|
||||
kind: "struct",
|
||||
fields: [
|
||||
{
|
||||
name: "version",
|
||||
type: "u32",
|
||||
},
|
||||
{
|
||||
name: "state",
|
||||
type: "u32",
|
||||
},
|
||||
{
|
||||
name: "authorizedPubkey",
|
||||
type: "publicKey",
|
||||
},
|
||||
{
|
||||
name: "nonce",
|
||||
type: "publicKey",
|
||||
},
|
||||
{
|
||||
name: "feeCalculator",
|
||||
type: {
|
||||
defined: "FeeCalculator",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
types: [
|
||||
{
|
||||
name: "FeeCalculator",
|
||||
type: {
|
||||
kind: "struct",
|
||||
fields: [
|
||||
{
|
||||
name: "lamportsPerSignature",
|
||||
type: "u64",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
Loading…
Reference in New Issue