[xc-admin] Add wormhole logic to the crank-executor (#504)

* Add wormhole and fix some bugs

* Export WormholeMultisigInstruction

* Restore some unrelated parts of the code

* Cleanup

* Don't change this file
This commit is contained in:
guibescos 2023-01-17 17:19:13 -06:00 committed by GitHub
parent 1f64ce52b7
commit 1940a0bb2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 15 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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]

View File

@ -65,3 +65,6 @@ export class MultisigParser {
}
}
}
export { WormholeMultisigInstruction } from "./WormholeMultisigInstruction";
export { PythMultisigInstruction } from "./PythMultisigInstruction";

View File

@ -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<PublicKey> {
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<SquadInstruction> {
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,
};
}