Skip to content

Commit aba0390

Browse files
authored
Refactor (#599)
1 parent 234cac4 commit aba0390

File tree

7 files changed

+192
-148
lines changed

7 files changed

+192
-148
lines changed

governance/xc_admin/packages/crank_executor/src/index.ts

Lines changed: 22 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import SquadsMesh, { DEFAULT_MULTISIG_PROGRAM_ID, getIxPDA } from "@sqds/mesh";
1111
import * as fs from "fs";
1212
import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";
1313
import {
14+
envOrErr,
15+
getCreateAccountWithSeedInstruction,
1416
getProposals,
1517
MultisigParser,
1618
PythMultisigInstruction,
@@ -20,44 +22,29 @@ import BN from "bn.js";
2022
import { AnchorProvider } from "@project-serum/anchor";
2123
import {
2224
getPythClusterApiUrl,
23-
getPythProgramKeyForCluster,
2425
PythCluster,
2526
} from "@pythnetwork/client/lib/cluster";
2627
import {
2728
deriveFeeCollectorKey,
2829
getWormholeBridgeData,
2930
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
30-
import { parseProductData } from "@pythnetwork/client";
31+
import { AccountType, parseProductData } from "@pythnetwork/client";
3132

32-
export function envOrErr(env: string): string {
33-
const val = process.env[env];
34-
if (!val) {
35-
throw new Error(`environment variable "${env}" must be set`);
36-
}
37-
return String(process.env[env]);
38-
}
39-
40-
const PRODUCT_ACCOUNT_SIZE = 512;
41-
const PRICE_ACCOUNT_SIZE = 3312;
42-
43-
const CLUSTER: string = envOrErr("CLUSTER");
44-
const COMMITMENT: Commitment =
45-
(process.env.COMMITMENT as Commitment) ?? "confirmed";
33+
const CLUSTER: PythCluster = envOrErr("CLUSTER") as PythCluster;
4634
const VAULT: PublicKey = new PublicKey(envOrErr("VAULT"));
4735
const KEYPAIR: Keypair = Keypair.fromSecretKey(
4836
Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
4937
);
38+
const COMMITMENT: Commitment =
39+
(process.env.COMMITMENT as Commitment) ?? "confirmed";
5040

5141
async function run() {
5242
const squad = new SquadsMesh({
53-
connection: new Connection(
54-
getPythClusterApiUrl(CLUSTER as PythCluster),
55-
COMMITMENT
56-
),
43+
connection: new Connection(getPythClusterApiUrl(CLUSTER), COMMITMENT),
5744
wallet: new NodeWallet(KEYPAIR),
5845
multisigProgramId: DEFAULT_MULTISIG_PROGRAM_ID,
5946
});
60-
const multisigParser = MultisigParser.fromCluster(CLUSTER as PythCluster);
47+
const multisigParser = MultisigParser.fromCluster(CLUSTER);
6148

6249
const wormholeFee = multisigParser.wormholeBridgeAddress
6350
? (
@@ -111,25 +98,14 @@ async function run() {
11198
parsedInstruction.name == "addProduct"
11299
) {
113100
/// Add product, fetch the symbol from the instruction
114-
const productSeed = "product:" + parsedInstruction.args.symbol;
115-
const productAddress = await PublicKey.createWithSeed(
116-
squad.wallet.publicKey,
117-
productSeed,
118-
getPythProgramKeyForCluster(CLUSTER as PythCluster)
119-
);
120101
transaction.add(
121-
SystemProgram.createAccountWithSeed({
122-
fromPubkey: squad.wallet.publicKey,
123-
basePubkey: squad.wallet.publicKey,
124-
newAccountPubkey: productAddress,
125-
seed: productSeed,
126-
space: PRODUCT_ACCOUNT_SIZE,
127-
lamports:
128-
await squad.connection.getMinimumBalanceForRentExemption(
129-
PRODUCT_ACCOUNT_SIZE
130-
),
131-
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
132-
})
102+
await getCreateAccountWithSeedInstruction(
103+
squad.connection,
104+
CLUSTER,
105+
squad.wallet.publicKey,
106+
parsedInstruction.args.symbol,
107+
AccountType.Product
108+
)
133109
);
134110
} else if (
135111
parsedInstruction instanceof PythMultisigInstruction &&
@@ -140,26 +116,14 @@ async function run() {
140116
parsedInstruction.accounts.named.productAccount.pubkey
141117
);
142118
if (productAccount) {
143-
const priceSeed =
144-
"price:" + parseProductData(productAccount.data).product.symbol;
145-
const priceAddress = await PublicKey.createWithSeed(
146-
squad.wallet.publicKey,
147-
priceSeed,
148-
getPythProgramKeyForCluster(CLUSTER as PythCluster)
149-
);
150119
transaction.add(
151-
SystemProgram.createAccountWithSeed({
152-
fromPubkey: squad.wallet.publicKey,
153-
basePubkey: squad.wallet.publicKey,
154-
newAccountPubkey: priceAddress,
155-
seed: priceSeed,
156-
space: PRICE_ACCOUNT_SIZE,
157-
lamports:
158-
await squad.connection.getMinimumBalanceForRentExemption(
159-
PRICE_ACCOUNT_SIZE
160-
),
161-
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
162-
})
120+
await getCreateAccountWithSeedInstruction(
121+
squad.connection,
122+
CLUSTER,
123+
squad.wallet.publicKey,
124+
parseProductData(productAccount.data).product.symbol,
125+
AccountType.Price
126+
)
163127
);
164128
} else {
165129
throw Error("Product account not found");
Lines changed: 36 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import { ParsedVaa, parseVaa, postVaaSolana } from "@certusone/wormhole-sdk";
1+
import { parseVaa, postVaaSolana } from "@certusone/wormhole-sdk";
22
import { signTransactionFactory } from "@certusone/wormhole-sdk/lib/cjs/solana";
3-
import {
4-
derivePostedVaaKey,
5-
getPostedVaa,
6-
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
3+
import { derivePostedVaaKey } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
74
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
85
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
9-
import { parseProductData } from "@pythnetwork/client";
6+
import { AccountType, parseProductData } from "@pythnetwork/client";
107
import {
118
getPythClusterApiUrl,
12-
getPythProgramKeyForCluster,
139
PythCluster,
1410
} from "@pythnetwork/client/lib/cluster";
1511
import {
@@ -18,43 +14,31 @@ import {
1814
Connection,
1915
Keypair,
2016
PublicKey,
21-
SystemProgram,
2217
TransactionInstruction,
2318
} from "@solana/web3.js";
2419
import * as fs from "fs";
2520
import {
2621
decodeGovernancePayload,
2722
ExecutePostedVaa,
23+
getCreateAccountWithSeedInstruction,
2824
MultisigParser,
2925
PythMultisigInstruction,
3026
WORMHOLE_ADDRESS,
3127
WORMHOLE_API_ENDPOINT,
28+
CLAIM_RECORD_SEED,
29+
mapKey,
30+
REMOTE_EXECUTOR_ADDRESS,
31+
envOrErr,
3232
} from "xc_admin_common";
3333

34-
export function envOrErr(env: string): string {
35-
const val = process.env[env];
36-
if (!val) {
37-
throw new Error(`environment variable "${env}" must be set`);
38-
}
39-
return String(process.env[env]);
40-
}
41-
42-
const REMOTE_EXECUTOR_ADDRESS = new PublicKey(
43-
"exe6S3AxPVNmy46L4Nj6HrnnAVQUhwyYzMSNcnRn3qq"
44-
);
45-
46-
const PRODUCT_ACCOUNT_SIZE = 512;
47-
const PRICE_ACCOUNT_SIZE = 3312;
48-
const CLAIM_RECORD_SEED = "CLAIM_RECORD";
49-
const EXECUTOR_KEY_SEED = "EXECUTOR_KEY";
5034
const CLUSTER: PythCluster = envOrErr("CLUSTER") as PythCluster;
51-
const COMMITMENT: Commitment =
52-
(process.env.COMMITMENT as Commitment) ?? "confirmed";
53-
const OFFSET: number = Number(process.env.OFFSET ?? "-1");
5435
const EMITTER: PublicKey = new PublicKey(envOrErr("EMITTER"));
5536
const KEYPAIR: Keypair = Keypair.fromSecretKey(
5637
Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
5738
);
39+
const OFFSET: number = Number(process.env.OFFSET ?? "-1");
40+
const COMMITMENT: Commitment =
41+
(process.env.COMMITMENT as Commitment) ?? "confirmed";
5842

5943
async function run() {
6044
const provider = new AnchorProvider(
@@ -65,17 +49,15 @@ async function run() {
6549
preflightCommitment: COMMITMENT,
6650
}
6751
);
52+
const multisigParser = MultisigParser.fromCluster(CLUSTER);
6853

6954
const remoteExecutor = await Program.at(REMOTE_EXECUTOR_ADDRESS, provider);
7055

7156
const claimRecordAddress: PublicKey = PublicKey.findProgramAddressSync(
7257
[Buffer.from(CLAIM_RECORD_SEED), EMITTER.toBuffer()],
7358
remoteExecutor.programId
7459
)[0];
75-
const executorKey: PublicKey = PublicKey.findProgramAddressSync(
76-
[Buffer.from(EXECUTOR_KEY_SEED), EMITTER.toBuffer()],
77-
remoteExecutor.programId
78-
)[0];
60+
const executorKey: PublicKey = mapKey(EMITTER);
7961
const claimRecord = await remoteExecutor.account.claimRecord.fetchNullable(
8062
claimRecordAddress
8163
);
@@ -105,7 +87,6 @@ async function run() {
10587
governancePayload instanceof ExecutePostedVaa &&
10688
governancePayload.targetChainId == "pythnet"
10789
) {
108-
const multisigParser = MultisigParser.fromCluster(CLUSTER);
10990
const preInstructions: TransactionInstruction[] = [];
11091

11192
console.log(`Found VAA ${lastSequenceNumber}, relaying ...`);
@@ -139,25 +120,14 @@ async function run() {
139120
parsedInstruction instanceof PythMultisigInstruction &&
140121
parsedInstruction.name == "addProduct"
141122
) {
142-
const productSeed = "product:" + parsedInstruction.args.symbol;
143-
const productAddress = await PublicKey.createWithSeed(
144-
provider.wallet.publicKey,
145-
productSeed,
146-
getPythProgramKeyForCluster(CLUSTER as PythCluster)
147-
);
148123
preInstructions.push(
149-
SystemProgram.createAccountWithSeed({
150-
fromPubkey: provider.wallet.publicKey,
151-
basePubkey: provider.wallet.publicKey,
152-
newAccountPubkey: productAddress,
153-
seed: productSeed,
154-
space: PRODUCT_ACCOUNT_SIZE,
155-
lamports:
156-
await provider.connection.getMinimumBalanceForRentExemption(
157-
PRODUCT_ACCOUNT_SIZE
158-
),
159-
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
160-
})
124+
await getCreateAccountWithSeedInstruction(
125+
provider.connection,
126+
CLUSTER,
127+
provider.wallet.publicKey,
128+
parsedInstruction.args.symbol,
129+
AccountType.Product
130+
)
161131
);
162132
} else if (
163133
parsedInstruction instanceof PythMultisigInstruction &&
@@ -167,28 +137,14 @@ async function run() {
167137
parsedInstruction.accounts.named.productAccount.pubkey
168138
);
169139
if (productAccount) {
170-
const priceSeed =
171-
"price:" + parseProductData(productAccount.data).product.symbol;
172-
const priceAddress = await PublicKey.createWithSeed(
173-
provider.wallet.publicKey,
174-
priceSeed,
175-
getPythProgramKeyForCluster(CLUSTER as PythCluster)
176-
);
177140
preInstructions.push(
178-
SystemProgram.createAccountWithSeed({
179-
fromPubkey: provider.wallet.publicKey,
180-
basePubkey: provider.wallet.publicKey,
181-
newAccountPubkey: priceAddress,
182-
seed: priceSeed,
183-
space: PRICE_ACCOUNT_SIZE,
184-
lamports:
185-
await provider.connection.getMinimumBalanceForRentExemption(
186-
PRICE_ACCOUNT_SIZE
187-
),
188-
programId: getPythProgramKeyForCluster(
189-
CLUSTER as PythCluster
190-
),
191-
})
141+
await getCreateAccountWithSeedInstruction(
142+
provider.connection,
143+
CLUSTER,
144+
provider.wallet.publicKey,
145+
parseProductData(productAccount.data).product.symbol,
146+
AccountType.Price
147+
)
192148
);
193149
} else {
194150
throw Error("Product account not found");
@@ -204,22 +160,25 @@ async function run() {
204160
})
205161
.remainingAccounts(extraAccountMetas)
206162
.preInstructions(preInstructions)
207-
.rpc();
163+
.rpc({ skipPreflight: true });
208164
}
209165
} else if (response.code == 5) {
210-
console.log(`Wormhole API failure`);
211-
console.log(
212-
`${wormholeApi}/v1/signed_vaa/1/${EMITTER.toBuffer().toString(
166+
throw new Error(
167+
`Wormhole API failure :${wormholeApi}/v1/signed_vaa/1/${EMITTER.toBuffer().toString(
213168
"hex"
214169
)}/${lastSequenceNumber}`
215170
);
216-
break;
217171
} else {
218172
throw new Error("Could not connect to wormhole api");
219173
}
220174
}
221175
}
222176

223177
(async () => {
224-
await run();
178+
try {
179+
await run();
180+
} catch (err) {
181+
console.error(err);
182+
throw new Error();
183+
}
225184
})();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function envOrErr(env: string): string {
2+
const val = process.env[env];
3+
if (!val) {
4+
throw new Error(`environment variable "${env}" must be set`);
5+
}
6+
return String(process.env[env]);
7+
}

0 commit comments

Comments
 (0)