|
|
@@ -28,14 +28,43 @@ import {
|
|
|
WORMHOLE_ADDRESS,
|
|
|
} from "xc_admin_common";
|
|
|
import { pythOracleProgram } from "@pythnetwork/client";
|
|
|
+import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider";
|
|
|
+import { LedgerNodeWallet } from "./ledger";
|
|
|
+
|
|
|
+export async function loadHotWalletOrLedger(
|
|
|
+ wallet: string,
|
|
|
+ lda: number,
|
|
|
+ ldc: number
|
|
|
+): Promise<Wallet> {
|
|
|
+ if (wallet === "ledger") {
|
|
|
+ return await LedgerNodeWallet.createWallet(lda, ldc);
|
|
|
+ } else {
|
|
|
+ return new NodeWallet(
|
|
|
+ Keypair.fromSecretKey(
|
|
|
+ Uint8Array.from(JSON.parse(fs.readFileSync(wallet, "ascii")))
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
const mutlisigCommand = (name: string, description: string) =>
|
|
|
program
|
|
|
.command(name)
|
|
|
.description(description)
|
|
|
.requiredOption("-c, --cluster <network>", "solana cluster to use")
|
|
|
- .requiredOption("-w, --wallet <filepath>", "path to the operations key")
|
|
|
- .requiredOption("-v, --vault <pubkey>", "multisig address");
|
|
|
+ .requiredOption(
|
|
|
+ "-w, --wallet <filepath>",
|
|
|
+ 'path to the operations key or "ledger"'
|
|
|
+ )
|
|
|
+ .requiredOption("-v, --vault <pubkey>", "multisig address")
|
|
|
+ .option(
|
|
|
+ "-lda, --ledger-derivation-account <number>",
|
|
|
+ "ledger derivation account to use"
|
|
|
+ )
|
|
|
+ .option(
|
|
|
+ "-ldc, --ledger-derivation-change <number>",
|
|
|
+ "ledger derivation change to use"
|
|
|
+ );
|
|
|
|
|
|
program
|
|
|
.name("xc_admin_cli")
|
|
|
@@ -56,10 +85,10 @@ mutlisigCommand(
|
|
|
)
|
|
|
|
|
|
.action(async (options: any) => {
|
|
|
- const wallet = new NodeWallet(
|
|
|
- Keypair.fromSecretKey(
|
|
|
- Uint8Array.from(JSON.parse(fs.readFileSync(options.wallet, "ascii")))
|
|
|
- )
|
|
|
+ const wallet = await loadHotWalletOrLedger(
|
|
|
+ options.wallet,
|
|
|
+ options.ledgerDerivationAccount,
|
|
|
+ options.ledgerDerivationChange
|
|
|
);
|
|
|
const cluster: PythCluster = options.cluster;
|
|
|
const programId: PublicKey = new PublicKey(options.programId);
|
|
|
@@ -104,7 +133,7 @@ mutlisigCommand(
|
|
|
.accept()
|
|
|
.accounts({
|
|
|
currentAuthority: current,
|
|
|
- newAuthority: mapKey(vaultAuthority),
|
|
|
+ newAuthority: isRemote ? mapKey(vaultAuthority) : vaultAuthority,
|
|
|
programAccount: programId,
|
|
|
programDataAccount,
|
|
|
bpfUpgradableLoader: BPF_UPGRADABLE_LOADER,
|
|
|
@@ -128,10 +157,10 @@ mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
|
|
|
.requiredOption("-b, --buffer <pubkey>", "buffer account")
|
|
|
|
|
|
.action(async (options: any) => {
|
|
|
- const wallet = new NodeWallet(
|
|
|
- Keypair.fromSecretKey(
|
|
|
- Uint8Array.from(JSON.parse(fs.readFileSync(options.wallet, "ascii")))
|
|
|
- )
|
|
|
+ const wallet = await loadHotWalletOrLedger(
|
|
|
+ options.wallet,
|
|
|
+ options.ledgerDerivationAccount,
|
|
|
+ options.ledgerDerivationChange
|
|
|
);
|
|
|
const cluster: PythCluster = options.cluster;
|
|
|
const programId: PublicKey = new PublicKey(options.programId);
|
|
|
@@ -166,7 +195,11 @@ mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
|
|
|
{ pubkey: wallet.publicKey, isSigner: false, isWritable: true },
|
|
|
{ pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
|
|
|
{ pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false },
|
|
|
- { pubkey: mapKey(vaultAuthority), isSigner: true, isWritable: false },
|
|
|
+ {
|
|
|
+ pubkey: isRemote ? mapKey(vaultAuthority) : vaultAuthority,
|
|
|
+ isSigner: true,
|
|
|
+ isWritable: false,
|
|
|
+ },
|
|
|
],
|
|
|
};
|
|
|
|
|
|
@@ -186,10 +219,10 @@ mutlisigCommand(
|
|
|
.requiredOption("-p, --price <pubkey>", "Price account to modify")
|
|
|
.requiredOption("-e, --exponent <number>", "New exponent")
|
|
|
.action(async (options: any) => {
|
|
|
- const wallet = new NodeWallet(
|
|
|
- Keypair.fromSecretKey(
|
|
|
- Uint8Array.from(JSON.parse(fs.readFileSync(options.wallet, "ascii")))
|
|
|
- )
|
|
|
+ const wallet = await loadHotWalletOrLedger(
|
|
|
+ options.wallet,
|
|
|
+ options.ledgerDerivationAccount,
|
|
|
+ options.ledgerDerivationChange
|
|
|
);
|
|
|
const cluster: PythCluster = options.cluster;
|
|
|
const vault: PublicKey = new PublicKey(options.vault);
|
|
|
@@ -222,7 +255,10 @@ program
|
|
|
.command("parse-transaction")
|
|
|
.description("Parse a transaction sitting in the multisig")
|
|
|
.requiredOption("-c, --cluster <network>", "solana cluster to use")
|
|
|
- .requiredOption("-t, --transaction <pubkey>", "path to the operations key")
|
|
|
+ .requiredOption(
|
|
|
+ "-t, --transaction <pubkey>",
|
|
|
+ "address of the outstanding transaction"
|
|
|
+ )
|
|
|
.action(async (options: any) => {
|
|
|
const cluster = options.cluster;
|
|
|
const transaction: PublicKey = new PublicKey(options.transaction);
|
|
|
@@ -245,4 +281,22 @@ program
|
|
|
console.log(JSON.stringify(parsed, null, 2));
|
|
|
});
|
|
|
|
|
|
+mutlisigCommand("approve", "Approve a transaction sitting in the multisig")
|
|
|
+ .requiredOption(
|
|
|
+ "-t, --transaction <pubkey>",
|
|
|
+ "address of the outstanding transaction"
|
|
|
+ )
|
|
|
+ .action(async (options: any) => {
|
|
|
+ const wallet = await loadHotWalletOrLedger(
|
|
|
+ options.wallet,
|
|
|
+ options.ledgerDerivationAccount,
|
|
|
+ options.ledgerDerivationChange
|
|
|
+ );
|
|
|
+ const transaction: PublicKey = new PublicKey(options.transaction);
|
|
|
+ const cluster: PythCluster = options.cluster;
|
|
|
+
|
|
|
+ const squad = SquadsMesh.endpoint(getPythClusterApiUrl(cluster), wallet);
|
|
|
+ await squad.approveTransaction(transaction);
|
|
|
+ });
|
|
|
+
|
|
|
program.parse();
|