feat: add Keypair class and deprecate Account (#17098)

* feat: add Keypair class and deprecate Account

* chore: fix lint issues

* chore: rename TransactionSigner to Signer
This commit is contained in:
Justin Starry
2021-05-07 16:59:51 +08:00
committed by GitHub
parent 0b5167bf51
commit f43f0afa55
20 changed files with 339 additions and 213 deletions

View File

@@ -6,6 +6,8 @@ import {PublicKey} from './publickey';
/**
* An account key pair (public and secret keys).
*
* @deprecated since v1.10.0, please use {@link Keypair} instead.
*/
export class Account {
/** @internal */

View File

@@ -1,7 +1,7 @@
import {Account} from './account';
import {PublicKey} from './publickey';
import {Loader} from './loader';
import type {Connection} from './connection';
import type {Signer} from './keypair';
export const BPF_LOADER_PROGRAM_ID = new PublicKey(
'BPFLoader2111111111111111111111111111111111',
@@ -33,8 +33,8 @@ export class BpfLoader {
*/
static load(
connection: Connection,
payer: Account,
program: Account,
payer: Signer,
program: Signer,
elf: Buffer | Uint8Array | Array<number>,
loaderProgramId: PublicKey,
): Promise<boolean> {

View File

@@ -29,6 +29,7 @@ import {IWSRequestParams} from 'rpc-websockets/dist/lib/client';
import {AgentManager} from './agent-manager';
import {NonceAccount} from './nonce-account';
import {PublicKey} from './publickey';
import {Signer} from './keypair';
import {MS_PER_SLOT} from './timing';
import {Transaction} from './transaction';
import {Message} from './message';
@@ -37,7 +38,6 @@ import {promiseTimeout} from './util/promise-timeout';
import {toBuffer} from './util/to-buffer';
import type {Blockhash} from './blockhash';
import type {FeeCalculator} from './fee-calculator';
import type {Account} from './account';
import type {TransactionSignature} from './transaction';
import type {CompiledInstruction} from './message';
@@ -3213,7 +3213,7 @@ export class Connection {
*/
async simulateTransaction(
transaction: Transaction,
signers?: Array<Account>,
signers?: Array<Signer>,
): Promise<RpcResponseAndContext<SimulatedTransactionResponse>> {
if (transaction.nonceInfo && signers) {
transaction.sign(...signers);
@@ -3274,7 +3274,7 @@ export class Connection {
*/
async sendTransaction(
transaction: Transaction,
signers: Array<Account>,
signers: Array<Signer>,
options?: SendOptions,
): Promise<TransactionSignature> {
if (transaction.nonceInfo) {

View File

@@ -4,6 +4,7 @@ export * from './bpf-loader-deprecated';
export * from './bpf-loader';
export * from './connection';
export * from './fee-calculator';
export * from './keypair';
export * from './loader';
export * from './message';
export * from './nonce-account';

84
web3.js/src/keypair.ts Normal file
View File

@@ -0,0 +1,84 @@
import * as nacl from 'tweetnacl';
import type {SignKeyPair} from 'tweetnacl';
import {PublicKey} from './publickey';
/**
* Keypair signer interface
*/
export interface Signer {
publicKey: PublicKey;
secretKey: Uint8Array;
}
/**
* An account keypair used for signing transactions.
*/
export class Keypair {
/**
* @internal
*
* Create a new keypair instance from a {@link SignKeyPair}.
*
* @param keypair ed25519 keypair
*/
constructor(private keypair: SignKeyPair) {}
/**
* Generate a new random keypair
*/
static generate(): Keypair {
return new Keypair(nacl.sign.keyPair());
}
/**
* Create a keypair from a raw secret key byte array.
*
* This method should only be used to recreate a keypair from a previously
* generated secret key. Generating keypairs from a random seed should be done
* with the {@link Keypair.fromSeed} method.
*
* @throws error if the provided secret key is invalid and validation is not skipped.
*
* @param secretKey secret key byte array
* @param options: skip secret key validation
*/
static fromSecretKey(
secretKey: Uint8Array,
options?: {skipValidation?: boolean},
): Keypair {
const keypair = nacl.sign.keyPair.fromSecretKey(secretKey);
if (!options || !options.skipValidation) {
const encoder = new TextEncoder();
const signData = encoder.encode('@solana/web3.js-validation-v1');
const signature = nacl.sign.detached(signData, keypair.secretKey);
if (!nacl.sign.detached.verify(signData, signature, keypair.publicKey)) {
throw new Error('provided secretKey is invalid');
}
}
return new Keypair(keypair);
}
/**
* Generate a keypair from a 32 byte seed.
*
* @param seed seed byte array
*/
static fromSeed(seed: Uint8Array): Keypair {
return new Keypair(nacl.sign.keyPair.fromSeed(seed));
}
/**
* The public key for this keypair
*/
get publicKey(): PublicKey {
return new PublicKey(this.keypair.publicKey);
}
/**
* The raw secret key for this keypair
*/
get secretKey(): Uint8Array {
return this.keypair.secretKey;
}
}

View File

@@ -1,13 +1,13 @@
import {Buffer} from 'buffer';
import * as BufferLayout from 'buffer-layout';
import {Account} from './account';
import {PublicKey} from './publickey';
import {Transaction, PACKET_DATA_SIZE} from './transaction';
import {SYSVAR_RENT_PUBKEY} from './sysvar';
import {sendAndConfirmTransaction} from './util/send-and-confirm-transaction';
import {sleep} from './util/sleep';
import type {Connection} from './connection';
import type {Signer} from './keypair';
import {SystemProgram} from './system-program';
// Keep program chunks under PACKET_DATA_SIZE, leaving enough room for the
@@ -58,8 +58,8 @@ export class Loader {
*/
static async load(
connection: Connection,
payer: Account,
program: Account,
payer: Signer,
program: Signer,
programId: PublicKey,
data: Buffer | Uint8Array | Array<number>,
): Promise<boolean> {

View File

@@ -3,13 +3,13 @@ import nacl from 'tweetnacl';
import bs58 from 'bs58';
import {Buffer} from 'buffer';
import type {CompiledInstruction} from './message';
import {Message} from './message';
import {PublicKey} from './publickey';
import {Account} from './account';
import * as shortvec from './util/shortvec-encoding';
import type {Blockhash} from './blockhash';
import {toBuffer} from './util/to-buffer';
import type {Signer} from './keypair';
import type {Blockhash} from './blockhash';
import type {CompiledInstruction} from './message';
/**
* Transaction signature as base-58 encoded string
@@ -432,7 +432,7 @@ export class Transaction {
}
/**
* Sign the Transaction with the specified accounts. Multiple signatures may
* Sign the Transaction with the specified signers. Multiple signatures may
* be applied to a Transaction. The first signature is considered "primary"
* and is used identify and confirm transactions.
*
@@ -445,7 +445,7 @@ export class Transaction {
*
* The Transaction must be assigned a valid `recentBlockhash` before invoking this method
*/
sign(...signers: Array<Account>) {
sign(...signers: Array<Signer>) {
if (signers.length === 0) {
throw new Error('No signers');
}
@@ -480,7 +480,7 @@ export class Transaction {
*
* All the caveats from the `sign` method apply to `partialSign`
*/
partialSign(...signers: Array<Account>) {
partialSign(...signers: Array<Signer>) {
if (signers.length === 0) {
throw new Error('No signers');
}
@@ -505,7 +505,7 @@ export class Transaction {
/**
* @internal
*/
_partialSign(message: Message, ...signers: Array<Account>) {
_partialSign(message: Message, ...signers: Array<Signer>) {
const signData = message.serialize();
signers.forEach(signer => {
const signature = nacl.sign.detached(signData, signer.secretKey);

View File

@@ -1,7 +1,7 @@
import {Connection} from '../connection';
import {Transaction} from '../transaction';
import type {Account} from '../account';
import type {ConfirmOptions} from '../connection';
import type {Signer} from '../keypair';
import type {TransactionSignature} from '../transaction';
/**
@@ -11,14 +11,14 @@ import type {TransactionSignature} from '../transaction';
*
* @param {Connection} connection
* @param {Transaction} transaction
* @param {Array<Account>} signers
* @param {Array<Signer>} signers
* @param {ConfirmOptions} [options]
* @returns {Promise<TransactionSignature>}
*/
export async function sendAndConfirmTransaction(
connection: Connection,
transaction: Transaction,
signers: Array<Account>,
signers: Array<Signer>,
options?: ConfirmOptions,
): Promise<TransactionSignature> {
const sendOptions = options && {