Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 22 additions & 58 deletions governance/xc_admin/packages/crank_executor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import SquadsMesh, { DEFAULT_MULTISIG_PROGRAM_ID, getIxPDA } from "@sqds/mesh";
import * as fs from "fs";
import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";
import {
envOrErr,
getCreateAccountWithSeedInstruction,
getProposals,
MultisigParser,
PythMultisigInstruction,
Expand All @@ -20,44 +22,29 @@ import BN from "bn.js";
import { AnchorProvider } from "@project-serum/anchor";
import {
getPythClusterApiUrl,
getPythProgramKeyForCluster,
PythCluster,
} from "@pythnetwork/client/lib/cluster";
import {
deriveFeeCollectorKey,
getWormholeBridgeData,
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
import { parseProductData } from "@pythnetwork/client";
import { AccountType, parseProductData } from "@pythnetwork/client";

export function envOrErr(env: string): string {
const val = process.env[env];
if (!val) {
throw new Error(`environment variable "${env}" must be set`);
}
return String(process.env[env]);
}

const PRODUCT_ACCOUNT_SIZE = 512;
const PRICE_ACCOUNT_SIZE = 3312;

const CLUSTER: string = envOrErr("CLUSTER");
const COMMITMENT: Commitment =
(process.env.COMMITMENT as Commitment) ?? "confirmed";
const CLUSTER: PythCluster = envOrErr("CLUSTER") as PythCluster;
const VAULT: PublicKey = new PublicKey(envOrErr("VAULT"));
const KEYPAIR: Keypair = Keypair.fromSecretKey(
Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
);
const COMMITMENT: Commitment =
(process.env.COMMITMENT as Commitment) ?? "confirmed";

async function run() {
const squad = new SquadsMesh({
connection: new Connection(
getPythClusterApiUrl(CLUSTER as PythCluster),
COMMITMENT
),
connection: new Connection(getPythClusterApiUrl(CLUSTER), COMMITMENT),
wallet: new NodeWallet(KEYPAIR),
multisigProgramId: DEFAULT_MULTISIG_PROGRAM_ID,
});
const multisigParser = MultisigParser.fromCluster(CLUSTER as PythCluster);
const multisigParser = MultisigParser.fromCluster(CLUSTER);

const wormholeFee = multisigParser.wormholeBridgeAddress
? (
Expand Down Expand Up @@ -111,25 +98,14 @@ async function run() {
parsedInstruction.name == "addProduct"
) {
/// Add product, fetch the symbol from the instruction
const productSeed = "product:" + parsedInstruction.args.symbol;
const productAddress = await PublicKey.createWithSeed(
squad.wallet.publicKey,
productSeed,
getPythProgramKeyForCluster(CLUSTER as PythCluster)
);
transaction.add(
SystemProgram.createAccountWithSeed({
fromPubkey: squad.wallet.publicKey,
basePubkey: squad.wallet.publicKey,
newAccountPubkey: productAddress,
seed: productSeed,
space: PRODUCT_ACCOUNT_SIZE,
lamports:
await squad.connection.getMinimumBalanceForRentExemption(
PRODUCT_ACCOUNT_SIZE
),
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
})
await getCreateAccountWithSeedInstruction(
squad.connection,
CLUSTER,
squad.wallet.publicKey,
parsedInstruction.args.symbol,
AccountType.Product
)
);
} else if (
parsedInstruction instanceof PythMultisigInstruction &&
Expand All @@ -140,26 +116,14 @@ async function run() {
parsedInstruction.accounts.named.productAccount.pubkey
);
if (productAccount) {
const priceSeed =
"price:" + parseProductData(productAccount.data).product.symbol;
const priceAddress = await PublicKey.createWithSeed(
squad.wallet.publicKey,
priceSeed,
getPythProgramKeyForCluster(CLUSTER as PythCluster)
);
transaction.add(
SystemProgram.createAccountWithSeed({
fromPubkey: squad.wallet.publicKey,
basePubkey: squad.wallet.publicKey,
newAccountPubkey: priceAddress,
seed: priceSeed,
space: PRICE_ACCOUNT_SIZE,
lamports:
await squad.connection.getMinimumBalanceForRentExemption(
PRICE_ACCOUNT_SIZE
),
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
})
await getCreateAccountWithSeedInstruction(
squad.connection,
CLUSTER,
squad.wallet.publicKey,
parseProductData(productAccount.data).product.symbol,
AccountType.Price
)
);
} else {
throw Error("Product account not found");
Expand Down
113 changes: 36 additions & 77 deletions governance/xc_admin/packages/crank_pythnet_relayer/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { ParsedVaa, parseVaa, postVaaSolana } from "@certusone/wormhole-sdk";
import { parseVaa, postVaaSolana } from "@certusone/wormhole-sdk";
import { signTransactionFactory } from "@certusone/wormhole-sdk/lib/cjs/solana";
import {
derivePostedVaaKey,
getPostedVaa,
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
import { derivePostedVaaKey } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
import { parseProductData } from "@pythnetwork/client";
import { AccountType, parseProductData } from "@pythnetwork/client";
import {
getPythClusterApiUrl,
getPythProgramKeyForCluster,
PythCluster,
} from "@pythnetwork/client/lib/cluster";
import {
Expand All @@ -18,43 +14,31 @@ import {
Connection,
Keypair,
PublicKey,
SystemProgram,
TransactionInstruction,
} from "@solana/web3.js";
import * as fs from "fs";
import {
decodeGovernancePayload,
ExecutePostedVaa,
getCreateAccountWithSeedInstruction,
MultisigParser,
PythMultisigInstruction,
WORMHOLE_ADDRESS,
WORMHOLE_API_ENDPOINT,
CLAIM_RECORD_SEED,
mapKey,
REMOTE_EXECUTOR_ADDRESS,
envOrErr,
} from "xc_admin_common";

export function envOrErr(env: string): string {
const val = process.env[env];
if (!val) {
throw new Error(`environment variable "${env}" must be set`);
}
return String(process.env[env]);
}

const REMOTE_EXECUTOR_ADDRESS = new PublicKey(
"exe6S3AxPVNmy46L4Nj6HrnnAVQUhwyYzMSNcnRn3qq"
);

const PRODUCT_ACCOUNT_SIZE = 512;
const PRICE_ACCOUNT_SIZE = 3312;
const CLAIM_RECORD_SEED = "CLAIM_RECORD";
const EXECUTOR_KEY_SEED = "EXECUTOR_KEY";
const CLUSTER: PythCluster = envOrErr("CLUSTER") as PythCluster;
const COMMITMENT: Commitment =
(process.env.COMMITMENT as Commitment) ?? "confirmed";
const OFFSET: number = Number(process.env.OFFSET ?? "-1");
const EMITTER: PublicKey = new PublicKey(envOrErr("EMITTER"));
const KEYPAIR: Keypair = Keypair.fromSecretKey(
Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
);
const OFFSET: number = Number(process.env.OFFSET ?? "-1");
const COMMITMENT: Commitment =
(process.env.COMMITMENT as Commitment) ?? "confirmed";

async function run() {
const provider = new AnchorProvider(
Expand All @@ -65,17 +49,15 @@ async function run() {
preflightCommitment: COMMITMENT,
}
);
const multisigParser = MultisigParser.fromCluster(CLUSTER);

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

const claimRecordAddress: PublicKey = PublicKey.findProgramAddressSync(
[Buffer.from(CLAIM_RECORD_SEED), EMITTER.toBuffer()],
remoteExecutor.programId
)[0];
const executorKey: PublicKey = PublicKey.findProgramAddressSync(
[Buffer.from(EXECUTOR_KEY_SEED), EMITTER.toBuffer()],
remoteExecutor.programId
)[0];
const executorKey: PublicKey = mapKey(EMITTER);
const claimRecord = await remoteExecutor.account.claimRecord.fetchNullable(
claimRecordAddress
);
Expand Down Expand Up @@ -105,7 +87,6 @@ async function run() {
governancePayload instanceof ExecutePostedVaa &&
governancePayload.targetChainId == "pythnet"
) {
const multisigParser = MultisigParser.fromCluster(CLUSTER);
const preInstructions: TransactionInstruction[] = [];

console.log(`Found VAA ${lastSequenceNumber}, relaying ...`);
Expand Down Expand Up @@ -139,25 +120,14 @@ async function run() {
parsedInstruction instanceof PythMultisigInstruction &&
parsedInstruction.name == "addProduct"
) {
const productSeed = "product:" + parsedInstruction.args.symbol;
const productAddress = await PublicKey.createWithSeed(
provider.wallet.publicKey,
productSeed,
getPythProgramKeyForCluster(CLUSTER as PythCluster)
);
preInstructions.push(
SystemProgram.createAccountWithSeed({
fromPubkey: provider.wallet.publicKey,
basePubkey: provider.wallet.publicKey,
newAccountPubkey: productAddress,
seed: productSeed,
space: PRODUCT_ACCOUNT_SIZE,
lamports:
await provider.connection.getMinimumBalanceForRentExemption(
PRODUCT_ACCOUNT_SIZE
),
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
})
await getCreateAccountWithSeedInstruction(
provider.connection,
CLUSTER,
provider.wallet.publicKey,
parsedInstruction.args.symbol,
AccountType.Product
)
);
} else if (
parsedInstruction instanceof PythMultisigInstruction &&
Expand All @@ -167,28 +137,14 @@ async function run() {
parsedInstruction.accounts.named.productAccount.pubkey
);
if (productAccount) {
const priceSeed =
"price:" + parseProductData(productAccount.data).product.symbol;
const priceAddress = await PublicKey.createWithSeed(
provider.wallet.publicKey,
priceSeed,
getPythProgramKeyForCluster(CLUSTER as PythCluster)
);
preInstructions.push(
SystemProgram.createAccountWithSeed({
fromPubkey: provider.wallet.publicKey,
basePubkey: provider.wallet.publicKey,
newAccountPubkey: priceAddress,
seed: priceSeed,
space: PRICE_ACCOUNT_SIZE,
lamports:
await provider.connection.getMinimumBalanceForRentExemption(
PRICE_ACCOUNT_SIZE
),
programId: getPythProgramKeyForCluster(
CLUSTER as PythCluster
),
})
await getCreateAccountWithSeedInstruction(
provider.connection,
CLUSTER,
provider.wallet.publicKey,
parseProductData(productAccount.data).product.symbol,
AccountType.Price
)
);
} else {
throw Error("Product account not found");
Expand All @@ -204,22 +160,25 @@ async function run() {
})
.remainingAccounts(extraAccountMetas)
.preInstructions(preInstructions)
.rpc();
.rpc({ skipPreflight: true });
}
} else if (response.code == 5) {
console.log(`Wormhole API failure`);
console.log(
`${wormholeApi}/v1/signed_vaa/1/${EMITTER.toBuffer().toString(
throw new Error(
`Wormhole API failure :${wormholeApi}/v1/signed_vaa/1/${EMITTER.toBuffer().toString(
"hex"
)}/${lastSequenceNumber}`
);
break;
} else {
throw new Error("Could not connect to wormhole api");
}
}
}

(async () => {
await run();
try {
await run();
} catch (err) {
console.error(err);
throw new Error();
}
})();
7 changes: 7 additions & 0 deletions governance/xc_admin/packages/xc_admin_common/src/cranks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function envOrErr(env: string): string {
const val = process.env[env];
if (!val) {
throw new Error(`environment variable "${env}" must be set`);
}
return String(process.env[env]);
}
Loading