fix: add tx instruction->transfer data functionality
This commit is contained in:
committed by
Michael Vines
parent
ee3acbf1ba
commit
daba1a7856
@ -2,9 +2,154 @@
|
||||
|
||||
import * as BufferLayout from 'buffer-layout';
|
||||
|
||||
import {Transaction} from './transaction';
|
||||
import {Transaction, TransactionInstruction} from './transaction';
|
||||
import {PublicKey} from './publickey';
|
||||
import * as Layout from './layout';
|
||||
import type {TransactionInstructionCtorFields} from './transaction';
|
||||
|
||||
/**
|
||||
* System Instruction class
|
||||
*/
|
||||
export class SystemInstruction extends TransactionInstruction {
|
||||
/**
|
||||
* Type of SystemInstruction
|
||||
*/
|
||||
type: SystemInstructionType;
|
||||
|
||||
constructor(
|
||||
opts?: TransactionInstructionCtorFields,
|
||||
type?: SystemInstructionType,
|
||||
) {
|
||||
if (
|
||||
opts &&
|
||||
opts.programId &&
|
||||
!opts.programId.equals(SystemProgram.programId)
|
||||
) {
|
||||
throw new Error('programId incorrect; not a SystemInstruction');
|
||||
}
|
||||
super(opts);
|
||||
if (type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
static from(instruction: TransactionInstruction): SystemInstruction {
|
||||
if (!instruction.programId.equals(SystemProgram.programId)) {
|
||||
throw new Error('programId incorrect; not SystemProgram');
|
||||
}
|
||||
|
||||
const instructionTypeLayout = BufferLayout.u32('instruction');
|
||||
const typeIndex = instructionTypeLayout.decode(instruction.data);
|
||||
let type;
|
||||
for (const t in SystemInstructionEnum) {
|
||||
if (SystemInstructionEnum[t].index == typeIndex) {
|
||||
type = SystemInstructionEnum[t];
|
||||
}
|
||||
}
|
||||
if (!type) {
|
||||
throw new Error('Instruction type incorrect; not a SystemInstruction');
|
||||
}
|
||||
return new SystemInstruction(
|
||||
{
|
||||
keys: instruction.keys,
|
||||
programId: instruction.programId,
|
||||
data: instruction.data,
|
||||
},
|
||||
type,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The `from` public key of the instruction;
|
||||
* returns null if SystemInstructionType does not support this field
|
||||
*/
|
||||
get From(): PublicKey | null {
|
||||
if (
|
||||
this.type == SystemInstructionEnum.CREATE ||
|
||||
this.type == SystemInstructionEnum.TRANSFER
|
||||
) {
|
||||
return this.keys[0].pubkey;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `to` public key of the instruction;
|
||||
* returns null if SystemInstructionType does not support this field
|
||||
*/
|
||||
get To(): PublicKey | null {
|
||||
if (
|
||||
this.type == SystemInstructionEnum.CREATE ||
|
||||
this.type == SystemInstructionEnum.TRANSFER
|
||||
) {
|
||||
return this.keys[1].pubkey;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `amount` or `lamports` of the instruction;
|
||||
* returns null if SystemInstructionType does not support this field
|
||||
*/
|
||||
get Amount(): number | null {
|
||||
const data = this.type.layout.decode(this.data);
|
||||
if (this.type == SystemInstructionEnum.TRANSFER) {
|
||||
return data.amount;
|
||||
} else if (this.type == SystemInstructionEnum.CREATE) {
|
||||
return data.lamports;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} SystemInstructionType
|
||||
* @property (index} The System Instruction index (from solana-sdk)
|
||||
* @property (BufferLayout} The BufferLayout to use to build data
|
||||
*/
|
||||
type SystemInstructionType = {|
|
||||
index: number,
|
||||
layout: typeof BufferLayout,
|
||||
|};
|
||||
|
||||
/**
|
||||
* An enumeration of valid SystemInstructionTypes
|
||||
*/
|
||||
const SystemInstructionEnum = Object.freeze({
|
||||
CREATE: {
|
||||
index: 0,
|
||||
layout: BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
BufferLayout.ns64('lamports'),
|
||||
BufferLayout.ns64('space'),
|
||||
Layout.publicKey('programId'),
|
||||
]),
|
||||
},
|
||||
ASSIGN: {
|
||||
index: 1,
|
||||
layout: BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
Layout.publicKey('programId'),
|
||||
]),
|
||||
},
|
||||
TRANSFER: {
|
||||
index: 2,
|
||||
layout: BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
BufferLayout.ns64('amount'),
|
||||
]),
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Populate a buffer of instruction data using the SystemInstructionType
|
||||
*/
|
||||
function encodeData(type: SystemInstructionType, fields: Object): Buffer {
|
||||
const data = Buffer.alloc(type.layout.span);
|
||||
const layoutFields = Object.assign({instruction: type.index}, fields);
|
||||
type.layout.encode(layoutFields, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory class for transactions to interact with the System program
|
||||
@ -29,23 +174,12 @@ export class SystemProgram {
|
||||
space: number,
|
||||
programId: PublicKey,
|
||||
): Transaction {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
BufferLayout.ns64('lamports'),
|
||||
BufferLayout.ns64('space'),
|
||||
Layout.publicKey('programId'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 0, // Create Account instruction
|
||||
lamports,
|
||||
space,
|
||||
programId: programId.toBuffer(),
|
||||
},
|
||||
data,
|
||||
);
|
||||
const type = SystemInstructionEnum.CREATE;
|
||||
const data = encodeData(type, {
|
||||
lamports,
|
||||
space,
|
||||
programId: programId.toBuffer(),
|
||||
});
|
||||
|
||||
return new Transaction().add({
|
||||
keys: [
|
||||
@ -61,19 +195,8 @@ export class SystemProgram {
|
||||
* Generate a Transaction that transfers lamports from one account to another
|
||||
*/
|
||||
static transfer(from: PublicKey, to: PublicKey, amount: number): Transaction {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
BufferLayout.ns64('amount'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 2, // Move instruction
|
||||
amount,
|
||||
},
|
||||
data,
|
||||
);
|
||||
const type = SystemInstructionEnum.TRANSFER;
|
||||
const data = encodeData(type, {amount});
|
||||
|
||||
return new Transaction().add({
|
||||
keys: [
|
||||
@ -89,19 +212,8 @@ export class SystemProgram {
|
||||
* Generate a Transaction that assigns an account to a program
|
||||
*/
|
||||
static assign(from: PublicKey, programId: PublicKey): Transaction {
|
||||
const dataLayout = BufferLayout.struct([
|
||||
BufferLayout.u32('instruction'),
|
||||
Layout.publicKey('programId'),
|
||||
]);
|
||||
|
||||
const data = Buffer.alloc(dataLayout.span);
|
||||
dataLayout.encode(
|
||||
{
|
||||
instruction: 1, // Assign instruction
|
||||
programId: programId.toBuffer(),
|
||||
},
|
||||
data,
|
||||
);
|
||||
const type = SystemInstructionEnum.ASSIGN;
|
||||
const data = encodeData(type, {programId: programId.toBuffer()});
|
||||
|
||||
return new Transaction().add({
|
||||
keys: [{pubkey: from, isSigner: true, isDebitable: true}],
|
||||
|
Reference in New Issue
Block a user