[xc-admin] Add message buffer instructions (#869)
* [xc-admin] Add message buffer instructions * Use coral-xyz/anchor * Address feedbacks * Address feedbacks
This commit is contained in:
parent
183081cc20
commit
95ca9d1d92
|
@ -7,6 +7,7 @@ WORKDIR /home/node/
|
|||
USER 1000
|
||||
|
||||
COPY --chown=1000:1000 governance/xc_admin governance/xc_admin
|
||||
COPY --chown=1000:1000 pythnet/message_buffer pythnet/message_buffer
|
||||
|
||||
RUN npx lerna run build --scope="{crank_executor,crank_pythnet_relayer,proposer_server}" --include-dependencies
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.8",
|
||||
"@coral-xyz/anchor": "^0.26.0",
|
||||
"@pythnetwork/client": "^2.17.0",
|
||||
"@solana/buffer-layout": "^4.0.1",
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
import { AnchorProvider, Wallet, Program, Idl } from "@coral-xyz/anchor";
|
||||
import {
|
||||
getPythClusterApiUrl,
|
||||
PythCluster,
|
||||
} from "@pythnetwork/client/lib/cluster";
|
||||
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
||||
import {
|
||||
MessageBufferMultisigInstruction,
|
||||
MESSAGE_BUFFER_PROGRAM_ID,
|
||||
MultisigInstructionProgram,
|
||||
MultisigParser,
|
||||
} from "..";
|
||||
import messageBuffer from "message_buffer/idl/message_buffer.json";
|
||||
import { MessageBuffer } from "message_buffer/idl/message_buffer";
|
||||
|
||||
test("Message buffer multisig instruction parse: create buffer", (done) => {
|
||||
jest.setTimeout(60000);
|
||||
|
||||
const cluster: PythCluster = "pythtest-crosschain";
|
||||
|
||||
const messageBufferProgram = new Program(
|
||||
messageBuffer as Idl,
|
||||
new PublicKey(MESSAGE_BUFFER_PROGRAM_ID),
|
||||
new AnchorProvider(
|
||||
new Connection(getPythClusterApiUrl(cluster)),
|
||||
new Wallet(new Keypair()),
|
||||
AnchorProvider.defaultOptions()
|
||||
)
|
||||
) as unknown as Program<MessageBuffer>;
|
||||
|
||||
const parser = MultisigParser.fromCluster(cluster);
|
||||
|
||||
const allowedProgramAuth = PublicKey.unique();
|
||||
const baseAccountKey = PublicKey.unique();
|
||||
|
||||
messageBufferProgram.methods
|
||||
.createBuffer(allowedProgramAuth, baseAccountKey, 100)
|
||||
.accounts({
|
||||
admin: PublicKey.unique(),
|
||||
payer: PublicKey.unique(),
|
||||
})
|
||||
.remainingAccounts([
|
||||
{
|
||||
pubkey: PublicKey.unique(),
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
])
|
||||
.instruction()
|
||||
.then((instruction) => {
|
||||
const parsedInstruction = parser.parseInstruction(instruction);
|
||||
|
||||
if (parsedInstruction instanceof MessageBufferMultisigInstruction) {
|
||||
expect(parsedInstruction.program).toBe(
|
||||
MultisigInstructionProgram.MessageBuffer
|
||||
);
|
||||
expect(parsedInstruction.name).toBe("createBuffer");
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["whitelist"].pubkey.equals(
|
||||
instruction.keys[0].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["whitelist"].isSigner).toBe(
|
||||
instruction.keys[0].isSigner
|
||||
);
|
||||
expect(parsedInstruction.accounts.named["whitelist"].isWritable).toBe(
|
||||
instruction.keys[0].isWritable
|
||||
);
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["admin"].pubkey.equals(
|
||||
instruction.keys[1].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["admin"].isSigner).toBe(
|
||||
instruction.keys[1].isSigner
|
||||
);
|
||||
expect(parsedInstruction.accounts.named["admin"].isWritable).toBe(
|
||||
instruction.keys[1].isWritable
|
||||
);
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["payer"].pubkey.equals(
|
||||
instruction.keys[2].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["payer"].isSigner).toBe(
|
||||
instruction.keys[2].isSigner
|
||||
);
|
||||
expect(parsedInstruction.accounts.named["payer"].isWritable).toBe(
|
||||
instruction.keys[2].isWritable
|
||||
);
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["systemProgram"].pubkey.equals(
|
||||
instruction.keys[3].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["systemProgram"].isSigner).toBe(
|
||||
instruction.keys[3].isSigner
|
||||
);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["systemProgram"].isWritable
|
||||
).toBe(instruction.keys[3].isWritable);
|
||||
|
||||
expect(parsedInstruction.accounts.remaining.length).toBe(1);
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.remaining[0].pubkey.equals(
|
||||
instruction.keys[4].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.remaining[0].isSigner).toBe(
|
||||
instruction.keys[4].isSigner
|
||||
);
|
||||
expect(parsedInstruction.accounts.remaining[0].isWritable).toBe(
|
||||
instruction.keys[4].isWritable
|
||||
);
|
||||
|
||||
expect(
|
||||
parsedInstruction.args.allowedProgramAuth.equals(allowedProgramAuth)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
parsedInstruction.args.baseAccountKey.equals(baseAccountKey)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.args.targetSize).toBe(100);
|
||||
|
||||
done();
|
||||
} else {
|
||||
done("Not instance of MessageBufferMultisigInstruction");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test("Message buffer multisig instruction parse: delete buffer", (done) => {
|
||||
jest.setTimeout(60000);
|
||||
|
||||
const cluster: PythCluster = "pythtest-crosschain";
|
||||
|
||||
const messageBufferProgram = new Program(
|
||||
messageBuffer as Idl,
|
||||
new PublicKey(MESSAGE_BUFFER_PROGRAM_ID),
|
||||
new AnchorProvider(
|
||||
new Connection(getPythClusterApiUrl(cluster)),
|
||||
new Wallet(new Keypair()),
|
||||
AnchorProvider.defaultOptions()
|
||||
)
|
||||
) as unknown as Program<MessageBuffer>;
|
||||
|
||||
const parser = MultisigParser.fromCluster(cluster);
|
||||
|
||||
const allowedProgramAuth = PublicKey.unique();
|
||||
const baseAccountKey = PublicKey.unique();
|
||||
|
||||
messageBufferProgram.methods
|
||||
.deleteBuffer(allowedProgramAuth, baseAccountKey)
|
||||
.accounts({
|
||||
admin: PublicKey.unique(),
|
||||
payer: PublicKey.unique(),
|
||||
messageBuffer: PublicKey.unique(),
|
||||
})
|
||||
.instruction()
|
||||
.then((instruction) => {
|
||||
const parsedInstruction = parser.parseInstruction(instruction);
|
||||
|
||||
if (parsedInstruction instanceof MessageBufferMultisigInstruction) {
|
||||
expect(parsedInstruction.program).toBe(
|
||||
MultisigInstructionProgram.MessageBuffer
|
||||
);
|
||||
expect(parsedInstruction.name).toBe("deleteBuffer");
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["whitelist"].pubkey.equals(
|
||||
instruction.keys[0].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["whitelist"].isSigner).toBe(
|
||||
instruction.keys[0].isSigner
|
||||
);
|
||||
expect(parsedInstruction.accounts.named["whitelist"].isWritable).toBe(
|
||||
instruction.keys[0].isWritable
|
||||
);
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["admin"].pubkey.equals(
|
||||
instruction.keys[1].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["admin"].isSigner).toBe(
|
||||
instruction.keys[1].isSigner
|
||||
);
|
||||
expect(parsedInstruction.accounts.named["admin"].isWritable).toBe(
|
||||
instruction.keys[1].isWritable
|
||||
);
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["payer"].pubkey.equals(
|
||||
instruction.keys[2].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["payer"].isSigner).toBe(
|
||||
instruction.keys[2].isSigner
|
||||
);
|
||||
expect(parsedInstruction.accounts.named["payer"].isWritable).toBe(
|
||||
instruction.keys[2].isWritable
|
||||
);
|
||||
|
||||
expect(
|
||||
parsedInstruction.accounts.named["messageBuffer"].pubkey.equals(
|
||||
instruction.keys[3].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["messageBuffer"].isSigner).toBe(
|
||||
instruction.keys[3].isSigner
|
||||
);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["messageBuffer"].isWritable
|
||||
).toBe(instruction.keys[3].isWritable);
|
||||
|
||||
expect(parsedInstruction.accounts.remaining.length).toBe(0);
|
||||
|
||||
expect(
|
||||
parsedInstruction.args.allowedProgramAuth.equals(allowedProgramAuth)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
parsedInstruction.args.baseAccountKey.equals(baseAccountKey)
|
||||
).toBeTruthy();
|
||||
|
||||
done();
|
||||
} else {
|
||||
done("Not instance of MessageBufferMultisigInstruction");
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
import { AnchorProvider, Wallet } from "@project-serum/anchor";
|
||||
import { AnchorProvider, Wallet } from "@coral-xyz/anchor";
|
||||
import { pythOracleProgram } from "@pythnetwork/client";
|
||||
import {
|
||||
getPythClusterApiUrl,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { AnchorProvider, Wallet } from "@project-serum/anchor";
|
||||
import { AnchorProvider, Wallet } from "@coral-xyz/anchor";
|
||||
import { pythOracleProgram } from "@pythnetwork/client";
|
||||
import {
|
||||
getPythClusterApiUrl,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createWormholeProgramInterface } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
|
||||
import { AnchorProvider, Wallet } from "@project-serum/anchor";
|
||||
import { AnchorProvider, Wallet } from "@coral-xyz/anchor";
|
||||
import {
|
||||
getPythClusterApiUrl,
|
||||
PythCluster,
|
||||
|
|
|
@ -8,3 +8,4 @@ export * from "./remote_executor";
|
|||
export * from "./bpf_upgradable_loader";
|
||||
export * from "./deterministic_oracle_accounts";
|
||||
export * from "./cranks";
|
||||
export * from "./message_buffer";
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import { getPythProgramKeyForCluster, PythCluster } from "@pythnetwork/client";
|
||||
import { PublicKey } from "@solana/web3.js";
|
||||
|
||||
/**
|
||||
* Address of the message buffer program.
|
||||
*/
|
||||
export const MESSAGE_BUFFER_PROGRAM_ID: PublicKey = new PublicKey(
|
||||
"7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM"
|
||||
);
|
||||
|
||||
export const MESSAGE_BUFFER_BUFFER_SIZE = 2048;
|
||||
|
||||
export function isMessageBufferAvailable(cluster: PythCluster): boolean {
|
||||
return cluster === "pythtest-crosschain";
|
||||
}
|
||||
|
||||
export function getPythOracleMessageBufferCpiAuth(
|
||||
cluster: PythCluster
|
||||
): PublicKey {
|
||||
const pythOracleProgramId = getPythProgramKeyForCluster(cluster);
|
||||
return PublicKey.findProgramAddressSync(
|
||||
[Buffer.from("upd_price_write"), MESSAGE_BUFFER_PROGRAM_ID.toBuffer()],
|
||||
pythOracleProgramId
|
||||
)[0];
|
||||
}
|
||||
|
||||
// TODO: We can remove this when createBuffer takes message buffer account
|
||||
// as a named account because Anchor can automatically find the address.
|
||||
export function getMessageBufferAddressForPrice(
|
||||
cluster: PythCluster,
|
||||
priceAccount: PublicKey
|
||||
): PublicKey {
|
||||
return PublicKey.findProgramAddressSync(
|
||||
[
|
||||
getPythOracleMessageBufferCpiAuth(cluster).toBuffer(),
|
||||
Buffer.from("message"),
|
||||
priceAccount.toBuffer(),
|
||||
],
|
||||
MESSAGE_BUFFER_PROGRAM_ID
|
||||
)[0];
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import {
|
||||
MultisigInstruction,
|
||||
MultisigInstructionProgram,
|
||||
UNRECOGNIZED_INSTRUCTION,
|
||||
} from ".";
|
||||
import { AnchorAccounts, resolveAccountNames } from "./anchor";
|
||||
import messageBuffer from "message_buffer/idl/message_buffer.json";
|
||||
import { TransactionInstruction } from "@solana/web3.js";
|
||||
import { Idl, BorshCoder } from "@coral-xyz/anchor";
|
||||
|
||||
export class MessageBufferMultisigInstruction implements MultisigInstruction {
|
||||
readonly program = MultisigInstructionProgram.MessageBuffer;
|
||||
readonly name: string;
|
||||
readonly args: { [key: string]: any };
|
||||
readonly accounts: AnchorAccounts;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: { [key: string]: any },
|
||||
accounts: AnchorAccounts
|
||||
) {
|
||||
this.name = name;
|
||||
this.args = args;
|
||||
this.accounts = accounts;
|
||||
}
|
||||
|
||||
static fromTransactionInstruction(
|
||||
instruction: TransactionInstruction
|
||||
): MessageBufferMultisigInstruction {
|
||||
const messageBufferInstructionCoder = new BorshCoder(messageBuffer as Idl)
|
||||
.instruction;
|
||||
|
||||
const deserializedData = messageBufferInstructionCoder.decode(
|
||||
instruction.data
|
||||
);
|
||||
|
||||
if (deserializedData) {
|
||||
return new MessageBufferMultisigInstruction(
|
||||
deserializedData.name,
|
||||
deserializedData.data,
|
||||
resolveAccountNames(
|
||||
messageBuffer as Idl,
|
||||
deserializedData.name,
|
||||
instruction
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return new MessageBufferMultisigInstruction(
|
||||
UNRECOGNIZED_INSTRUCTION,
|
||||
{ data: instruction.data },
|
||||
{ named: {}, remaining: instruction.keys }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,9 @@ import {
|
|||
PythCluster,
|
||||
} from "@pythnetwork/client/lib/cluster";
|
||||
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
||||
import { MESSAGE_BUFFER_PROGRAM_ID } from "../message_buffer";
|
||||
import { WORMHOLE_ADDRESS } from "../wormhole";
|
||||
import { MessageBufferMultisigInstruction } from "./MessageBufferMultisigInstruction";
|
||||
import { PythMultisigInstruction } from "./PythMultisigInstruction";
|
||||
import { WormholeMultisigInstruction } from "./WormholeMultisigInstruction";
|
||||
|
||||
|
@ -11,6 +13,7 @@ export const UNRECOGNIZED_INSTRUCTION = "unrecognizedInstruction";
|
|||
export enum MultisigInstructionProgram {
|
||||
PythOracle,
|
||||
WormholeBridge,
|
||||
MessageBuffer,
|
||||
UnrecognizedProgram,
|
||||
}
|
||||
|
||||
|
@ -60,6 +63,10 @@ export class MultisigParser {
|
|||
);
|
||||
} else if (instruction.programId.equals(this.pythOracleAddress)) {
|
||||
return PythMultisigInstruction.fromTransactionInstruction(instruction);
|
||||
} else if (instruction.programId.equals(MESSAGE_BUFFER_PROGRAM_ID)) {
|
||||
return MessageBufferMultisigInstruction.fromTransactionInstruction(
|
||||
instruction
|
||||
);
|
||||
} else {
|
||||
return UnrecognizedProgram.fromTransactionInstruction(instruction);
|
||||
}
|
||||
|
@ -68,3 +75,4 @@ export class MultisigParser {
|
|||
|
||||
export { WormholeMultisigInstruction } from "./WormholeMultisigInstruction";
|
||||
export { PythMultisigInstruction } from "./PythMultisigInstruction";
|
||||
export { MessageBufferMultisigInstruction } from "./MessageBufferMultisigInstruction";
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
PACKET_DATA_SIZE,
|
||||
} from "@solana/web3.js";
|
||||
import { BN } from "bn.js";
|
||||
import { AnchorProvider } from "@project-serum/anchor";
|
||||
import { AnchorProvider } from "@coral-xyz/anchor";
|
||||
import {
|
||||
createWormholeProgramInterface,
|
||||
deriveWormholeBridgeDataKey,
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
import { AnchorProvider, Program } from '@coral-xyz/anchor'
|
||||
import { AnchorProvider, Idl, Program } from '@coral-xyz/anchor'
|
||||
import { AccountType, getPythProgramKeyForCluster } from '@pythnetwork/client'
|
||||
import { PythOracle, pythOracleProgram } from '@pythnetwork/client/lib/anchor'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { Cluster, PublicKey, TransactionInstruction } from '@solana/web3.js'
|
||||
import messageBuffer from 'message_buffer/idl/message_buffer.json'
|
||||
import { MessageBuffer } from 'message_buffer/idl/message_buffer'
|
||||
import axios from 'axios'
|
||||
import { useCallback, useContext, useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import {
|
||||
findDetermisticAccountAddress,
|
||||
getMultisigCluster,
|
||||
getPythOracleMessageBufferCpiAuth,
|
||||
isMessageBufferAvailable,
|
||||
isRemoteCluster,
|
||||
mapKey,
|
||||
MESSAGE_BUFFER_PROGRAM_ID,
|
||||
MESSAGE_BUFFER_BUFFER_SIZE,
|
||||
PRICE_FEED_MULTISIG,
|
||||
proposeInstructions,
|
||||
WORMHOLE_ADDRESS,
|
||||
PRICE_FEED_OPS_KEY,
|
||||
getMessageBufferAddressForPrice,
|
||||
} from 'xc_admin_common'
|
||||
import { ClusterContext } from '../../contexts/ClusterContext'
|
||||
import { useMultisigContext } from '../../contexts/MultisigContext'
|
||||
|
@ -42,6 +50,9 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
const [pythProgramClient, setPythProgramClient] =
|
||||
useState<Program<PythOracle>>()
|
||||
|
||||
const [messageBufferClient, setMessageBufferClient] =
|
||||
useState<Program<MessageBuffer>>()
|
||||
|
||||
const openModal = () => {
|
||||
setIsModalOpen(true)
|
||||
}
|
||||
|
@ -323,6 +334,33 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
.instruction()
|
||||
)
|
||||
|
||||
if (isMessageBufferAvailable(cluster) && messageBufferClient) {
|
||||
// create create buffer instruction for the price account
|
||||
instructions.push(
|
||||
await messageBufferClient.methods
|
||||
.createBuffer(
|
||||
getPythOracleMessageBufferCpiAuth(cluster),
|
||||
priceAccountKey,
|
||||
MESSAGE_BUFFER_BUFFER_SIZE
|
||||
)
|
||||
.accounts({
|
||||
admin: fundingAccount,
|
||||
payer: PRICE_FEED_OPS_KEY,
|
||||
})
|
||||
.remainingAccounts([
|
||||
{
|
||||
pubkey: getMessageBufferAddressForPrice(
|
||||
cluster,
|
||||
priceAccountKey
|
||||
),
|
||||
isSigner: false,
|
||||
isWritable: true,
|
||||
},
|
||||
])
|
||||
.instruction()
|
||||
)
|
||||
}
|
||||
|
||||
// create add publisher instruction if there are any publishers
|
||||
|
||||
for (let publisherKey of newChanges.priceAccounts[0].publishers) {
|
||||
|
@ -350,6 +388,8 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
)
|
||||
}
|
||||
} else if (!newChanges) {
|
||||
const priceAccount = new PublicKey(prev.priceAccounts[0].address)
|
||||
|
||||
// if new is undefined, it means that the symbol is deleted
|
||||
// create delete price account instruction
|
||||
instructions.push(
|
||||
|
@ -358,10 +398,11 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
.accounts({
|
||||
fundingAccount,
|
||||
productAccount: new PublicKey(prev.address),
|
||||
priceAccount: new PublicKey(prev.priceAccounts[0].address),
|
||||
priceAccount,
|
||||
})
|
||||
.instruction()
|
||||
)
|
||||
|
||||
// create delete product account instruction
|
||||
instructions.push(
|
||||
await pythProgramClient.methods
|
||||
|
@ -373,6 +414,26 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
})
|
||||
.instruction()
|
||||
)
|
||||
|
||||
if (isMessageBufferAvailable(cluster) && messageBufferClient) {
|
||||
// create delete buffer instruction for the price buffer
|
||||
instructions.push(
|
||||
await messageBufferClient.methods
|
||||
.deleteBuffer(
|
||||
getPythOracleMessageBufferCpiAuth(cluster),
|
||||
priceAccount
|
||||
)
|
||||
.accounts({
|
||||
admin: fundingAccount,
|
||||
payer: PRICE_FEED_OPS_KEY,
|
||||
messageBuffer: getMessageBufferAddressForPrice(
|
||||
cluster,
|
||||
priceAccount
|
||||
),
|
||||
})
|
||||
.instruction()
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// check if metadata has changed
|
||||
if (
|
||||
|
@ -741,6 +802,16 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
setPythProgramClient(
|
||||
pythOracleProgram(getPythProgramKeyForCluster(cluster), provider)
|
||||
)
|
||||
|
||||
if (isMessageBufferAvailable(cluster)) {
|
||||
setMessageBufferClient(
|
||||
new Program(
|
||||
messageBuffer as Idl,
|
||||
new PublicKey(MESSAGE_BUFFER_PROGRAM_ID),
|
||||
provider
|
||||
) as unknown as Program<MessageBuffer>
|
||||
)
|
||||
}
|
||||
}
|
||||
}, [connection, connected, cluster, proposeSquads])
|
||||
|
||||
|
|
|
@ -17,9 +17,11 @@ import {
|
|||
getMultisigCluster,
|
||||
getProposals,
|
||||
MultisigInstruction,
|
||||
MultisigInstructionProgram,
|
||||
MultisigParser,
|
||||
PRICE_FEED_MULTISIG,
|
||||
PythMultisigInstruction,
|
||||
MessageBufferMultisigInstruction,
|
||||
UnrecognizedProgram,
|
||||
WormholeMultisigInstruction,
|
||||
} from 'xc_admin_common'
|
||||
|
@ -788,9 +790,12 @@ const Proposal = ({
|
|||
{parsedInstruction instanceof
|
||||
PythMultisigInstruction
|
||||
? 'Pyth Oracle'
|
||||
: innerInstruction instanceof
|
||||
: parsedInstruction instanceof
|
||||
WormholeMultisigInstruction
|
||||
? 'Wormhole'
|
||||
: parsedInstruction instanceof
|
||||
MessageBufferMultisigInstruction
|
||||
? 'Message Buffer'
|
||||
: 'Unknown'}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -803,7 +808,9 @@ const Proposal = ({
|
|||
{parsedInstruction instanceof
|
||||
PythMultisigInstruction ||
|
||||
parsedInstruction instanceof
|
||||
WormholeMultisigInstruction
|
||||
WormholeMultisigInstruction ||
|
||||
parsedInstruction instanceof
|
||||
MessageBufferMultisigInstruction
|
||||
? parsedInstruction.name
|
||||
: 'Unknown'}
|
||||
</div>
|
||||
|
@ -816,7 +823,9 @@ const Proposal = ({
|
|||
{parsedInstruction instanceof
|
||||
PythMultisigInstruction ||
|
||||
parsedInstruction instanceof
|
||||
WormholeMultisigInstruction ? (
|
||||
WormholeMultisigInstruction ||
|
||||
parsedInstruction instanceof
|
||||
MessageBufferMultisigInstruction ? (
|
||||
Object.keys(parsedInstruction.args).length >
|
||||
0 ? (
|
||||
<div className="col-span-4 mt-2 bg-[#444157] p-4 lg:col-span-3 lg:mt-0">
|
||||
|
@ -906,7 +915,9 @@ const Proposal = ({
|
|||
{parsedInstruction instanceof
|
||||
PythMultisigInstruction ||
|
||||
parsedInstruction instanceof
|
||||
WormholeMultisigInstruction ? (
|
||||
WormholeMultisigInstruction ||
|
||||
parsedInstruction instanceof
|
||||
MessageBufferMultisigInstruction ? (
|
||||
<div
|
||||
key={`${index}_accounts`}
|
||||
className="grid grid-cols-4 justify-between"
|
||||
|
@ -983,9 +994,36 @@ const Proposal = ({
|
|||
) : null}
|
||||
</>
|
||||
))}
|
||||
{parsedInstruction.accounts.remaining.map(
|
||||
(accountMeta, index) => (
|
||||
<>
|
||||
<div
|
||||
key="rem-{index}"
|
||||
className="flex justify-between border-t border-beige-300 py-3"
|
||||
>
|
||||
<div className="max-w-[80px] break-words sm:max-w-none sm:break-normal">
|
||||
Remaining {index + 1}
|
||||
</div>
|
||||
<div className="space-y-2 sm:flex sm:space-y-0 sm:space-x-2">
|
||||
<div className="flex items-center space-x-2 sm:ml-2">
|
||||
{accountMeta.isSigner ? (
|
||||
<SignerTag />
|
||||
) : null}
|
||||
{accountMeta.isWritable ? (
|
||||
<WritableTag />
|
||||
) : null}
|
||||
</div>
|
||||
<CopyPubkey
|
||||
pubkey={accountMeta.pubkey.toBase58()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div>No arguments</div>
|
||||
<div>No accounts</div>
|
||||
)}
|
||||
</div>
|
||||
) : parsedInstruction instanceof
|
||||
|
@ -1125,7 +1163,10 @@ const Proposals = ({
|
|||
keys: remoteIx.keys as AccountMeta[],
|
||||
})
|
||||
return (
|
||||
parsedRemoteInstruction instanceof PythMultisigInstruction
|
||||
parsedRemoteInstruction instanceof
|
||||
PythMultisigInstruction ||
|
||||
parsedRemoteInstruction instanceof
|
||||
MessageBufferMultisigInstruction
|
||||
)
|
||||
}) &&
|
||||
ix.governanceAction.targetChainId === 'pythnet')
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
"react-hot-toast": "^2.4.0",
|
||||
"typescript": "4.9.4",
|
||||
"use-debounce": "^9.0.2",
|
||||
"xc_admin_common": "*"
|
||||
"xc_admin_common": "*",
|
||||
"message_buffer": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "^6.3.1",
|
||||
|
|
|
@ -1333,6 +1333,7 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.8",
|
||||
"@coral-xyz/anchor": "^0.26.0",
|
||||
"@pythnetwork/client": "^2.17.0",
|
||||
"@solana/buffer-layout": "^4.0.1",
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
|
@ -1421,6 +1422,7 @@
|
|||
"axios": "^1.4.0",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"gsap": "^3.11.4",
|
||||
"message_buffer": "*",
|
||||
"next": "12.2.5",
|
||||
"next-seo": "^5.15.0",
|
||||
"react": "18.2.0",
|
||||
|
@ -106543,6 +106545,7 @@
|
|||
"version": "file:governance/xc_admin/packages/xc_admin_common",
|
||||
"requires": {
|
||||
"@certusone/wormhole-sdk": "^0.9.8",
|
||||
"@coral-xyz/anchor": "^0.26.0",
|
||||
"@pythnetwork/client": "^2.17.0",
|
||||
"@solana/buffer-layout": "^4.0.1",
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
|
@ -106626,6 +106629,7 @@
|
|||
"eslint": "8.22.0",
|
||||
"eslint-config-next": "12.2.5",
|
||||
"gsap": "^3.11.4",
|
||||
"message_buffer": "*",
|
||||
"next": "12.2.5",
|
||||
"next-seo": "^5.15.0",
|
||||
"postcss": "^8.4.16",
|
||||
|
|
Loading…
Reference in New Issue