feat(system-program): add createAccountWithSeed
This commit is contained in:
parent
cc550dfb08
commit
0760853871
|
@ -220,6 +220,14 @@ declare module '@solana/web3.js' {
|
|||
amount: number,
|
||||
): Transaction;
|
||||
static assign(from: PublicKey, programId: PublicKey): Transaction;
|
||||
static createAccountWithSeed(
|
||||
from: PublicKey,
|
||||
newAccount: PublicKey,
|
||||
seed: string,
|
||||
lamports: number,
|
||||
space: number,
|
||||
programId: PublicKey,
|
||||
): Transaction;
|
||||
}
|
||||
|
||||
// === src/validator-info.js ===
|
||||
|
|
|
@ -43,5 +43,25 @@ export const rustString = (property: string = 'string') => {
|
|||
return _encode(data, buffer, offset);
|
||||
};
|
||||
|
||||
rsl.alloc = str => {
|
||||
return (
|
||||
BufferLayout.u32().span +
|
||||
BufferLayout.u32().span +
|
||||
Buffer.from(str, 'utf8').length
|
||||
);
|
||||
};
|
||||
|
||||
return rsl;
|
||||
};
|
||||
|
||||
export function getAlloc(type: Object, fields: Object): number {
|
||||
let alloc = 0;
|
||||
type.layout.fields.forEach(item => {
|
||||
if (item.span >= 0) {
|
||||
alloc += item.span;
|
||||
} else if (typeof item.alloc === 'function') {
|
||||
alloc += item.alloc(fields[item.property]);
|
||||
}
|
||||
});
|
||||
return alloc;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ export class SystemInstruction extends TransactionInstruction {
|
|||
get fromPublicKey(): PublicKey | null {
|
||||
if (
|
||||
this.type == SystemInstructionLayout.Create ||
|
||||
this.type == SystemInstructionLayout.CreateWithSeed ||
|
||||
this.type == SystemInstructionLayout.Transfer
|
||||
) {
|
||||
return this.keys[0].pubkey;
|
||||
|
@ -80,6 +81,7 @@ export class SystemInstruction extends TransactionInstruction {
|
|||
get toPublicKey(): PublicKey | null {
|
||||
if (
|
||||
this.type == SystemInstructionLayout.Create ||
|
||||
this.type == SystemInstructionLayout.CreateWithSeed ||
|
||||
this.type == SystemInstructionLayout.Transfer
|
||||
) {
|
||||
return this.keys[1].pubkey;
|
||||
|
@ -95,7 +97,10 @@ export class SystemInstruction extends TransactionInstruction {
|
|||
const data = this.type.layout.decode(this.data);
|
||||
if (this.type == SystemInstructionLayout.Transfer) {
|
||||
return data.amount;
|
||||
} else if (this.type == SystemInstructionLayout.Create) {
|
||||
} else if (
|
||||
this.type == SystemInstructionLayout.Create ||
|
||||
this.type == SystemInstructionLayout.CreateWithSeed
|
||||
) {
|
||||
return data.lamports;
|
||||
}
|
||||
return null;
|
||||
|
@ -139,13 +144,25 @@ const SystemInstructionLayout = Object.freeze({
|
|||
BufferLayout.ns64('amount'),
|
||||
]),
|
||||
},
|
||||
CreateWithSeed: {
|
||||
index: 3,
|
||||
layout: BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
Layout.rustString('seed'),
|
||||
BufferLayout.ns64('lamports'),
|
||||
BufferLayout.ns64('space'),
|
||||
Layout.publicKey('programId'),
|
||||
]),
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Populate a buffer of instruction data using the SystemInstructionType
|
||||
*/
|
||||
function encodeData(type: SystemInstructionType, fields: Object): Buffer {
|
||||
const data = Buffer.alloc(type.layout.span);
|
||||
const allocLength =
|
||||
type.layout.span >= 0 ? type.layout.span : Layout.getAlloc(type, fields);
|
||||
const data = Buffer.alloc(allocLength);
|
||||
const layoutFields = Object.assign({instruction: type.index}, fields);
|
||||
type.layout.encode(layoutFields, data);
|
||||
return data;
|
||||
|
@ -221,4 +238,34 @@ export class SystemProgram {
|
|||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a Transaction that creates a new account at
|
||||
* an address generated with `from`, a seed, and programId
|
||||
*/
|
||||
static createAccountWithSeed(
|
||||
from: PublicKey,
|
||||
newAccount: PublicKey,
|
||||
seed: string,
|
||||
lamports: number,
|
||||
space: number,
|
||||
programId: PublicKey,
|
||||
): Transaction {
|
||||
const type = SystemInstructionLayout.CreateWithSeed;
|
||||
const data = encodeData(type, {
|
||||
seed,
|
||||
lamports,
|
||||
space,
|
||||
programId: programId.toBuffer(),
|
||||
});
|
||||
|
||||
return new Transaction().add({
|
||||
keys: [
|
||||
{pubkey: from, isSigner: true, isWritable: true},
|
||||
{pubkey: newAccount, isSigner: false, isWritable: true},
|
||||
],
|
||||
programId: SystemProgram.programId,
|
||||
data,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,25 @@ test('assign', () => {
|
|||
// TODO: Validate transaction contents more
|
||||
});
|
||||
|
||||
test('createAccountWithSeed', () => {
|
||||
const from = new Account();
|
||||
const newAccount = new Account();
|
||||
let transaction;
|
||||
|
||||
transaction = SystemProgram.createAccountWithSeed(
|
||||
from.publicKey,
|
||||
newAccount.publicKey,
|
||||
'hi there',
|
||||
123,
|
||||
BudgetProgram.space,
|
||||
BudgetProgram.programId,
|
||||
);
|
||||
|
||||
expect(transaction.keys).toHaveLength(2);
|
||||
expect(transaction.programId).toEqual(SystemProgram.programId);
|
||||
// TODO: Validate transaction contents more
|
||||
});
|
||||
|
||||
test('SystemInstruction create', () => {
|
||||
const from = new Account();
|
||||
const to = new Account();
|
||||
|
@ -104,6 +123,30 @@ test('SystemInstruction assign', () => {
|
|||
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
|
||||
});
|
||||
|
||||
test('SystemInstruction createWithSeed', () => {
|
||||
const from = new Account();
|
||||
const to = new Account();
|
||||
const program = new Account();
|
||||
const amount = 42;
|
||||
const space = 100;
|
||||
const recentBlockhash = 'EETubP5AKHgjPAhzPAFcb8BAY1hMH639CWCFTqi3hq1k'; // Arbitrary known recentBlockhash
|
||||
const create = SystemProgram.createAccountWithSeed(
|
||||
from.publicKey,
|
||||
to.publicKey,
|
||||
'hi there',
|
||||
amount,
|
||||
space,
|
||||
program.publicKey,
|
||||
);
|
||||
const transaction = new Transaction({recentBlockhash}).add(create);
|
||||
|
||||
const systemInstruction = SystemInstruction.from(transaction.instructions[0]);
|
||||
expect(systemInstruction.fromPublicKey).toEqual(from.publicKey);
|
||||
expect(systemInstruction.toPublicKey).toEqual(to.publicKey);
|
||||
expect(systemInstruction.amount).toEqual(amount);
|
||||
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
|
||||
});
|
||||
|
||||
test('non-SystemInstruction error', () => {
|
||||
const from = new Account();
|
||||
const program = new Account();
|
||||
|
|
Loading…
Reference in New Issue