feat(system-program): add createAccountWithSeed
This commit is contained in:
committed by
Michael Vines
parent
cc550dfb08
commit
0760853871
@ -220,6 +220,14 @@ declare module '@solana/web3.js' {
|
|||||||
amount: number,
|
amount: number,
|
||||||
): Transaction;
|
): Transaction;
|
||||||
static assign(from: PublicKey, programId: PublicKey): 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 ===
|
// === src/validator-info.js ===
|
||||||
|
@ -43,5 +43,25 @@ export const rustString = (property: string = 'string') => {
|
|||||||
return _encode(data, buffer, offset);
|
return _encode(data, buffer, offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rsl.alloc = str => {
|
||||||
|
return (
|
||||||
|
BufferLayout.u32().span +
|
||||||
|
BufferLayout.u32().span +
|
||||||
|
Buffer.from(str, 'utf8').length
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return rsl;
|
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 {
|
get fromPublicKey(): PublicKey | null {
|
||||||
if (
|
if (
|
||||||
this.type == SystemInstructionLayout.Create ||
|
this.type == SystemInstructionLayout.Create ||
|
||||||
|
this.type == SystemInstructionLayout.CreateWithSeed ||
|
||||||
this.type == SystemInstructionLayout.Transfer
|
this.type == SystemInstructionLayout.Transfer
|
||||||
) {
|
) {
|
||||||
return this.keys[0].pubkey;
|
return this.keys[0].pubkey;
|
||||||
@ -80,6 +81,7 @@ export class SystemInstruction extends TransactionInstruction {
|
|||||||
get toPublicKey(): PublicKey | null {
|
get toPublicKey(): PublicKey | null {
|
||||||
if (
|
if (
|
||||||
this.type == SystemInstructionLayout.Create ||
|
this.type == SystemInstructionLayout.Create ||
|
||||||
|
this.type == SystemInstructionLayout.CreateWithSeed ||
|
||||||
this.type == SystemInstructionLayout.Transfer
|
this.type == SystemInstructionLayout.Transfer
|
||||||
) {
|
) {
|
||||||
return this.keys[1].pubkey;
|
return this.keys[1].pubkey;
|
||||||
@ -95,7 +97,10 @@ export class SystemInstruction extends TransactionInstruction {
|
|||||||
const data = this.type.layout.decode(this.data);
|
const data = this.type.layout.decode(this.data);
|
||||||
if (this.type == SystemInstructionLayout.Transfer) {
|
if (this.type == SystemInstructionLayout.Transfer) {
|
||||||
return data.amount;
|
return data.amount;
|
||||||
} else if (this.type == SystemInstructionLayout.Create) {
|
} else if (
|
||||||
|
this.type == SystemInstructionLayout.Create ||
|
||||||
|
this.type == SystemInstructionLayout.CreateWithSeed
|
||||||
|
) {
|
||||||
return data.lamports;
|
return data.lamports;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -139,13 +144,25 @@ const SystemInstructionLayout = Object.freeze({
|
|||||||
BufferLayout.ns64('amount'),
|
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
|
* Populate a buffer of instruction data using the SystemInstructionType
|
||||||
*/
|
*/
|
||||||
function encodeData(type: SystemInstructionType, fields: Object): Buffer {
|
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);
|
const layoutFields = Object.assign({instruction: type.index}, fields);
|
||||||
type.layout.encode(layoutFields, data);
|
type.layout.encode(layoutFields, data);
|
||||||
return data;
|
return data;
|
||||||
@ -221,4 +238,34 @@ export class SystemProgram {
|
|||||||
data,
|
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
|
// 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', () => {
|
test('SystemInstruction create', () => {
|
||||||
const from = new Account();
|
const from = new Account();
|
||||||
const to = new Account();
|
const to = new Account();
|
||||||
@ -104,6 +123,30 @@ test('SystemInstruction assign', () => {
|
|||||||
expect(systemInstruction.programId).toEqual(SystemProgram.programId);
|
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', () => {
|
test('non-SystemInstruction error', () => {
|
||||||
const from = new Account();
|
const from = new Account();
|
||||||
const program = new Account();
|
const program = new Account();
|
||||||
|
Reference in New Issue
Block a user