@@ -28,14 +28,43 @@ import {
28
28
WORMHOLE_ADDRESS ,
29
29
} from "xc_admin_common" ;
30
30
import { 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
+ }
31
49
32
50
const mutlisigCommand = ( name : string , description : string ) =>
33
51
program
34
52
. command ( name )
35
53
. description ( description )
36
54
. 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
+ ) ;
39
68
40
69
program
41
70
. name ( "xc_admin_cli" )
@@ -56,10 +85,10 @@ mutlisigCommand(
56
85
)
57
86
58
87
. 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
63
92
) ;
64
93
const cluster : PythCluster = options . cluster ;
65
94
const programId : PublicKey = new PublicKey ( options . programId ) ;
@@ -104,7 +133,7 @@ mutlisigCommand(
104
133
. accept ( )
105
134
. accounts ( {
106
135
currentAuthority : current ,
107
- newAuthority : mapKey ( vaultAuthority ) ,
136
+ newAuthority : isRemote ? mapKey ( vaultAuthority ) : vaultAuthority ,
108
137
programAccount : programId ,
109
138
programDataAccount,
110
139
bpfUpgradableLoader : BPF_UPGRADABLE_LOADER ,
@@ -128,10 +157,10 @@ mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
128
157
. requiredOption ( "-b, --buffer <pubkey>" , "buffer account" )
129
158
130
159
. 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
135
164
) ;
136
165
const cluster : PythCluster = options . cluster ;
137
166
const programId : PublicKey = new PublicKey ( options . programId ) ;
@@ -166,7 +195,11 @@ mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
166
195
{ pubkey : wallet . publicKey , isSigner : false , isWritable : true } ,
167
196
{ pubkey : SYSVAR_RENT_PUBKEY , isSigner : false , isWritable : false } ,
168
197
{ 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
+ } ,
170
203
] ,
171
204
} ;
172
205
@@ -186,10 +219,10 @@ mutlisigCommand(
186
219
. requiredOption ( "-p, --price <pubkey>" , "Price account to modify" )
187
220
. requiredOption ( "-e, --exponent <number>" , "New exponent" )
188
221
. 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
193
226
) ;
194
227
const cluster : PythCluster = options . cluster ;
195
228
const vault : PublicKey = new PublicKey ( options . vault ) ;
@@ -222,7 +255,10 @@ program
222
255
. command ( "parse-transaction" )
223
256
. description ( "Parse a transaction sitting in the multisig" )
224
257
. 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
+ )
226
262
. action ( async ( options : any ) => {
227
263
const cluster = options . cluster ;
228
264
const transaction : PublicKey = new PublicKey ( options . transaction ) ;
@@ -245,4 +281,22 @@ program
245
281
console . log ( JSON . stringify ( parsed , null , 2 ) ) ;
246
282
} ) ;
247
283
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
+
248
302
program . parse ( ) ;
0 commit comments