diff --git a/governance/xc-admin/package-lock.json b/governance/xc-admin/package-lock.json index 33a6a1dc..0278a78d 100644 --- a/governance/xc-admin/package-lock.json +++ b/governance/xc-admin/package-lock.json @@ -1948,7 +1948,8 @@ }, "node_modules/@certusone/wormhole-sdk": { "version": "0.9.9", - "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.9.9.tgz", + "integrity": "sha512-seausUXqUIvUN19u4ef0VgMXNvyftQHrq5+A8AHHbsk14oBGRbvQ5JqeI+vgtKUMggK8jCaa/ICR1TnD7MW67Q==", "dependencies": { "@certusone/wormhole-sdk-proto-web": "0.0.6", "@certusone/wormhole-sdk-wasm": "^0.0.1", @@ -25188,6 +25189,7 @@ "version": "0.0.0", "license": "ISC", "dependencies": { + "@certusone/wormhole-sdk": "^0.9.9", "@coral-xyz/anchor": "^0.26.0", "@pythnetwork/client": "^2.9.0", "@solana/web3.js": "^1.73.0", @@ -25244,7 +25246,6 @@ "@headlessui/react": "^1.7.7", "@pythnetwork/client": "^2.9.0", "@solana/wallet-adapter-base": "^0.9.20", - "@solana/wallet-adapter-react": "^0.15.28", "@solana/wallet-adapter-react-ui": "^0.9.27", "@solana/wallet-adapter-wallets": "^0.19.10", "@solana/web3.js": "^1.73.0", @@ -26402,6 +26403,8 @@ }, "@certusone/wormhole-sdk": { "version": "0.9.9", + "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.9.9.tgz", + "integrity": "sha512-seausUXqUIvUN19u4ef0VgMXNvyftQHrq5+A8AHHbsk14oBGRbvQ5JqeI+vgtKUMggK8jCaa/ICR1TnD7MW67Q==", "requires": { "@certusone/wormhole-sdk-proto-web": "0.0.6", "@certusone/wormhole-sdk-wasm": "^0.0.1", @@ -33203,6 +33206,7 @@ "crank-executor": { "version": "file:packages/crank-executor", "requires": { + "@certusone/wormhole-sdk": "^0.9.9", "@coral-xyz/anchor": "^0.26.0", "@pythnetwork/client": "^2.9.0", "@solana/web3.js": "^1.73.0", @@ -41995,7 +41999,6 @@ "@headlessui/react": "^1.7.7", "@pythnetwork/client": "^2.9.0", "@solana/wallet-adapter-base": "^0.9.20", - "@solana/wallet-adapter-react": "*", "@solana/wallet-adapter-react-ui": "^0.9.27", "@solana/wallet-adapter-wallets": "^0.19.10", "@solana/web3.js": "^1.73.0", diff --git a/governance/xc-admin/packages/crank-executor/package.json b/governance/xc-admin/packages/crank-executor/package.json index e303ac48..78575bef 100644 --- a/governance/xc-admin/packages/crank-executor/package.json +++ b/governance/xc-admin/packages/crank-executor/package.json @@ -18,6 +18,7 @@ "format": "prettier --write \"src/**/*.ts\"" }, "dependencies": { + "@certusone/wormhole-sdk": "^0.9.9", "@coral-xyz/anchor": "^0.26.0", "@pythnetwork/client": "^2.9.0", "@solana/web3.js": "^1.73.0", diff --git a/governance/xc-admin/packages/crank-executor/src/index.ts b/governance/xc-admin/packages/crank-executor/src/index.ts index 4f767c63..9956dbc8 100644 --- a/governance/xc-admin/packages/crank-executor/src/index.ts +++ b/governance/xc-admin/packages/crank-executor/src/index.ts @@ -1,21 +1,31 @@ import { + AccountMeta, Commitment, Connection, Keypair, PublicKey, SendTransactionError, + SystemProgram, Transaction, } from "@solana/web3.js"; 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 { getProposals } from "xc-admin-common"; +import { + getProposals, + MultisigParser, + WormholeMultisigInstruction, +} from "xc-admin-common"; import BN from "bn.js"; import { AnchorProvider } from "@project-serum/anchor"; import { getPythClusterApiUrl, PythCluster, } from "@pythnetwork/client/lib/cluster"; +import { + deriveFeeCollectorKey, + getWormholeBridgeData, +} from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole"; export function envOrErr(env: string): string { const val = process.env[env]; @@ -42,6 +52,15 @@ async function run() { wallet: new NodeWallet(KEYPAIR), multisigProgramId: DEFAULT_MULTISIG_PROGRAM_ID, }); + const multisigParser = MultisigParser.fromCluster(CLUSTER as PythCluster); + const wormholeFee = ( + await getWormholeBridgeData( + squad.connection, + multisigParser.wormholeBridgeAddress!, + COMMITMENT + ) + ).config.fee; + const proposals = await getProposals(squad, VAULT, undefined, "executeReady"); for (const proposal of proposals) { // If we have previously cancelled because the proposal was failing, don't attempt @@ -51,7 +70,35 @@ async function run() { i <= proposal.instructionIndex; i++ ) { - const transaction = new Transaction().add( + const instructionPda = getIxPDA( + proposal.publicKey, + new BN(i), + squad.multisigProgramId + )[0]; + const instruction = await squad.getInstruction(instructionPda); + const parsedInstruction = multisigParser.parseInstruction({ + programId: instruction.programId, + data: instruction.data as Buffer, + keys: instruction.keys as AccountMeta[], + }); + const transaction = new Transaction(); + + if ( + parsedInstruction instanceof WormholeMultisigInstruction && + parsedInstruction.name == "postMessage" + ) { + transaction.add( + SystemProgram.transfer({ + lamports: wormholeFee, + toPubkey: deriveFeeCollectorKey( + multisigParser.wormholeBridgeAddress! + ), + fromPubkey: squad.wallet.publicKey, + }) + ); + } + + transaction.add( await squad.buildExecuteInstruction( proposal.publicKey, getIxPDA(proposal.publicKey, new BN(i), squad.multisigProgramId)[0] 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 2e19da60..5dcbbc30 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 @@ -65,3 +65,6 @@ export class MultisigParser { } } } + +export { WormholeMultisigInstruction } from "./WormholeMultisigInstruction"; +export { PythMultisigInstruction } from "./PythMultisigInstruction"; 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 91e89768..a1404e67 100644 --- a/governance/xc-admin/packages/xc-admin-common/src/propose.ts +++ b/governance/xc-admin/packages/xc-admin-common/src/propose.ts @@ -3,12 +3,17 @@ import { PublicKey, Transaction, TransactionInstruction, + SYSVAR_RENT_PUBKEY, + SYSVAR_CLOCK_PUBKEY, + SystemProgram, } from "@solana/web3.js"; import { BN } from "bn.js"; import { AnchorProvider } from "@project-serum/anchor"; import { createWormholeProgramInterface, - getPostMessageAccounts, + deriveWormholeBridgeDataKey, + deriveEmitterSequenceKey, + deriveFeeCollectorKey, } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole"; import { ExecutePostedVaa } from "./governance_payload/ExecutePostedVaa"; @@ -36,7 +41,6 @@ export async function proposeInstructions( ): Promise { const msAccount = await squad.getMultisig(vault); let txToSend: Transaction[] = []; - const createProposal = new Transaction().add( await squad.buildCreateTransaction( msAccount.publicKey, @@ -61,7 +65,7 @@ export async function proposeInstructions( vault, newProposalAddress, instructions[i], - i, + i + 1, wormholeAddress ); txToSend.push( @@ -134,7 +138,7 @@ export async function wrapAsRemoteInstruction( instructionIndex: number, wormholeAddress: PublicKey ): Promise { - const emitter = squad.getAuthorityPDA(vault, 0); + const emitter = squad.getAuthorityPDA(vault, 1); const [messagePDA, messagePdaBump] = getIxAuthorityPDA( proposalAddress, @@ -156,12 +160,7 @@ export async function wrapAsRemoteInstruction( instruction, ]).encode(); - const accounts = getPostMessageAccounts( - wormholeAddress, - emitter, - emitter, - messagePDA - ); + const accounts = getPostMessageAccounts(wormholeAddress, emitter, messagePDA); return { instruction: await wormholeProgram.methods @@ -173,3 +172,20 @@ export async function wrapAsRemoteInstruction( authorityType: "custom", }; } +function getPostMessageAccounts( + wormholeAddress: PublicKey, + emitter: PublicKey, + message: PublicKey +) { + return { + bridge: deriveWormholeBridgeDataKey(wormholeAddress), + message, + emitter, + sequence: deriveEmitterSequenceKey(emitter, wormholeAddress), + payer: emitter, + feeCollector: deriveFeeCollectorKey(wormholeAddress), + clock: SYSVAR_CLOCK_PUBKEY, + rent: SYSVAR_RENT_PUBKEY, + systemProgram: SystemProgram.programId, + }; +}