diff --git a/governance/xc_admin/Dockerfile b/governance/xc_admin/Dockerfile index 6edd47a2..aac6125a 100644 --- a/governance/xc_admin/Dockerfile +++ b/governance/xc_admin/Dockerfile @@ -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 diff --git a/governance/xc_admin/packages/xc_admin_common/package.json b/governance/xc_admin/packages/xc_admin_common/package.json index f07df6ea..472f9728 100644 --- a/governance/xc_admin/packages/xc_admin_common/package.json +++ b/governance/xc_admin/packages/xc_admin_common/package.json @@ -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", diff --git a/governance/xc_admin/packages/xc_admin_common/src/__tests__/MessageBufferMultisigInstruction.test.ts b/governance/xc_admin/packages/xc_admin_common/src/__tests__/MessageBufferMultisigInstruction.test.ts new file mode 100644 index 00000000..52e68e2d --- /dev/null +++ b/governance/xc_admin/packages/xc_admin_common/src/__tests__/MessageBufferMultisigInstruction.test.ts @@ -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; + + 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; + + 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"); + } + }); +}); diff --git a/governance/xc_admin/packages/xc_admin_common/src/__tests__/PythMultisigInstruction.test.ts b/governance/xc_admin/packages/xc_admin_common/src/__tests__/PythMultisigInstruction.test.ts index 31dc5569..918963fe 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/__tests__/PythMultisigInstruction.test.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/__tests__/PythMultisigInstruction.test.ts @@ -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, diff --git a/governance/xc_admin/packages/xc_admin_common/src/__tests__/TransactionSize.test.ts b/governance/xc_admin/packages/xc_admin_common/src/__tests__/TransactionSize.test.ts index e81f4621..5f69e4c0 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/__tests__/TransactionSize.test.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/__tests__/TransactionSize.test.ts @@ -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, diff --git a/governance/xc_admin/packages/xc_admin_common/src/__tests__/WormholeMultisigInstruction.test.ts b/governance/xc_admin/packages/xc_admin_common/src/__tests__/WormholeMultisigInstruction.test.ts index 93a6030d..255109f7 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/__tests__/WormholeMultisigInstruction.test.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/__tests__/WormholeMultisigInstruction.test.ts @@ -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, diff --git a/governance/xc_admin/packages/xc_admin_common/src/index.ts b/governance/xc_admin/packages/xc_admin_common/src/index.ts index d928593b..f61e656e 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/index.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/index.ts @@ -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"; diff --git a/governance/xc_admin/packages/xc_admin_common/src/message_buffer.ts b/governance/xc_admin/packages/xc_admin_common/src/message_buffer.ts new file mode 100644 index 00000000..64241fe6 --- /dev/null +++ b/governance/xc_admin/packages/xc_admin_common/src/message_buffer.ts @@ -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]; +} diff --git a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/MessageBufferMultisigInstruction.ts b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/MessageBufferMultisigInstruction.ts new file mode 100644 index 00000000..552cc8ac --- /dev/null +++ b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/MessageBufferMultisigInstruction.ts @@ -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 } + ); + } + } +} diff --git a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts index 5dcbbc30..75fb8448 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/multisig_transaction/index.ts @@ -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"; diff --git a/governance/xc_admin/packages/xc_admin_common/src/propose.ts b/governance/xc_admin/packages/xc_admin_common/src/propose.ts index d5d759eb..41a39354 100644 --- a/governance/xc_admin/packages/xc_admin_common/src/propose.ts +++ b/governance/xc_admin/packages/xc_admin_common/src/propose.ts @@ -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, diff --git a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx index dd63d9b4..b1990cfe 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx +++ b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/General.tsx @@ -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>() + const [messageBufferClient, setMessageBufferClient] = + useState>() + 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 + ) + } } }, [connection, connected, cluster, proposeSquads]) diff --git a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/Proposals.tsx b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/Proposals.tsx index d55e74d8..95524a30 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/components/tabs/Proposals.tsx +++ b/governance/xc_admin/packages/xc_admin_frontend/components/tabs/Proposals.tsx @@ -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'} @@ -803,7 +808,9 @@ const Proposal = ({ {parsedInstruction instanceof PythMultisigInstruction || parsedInstruction instanceof - WormholeMultisigInstruction + WormholeMultisigInstruction || + parsedInstruction instanceof + MessageBufferMultisigInstruction ? parsedInstruction.name : 'Unknown'} @@ -816,7 +823,9 @@ const Proposal = ({ {parsedInstruction instanceof PythMultisigInstruction || parsedInstruction instanceof - WormholeMultisigInstruction ? ( + WormholeMultisigInstruction || + parsedInstruction instanceof + MessageBufferMultisigInstruction ? ( Object.keys(parsedInstruction.args).length > 0 ? (
@@ -906,7 +915,9 @@ const Proposal = ({ {parsedInstruction instanceof PythMultisigInstruction || parsedInstruction instanceof - WormholeMultisigInstruction ? ( + WormholeMultisigInstruction || + parsedInstruction instanceof + MessageBufferMultisigInstruction ? (
))} + {parsedInstruction.accounts.remaining.map( + (accountMeta, index) => ( + <> +
+
+ Remaining {index + 1} +
+
+
+ {accountMeta.isSigner ? ( + + ) : null} + {accountMeta.isWritable ? ( + + ) : null} +
+ +
+
+ + ) + )}
) : ( -
No arguments
+
No accounts
)}
) : 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') diff --git a/governance/xc_admin/packages/xc_admin_frontend/package.json b/governance/xc_admin/packages/xc_admin_frontend/package.json index 87a5e35f..04106344 100644 --- a/governance/xc_admin/packages/xc_admin_frontend/package.json +++ b/governance/xc_admin/packages/xc_admin_frontend/package.json @@ -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", diff --git a/package-lock.json b/package-lock.json index 97d8dece..b71b1cdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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",