Refactor (#599)
This commit is contained in:
parent
234cac4261
commit
aba0390495
|
@ -11,6 +11,8 @@ import SquadsMesh, { DEFAULT_MULTISIG_PROGRAM_ID, getIxPDA } from "@sqds/mesh";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";
|
import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";
|
||||||
import {
|
import {
|
||||||
|
envOrErr,
|
||||||
|
getCreateAccountWithSeedInstruction,
|
||||||
getProposals,
|
getProposals,
|
||||||
MultisigParser,
|
MultisigParser,
|
||||||
PythMultisigInstruction,
|
PythMultisigInstruction,
|
||||||
|
@ -20,44 +22,29 @@ import BN from "bn.js";
|
||||||
import { AnchorProvider } from "@project-serum/anchor";
|
import { AnchorProvider } from "@project-serum/anchor";
|
||||||
import {
|
import {
|
||||||
getPythClusterApiUrl,
|
getPythClusterApiUrl,
|
||||||
getPythProgramKeyForCluster,
|
|
||||||
PythCluster,
|
PythCluster,
|
||||||
} from "@pythnetwork/client/lib/cluster";
|
} from "@pythnetwork/client/lib/cluster";
|
||||||
import {
|
import {
|
||||||
deriveFeeCollectorKey,
|
deriveFeeCollectorKey,
|
||||||
getWormholeBridgeData,
|
getWormholeBridgeData,
|
||||||
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
|
} 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 CLUSTER: PythCluster = envOrErr("CLUSTER") as PythCluster;
|
||||||
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 VAULT: PublicKey = new PublicKey(envOrErr("VAULT"));
|
const VAULT: PublicKey = new PublicKey(envOrErr("VAULT"));
|
||||||
const KEYPAIR: Keypair = Keypair.fromSecretKey(
|
const KEYPAIR: Keypair = Keypair.fromSecretKey(
|
||||||
Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
|
Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
|
||||||
);
|
);
|
||||||
|
const COMMITMENT: Commitment =
|
||||||
|
(process.env.COMMITMENT as Commitment) ?? "confirmed";
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
const squad = new SquadsMesh({
|
const squad = new SquadsMesh({
|
||||||
connection: new Connection(
|
connection: new Connection(getPythClusterApiUrl(CLUSTER), COMMITMENT),
|
||||||
getPythClusterApiUrl(CLUSTER as PythCluster),
|
|
||||||
COMMITMENT
|
|
||||||
),
|
|
||||||
wallet: new NodeWallet(KEYPAIR),
|
wallet: new NodeWallet(KEYPAIR),
|
||||||
multisigProgramId: DEFAULT_MULTISIG_PROGRAM_ID,
|
multisigProgramId: DEFAULT_MULTISIG_PROGRAM_ID,
|
||||||
});
|
});
|
||||||
const multisigParser = MultisigParser.fromCluster(CLUSTER as PythCluster);
|
const multisigParser = MultisigParser.fromCluster(CLUSTER);
|
||||||
|
|
||||||
const wormholeFee = multisigParser.wormholeBridgeAddress
|
const wormholeFee = multisigParser.wormholeBridgeAddress
|
||||||
? (
|
? (
|
||||||
|
@ -111,25 +98,14 @@ async function run() {
|
||||||
parsedInstruction.name == "addProduct"
|
parsedInstruction.name == "addProduct"
|
||||||
) {
|
) {
|
||||||
/// Add product, fetch the symbol from the instruction
|
/// 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(
|
transaction.add(
|
||||||
SystemProgram.createAccountWithSeed({
|
await getCreateAccountWithSeedInstruction(
|
||||||
fromPubkey: squad.wallet.publicKey,
|
squad.connection,
|
||||||
basePubkey: squad.wallet.publicKey,
|
CLUSTER,
|
||||||
newAccountPubkey: productAddress,
|
squad.wallet.publicKey,
|
||||||
seed: productSeed,
|
parsedInstruction.args.symbol,
|
||||||
space: PRODUCT_ACCOUNT_SIZE,
|
AccountType.Product
|
||||||
lamports:
|
)
|
||||||
await squad.connection.getMinimumBalanceForRentExemption(
|
|
||||||
PRODUCT_ACCOUNT_SIZE
|
|
||||||
),
|
|
||||||
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
parsedInstruction instanceof PythMultisigInstruction &&
|
parsedInstruction instanceof PythMultisigInstruction &&
|
||||||
|
@ -140,26 +116,14 @@ async function run() {
|
||||||
parsedInstruction.accounts.named.productAccount.pubkey
|
parsedInstruction.accounts.named.productAccount.pubkey
|
||||||
);
|
);
|
||||||
if (productAccount) {
|
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(
|
transaction.add(
|
||||||
SystemProgram.createAccountWithSeed({
|
await getCreateAccountWithSeedInstruction(
|
||||||
fromPubkey: squad.wallet.publicKey,
|
squad.connection,
|
||||||
basePubkey: squad.wallet.publicKey,
|
CLUSTER,
|
||||||
newAccountPubkey: priceAddress,
|
squad.wallet.publicKey,
|
||||||
seed: priceSeed,
|
parseProductData(productAccount.data).product.symbol,
|
||||||
space: PRICE_ACCOUNT_SIZE,
|
AccountType.Price
|
||||||
lamports:
|
)
|
||||||
await squad.connection.getMinimumBalanceForRentExemption(
|
|
||||||
PRICE_ACCOUNT_SIZE
|
|
||||||
),
|
|
||||||
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
throw Error("Product account not found");
|
throw Error("Product account not found");
|
||||||
|
|
|
@ -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 { signTransactionFactory } from "@certusone/wormhole-sdk/lib/cjs/solana";
|
||||||
import {
|
import { derivePostedVaaKey } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
|
||||||
derivePostedVaaKey,
|
|
||||||
getPostedVaa,
|
|
||||||
} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
|
|
||||||
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
|
import { AnchorProvider, BN, Program } from "@coral-xyz/anchor";
|
||||||
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
|
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
|
||||||
import { parseProductData } from "@pythnetwork/client";
|
import { AccountType, parseProductData } from "@pythnetwork/client";
|
||||||
import {
|
import {
|
||||||
getPythClusterApiUrl,
|
getPythClusterApiUrl,
|
||||||
getPythProgramKeyForCluster,
|
|
||||||
PythCluster,
|
PythCluster,
|
||||||
} from "@pythnetwork/client/lib/cluster";
|
} from "@pythnetwork/client/lib/cluster";
|
||||||
import {
|
import {
|
||||||
|
@ -18,43 +14,31 @@ import {
|
||||||
Connection,
|
Connection,
|
||||||
Keypair,
|
Keypair,
|
||||||
PublicKey,
|
PublicKey,
|
||||||
SystemProgram,
|
|
||||||
TransactionInstruction,
|
TransactionInstruction,
|
||||||
} from "@solana/web3.js";
|
} from "@solana/web3.js";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import {
|
import {
|
||||||
decodeGovernancePayload,
|
decodeGovernancePayload,
|
||||||
ExecutePostedVaa,
|
ExecutePostedVaa,
|
||||||
|
getCreateAccountWithSeedInstruction,
|
||||||
MultisigParser,
|
MultisigParser,
|
||||||
PythMultisigInstruction,
|
PythMultisigInstruction,
|
||||||
WORMHOLE_ADDRESS,
|
WORMHOLE_ADDRESS,
|
||||||
WORMHOLE_API_ENDPOINT,
|
WORMHOLE_API_ENDPOINT,
|
||||||
|
CLAIM_RECORD_SEED,
|
||||||
|
mapKey,
|
||||||
|
REMOTE_EXECUTOR_ADDRESS,
|
||||||
|
envOrErr,
|
||||||
} from "xc_admin_common";
|
} 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 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 EMITTER: PublicKey = new PublicKey(envOrErr("EMITTER"));
|
||||||
const KEYPAIR: Keypair = Keypair.fromSecretKey(
|
const KEYPAIR: Keypair = Keypair.fromSecretKey(
|
||||||
Uint8Array.from(JSON.parse(fs.readFileSync(envOrErr("WALLET"), "ascii")))
|
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() {
|
async function run() {
|
||||||
const provider = new AnchorProvider(
|
const provider = new AnchorProvider(
|
||||||
|
@ -65,6 +49,7 @@ async function run() {
|
||||||
preflightCommitment: COMMITMENT,
|
preflightCommitment: COMMITMENT,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
const multisigParser = MultisigParser.fromCluster(CLUSTER);
|
||||||
|
|
||||||
const remoteExecutor = await Program.at(REMOTE_EXECUTOR_ADDRESS, provider);
|
const remoteExecutor = await Program.at(REMOTE_EXECUTOR_ADDRESS, provider);
|
||||||
|
|
||||||
|
@ -72,10 +57,7 @@ async function run() {
|
||||||
[Buffer.from(CLAIM_RECORD_SEED), EMITTER.toBuffer()],
|
[Buffer.from(CLAIM_RECORD_SEED), EMITTER.toBuffer()],
|
||||||
remoteExecutor.programId
|
remoteExecutor.programId
|
||||||
)[0];
|
)[0];
|
||||||
const executorKey: PublicKey = PublicKey.findProgramAddressSync(
|
const executorKey: PublicKey = mapKey(EMITTER);
|
||||||
[Buffer.from(EXECUTOR_KEY_SEED), EMITTER.toBuffer()],
|
|
||||||
remoteExecutor.programId
|
|
||||||
)[0];
|
|
||||||
const claimRecord = await remoteExecutor.account.claimRecord.fetchNullable(
|
const claimRecord = await remoteExecutor.account.claimRecord.fetchNullable(
|
||||||
claimRecordAddress
|
claimRecordAddress
|
||||||
);
|
);
|
||||||
|
@ -105,7 +87,6 @@ async function run() {
|
||||||
governancePayload instanceof ExecutePostedVaa &&
|
governancePayload instanceof ExecutePostedVaa &&
|
||||||
governancePayload.targetChainId == "pythnet"
|
governancePayload.targetChainId == "pythnet"
|
||||||
) {
|
) {
|
||||||
const multisigParser = MultisigParser.fromCluster(CLUSTER);
|
|
||||||
const preInstructions: TransactionInstruction[] = [];
|
const preInstructions: TransactionInstruction[] = [];
|
||||||
|
|
||||||
console.log(`Found VAA ${lastSequenceNumber}, relaying ...`);
|
console.log(`Found VAA ${lastSequenceNumber}, relaying ...`);
|
||||||
|
@ -139,25 +120,14 @@ async function run() {
|
||||||
parsedInstruction instanceof PythMultisigInstruction &&
|
parsedInstruction instanceof PythMultisigInstruction &&
|
||||||
parsedInstruction.name == "addProduct"
|
parsedInstruction.name == "addProduct"
|
||||||
) {
|
) {
|
||||||
const productSeed = "product:" + parsedInstruction.args.symbol;
|
|
||||||
const productAddress = await PublicKey.createWithSeed(
|
|
||||||
provider.wallet.publicKey,
|
|
||||||
productSeed,
|
|
||||||
getPythProgramKeyForCluster(CLUSTER as PythCluster)
|
|
||||||
);
|
|
||||||
preInstructions.push(
|
preInstructions.push(
|
||||||
SystemProgram.createAccountWithSeed({
|
await getCreateAccountWithSeedInstruction(
|
||||||
fromPubkey: provider.wallet.publicKey,
|
provider.connection,
|
||||||
basePubkey: provider.wallet.publicKey,
|
CLUSTER,
|
||||||
newAccountPubkey: productAddress,
|
provider.wallet.publicKey,
|
||||||
seed: productSeed,
|
parsedInstruction.args.symbol,
|
||||||
space: PRODUCT_ACCOUNT_SIZE,
|
AccountType.Product
|
||||||
lamports:
|
)
|
||||||
await provider.connection.getMinimumBalanceForRentExemption(
|
|
||||||
PRODUCT_ACCOUNT_SIZE
|
|
||||||
),
|
|
||||||
programId: getPythProgramKeyForCluster(CLUSTER as PythCluster),
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
parsedInstruction instanceof PythMultisigInstruction &&
|
parsedInstruction instanceof PythMultisigInstruction &&
|
||||||
|
@ -167,28 +137,14 @@ async function run() {
|
||||||
parsedInstruction.accounts.named.productAccount.pubkey
|
parsedInstruction.accounts.named.productAccount.pubkey
|
||||||
);
|
);
|
||||||
if (productAccount) {
|
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(
|
preInstructions.push(
|
||||||
SystemProgram.createAccountWithSeed({
|
await getCreateAccountWithSeedInstruction(
|
||||||
fromPubkey: provider.wallet.publicKey,
|
provider.connection,
|
||||||
basePubkey: provider.wallet.publicKey,
|
CLUSTER,
|
||||||
newAccountPubkey: priceAddress,
|
provider.wallet.publicKey,
|
||||||
seed: priceSeed,
|
parseProductData(productAccount.data).product.symbol,
|
||||||
space: PRICE_ACCOUNT_SIZE,
|
AccountType.Price
|
||||||
lamports:
|
)
|
||||||
await provider.connection.getMinimumBalanceForRentExemption(
|
|
||||||
PRICE_ACCOUNT_SIZE
|
|
||||||
),
|
|
||||||
programId: getPythProgramKeyForCluster(
|
|
||||||
CLUSTER as PythCluster
|
|
||||||
),
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
throw Error("Product account not found");
|
throw Error("Product account not found");
|
||||||
|
@ -204,16 +160,14 @@ async function run() {
|
||||||
})
|
})
|
||||||
.remainingAccounts(extraAccountMetas)
|
.remainingAccounts(extraAccountMetas)
|
||||||
.preInstructions(preInstructions)
|
.preInstructions(preInstructions)
|
||||||
.rpc();
|
.rpc({ skipPreflight: true });
|
||||||
}
|
}
|
||||||
} else if (response.code == 5) {
|
} else if (response.code == 5) {
|
||||||
console.log(`Wormhole API failure`);
|
throw new Error(
|
||||||
console.log(
|
`Wormhole API failure :${wormholeApi}/v1/signed_vaa/1/${EMITTER.toBuffer().toString(
|
||||||
`${wormholeApi}/v1/signed_vaa/1/${EMITTER.toBuffer().toString(
|
|
||||||
"hex"
|
"hex"
|
||||||
)}/${lastSequenceNumber}`
|
)}/${lastSequenceNumber}`
|
||||||
);
|
);
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Could not connect to wormhole api");
|
throw new Error("Could not connect to wormhole api");
|
||||||
}
|
}
|
||||||
|
@ -221,5 +175,10 @@ async function run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await run();
|
try {
|
||||||
|
await run();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -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]);
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
import {
|
||||||
|
AccountType,
|
||||||
|
getPythProgramKeyForCluster,
|
||||||
|
PythCluster,
|
||||||
|
} from "@pythnetwork/client";
|
||||||
|
import {
|
||||||
|
Connection,
|
||||||
|
PublicKey,
|
||||||
|
SystemProgram,
|
||||||
|
TransactionInstruction,
|
||||||
|
} from "@solana/web3.js";
|
||||||
|
import { OPS_KEY } from "./multisig";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get seed for deterministic creation of a price/product account
|
||||||
|
* @param type Type of the account
|
||||||
|
* @param symbol Symbol of the price feed
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function getSeed(accountType: AccountType, symbol: string): string {
|
||||||
|
switch (accountType) {
|
||||||
|
case AccountType.Price:
|
||||||
|
return "price:" + symbol;
|
||||||
|
case AccountType.Product:
|
||||||
|
return "product:" + symbol;
|
||||||
|
default:
|
||||||
|
throw new Error("Unimplemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get required account size for a given oracle account type
|
||||||
|
* @param accountType Type of the account
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function getAccountTypeSize(accountType: AccountType): number {
|
||||||
|
switch (accountType) {
|
||||||
|
case AccountType.Price:
|
||||||
|
return 3312;
|
||||||
|
case AccountType.Product:
|
||||||
|
return 512;
|
||||||
|
default:
|
||||||
|
throw new Error("Unimplemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the address and the seed of a deterministic price/product account
|
||||||
|
* @param type Type of the account
|
||||||
|
* @param symbol Symbol of the price feed
|
||||||
|
* @param cluster Cluster in which to create the deterministic account
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function findDetermisticAccountAddress(
|
||||||
|
type: AccountType,
|
||||||
|
symbol: string,
|
||||||
|
cluster: PythCluster
|
||||||
|
): Promise<[PublicKey, string]> {
|
||||||
|
const seed: string = getSeed(type, symbol);
|
||||||
|
const address: PublicKey = await PublicKey.createWithSeed(
|
||||||
|
OPS_KEY,
|
||||||
|
seed,
|
||||||
|
getPythProgramKeyForCluster(cluster)
|
||||||
|
);
|
||||||
|
return [address, seed];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get instruction to create a determistic price/product account
|
||||||
|
* @param connection Connection used to compute rent, should be connected to `cluster`
|
||||||
|
* @param cluster Cluster in which to create the determistic account
|
||||||
|
* @param base Base for the determistic derivation
|
||||||
|
* @param symbol Symbol of the price feed
|
||||||
|
* @param accountType Type of the account
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function getCreateAccountWithSeedInstruction(
|
||||||
|
connection: Connection,
|
||||||
|
cluster: PythCluster,
|
||||||
|
base: PublicKey,
|
||||||
|
symbol: string,
|
||||||
|
accountType: AccountType
|
||||||
|
): Promise<TransactionInstruction> {
|
||||||
|
const [address, seed]: [PublicKey, string] =
|
||||||
|
await findDetermisticAccountAddress(accountType, symbol, cluster);
|
||||||
|
return SystemProgram.createAccountWithSeed({
|
||||||
|
fromPubkey: base,
|
||||||
|
basePubkey: base,
|
||||||
|
newAccountPubkey: address,
|
||||||
|
seed: seed,
|
||||||
|
space: getAccountTypeSize(accountType),
|
||||||
|
lamports: await connection.getMinimumBalanceForRentExemption(
|
||||||
|
getAccountTypeSize(accountType)
|
||||||
|
),
|
||||||
|
programId: getPythProgramKeyForCluster(cluster),
|
||||||
|
});
|
||||||
|
}
|
|
@ -6,3 +6,5 @@ export * from "./multisig_transaction";
|
||||||
export * from "./cluster";
|
export * from "./cluster";
|
||||||
export * from "./remote_executor";
|
export * from "./remote_executor";
|
||||||
export * from "./bpf_upgradable_loader";
|
export * from "./bpf_upgradable_loader";
|
||||||
|
export * from "./deterministic_oracle_accounts";
|
||||||
|
export * from "./cranks";
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
import { PublicKey } from "@solana/web3.js";
|
import { PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seed for the claim PDA of the remote executor
|
||||||
|
*/
|
||||||
|
export const CLAIM_RECORD_SEED: string = "CLAIM_RECORD";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seed for the executor PDA of the remote executor
|
||||||
|
*/
|
||||||
|
const EXECUTOR_KEY_SEED: string = "EXECUTOR_KEY";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Address of the remote executor (same on all networks)
|
* Address of the remote executor (same on all networks)
|
||||||
*/
|
*/
|
||||||
export const REMOTE_EXECUTOR_ADDRESS = new PublicKey(
|
export const REMOTE_EXECUTOR_ADDRESS: PublicKey = new PublicKey(
|
||||||
"exe6S3AxPVNmy46L4Nj6HrnnAVQUhwyYzMSNcnRn3qq"
|
"exe6S3AxPVNmy46L4Nj6HrnnAVQUhwyYzMSNcnRn3qq"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -14,7 +24,7 @@ export const REMOTE_EXECUTOR_ADDRESS = new PublicKey(
|
||||||
*/
|
*/
|
||||||
export function mapKey(key: PublicKey): PublicKey {
|
export function mapKey(key: PublicKey): PublicKey {
|
||||||
return PublicKey.findProgramAddressSync(
|
return PublicKey.findProgramAddressSync(
|
||||||
[Buffer.from("EXECUTOR_KEY"), key.toBytes()],
|
[Buffer.from(EXECUTOR_KEY_SEED), key.toBytes()],
|
||||||
REMOTE_EXECUTOR_ADDRESS
|
REMOTE_EXECUTOR_ADDRESS
|
||||||
)[0];
|
)[0];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { AnchorProvider, Program, Wallet } from '@coral-xyz/anchor'
|
import { AnchorProvider, Program, Wallet } from '@coral-xyz/anchor'
|
||||||
import { getPythProgramKeyForCluster } from '@pythnetwork/client'
|
import { AccountType, getPythProgramKeyForCluster } from '@pythnetwork/client'
|
||||||
import { PythOracle, pythOracleProgram } from '@pythnetwork/client/lib/anchor'
|
import { PythOracle, pythOracleProgram } from '@pythnetwork/client/lib/anchor'
|
||||||
import { useAnchorWallet, useWallet } from '@solana/wallet-adapter-react'
|
import { useAnchorWallet, useWallet } from '@solana/wallet-adapter-react'
|
||||||
import { WalletModalButton } from '@solana/wallet-adapter-react-ui'
|
import { WalletModalButton } from '@solana/wallet-adapter-react-ui'
|
||||||
|
@ -7,6 +7,7 @@ import { Cluster, PublicKey, TransactionInstruction } from '@solana/web3.js'
|
||||||
import { useCallback, useContext, useEffect, useState } from 'react'
|
import { useCallback, useContext, useEffect, useState } from 'react'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import {
|
import {
|
||||||
|
findDetermisticAccountAddress,
|
||||||
getMultisigCluster,
|
getMultisigCluster,
|
||||||
isRemoteCluster,
|
isRemoteCluster,
|
||||||
mapKey,
|
mapKey,
|
||||||
|
@ -258,11 +259,13 @@ const General = () => {
|
||||||
// if prev is undefined, it means that the symbol is new
|
// if prev is undefined, it means that the symbol is new
|
||||||
if (!prev) {
|
if (!prev) {
|
||||||
// deterministically generate product account key
|
// deterministically generate product account key
|
||||||
const productAccountKey = await PublicKey.createWithSeed(
|
const productAccountKey: PublicKey = (
|
||||||
OPS_KEY,
|
await findDetermisticAccountAddress(
|
||||||
'product:' + symbol,
|
AccountType.Product,
|
||||||
pythProgramClient.programId
|
symbol,
|
||||||
)
|
cluster
|
||||||
|
)
|
||||||
|
)[0]
|
||||||
// create add product account instruction
|
// create add product account instruction
|
||||||
instructions.push(
|
instructions.push(
|
||||||
await pythProgramClient.methods
|
await pythProgramClient.methods
|
||||||
|
@ -276,11 +279,13 @@ const General = () => {
|
||||||
)
|
)
|
||||||
|
|
||||||
// deterministically generate price account key
|
// deterministically generate price account key
|
||||||
const priceAccountKey = await PublicKey.createWithSeed(
|
const priceAccountKey: PublicKey = (
|
||||||
OPS_KEY,
|
await findDetermisticAccountAddress(
|
||||||
'price:' + symbol,
|
AccountType.Price,
|
||||||
pythProgramClient.programId
|
symbol,
|
||||||
)
|
cluster
|
||||||
|
)
|
||||||
|
)[0]
|
||||||
// create add price account instruction
|
// create add price account instruction
|
||||||
instructions.push(
|
instructions.push(
|
||||||
await pythProgramClient.methods
|
await pythProgramClient.methods
|
||||||
|
|
Loading…
Reference in New Issue