wormhole-circle-integration/solana/ts/tests/10__testnetFork.ts

263 lines
8.8 KiB
TypeScript

import { MockEmitter, MockGuardians } from "@certusone/wormhole-sdk/lib/cjs/mock";
import * as anchor from "@coral-xyz/anchor";
import { expect } from "chai";
import { CircleIntegrationProgram } from "../src";
import {
GUARDIAN_KEY,
PAYER_PRIVATE_KEY,
expectIxErr,
expectIxOk,
loadProgramBpf,
postGovVaa,
} from "./helpers";
const WORMHOLE_CORE_BRIDGE_ADDRESS = new anchor.web3.PublicKey(
"3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5",
);
const ARTIFACTS_PATH = `${__dirname}/artifacts/testnet_wormhole_circle_integration_solana.so`;
const guardians = new MockGuardians(0, [GUARDIAN_KEY]);
describe("Circle Integration -- Testnet Fork", () => {
const connection = new anchor.web3.Connection("http://localhost:8899", "processed");
const payer = anchor.web3.Keypair.fromSecretKey(PAYER_PRIVATE_KEY);
const circleIntegration = new CircleIntegrationProgram(
connection,
"wcihrWf1s91vfukW7LW8ZvR1rzpeZ9BrtZ8oyPkWK5d",
);
describe("Upgrade Contract", () => {
const localVariables = new Map<string, any>();
it("Deploy Implementation", async () => {
const implementation = await loadProgramBpf(
ARTIFACTS_PATH,
circleIntegration.upgradeAuthorityAddress(),
);
localVariables.set("implementation", implementation);
});
it("Invoke `upgrade_contract` on Forked Circle Integration", async () => {
const implementation = localVariables.get("implementation") as anchor.web3.PublicKey;
expect(localVariables.delete("implementation")).is.true;
const vaa = await postGovVaa(
connection,
payer,
guardians,
0n,
{
upgradeContract: {
targetChain: 1,
implementation,
},
},
{
coreBridgeAddress: WORMHOLE_CORE_BRIDGE_ADDRESS,
},
);
const ix = await circleIntegration.upgradeContractIx({
payer: payer.publicKey,
vaa,
});
await expectIxOk(connection, [ix], [payer]);
});
it("Deploy Same Implementation and Invoke `upgrade_contract` with Another VAA", async () => {
const implementation = await loadProgramBpf(
ARTIFACTS_PATH,
circleIntegration.upgradeAuthorityAddress(),
);
const vaa = await postGovVaa(
connection,
payer,
guardians,
1n,
{
upgradeContract: {
targetChain: 1,
implementation,
},
},
{
coreBridgeAddress: WORMHOLE_CORE_BRIDGE_ADDRESS,
},
);
const ix = await circleIntegration.upgradeContractIx({
payer: payer.publicKey,
vaa,
});
await expectIxOk(connection, [ix], [payer]);
// Save for later.
localVariables.set("vaa", vaa);
});
it("Cannot Invoke `upgrade_contract` with Same VAA", async () => {
const vaa = localVariables.get("vaa") as anchor.web3.PublicKey;
expect(localVariables.delete("vaa")).is.true;
const ix = await circleIntegration.upgradeContractIx({
payer: payer.publicKey,
vaa,
});
// NOTE: The claim account created in the upgrade contract instruction doesn't trigger
// the protection for a replay attack. The account data in the program data does. But
// we will keep this test here just in case something changes in the future.
await expectIxErr(connection, [ix], [payer], "invalid account data for instruction");
});
it("Cannot Invoke `upgrade_contract` with Implementation Mismatch", async () => {
const implementation = await loadProgramBpf(
ARTIFACTS_PATH,
circleIntegration.upgradeAuthorityAddress(),
);
const anotherImplementation = await loadProgramBpf(
ARTIFACTS_PATH,
circleIntegration.upgradeAuthorityAddress(),
);
const vaa = await postGovVaa(
connection,
payer,
guardians,
0n,
{
upgradeContract: {
targetChain: 1,
implementation: anotherImplementation,
},
},
{
coreBridgeAddress: WORMHOLE_CORE_BRIDGE_ADDRESS,
},
);
// Create the upgrade instruction, but pass a different implementation.
const ix = await circleIntegration.upgradeContractIx({
payer: payer.publicKey,
vaa,
buffer: implementation,
});
await expectIxErr(connection, [ix], [payer], "Error Code: ImplementationMismatch");
});
it("Cannot Invoke `upgrade_contract` with Invalid Governance Emitter", async () => {
const implementation = await loadProgramBpf(
ARTIFACTS_PATH,
circleIntegration.upgradeAuthorityAddress(),
);
// Create a bad governance emitter by using an invalid address.
const invalidEmitter = new MockEmitter(
circleIntegration.ID.toBuffer().toString("hex"),
1,
12121212,
);
const vaa = await postGovVaa(
connection,
payer,
guardians,
2n,
{
upgradeContract: {
targetChain: 1,
implementation,
},
},
{
coreBridgeAddress: WORMHOLE_CORE_BRIDGE_ADDRESS,
governanceEmitter: invalidEmitter,
},
);
// Create the upgrade instruction, but pass a different implementation.
const ix = await circleIntegration.upgradeContractIx({
payer: payer.publicKey,
vaa,
buffer: implementation,
});
await expectIxErr(connection, [ix], [payer], "Error Code: InvalidGovernanceEmitter");
});
it("Cannot Invoke `upgrade_contract` with Governance For Another Chain", async () => {
const implementation = await loadProgramBpf(
ARTIFACTS_PATH,
circleIntegration.upgradeAuthorityAddress(),
);
const vaa = await postGovVaa(
connection,
payer,
guardians,
2n,
{
upgradeContract: {
targetChain: 2,
implementation,
},
},
{
coreBridgeAddress: WORMHOLE_CORE_BRIDGE_ADDRESS,
},
);
const ix = await circleIntegration.upgradeContractIx({
payer: payer.publicKey,
vaa,
});
await expectIxErr(connection, [ix], [payer], "Error Code: GovernanceForAnotherChain");
});
it("Cannot Invoke `upgrade_contract` with Invalid Governance Action", async () => {
const implementation = await loadProgramBpf(
ARTIFACTS_PATH,
circleIntegration.upgradeAuthorityAddress(),
);
const vaa = await postGovVaa(
connection,
payer,
guardians,
2n,
{
registerEmitterAndDomain: {
targetChain: 1,
foreignChain: 2,
foreignEmitter: Array.from(
Buffer.from(
"000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
"hex",
),
),
cctpDomain: 0,
},
},
{
coreBridgeAddress: WORMHOLE_CORE_BRIDGE_ADDRESS,
},
);
const ix = await circleIntegration.upgradeContractIx({
payer: payer.publicKey,
vaa,
buffer: implementation,
});
await expectIxErr(connection, [ix], [payer], "Error Code: InvalidGovernanceAction");
});
});
});