4
4
Connection ,
5
5
Keypair ,
6
6
PublicKey ,
7
- SendTransactionError ,
8
7
SystemProgram ,
9
8
Transaction ,
10
9
} from "@solana/web3.js" ;
@@ -14,18 +13,21 @@ import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";
14
13
import {
15
14
getProposals ,
16
15
MultisigParser ,
16
+ PythMultisigInstruction ,
17
17
WormholeMultisigInstruction ,
18
18
} from "xc_admin_common" ;
19
19
import BN from "bn.js" ;
20
20
import { AnchorProvider } from "@project-serum/anchor" ;
21
21
import {
22
22
getPythClusterApiUrl ,
23
+ getPythProgramKeyForCluster ,
23
24
PythCluster ,
24
25
} from "@pythnetwork/client/lib/cluster" ;
25
26
import {
26
27
deriveFeeCollectorKey ,
27
28
getWormholeBridgeData ,
28
29
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole" ;
30
+ import { parseProductData } from "@pythnetwork/client" ;
29
31
30
32
export function envOrErr ( env : string ) : string {
31
33
const val = process . env [ env ] ;
@@ -35,6 +37,9 @@ export function envOrErr(env: string): string {
35
37
return String ( process . env [ env ] ) ;
36
38
}
37
39
40
+ const PRODUCT_ACCOUNT_SIZE = 512 ;
41
+ const PRICE_ACCOUNT_SIZE = 3312 ;
42
+
38
43
const CLUSTER : string = envOrErr ( "CLUSTER" ) ;
39
44
const COMMITMENT : Commitment =
40
45
( process . env . COMMITMENT as Commitment ) ?? "confirmed" ;
@@ -65,6 +70,7 @@ async function run() {
65
70
: 0 ;
66
71
67
72
const proposals = await getProposals ( squad , VAULT , undefined , "executeReady" ) ;
73
+
68
74
for ( const proposal of proposals ) {
69
75
console . log ( "Trying to execute: " , proposal . publicKey . toBase58 ( ) ) ;
70
76
// If we have previously cancelled because the proposal was failing, don't attempt
@@ -100,6 +106,92 @@ async function run() {
100
106
fromPubkey : squad . wallet . publicKey ,
101
107
} )
102
108
) ;
109
+ } else if (
110
+ parsedInstruction instanceof PythMultisigInstruction &&
111
+ parsedInstruction . name == "addProduct"
112
+ ) {
113
+ /// Add product, fetch the symbol from updProduct to get the address
114
+ i += 1 ;
115
+ const nextInstructionPda = getIxPDA (
116
+ proposal . publicKey ,
117
+ new BN ( i ) ,
118
+ squad . multisigProgramId
119
+ ) [ 0 ] ;
120
+ const nextInstruction = await squad . getInstruction (
121
+ nextInstructionPda
122
+ ) ;
123
+ const nextParsedInstruction = multisigParser . parseInstruction ( {
124
+ programId : nextInstruction . programId ,
125
+ data : nextInstruction . data as Buffer ,
126
+ keys : nextInstruction . keys as AccountMeta [ ] ,
127
+ } ) ;
128
+
129
+ if (
130
+ nextParsedInstruction instanceof PythMultisigInstruction &&
131
+ nextParsedInstruction . name == "updProduct"
132
+ ) {
133
+ const productSeed = "product:" + nextParsedInstruction . args . symbol ;
134
+ const productAddress = await PublicKey . createWithSeed (
135
+ squad . wallet . publicKey ,
136
+ productSeed ,
137
+ getPythProgramKeyForCluster ( CLUSTER as PythCluster )
138
+ ) ;
139
+ transaction . add (
140
+ SystemProgram . createAccountWithSeed ( {
141
+ fromPubkey : squad . wallet . publicKey ,
142
+ basePubkey : squad . wallet . publicKey ,
143
+ newAccountPubkey : productAddress ,
144
+ seed : productSeed ,
145
+ space : PRODUCT_ACCOUNT_SIZE ,
146
+ lamports :
147
+ await squad . connection . getMinimumBalanceForRentExemption (
148
+ PRODUCT_ACCOUNT_SIZE
149
+ ) ,
150
+ programId : getPythProgramKeyForCluster ( CLUSTER as PythCluster ) ,
151
+ } )
152
+ ) ;
153
+ transaction . add (
154
+ await squad . buildExecuteInstruction (
155
+ proposal . publicKey ,
156
+ getIxPDA (
157
+ proposal . publicKey ,
158
+ new BN ( i - 1 ) ,
159
+ squad . multisigProgramId
160
+ ) [ 0 ]
161
+ )
162
+ ) ;
163
+ }
164
+ } else if (
165
+ parsedInstruction instanceof PythMultisigInstruction &&
166
+ parsedInstruction . name == "addPrice"
167
+ ) {
168
+ /// Add price, fetch the symbol from the product account
169
+ const productAccount = await squad . connection . getAccountInfo (
170
+ parsedInstruction . accounts . named . productAccount . pubkey
171
+ ) ;
172
+ if ( productAccount ?. data ) {
173
+ const priceSeed =
174
+ "price:" + parseProductData ( productAccount . data ) . product . symbol ;
175
+ const priceAddress = await PublicKey . createWithSeed (
176
+ squad . wallet . publicKey ,
177
+ priceSeed ,
178
+ getPythProgramKeyForCluster ( CLUSTER as PythCluster )
179
+ ) ;
180
+ transaction . add (
181
+ SystemProgram . createAccountWithSeed ( {
182
+ fromPubkey : squad . wallet . publicKey ,
183
+ basePubkey : squad . wallet . publicKey ,
184
+ newAccountPubkey : priceAddress ,
185
+ seed : priceSeed ,
186
+ space : PRICE_ACCOUNT_SIZE ,
187
+ lamports :
188
+ await squad . connection . getMinimumBalanceForRentExemption (
189
+ PRICE_ACCOUNT_SIZE
190
+ ) ,
191
+ programId : getPythProgramKeyForCluster ( CLUSTER as PythCluster ) ,
192
+ } )
193
+ ) ;
194
+ }
103
195
}
104
196
105
197
transaction . add (
@@ -109,20 +201,10 @@ async function run() {
109
201
)
110
202
) ;
111
203
112
- try {
113
- await new AnchorProvider ( squad . connection , squad . wallet , {
114
- commitment : COMMITMENT ,
115
- preflightCommitment : COMMITMENT ,
116
- } ) . sendAndConfirm ( transaction , [ ] ) ;
117
- } catch ( error ) {
118
- // Mark the transaction as cancelled if we failed to run it
119
- if ( error instanceof SendTransactionError ) {
120
- console . error ( error ) ;
121
- await squad . cancelTransaction ( proposal . publicKey ) ;
122
- console . log ( "Cancelled: " , proposal . publicKey . toBase58 ( ) ) ;
123
- }
124
- break ;
125
- }
204
+ await new AnchorProvider ( squad . connection , squad . wallet , {
205
+ commitment : COMMITMENT ,
206
+ preflightCommitment : COMMITMENT ,
207
+ } ) . sendAndConfirm ( transaction , [ ] , { skipPreflight : true } ) ;
126
208
}
127
209
} else {
128
210
console . log ( "Skipping: " , proposal . publicKey . toBase58 ( ) ) ;
0 commit comments