Run prettier (#318)
Co-authored-by: Jayant Krishnamurthy <jkrishnamurthy@jumptrading.com>
This commit is contained in:
parent
863a983a1a
commit
89cc35d3a0
|
@ -11,7 +11,8 @@ import {
|
||||||
Keypair,
|
Keypair,
|
||||||
LAMPORTS_PER_SOL,
|
LAMPORTS_PER_SOL,
|
||||||
PublicKey,
|
PublicKey,
|
||||||
SystemProgram, TransactionInstruction,
|
SystemProgram,
|
||||||
|
TransactionInstruction,
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import Squads from "@sqds/mesh";
|
import Squads from "@sqds/mesh";
|
||||||
import bs58 from "bs58";
|
import bs58 from "bs58";
|
||||||
|
@ -47,7 +48,13 @@ program
|
||||||
)
|
)
|
||||||
.option("-p, --payload <hex-string>", "payload to sign", "0xdeadbeef")
|
.option("-p, --payload <hex-string>", "payload to sign", "0xdeadbeef")
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const squad = await getSquadsClient(options.cluster, options.ledger, options.ledgerDerivationAccount, options.ledgerDerivationChange, options.wallet);
|
const squad = await getSquadsClient(
|
||||||
|
options.cluster,
|
||||||
|
options.ledger,
|
||||||
|
options.ledgerDerivationAccount,
|
||||||
|
options.ledgerDerivationChange,
|
||||||
|
options.wallet
|
||||||
|
);
|
||||||
await createWormholeMsgMultisigTx(
|
await createWormholeMsgMultisigTx(
|
||||||
options.cluster,
|
options.cluster,
|
||||||
squad,
|
squad,
|
||||||
|
@ -59,7 +66,9 @@ program
|
||||||
|
|
||||||
program
|
program
|
||||||
.command("set-is-active")
|
.command("set-is-active")
|
||||||
.description("Create a new multisig transaction to set the attester is-active flag")
|
.description(
|
||||||
|
"Create a new multisig transaction to set the attester is-active flag"
|
||||||
|
)
|
||||||
.option("-c, --cluster <network>", "solana cluster to use", "devnet")
|
.option("-c, --cluster <network>", "solana cluster to use", "devnet")
|
||||||
.requiredOption("-v, --vault-address <address>", "multisig vault address")
|
.requiredOption("-v, --vault-address <address>", "multisig vault address")
|
||||||
.option("-l, --ledger", "use ledger")
|
.option("-l, --ledger", "use ledger")
|
||||||
|
@ -77,17 +86,38 @@ program
|
||||||
"keys/key.json"
|
"keys/key.json"
|
||||||
)
|
)
|
||||||
.option("-a, --attester <program id>")
|
.option("-a, --attester <program id>")
|
||||||
.option("-i, --is-active <true/false>", "set the isActive field to this value", true)
|
.option(
|
||||||
|
"-i, --is-active <true/false>",
|
||||||
|
"set the isActive field to this value",
|
||||||
|
true
|
||||||
|
)
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
const squad = await getSquadsClient(options.cluster, options.ledger, options.ledgerDerivationAccount, options.ledgerDerivationChange, options.wallet);
|
const squad = await getSquadsClient(
|
||||||
|
options.cluster,
|
||||||
|
options.ledger,
|
||||||
|
options.ledgerDerivationAccount,
|
||||||
|
options.ledgerDerivationChange,
|
||||||
|
options.wallet
|
||||||
|
);
|
||||||
const msAccount = await squad.getMultisig(options.vaultAddress);
|
const msAccount = await squad.getMultisig(options.vaultAddress);
|
||||||
const vaultAuthority = squad.getAuthorityPDA(
|
const vaultAuthority = squad.getAuthorityPDA(
|
||||||
msAccount.publicKey,
|
msAccount.publicKey,
|
||||||
msAccount.authorityIndex
|
msAccount.authorityIndex
|
||||||
);
|
);
|
||||||
const attesterProgramId = new PublicKey(options.attester);
|
const attesterProgramId = new PublicKey(options.attester);
|
||||||
const txKey = await createTx(squad, options.ledger, new PublicKey(options.vaultAddress));
|
const txKey = await createTx(
|
||||||
const instructions = [await setIsActiveIx(vaultAuthority, vaultAuthority, attesterProgramId, options.active)];
|
squad,
|
||||||
|
options.ledger,
|
||||||
|
new PublicKey(options.vaultAddress)
|
||||||
|
);
|
||||||
|
const instructions = [
|
||||||
|
await setIsActiveIx(
|
||||||
|
vaultAuthority,
|
||||||
|
vaultAuthority,
|
||||||
|
attesterProgramId,
|
||||||
|
options.active
|
||||||
|
),
|
||||||
|
];
|
||||||
await addInstructionsToTx(squad, options.ledger, txKey, instructions);
|
await addInstructionsToTx(squad, options.ledger, txKey, instructions);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -146,11 +176,12 @@ const solanaClusterMappingToWormholeNetwork: Record<Cluster, WormholeNetwork> =
|
||||||
"mainnet-beta": "MAINNET",
|
"mainnet-beta": "MAINNET",
|
||||||
};
|
};
|
||||||
|
|
||||||
async function getSquadsClient(cluster: Cluster,
|
async function getSquadsClient(
|
||||||
ledger: boolean,
|
cluster: Cluster,
|
||||||
ledgerDerivationAccount: number | undefined,
|
ledger: boolean,
|
||||||
ledgerDerivationChange: number | undefined,
|
ledgerDerivationAccount: number | undefined,
|
||||||
walletPath: string,
|
ledgerDerivationChange: number | undefined,
|
||||||
|
walletPath: string
|
||||||
) {
|
) {
|
||||||
let wallet: LedgerNodeWallet | NodeWallet;
|
let wallet: LedgerNodeWallet | NodeWallet;
|
||||||
if (ledger) {
|
if (ledger) {
|
||||||
|
@ -176,7 +207,7 @@ async function getSquadsClient(cluster: Cluster,
|
||||||
async function createTx(
|
async function createTx(
|
||||||
squad: Squads,
|
squad: Squads,
|
||||||
ledger: boolean,
|
ledger: boolean,
|
||||||
vault: PublicKey,
|
vault: PublicKey
|
||||||
): Promise<PublicKey> {
|
): Promise<PublicKey> {
|
||||||
const msAccount = await squad.getMultisig(vault);
|
const msAccount = await squad.getMultisig(vault);
|
||||||
|
|
||||||
|
@ -201,7 +232,9 @@ async function addInstructionsToTx(
|
||||||
instructions: TransactionInstruction[]
|
instructions: TransactionInstruction[]
|
||||||
) {
|
) {
|
||||||
for (let i = 0; i < instructions.length; i++) {
|
for (let i = 0; i < instructions.length; i++) {
|
||||||
console.log(`Adding instruction ${i}/${instructions.length} to transaction...`);
|
console.log(
|
||||||
|
`Adding instruction ${i}/${instructions.length} to transaction...`
|
||||||
|
);
|
||||||
if (ledger) {
|
if (ledger) {
|
||||||
console.log("Please approve the transaction on your ledger device...");
|
console.log("Please approve the transaction on your ledger device...");
|
||||||
}
|
}
|
||||||
|
@ -221,33 +254,36 @@ async function setIsActiveIx(
|
||||||
attesterProgramId: PublicKey,
|
attesterProgramId: PublicKey,
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
): Promise<TransactionInstruction> {
|
): Promise<TransactionInstruction> {
|
||||||
const configKey = PublicKey.createProgramAddressSync([Buffer.from("pyth2wormhole-config-v3")], attesterProgramId)
|
const configKey = PublicKey.createProgramAddressSync(
|
||||||
|
[Buffer.from("pyth2wormhole-config-v3")],
|
||||||
|
attesterProgramId
|
||||||
|
);
|
||||||
const config: AccountMeta = {
|
const config: AccountMeta = {
|
||||||
pubkey: configKey,
|
pubkey: configKey,
|
||||||
isSigner: false,
|
isSigner: false,
|
||||||
isWritable: true,
|
isWritable: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
const opsOwner: AccountMeta = {
|
const opsOwner: AccountMeta = {
|
||||||
pubkey: opsOwnerKey,
|
pubkey: opsOwnerKey,
|
||||||
isSigner: true,
|
isSigner: true,
|
||||||
isWritable: true,
|
isWritable: true,
|
||||||
}
|
};
|
||||||
const payer: AccountMeta = {
|
const payer: AccountMeta = {
|
||||||
pubkey: payerKey,
|
pubkey: payerKey,
|
||||||
isSigner: true,
|
isSigner: true,
|
||||||
isWritable: true,
|
isWritable: true,
|
||||||
}
|
};
|
||||||
|
|
||||||
const isActiveInt = (isActive === true) ? 1 : 0;
|
const isActiveInt = isActive === true ? 1 : 0;
|
||||||
// first byte is the isActive instruction, second byte is true/false
|
// first byte is the isActive instruction, second byte is true/false
|
||||||
const data = new Buffer([4, isActiveInt])
|
const data = new Buffer([4, isActiveInt]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
keys: [config, opsOwner, payer],
|
keys: [config, opsOwner, payer],
|
||||||
programId: attesterProgramId,
|
programId: attesterProgramId,
|
||||||
data: data,
|
data: data,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getWormholeMessageIx(
|
async function getWormholeMessageIx(
|
||||||
|
@ -286,7 +322,7 @@ async function getWormholeMessageIx(
|
||||||
emitter.toBase58(),
|
emitter.toBase58(),
|
||||||
message.toBase58(),
|
message.toBase58(),
|
||||||
0,
|
0,
|
||||||
Uint8Array.from(Buffer.from(payload, 'hex')),
|
Uint8Array.from(Buffer.from(payload, "hex")),
|
||||||
"CONFIRMED"
|
"CONFIRMED"
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -312,9 +348,12 @@ async function createWormholeMsgMultisigTx(
|
||||||
|
|
||||||
const message = Keypair.generate();
|
const message = Keypair.generate();
|
||||||
|
|
||||||
fs.mkdirSync('keys', {recursive: true});
|
fs.mkdirSync("keys", { recursive: true });
|
||||||
// save message to Uint8 array keypair file called mesage.json
|
// save message to Uint8 array keypair file called mesage.json
|
||||||
fs.writeFileSync(`keys/message-${txKey.toBase58()}.json`, `[${message.secretKey.toString()}]`);
|
fs.writeFileSync(
|
||||||
|
`keys/message-${txKey.toBase58()}.json`,
|
||||||
|
`[${message.secretKey.toString()}]`
|
||||||
|
);
|
||||||
console.log(`Message Address: ${message.publicKey.toBase58()}`);
|
console.log(`Message Address: ${message.publicKey.toBase58()}`);
|
||||||
|
|
||||||
console.log("Creating wormhole instructions...");
|
console.log("Creating wormhole instructions...");
|
||||||
|
@ -431,7 +470,6 @@ async function executeMultisigTx(
|
||||||
);
|
);
|
||||||
await new Promise((resolve) => setTimeout(resolve, 10000));
|
await new Promise((resolve) => setTimeout(resolve, 10000));
|
||||||
|
|
||||||
|
|
||||||
const txDetails = await squad.connection.getParsedTransaction(
|
const txDetails = await squad.connection.getParsedTransaction(
|
||||||
signature,
|
signature,
|
||||||
"confirmed"
|
"confirmed"
|
||||||
|
@ -460,10 +498,10 @@ async function executeMultisigTx(
|
||||||
const { vaaBytes } = await response.json();
|
const { vaaBytes } = await response.json();
|
||||||
console.log(`VAA (Base64): ${vaaBytes}`);
|
console.log(`VAA (Base64): ${vaaBytes}`);
|
||||||
const parsedVaa = await parse(vaaBytes);
|
const parsedVaa = await parse(vaaBytes);
|
||||||
console.log(`VAA (Hex): ${Buffer.from(vaaBytes).toString('hex')}`)
|
console.log(`VAA (Hex): ${Buffer.from(vaaBytes).toString("hex")}`);
|
||||||
console.log(`Emitter chain: ${parsedVaa.emitter_chain}`);
|
console.log(`Emitter chain: ${parsedVaa.emitter_chain}`);
|
||||||
console.log(`Nonce: ${parsedVaa.nonce}`);
|
console.log(`Nonce: ${parsedVaa.nonce}`);
|
||||||
console.log(`Payload: ${Buffer.from(parsedVaa.payload).toString('hex')}`);
|
console.log(`Payload: ${Buffer.from(parsedVaa.payload).toString("hex")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function parse(data: string) {
|
async function parse(data: string) {
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
import type { default as Transport } from '@ledgerhq/hw-transport';
|
import type { default as Transport } from "@ledgerhq/hw-transport";
|
||||||
import { StatusCodes, TransportStatusError } from '@ledgerhq/hw-transport';
|
import { StatusCodes, TransportStatusError } from "@ledgerhq/hw-transport";
|
||||||
import type { Transaction } from '@solana/web3.js';
|
import type { Transaction } from "@solana/web3.js";
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
export function getDerivationPath(account?: number, change?: number): Buffer {
|
export function getDerivationPath(account?: number, change?: number): Buffer {
|
||||||
const length = account !== undefined ? (change === undefined ? 3 : 4) : 2;
|
const length = account !== undefined ? (change === undefined ? 3 : 4) : 2;
|
||||||
const derivationPath = Buffer.alloc(1 + length * 4);
|
const derivationPath = Buffer.alloc(1 + length * 4);
|
||||||
|
|
||||||
let offset = derivationPath.writeUInt8(length, 0);
|
let offset = derivationPath.writeUInt8(length, 0);
|
||||||
offset = derivationPath.writeUInt32BE(harden(44), offset); // Using BIP44
|
offset = derivationPath.writeUInt32BE(harden(44), offset); // Using BIP44
|
||||||
offset = derivationPath.writeUInt32BE(harden(501), offset); // Solana's BIP44 path
|
offset = derivationPath.writeUInt32BE(harden(501), offset); // Solana's BIP44 path
|
||||||
|
|
||||||
if (account !== undefined) {
|
if (account !== undefined) {
|
||||||
offset = derivationPath.writeUInt32BE(harden(account), offset);
|
offset = derivationPath.writeUInt32BE(harden(account), offset);
|
||||||
if (change !== undefined) {
|
if (change !== undefined) {
|
||||||
derivationPath.writeUInt32BE(harden(change), offset);
|
derivationPath.writeUInt32BE(harden(change), offset);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return derivationPath;
|
return derivationPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BIP32_HARDENED_BIT = (1 << 31) >>> 0;
|
const BIP32_HARDENED_BIT = (1 << 31) >>> 0;
|
||||||
|
|
||||||
function harden(n: number): number {
|
function harden(n: number): number {
|
||||||
return (n | BIP32_HARDENED_BIT) >>> 0;
|
return (n | BIP32_HARDENED_BIT) >>> 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const INS_GET_PUBKEY = 0x05;
|
const INS_GET_PUBKEY = 0x05;
|
||||||
|
@ -41,44 +41,70 @@ const MAX_PAYLOAD = 255;
|
||||||
const LEDGER_CLA = 0xe0;
|
const LEDGER_CLA = 0xe0;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export async function getPublicKey(transport: Transport, derivationPath: Buffer): Promise<PublicKey> {
|
export async function getPublicKey(
|
||||||
const bytes = await send(transport, INS_GET_PUBKEY, P1_NON_CONFIRM, derivationPath);
|
transport: Transport,
|
||||||
return new PublicKey(bytes);
|
derivationPath: Buffer
|
||||||
|
): Promise<PublicKey> {
|
||||||
|
const bytes = await send(
|
||||||
|
transport,
|
||||||
|
INS_GET_PUBKEY,
|
||||||
|
P1_NON_CONFIRM,
|
||||||
|
derivationPath
|
||||||
|
);
|
||||||
|
return new PublicKey(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export async function signTransaction(
|
export async function signTransaction(
|
||||||
transport: Transport,
|
transport: Transport,
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
derivationPath: Buffer
|
derivationPath: Buffer
|
||||||
): Promise<Buffer> {
|
): Promise<Buffer> {
|
||||||
const paths = Buffer.alloc(1);
|
const paths = Buffer.alloc(1);
|
||||||
paths.writeUInt8(1, 0);
|
paths.writeUInt8(1, 0);
|
||||||
|
|
||||||
const message = transaction.serializeMessage();
|
const message = transaction.serializeMessage();
|
||||||
const data = Buffer.concat([paths, derivationPath, message]);
|
const data = Buffer.concat([paths, derivationPath, message]);
|
||||||
|
|
||||||
return await send(transport, INS_SIGN_MESSAGE, P1_CONFIRM, data);
|
return await send(transport, INS_SIGN_MESSAGE, P1_CONFIRM, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function send(transport: Transport, instruction: number, p1: number, data: Buffer): Promise<Buffer> {
|
async function send(
|
||||||
let p2 = 0;
|
transport: Transport,
|
||||||
let offset = 0;
|
instruction: number,
|
||||||
|
p1: number,
|
||||||
|
data: Buffer
|
||||||
|
): Promise<Buffer> {
|
||||||
|
let p2 = 0;
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
if (data.length > MAX_PAYLOAD) {
|
if (data.length > MAX_PAYLOAD) {
|
||||||
while (data.length - offset > MAX_PAYLOAD) {
|
while (data.length - offset > MAX_PAYLOAD) {
|
||||||
const buffer = data.subarray(offset, offset + MAX_PAYLOAD);
|
const buffer = data.subarray(offset, offset + MAX_PAYLOAD);
|
||||||
const response = await transport.send(LEDGER_CLA, instruction, p1, p2 | P2_MORE, buffer);
|
const response = await transport.send(
|
||||||
// @ts-ignore -- TransportStatusError is a constructor Function, not a Class
|
LEDGER_CLA,
|
||||||
if (response.length !== 2) throw new TransportStatusError(StatusCodes.INCORRECT_DATA);
|
instruction,
|
||||||
|
p1,
|
||||||
|
p2 | P2_MORE,
|
||||||
|
buffer
|
||||||
|
);
|
||||||
|
// @ts-ignore -- TransportStatusError is a constructor Function, not a Class
|
||||||
|
if (response.length !== 2)
|
||||||
|
throw new TransportStatusError(StatusCodes.INCORRECT_DATA);
|
||||||
|
|
||||||
p2 |= P2_EXTEND;
|
p2 |= P2_EXTEND;
|
||||||
offset += MAX_PAYLOAD;
|
offset += MAX_PAYLOAD;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const buffer = data.subarray(offset);
|
const buffer = data.subarray(offset);
|
||||||
const response = await transport.send(LEDGER_CLA, instruction, p1, p2, buffer);
|
const response = await transport.send(
|
||||||
|
LEDGER_CLA,
|
||||||
|
instruction,
|
||||||
|
p1,
|
||||||
|
p2,
|
||||||
|
buffer
|
||||||
|
);
|
||||||
|
|
||||||
return response.subarray(0, response.length - 2);
|
return response.subarray(0, response.length - 2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue