Skip to content

Commit 5527782

Browse files
authored
feat(xc-admin): add price store instructions and executor support (#1900)
* feat(xc-admin): add price store instructions and executor support * refactor(governance/xc_admin): use switch, verify data and accounts
1 parent 29aa1b7 commit 5527782

File tree

4 files changed

+364
-2
lines changed

4 files changed

+364
-2
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { PublicKey } from "@solana/web3.js";
2+
import {
3+
createPriceStoreInstruction,
4+
parsePriceStoreInstruction,
5+
PriceStoreInstruction,
6+
} from "../price_store";
7+
8+
test("Price store instruction parse: roundtrip", (done) => {
9+
const items: PriceStoreInstruction[] = [
10+
{
11+
type: "Initialize",
12+
data: {
13+
payerKey: new PublicKey("Fe9vtgwRhbMSUsAjwUzupzRoJKofyyk1Rz8ZUrPmGHMr"),
14+
authorityKey: new PublicKey(
15+
"D9rnZSLjdYboFGDGHk5Qre2yBS8HYbc6374Zm6AeC1PB"
16+
),
17+
},
18+
},
19+
{
20+
type: "InitializePublisher",
21+
data: {
22+
authorityKey: new PublicKey(
23+
"D9rnZSLjdYboFGDGHk5Qre2yBS8HYbc6374Zm6AeC1PB"
24+
),
25+
publisherKey: new PublicKey(
26+
"EXAyN9UVu1x163PQkVzyNm4YunNkMGu5Ry7ntoyyQGTe"
27+
),
28+
bufferKey: new PublicKey(
29+
"7q6SS575jGDjE8bWsx4PiLVqS7cHJhjJBhysvRoP53WJ"
30+
),
31+
},
32+
},
33+
];
34+
for (const data of items) {
35+
const instruction = createPriceStoreInstruction(data);
36+
const parsed = parsePriceStoreInstruction(instruction);
37+
expect(parsed).toStrictEqual(data);
38+
}
39+
done();
40+
});

governance/xc_admin/packages/xc_admin_common/src/executor.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ import {
2525
TransactionBuilder,
2626
PriorityFeeConfig,
2727
} from "@pythnetwork/solana-utils";
28+
import {
29+
findDetermisticPublisherBufferAddress,
30+
PRICE_STORE_BUFFER_SPACE,
31+
PRICE_STORE_PROGRAM_ID,
32+
PriceStoreMultisigInstruction,
33+
} from "./price_store";
2834

2935
/**
3036
* Returns the instruction to pay the fee for a wormhole postMessage instruction
@@ -134,6 +140,27 @@ export async function executeProposal(
134140
} else {
135141
throw Error("Product account not found");
136142
}
143+
} else if (
144+
parsedInstruction instanceof PriceStoreMultisigInstruction &&
145+
parsedInstruction.name == "InitializePublisher"
146+
) {
147+
const [bufferKey, bufferSeed] =
148+
await findDetermisticPublisherBufferAddress(
149+
parsedInstruction.args.publisherKey
150+
);
151+
transaction.add(
152+
SystemProgram.createAccountWithSeed({
153+
fromPubkey: squad.wallet.publicKey,
154+
basePubkey: squad.wallet.publicKey,
155+
newAccountPubkey: bufferKey,
156+
seed: bufferSeed,
157+
space: PRICE_STORE_BUFFER_SPACE,
158+
lamports: await squad.connection.getMinimumBalanceForRentExemption(
159+
PRICE_STORE_BUFFER_SPACE
160+
),
161+
programId: PRICE_STORE_PROGRAM_ID,
162+
})
163+
);
137164
}
138165

139166
TransactionBuilder.addPriorityFee(transaction, priorityFeeConfig);

governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ import { BPF_UPGRADABLE_LOADER } from "../bpf_upgradable_loader";
2323
import { AnchorAccounts } from "./anchor";
2424
import { SolanaStakingMultisigInstruction } from "./SolanaStakingMultisigInstruction";
2525
import { DEFAULT_RECEIVER_PROGRAM_ID } from "@pythnetwork/pyth-solana-receiver";
26+
import {
27+
PRICE_STORE_PROGRAM_ID,
28+
PriceStoreMultisigInstruction,
29+
} from "../price_store";
2630

2731
export const UNRECOGNIZED_INSTRUCTION = "unrecognizedInstruction";
2832
export enum MultisigInstructionProgram {
@@ -36,6 +40,7 @@ export enum MultisigInstructionProgram {
3640
SolanaStakingProgram,
3741
SolanaReceiver,
3842
UnrecognizedProgram,
43+
PythPriceStore,
3944
}
4045

4146
export function getProgramName(program: MultisigInstructionProgram) {
@@ -58,6 +63,8 @@ export function getProgramName(program: MultisigInstructionProgram) {
5863
return "Pyth Staking Program";
5964
case MultisigInstructionProgram.SolanaReceiver:
6065
return "Pyth Solana Receiver";
66+
case MultisigInstructionProgram.PythPriceStore:
67+
return "Pyth Price Store";
6168
case MultisigInstructionProgram.UnrecognizedProgram:
6269
return "Unknown";
6370
}
@@ -99,18 +106,22 @@ export class UnrecognizedProgram implements MultisigInstruction {
99106
export class MultisigParser {
100107
readonly pythOracleAddress: PublicKey;
101108
readonly wormholeBridgeAddress: PublicKey | undefined;
109+
readonly pythPriceStoreAddress: PublicKey | undefined;
102110

103111
constructor(
104112
pythOracleAddress: PublicKey,
105-
wormholeBridgeAddress: PublicKey | undefined
113+
wormholeBridgeAddress: PublicKey | undefined,
114+
pythPriceStoreAddress: PublicKey | undefined
106115
) {
107116
this.pythOracleAddress = pythOracleAddress;
108117
this.wormholeBridgeAddress = wormholeBridgeAddress;
118+
this.pythPriceStoreAddress = pythPriceStoreAddress;
109119
}
110120
static fromCluster(cluster: PythCluster): MultisigParser {
111121
return new MultisigParser(
112122
getPythProgramKeyForCluster(cluster),
113-
WORMHOLE_ADDRESS[cluster]
123+
WORMHOLE_ADDRESS[cluster],
124+
PRICE_STORE_PROGRAM_ID
114125
);
115126
}
116127

@@ -124,6 +135,13 @@ export class MultisigParser {
124135
);
125136
} else if (instruction.programId.equals(this.pythOracleAddress)) {
126137
return PythMultisigInstruction.fromTransactionInstruction(instruction);
138+
} else if (
139+
this.pythPriceStoreAddress &&
140+
instruction.programId.equals(this.pythPriceStoreAddress)
141+
) {
142+
return PriceStoreMultisigInstruction.fromTransactionInstruction(
143+
instruction
144+
);
127145
} else if (
128146
instruction.programId.equals(MESSAGE_BUFFER_PROGRAM_ID) ||
129147
instruction.programId.equals(MESH_PROGRAM_ID) ||

0 commit comments

Comments
 (0)