@@ -28,14 +28,43 @@ import {
2828 WORMHOLE_ADDRESS ,
2929} from "xc_admin_common" ;
3030import { pythOracleProgram } from "@pythnetwork/client" ;
31+ import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider" ;
32+ import { LedgerNodeWallet } from "./ledger" ;
33+
34+ export async function loadHotWalletOrLedger (
35+ wallet : string ,
36+ lda : number ,
37+ ldc : number
38+ ) : Promise < Wallet > {
39+ if ( wallet === "ledger" ) {
40+ return await LedgerNodeWallet . createWallet ( lda , ldc ) ;
41+ } else {
42+ return new NodeWallet (
43+ Keypair . fromSecretKey (
44+ Uint8Array . from ( JSON . parse ( fs . readFileSync ( wallet , "ascii" ) ) )
45+ )
46+ ) ;
47+ }
48+ }
3149
3250const mutlisigCommand = ( name : string , description : string ) =>
3351 program
3452 . command ( name )
3553 . description ( description )
3654 . requiredOption ( "-c, --cluster <network>" , "solana cluster to use" )
37- . requiredOption ( "-w, --wallet <filepath>" , "path to the operations key" )
38- . requiredOption ( "-v, --vault <pubkey>" , "multisig address" ) ;
55+ . requiredOption (
56+ "-w, --wallet <filepath>" ,
57+ 'path to the operations key or "ledger"'
58+ )
59+ . requiredOption ( "-v, --vault <pubkey>" , "multisig address" )
60+ . option (
61+ "-lda, --ledger-derivation-account <number>" ,
62+ "ledger derivation account to use"
63+ )
64+ . option (
65+ "-ldc, --ledger-derivation-change <number>" ,
66+ "ledger derivation change to use"
67+ ) ;
3968
4069program
4170 . name ( "xc_admin_cli" )
@@ -56,10 +85,10 @@ mutlisigCommand(
5685 )
5786
5887 . action ( async ( options : any ) => {
59- const wallet = new NodeWallet (
60- Keypair . fromSecretKey (
61- Uint8Array . from ( JSON . parse ( fs . readFileSync ( options . wallet , "ascii" ) ) )
62- )
88+ const wallet = await loadHotWalletOrLedger (
89+ options . wallet ,
90+ options . ledgerDerivationAccount ,
91+ options . ledgerDerivationChange
6392 ) ;
6493 const cluster : PythCluster = options . cluster ;
6594 const programId : PublicKey = new PublicKey ( options . programId ) ;
@@ -104,7 +133,7 @@ mutlisigCommand(
104133 . accept ( )
105134 . accounts ( {
106135 currentAuthority : current ,
107- newAuthority : mapKey ( vaultAuthority ) ,
136+ newAuthority : isRemote ? mapKey ( vaultAuthority ) : vaultAuthority ,
108137 programAccount : programId ,
109138 programDataAccount,
110139 bpfUpgradableLoader : BPF_UPGRADABLE_LOADER ,
@@ -128,10 +157,10 @@ mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
128157 . requiredOption ( "-b, --buffer <pubkey>" , "buffer account" )
129158
130159 . action ( async ( options : any ) => {
131- const wallet = new NodeWallet (
132- Keypair . fromSecretKey (
133- Uint8Array . from ( JSON . parse ( fs . readFileSync ( options . wallet , "ascii" ) ) )
134- )
160+ const wallet = await loadHotWalletOrLedger (
161+ options . wallet ,
162+ options . ledgerDerivationAccount ,
163+ options . ledgerDerivationChange
135164 ) ;
136165 const cluster : PythCluster = options . cluster ;
137166 const programId : PublicKey = new PublicKey ( options . programId ) ;
@@ -166,7 +195,11 @@ mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
166195 { pubkey : wallet . publicKey , isSigner : false , isWritable : true } ,
167196 { pubkey : SYSVAR_RENT_PUBKEY , isSigner : false , isWritable : false } ,
168197 { pubkey : SYSVAR_CLOCK_PUBKEY , isSigner : false , isWritable : false } ,
169- { pubkey : mapKey ( vaultAuthority ) , isSigner : true , isWritable : false } ,
198+ {
199+ pubkey : isRemote ? mapKey ( vaultAuthority ) : vaultAuthority ,
200+ isSigner : true ,
201+ isWritable : false ,
202+ } ,
170203 ] ,
171204 } ;
172205
@@ -186,10 +219,10 @@ mutlisigCommand(
186219 . requiredOption ( "-p, --price <pubkey>" , "Price account to modify" )
187220 . requiredOption ( "-e, --exponent <number>" , "New exponent" )
188221 . action ( async ( options : any ) => {
189- const wallet = new NodeWallet (
190- Keypair . fromSecretKey (
191- Uint8Array . from ( JSON . parse ( fs . readFileSync ( options . wallet , "ascii" ) ) )
192- )
222+ const wallet = await loadHotWalletOrLedger (
223+ options . wallet ,
224+ options . ledgerDerivationAccount ,
225+ options . ledgerDerivationChange
193226 ) ;
194227 const cluster : PythCluster = options . cluster ;
195228 const vault : PublicKey = new PublicKey ( options . vault ) ;
@@ -222,7 +255,10 @@ program
222255 . command ( "parse-transaction" )
223256 . description ( "Parse a transaction sitting in the multisig" )
224257 . requiredOption ( "-c, --cluster <network>" , "solana cluster to use" )
225- . requiredOption ( "-t, --transaction <pubkey>" , "path to the operations key" )
258+ . requiredOption (
259+ "-t, --transaction <pubkey>" ,
260+ "address of the outstanding transaction"
261+ )
226262 . action ( async ( options : any ) => {
227263 const cluster = options . cluster ;
228264 const transaction : PublicKey = new PublicKey ( options . transaction ) ;
@@ -245,4 +281,22 @@ program
245281 console . log ( JSON . stringify ( parsed , null , 2 ) ) ;
246282 } ) ;
247283
284+ mutlisigCommand ( "approve" , "Approve a transaction sitting in the multisig" )
285+ . requiredOption (
286+ "-t, --transaction <pubkey>" ,
287+ "address of the outstanding transaction"
288+ )
289+ . action ( async ( options : any ) => {
290+ const wallet = await loadHotWalletOrLedger (
291+ options . wallet ,
292+ options . ledgerDerivationAccount ,
293+ options . ledgerDerivationChange
294+ ) ;
295+ const transaction : PublicKey = new PublicKey ( options . transaction ) ;
296+ const cluster : PythCluster = options . cluster ;
297+
298+ const squad = SquadsMesh . endpoint ( getPythClusterApiUrl ( cluster ) , wallet ) ;
299+ await squad . approveTransaction ( transaction ) ;
300+ } ) ;
301+
248302program . parse ( ) ;
0 commit comments