feat: allow passing seed to createNonceAccount

This commit is contained in:
Justin Starry 2020-05-05 13:30:55 +08:00 committed by Michael Vines
parent 5662808b4c
commit c5802bcbb6
5 changed files with 240 additions and 27 deletions

13
web3.js/module.d.ts vendored
View File

@ -606,6 +606,15 @@ declare module '@solana/web3.js' {
lamports: number;
};
export type CreateNonceAccountWithSeedParams = {
fromPubkey: PublicKey;
noncePubkey: PublicKey;
authorizedPubkey: PublicKey;
lamports: number;
basePubkey: PublicKey;
seed: string;
};
export type InitializeNonceParams = {
noncePubkey: PublicKey;
authorizedPubkey: PublicKey;
@ -638,7 +647,9 @@ declare module '@solana/web3.js' {
static createAccountWithSeed(
params: CreateAccountWithSeedParams,
): Transaction;
static createNonceAccount(params: CreateNonceAccountParams): Transaction;
static createNonceAccount(
params: CreateNonceAccountParams | CreateNonceAccountWithSeedParams,
): Transaction;
static nonceAdvance(params: AdvanceNonceParams): TransactionInstruction;
static nonceWithdraw(params: WithdrawNonceParams): Transaction;
static nonceAuthorize(params: AuthorizeNonceParams): Transaction;

View File

@ -621,6 +621,15 @@ declare module '@solana/web3.js' {
lamports: number,
|};
declare export type CreateNonceAccountWithSeedParams = {|
fromPubkey: PublicKey,
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
lamports: number,
basePubkey: PublicKey,
seed: string,
|};
declare export type InitializeNonceParams = {|
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
@ -653,7 +662,9 @@ declare module '@solana/web3.js' {
static createAccountWithSeed(
params: CreateAccountWithSeedParams,
): Transaction;
static createNonceAccount(params: CreateNonceAccountParams): Transaction;
static createNonceAccount(
params: CreateNonceAccountParams | CreateNonceAccountWithSeedParams,
): Transaction;
static nonceAdvance(params: AdvanceNonceParams): TransactionInstruction;
static nonceWithdraw(params: WithdrawNonceParams): Transaction;
static nonceAuthorize(params: AuthorizeNonceParams): Transaction;

View File

@ -73,9 +73,11 @@ export type CreateAccountWithSeedParams = {|
/**
* Create nonce account system transaction params
* @typedef {Object} AssignParams
* @typedef {Object} CreateNonceAccountParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} programId
* @property {PublicKey} noncePubkey
* @property {PublicKey} authorizedPubkey
* @property {number} lamports
*/
export type CreateNonceAccountParams = {|
fromPubkey: PublicKey,
@ -84,6 +86,25 @@ export type CreateNonceAccountParams = {|
lamports: number,
|};
/**
* Create nonce account with seed system transaction params
* @typedef {Object} CreateNonceAccountWithSeedParams
* @property {PublicKey} fromPubkey
* @property {PublicKey} noncePubkey
* @property {PublicKey} authorizedPubkey
* @property {PublicKey} basePubkey
* @property {string} seed
* @property {number} lamports
*/
export type CreateNonceAccountWithSeedParams = {|
fromPubkey: PublicKey,
noncePubkey: PublicKey,
authorizedPubkey: PublicKey,
lamports: number,
basePubkey: PublicKey,
seed: string,
|};
/**
* Initialize nonce account system instruction params
* @typedef {Object} InitializeNonceParams
@ -517,14 +538,29 @@ export class SystemProgram {
/**
* Generate a Transaction that creates a new Nonce account
*/
static createNonceAccount(params: CreateNonceAccountParams): Transaction {
let transaction = SystemProgram.createAccount({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
lamports: params.lamports,
space: NONCE_ACCOUNT_LENGTH,
programId: this.programId,
});
static createNonceAccount(
params: CreateNonceAccountParams | CreateNonceAccountWithSeedParams,
): Transaction {
let transaction;
if (params.basePubkey && params.seed) {
transaction = SystemProgram.createAccountWithSeed({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
basePubkey: params.basePubkey,
seed: params.seed,
lamports: params.lamports,
space: NONCE_ACCOUNT_LENGTH,
programId: this.programId,
});
} else {
transaction = SystemProgram.createAccount({
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
lamports: params.lamports,
space: NONCE_ACCOUNT_LENGTH,
programId: this.programId,
});
}
const initParams = {
noncePubkey: params.noncePubkey,

View File

@ -2,7 +2,7 @@
import bs58 from 'bs58';
import {Account, Connection, SystemProgram} from '../src';
import {Account, Connection, SystemProgram, PublicKey} from '../src';
import {NONCE_ACCOUNT_LENGTH} from '../src/nonce-account';
import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch';
import {mockGetRecentBlockhash} from './mockrpc/get-recent-blockhash';
@ -13,6 +13,17 @@ if (!mockRpcEnabled) {
jest.setTimeout(30000);
}
const expectedData = (authorizedPubkey: PublicKey): string => {
const expectedData = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
expectedData.writeInt32LE(0, 0); // Version, 4 bytes
expectedData.writeInt32LE(1, 4); // State, 4 bytes
authorizedPubkey.toBuffer().copy(expectedData, 8); // authorizedPubkey, 32 bytes
const mockNonce = new Account();
mockNonce.publicKey.toBuffer().copy(expectedData, 40); // Hash, 32 bytes
expectedData.writeUInt16LE(5000, 72); // feeCalculator, 8 bytes
return bs58.encode(expectedData);
};
test('create and query nonce account', async () => {
const from = new Account();
const nonceAccount = new Account();
@ -32,7 +43,6 @@ test('create and query nonce account', async () => {
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
NONCE_ACCOUNT_LENGTH,
'recent',
);
mockRpc.push([
@ -95,14 +105,6 @@ test('create and query nonce account', async () => {
});
await connection.sendTransaction(transaction, from, nonceAccount);
const expectedData = Buffer.alloc(NONCE_ACCOUNT_LENGTH);
expectedData.writeInt32LE(0, 0); // Version, 4 bytes
expectedData.writeInt32LE(1, 4); // State, 4 bytes
from.publicKey.toBuffer().copy(expectedData, 8); // authorizedPubkey, 32 bytes
const mockNonce = new Account();
mockNonce.publicKey.toBuffer().copy(expectedData, 40); // Hash, 32 bytes
expectedData.writeUInt16LE(5000, 72); // feeCalculator, 8 bytes
mockRpc.push([
url,
{
@ -118,17 +120,133 @@ test('create and query nonce account', async () => {
value: {
owner: '11111111111111111111111111111111',
lamports: minimumAmount,
data: bs58.encode(expectedData),
data: expectedData(from.publicKey),
executable: false,
},
},
},
]);
//
const nonceAccountData = await connection.getNonce(
nonceAccount.publicKey,
'recent',
);
const nonceAccountData = await connection.getNonce(nonceAccount.publicKey);
if (nonceAccountData === null) {
expect(nonceAccountData).not.toBeNull();
return;
}
expect(nonceAccountData.authorizedPubkey).toEqual(from.publicKey);
expect(bs58.decode(nonceAccountData.nonce).length).toBeGreaterThan(30);
});
test('create and query nonce account with seed', async () => {
const from = new Account();
const seed = 'seed';
const noncePubkey = await PublicKey.createWithSeed(
from.publicKey,
seed,
SystemProgram.programId,
);
const connection = new Connection(url, 'recent');
mockRpc.push([
url,
{
method: 'getMinimumBalanceForRentExemption',
params: [NONCE_ACCOUNT_LENGTH, {commitment: 'recent'}],
},
{
error: null,
result: 50,
},
]);
const minimumAmount = await connection.getMinimumBalanceForRentExemption(
NONCE_ACCOUNT_LENGTH,
);
mockRpc.push([
url,
{
method: 'requestAirdrop',
params: [
from.publicKey.toBase58(),
minimumAmount * 2,
{commitment: 'recent'},
],
},
{
error: null,
result:
'1WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
},
]);
await connection.requestAirdrop(from.publicKey, minimumAmount * 2);
mockRpc.push([
url,
{
method: 'getBalance',
params: [from.publicKey.toBase58(), {commitment: 'recent'}],
},
{
error: null,
result: {
context: {
slot: 11,
},
value: minimumAmount * 2,
},
},
]);
const balance = await connection.getBalance(from.publicKey);
expect(balance).toBe(minimumAmount * 2);
mockGetRecentBlockhash('recent');
mockRpc.push([
url,
{
method: 'sendTransaction',
},
{
error: null,
result:
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
},
]);
const transaction = SystemProgram.createNonceAccount({
fromPubkey: from.publicKey,
noncePubkey: noncePubkey,
basePubkey: from.publicKey,
seed,
authorizedPubkey: from.publicKey,
lamports: minimumAmount,
});
await connection.sendTransaction(transaction, from);
mockRpc.push([
url,
{
method: 'getAccountInfo',
params: [noncePubkey.toBase58(), {commitment: 'recent'}],
},
{
error: null,
result: {
context: {
slot: 11,
},
value: {
owner: '11111111111111111111111111111111',
lamports: minimumAmount,
data: expectedData(from.publicKey),
executable: false,
},
},
},
]);
//
const nonceAccountData = await connection.getNonce(noncePubkey);
if (nonceAccountData === null) {
expect(nonceAccountData).not.toBeNull();
return;

View File

@ -112,6 +112,43 @@ test('createNonceAccount', () => {
);
});
test('createNonceAccount with seed', () => {
const fromPubkey = new Account().publicKey;
const params = {
fromPubkey,
noncePubkey: new Account().publicKey,
authorizedPubkey: fromPubkey,
basePubkey: fromPubkey,
seed: 'hi there',
lamports: 123,
};
const transaction = SystemProgram.createNonceAccount(params);
expect(transaction.instructions).toHaveLength(2);
const [createInstruction, initInstruction] = transaction.instructions;
const createParams = {
fromPubkey: params.fromPubkey,
newAccountPubkey: params.noncePubkey,
basePubkey: fromPubkey,
seed: 'hi there',
lamports: params.lamports,
space: NONCE_ACCOUNT_LENGTH,
programId: SystemProgram.programId,
};
expect(createParams).toEqual(
SystemInstruction.decodeCreateWithSeed(createInstruction),
);
const initParams = {
noncePubkey: params.noncePubkey,
authorizedPubkey: fromPubkey,
};
expect(initParams).toEqual(
SystemInstruction.decodeNonceInitialize(initInstruction),
);
});
test('nonceAdvance', () => {
const params = {
noncePubkey: new Account().publicKey,