feat: add Secp256k1 support to solana-web3.js (#12958)
* feat: add secp256k1 instruction * feat: use buffer-layout for encoding as well * style: use consistent naming for types * style: update typings and make program functions static * fix: attempt to resolve rollup issue * fix: expose sysvar in typings * fix: remove decode instruction functionality (for now)
This commit is contained in:
parent
84d56c62ce
commit
368aeb2cee
|
@ -0,0 +1,4 @@
|
|||
declare module 'keccak' {
|
||||
// TODO: Fill in types
|
||||
declare module.exports: any;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
declare module 'secp256k1' {
|
||||
// TODO: Fill in types
|
||||
declare module.exports: any;
|
||||
}
|
|
@ -531,6 +531,7 @@ declare module '@solana/web3.js' {
|
|||
export const SYSVAR_RENT_PUBKEY: PublicKey;
|
||||
export const SYSVAR_REWARDS_PUBKEY: PublicKey;
|
||||
export const SYSVAR_STAKE_HISTORY_PUBKEY: PublicKey;
|
||||
export const SYSVAR_INSTRUCTIONS_PUBKEY: PublicKey;
|
||||
|
||||
// === src/vote-account.js ===
|
||||
export const VOTE_PROGRAM_ID: PublicKey;
|
||||
|
@ -966,6 +967,31 @@ declare module '@solana/web3.js' {
|
|||
): AuthorizeNonceParams;
|
||||
}
|
||||
|
||||
// === src/secp256k1-program.js ===
|
||||
export type CreateSecp256k1InstructionWithPublicKeyParams = {
|
||||
publicKey: Buffer | Uint8Array | Array<number>;
|
||||
message: Buffer | Uint8Array | Array<number>;
|
||||
signature: Buffer | Uint8Array | Array<number>;
|
||||
recoveryId: number;
|
||||
};
|
||||
|
||||
export type CreateSecp256k1InstructionWithPrivateKeyParams = {
|
||||
privateKey: Buffer | Uint8Array | Array<number>;
|
||||
message: Buffer | Uint8Array | Array<number>;
|
||||
};
|
||||
|
||||
export class Secp256k1Program {
|
||||
static get programId(): PublicKey;
|
||||
|
||||
static createInstructionWithPublicKey(
|
||||
params: CreateSecp256k1InstructionWithPublicKeyParams,
|
||||
): TransactionInstruction;
|
||||
|
||||
static createInstructionWithPrivateKey(
|
||||
params: CreateSecp256k1InstructionWithPrivateKeyParams,
|
||||
): TransactionInstruction;
|
||||
}
|
||||
|
||||
// === src/loader.js ===
|
||||
export class Loader {
|
||||
static getMinNumSignatures(dataLength: number): number;
|
||||
|
|
|
@ -536,6 +536,7 @@ declare module '@solana/web3.js' {
|
|||
declare export var SYSVAR_RENT_PUBKEY;
|
||||
declare export var SYSVAR_REWARDS_PUBKEY;
|
||||
declare export var SYSVAR_STAKE_HISTORY_PUBKEY;
|
||||
declare export var SYSVAR_INSTRUCTIONS_PUBKEY;
|
||||
|
||||
// === src/vote-account.js ===
|
||||
declare export var VOTE_PROGRAM_ID;
|
||||
|
@ -973,6 +974,31 @@ declare module '@solana/web3.js' {
|
|||
): AuthorizeNonceParams;
|
||||
}
|
||||
|
||||
// === src/secp256k1-program.js ===
|
||||
declare export type CreateSecp256k1InstructionWithPublicKeyParams = {|
|
||||
publicKey: Buffer | Uint8Array | Array<number>,
|
||||
message: Buffer | Uint8Array | Array<number>,
|
||||
signature: Buffer | Uint8Array | Array<number>,
|
||||
recoveryId: number,
|
||||
|};
|
||||
|
||||
declare export type CreateSecp256k1InstructionWithPrivateKeyParams = {|
|
||||
privateKey: Buffer | Uint8Array | Array<number>,
|
||||
message: Buffer | Uint8Array | Array<number>,
|
||||
|};
|
||||
|
||||
declare export class Secp256k1Program {
|
||||
static get programId(): PublicKey;
|
||||
|
||||
static createInstructionWithPublicKey(
|
||||
params: CreateSecp256k1InstructionWithPublicKeyParams,
|
||||
): TransactionInstruction;
|
||||
|
||||
static createInstructionWithPrivateKey(
|
||||
params: CreateSecp256k1InstructionWithPrivateKeyParams,
|
||||
): TransactionInstruction;
|
||||
}
|
||||
|
||||
// === src/loader.js ===
|
||||
declare export class Loader {
|
||||
static getMinNumSignatures(dataLength: number): number;
|
||||
|
|
|
@ -7163,8 +7163,7 @@
|
|||
"brorand": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
|
||||
},
|
||||
"browser-process-hrtime": {
|
||||
"version": "1.0.0",
|
||||
|
@ -11357,7 +11356,6 @@
|
|||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz",
|
||||
"integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"minimalistic-assert": "^1.0.1"
|
||||
|
@ -11380,7 +11378,6 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"hash.js": "^1.0.3",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
|
@ -14453,6 +14450,22 @@
|
|||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
"keccak": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz",
|
||||
"integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==",
|
||||
"requires": {
|
||||
"node-addon-api": "^2.0.0",
|
||||
"node-gyp-build": "^4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-gyp-build": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
|
||||
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"keypather": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/keypather/-/keypather-1.10.2.tgz",
|
||||
|
@ -15461,14 +15474,12 @@
|
|||
"minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
|
||||
},
|
||||
"minimalistic-crypto-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
|
||||
"dev": true
|
||||
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
|
@ -15606,6 +15617,11 @@
|
|||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
|
||||
},
|
||||
"node-addon-api": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
|
||||
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
|
||||
},
|
||||
"node-emoji": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
|
||||
|
@ -21328,6 +21344,42 @@
|
|||
"xmlchars": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"secp256k1": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
|
||||
"integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
|
||||
"requires": {
|
||||
"elliptic": "^6.5.2",
|
||||
"node-addon-api": "^2.0.0",
|
||||
"node-gyp-build": "^4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bn.js": {
|
||||
"version": "4.11.9",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
|
||||
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw=="
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.5.3",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
|
||||
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
|
||||
"requires": {
|
||||
"bn.js": "^4.4.0",
|
||||
"brorand": "^1.0.1",
|
||||
"hash.js": "^1.0.0",
|
||||
"hmac-drbg": "^1.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"minimalistic-crypto-utils": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node-gyp-build": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
|
||||
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"semantic-release": {
|
||||
"version": "17.2.1",
|
||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-17.2.1.tgz",
|
||||
|
|
|
@ -81,10 +81,12 @@
|
|||
"crypto-hash": "^1.2.2",
|
||||
"esdoc-inject-style-plugin": "^1.0.0",
|
||||
"jayson": "^3.0.1",
|
||||
"keccak": "^3.0.1",
|
||||
"mz": "^2.7.0",
|
||||
"node-fetch": "^2.2.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rpc-websockets": "^7.4.2",
|
||||
"secp256k1": "^4.0.2",
|
||||
"superstruct": "^0.8.3",
|
||||
"tweetnacl": "^1.0.0",
|
||||
"ws": "^7.0.0"
|
||||
|
|
|
@ -106,6 +106,8 @@ function generateConfig(configType) {
|
|||
'superstruct',
|
||||
'tweetnacl',
|
||||
'url',
|
||||
'secp256k1',
|
||||
'keccak',
|
||||
];
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -21,6 +21,7 @@ export {
|
|||
SystemProgram,
|
||||
SYSTEM_INSTRUCTION_LAYOUTS,
|
||||
} from './system-program';
|
||||
export {Secp256k1Program} from './secp256k1-program';
|
||||
export {Transaction, TransactionInstruction} from './transaction';
|
||||
export {VALIDATOR_INFO_KEY, ValidatorInfo} from './validator-info';
|
||||
export {VOTE_PROGRAM_ID, VoteAccount} from './vote-account';
|
||||
|
@ -29,6 +30,7 @@ export {
|
|||
SYSVAR_RENT_PUBKEY,
|
||||
SYSVAR_REWARDS_PUBKEY,
|
||||
SYSVAR_STAKE_HISTORY_PUBKEY,
|
||||
SYSVAR_INSTRUCTIONS_PUBKEY,
|
||||
} from './sysvar';
|
||||
export {sendAndConfirmTransaction} from './util/send-and-confirm-transaction';
|
||||
export {sendAndConfirmRawTransaction} from './util/send-and-confirm-raw-transaction';
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
// @flow
|
||||
|
||||
import * as BufferLayout from 'buffer-layout';
|
||||
import secp256k1 from 'secp256k1';
|
||||
import createKeccakHash from 'keccak';
|
||||
import assert from 'assert';
|
||||
|
||||
import {PublicKey} from './publickey';
|
||||
import {TransactionInstruction} from './transaction';
|
||||
import {toBuffer} from './util/to-buffer';
|
||||
|
||||
const {publicKeyCreate, ecdsaSign} = secp256k1;
|
||||
|
||||
const PRIVATE_KEY_BYTES = 32;
|
||||
const PUBLIC_KEY_BYTES = 65;
|
||||
const HASHED_PUBKEY_SERIALIZED_SIZE = 20;
|
||||
const SIGNATURE_OFFSETS_SERIALIZED_SIZE = 11;
|
||||
|
||||
/**
|
||||
* Create a Secp256k1 instruction using a public key params
|
||||
* @typedef {Object} CreateSecp256k1InstructionWithPublicKeyParams
|
||||
* @property {Buffer | Uint8Array | Array<number>} publicKey
|
||||
* @property {Buffer | Uint8Array | Array<number>} message
|
||||
* @property {Buffer | Uint8Array | Array<number>} signature
|
||||
* @property {number} recoveryId
|
||||
*/
|
||||
export type CreateSecp256k1InstructionWithPublicKeyParams = {|
|
||||
publicKey: Buffer | Uint8Array | Array<number>,
|
||||
message: Buffer | Uint8Array | Array<number>,
|
||||
signature: Buffer | Uint8Array | Array<number>,
|
||||
recoveryId: number,
|
||||
|};
|
||||
|
||||
/**
|
||||
* Create a Secp256k1 instruction using a private key params
|
||||
* @typedef {Object} CreateSecp256k1InstructionWithPrivateKeyParams
|
||||
* @property {Buffer | Uint8Array | Array<number>} privateKey
|
||||
* @property {Buffer | Uint8Array | Array<number>} message
|
||||
*/
|
||||
export type CreateSecp256k1InstructionWithPrivateKeyParams = {|
|
||||
privateKey: Buffer | Uint8Array | Array<number>,
|
||||
message: Buffer | Uint8Array | Array<number>,
|
||||
|};
|
||||
|
||||
const SECP256K1_INSTRUCTION_LAYOUT = BufferLayout.struct([
|
||||
BufferLayout.u8('numSignatures'),
|
||||
BufferLayout.u16('signatureOffset'),
|
||||
BufferLayout.u8('signatureInstructionIndex'),
|
||||
BufferLayout.u16('ethAddressOffset'),
|
||||
BufferLayout.u8('ethAddressInstructionIndex'),
|
||||
BufferLayout.u16('messageDataOffset'),
|
||||
BufferLayout.u16('messageDataSize'),
|
||||
BufferLayout.u8('messageInstructionIndex'),
|
||||
BufferLayout.blob(20, 'ethPublicKey'),
|
||||
BufferLayout.blob(64, 'signature'),
|
||||
BufferLayout.u8('recoveryId'),
|
||||
]);
|
||||
|
||||
export class Secp256k1Program {
|
||||
/**
|
||||
* Public key that identifies the Secp256k program
|
||||
*/
|
||||
static get programId(): PublicKey {
|
||||
return new PublicKey('KeccakSecp256k11111111111111111111111111111');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a secp256k1 instruction with public key
|
||||
*/
|
||||
static createInstructionWithPublicKey(
|
||||
params: CreateSecp256k1InstructionWithPublicKeyParams,
|
||||
): TransactionInstruction {
|
||||
const {publicKey, message, signature, recoveryId} = params;
|
||||
|
||||
assert(
|
||||
publicKey.length === PUBLIC_KEY_BYTES,
|
||||
`Public key must be ${PUBLIC_KEY_BYTES} bytes`,
|
||||
);
|
||||
|
||||
let ethPublicKey;
|
||||
try {
|
||||
ethPublicKey = constructEthPubkey(publicKey);
|
||||
} catch (error) {
|
||||
throw new Error(`Error constructing ethereum public key: ${error}`);
|
||||
}
|
||||
|
||||
const dataStart = 1 + SIGNATURE_OFFSETS_SERIALIZED_SIZE;
|
||||
const ethAddressOffset = dataStart;
|
||||
const signatureOffset = dataStart + ethPublicKey.length;
|
||||
const messageDataOffset = signatureOffset + signature.length + 1;
|
||||
const numSignatures = 1;
|
||||
|
||||
const instructionData = Buffer.alloc(
|
||||
SECP256K1_INSTRUCTION_LAYOUT.span + message.length,
|
||||
);
|
||||
|
||||
SECP256K1_INSTRUCTION_LAYOUT.encode(
|
||||
{
|
||||
numSignatures: numSignatures,
|
||||
signatureOffset: signatureOffset,
|
||||
signatureInstructionIndex: 0,
|
||||
ethAddressOffset: ethAddressOffset,
|
||||
ethAddressInstructionIndex: 0,
|
||||
messageDataOffset: messageDataOffset,
|
||||
messageDataSize: message.length,
|
||||
messageInstructionIndex: 0,
|
||||
signature: toBuffer(signature),
|
||||
ethPublicKey: ethPublicKey,
|
||||
recoveryId: recoveryId,
|
||||
},
|
||||
instructionData,
|
||||
);
|
||||
|
||||
instructionData.fill(toBuffer(message), SECP256K1_INSTRUCTION_LAYOUT.span);
|
||||
|
||||
return new TransactionInstruction({
|
||||
keys: [],
|
||||
programId: Secp256k1Program.programId,
|
||||
data: instructionData,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a secp256k1 instruction with private key
|
||||
*/
|
||||
static createInstructionWithPrivateKey(
|
||||
params: CreateSecp256k1InstructionWithPrivateKeyParams,
|
||||
): TransactionInstruction {
|
||||
const {privateKey, message} = params;
|
||||
|
||||
assert(
|
||||
privateKey.length === PRIVATE_KEY_BYTES,
|
||||
`Private key must be ${PRIVATE_KEY_BYTES} bytes`,
|
||||
);
|
||||
|
||||
try {
|
||||
const publicKey = publicKeyCreate(privateKey, false);
|
||||
const messageHash = createKeccakHash('keccak256')
|
||||
.update(toBuffer(message))
|
||||
.digest();
|
||||
const {signature, recid: recoveryId} = ecdsaSign(messageHash, privateKey);
|
||||
|
||||
return this.createInstructionWithPublicKey({
|
||||
publicKey,
|
||||
message,
|
||||
signature,
|
||||
recoveryId,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Error creating instruction; ${error}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function constructEthPubkey(
|
||||
publicKey: Buffer | Uint8Array | Array<number>,
|
||||
): Buffer {
|
||||
return createKeccakHash('keccak256')
|
||||
.update(toBuffer(publicKey.slice(1))) // throw away leading byte
|
||||
.digest()
|
||||
.slice(-HASHED_PUBKEY_SERIALIZED_SIZE);
|
||||
}
|
|
@ -20,3 +20,7 @@ export const SYSVAR_REWARDS_PUBKEY = new PublicKey(
|
|||
export const SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey(
|
||||
'SysvarStakeHistory1111111111111111111111111',
|
||||
);
|
||||
|
||||
export const SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey(
|
||||
'Sysvar1nstructions1111111111111111111111111',
|
||||
);
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
// @flow
|
||||
|
||||
import createKeccakHash from 'keccak';
|
||||
import secp256k1 from 'secp256k1';
|
||||
import {randomBytes} from 'crypto';
|
||||
|
||||
import {Secp256k1Program} from '../src/secp256k1-program';
|
||||
import {mockRpcEnabled} from './__mocks__/node-fetch';
|
||||
import {url} from './url';
|
||||
import {
|
||||
Connection,
|
||||
Account,
|
||||
sendAndConfirmTransaction,
|
||||
LAMPORTS_PER_SOL,
|
||||
Transaction,
|
||||
} from '../src';
|
||||
|
||||
const {privateKeyVerify, ecdsaSign, publicKeyCreate} = secp256k1;
|
||||
|
||||
if (!mockRpcEnabled) {
|
||||
jest.setTimeout(20000);
|
||||
}
|
||||
|
||||
test('live create secp256k1 instruction with public key', async () => {
|
||||
if (mockRpcEnabled) {
|
||||
console.log('non-live test skipped');
|
||||
return;
|
||||
}
|
||||
|
||||
const message = Buffer.from('This is a message');
|
||||
|
||||
let privateKey;
|
||||
do {
|
||||
privateKey = randomBytes(32);
|
||||
} while (!privateKeyVerify(privateKey));
|
||||
|
||||
const publicKey = publicKeyCreate(privateKey, false);
|
||||
const messageHash = createKeccakHash('keccak256').update(message).digest();
|
||||
const {signature, recid: recoveryId} = ecdsaSign(messageHash, privateKey);
|
||||
|
||||
const instruction = Secp256k1Program.createInstructionWithPublicKey({
|
||||
publicKey,
|
||||
message,
|
||||
signature,
|
||||
recoveryId,
|
||||
});
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(instruction);
|
||||
|
||||
const connection = new Connection(url, 'recent');
|
||||
const from = new Account();
|
||||
await connection.requestAirdrop(from.publicKey, 2 * LAMPORTS_PER_SOL);
|
||||
|
||||
await sendAndConfirmTransaction(connection, transaction, [from], {
|
||||
commitment: 'single',
|
||||
skipPreflight: true,
|
||||
});
|
||||
});
|
||||
|
||||
test('live create secp256k1 instruction with private key', async () => {
|
||||
if (mockRpcEnabled) {
|
||||
console.log('non-live test skipped');
|
||||
return;
|
||||
}
|
||||
|
||||
let privateKey;
|
||||
do {
|
||||
privateKey = randomBytes(32);
|
||||
} while (!privateKeyVerify(privateKey));
|
||||
|
||||
const instruction = Secp256k1Program.createInstructionWithPrivateKey({
|
||||
privateKey,
|
||||
message: Buffer.from('Test 123'),
|
||||
});
|
||||
|
||||
const transaction = new Transaction();
|
||||
transaction.add(instruction);
|
||||
|
||||
const connection = new Connection(url, 'recent');
|
||||
const from = new Account();
|
||||
await connection.requestAirdrop(from.publicKey, 2 * LAMPORTS_PER_SOL);
|
||||
|
||||
await sendAndConfirmTransaction(connection, transaction, [from], {
|
||||
commitment: 'single',
|
||||
skipPreflight: true,
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue