wormhole/testing/solana-test-validator/sdk-tests/0_deploy_and_upgrade.ts

362 lines
12 KiB
TypeScript

import { expect } from "chai";
import * as web3 from "@solana/web3.js";
import fs from "fs";
import { MockGuardians, GovernanceEmitter } from "../../../sdk/js/src/mock";
import {
getGuardianSet,
getWormholeBridgeData,
createInitializeInstruction as createWormholeInitializeInstruction,
deriveUpgradeAuthorityKey,
createUpgradeContractInstruction as createWormholeUpgradeContractInstruction,
} from "../../../sdk/js/src/solana/wormhole";
import {
createInitializeInstruction as createTokenBridgeInitializeInstruction,
createUpgradeContractInstruction as createTokenBridgeUpgradeContractInstruction,
getTokenBridgeConfig,
} from "../../../sdk/js/src/solana/tokenBridge";
import {
createInitializeInstruction as createNftBridgeInitializeInstruction,
createUpgradeContractInstruction as createNftBridgeUpgradeContractInstruction,
} from "../../../sdk/js/src/solana/nftBridge";
import { postVaa } from "../../../sdk/js/src/solana/sendAndConfirmPostVaa";
import { NodeWallet } from "../../../sdk/js/src/solana/utils";
import {
CORE_BRIDGE_ADDRESS,
GOVERNANCE_EMITTER_ADDRESS,
GUARDIAN_KEYS,
GUARDIAN_SET_INDEX,
LOCALHOST,
NFT_BRIDGE_ADDRESS,
TOKEN_BRIDGE_ADDRESS,
} from "./helpers/consts";
import {
deployProgram,
execSolanaWriteBufferAndSetBufferAuthority,
} from "./helpers/utils";
import { getNftBridgeConfig } from "../../../sdk/js/src/solana/nftBridge";
describe("Deploy and Upgrade Programs", () => {
const connection = new web3.Connection(LOCALHOST, "processed");
const payerPath = `${__dirname}/keys/pFCBP4bhqdSsrWUVTgqhPsLrfEdChBK17vgFM7TxjxQ.json`;
const wallet = NodeWallet.fromSecretKey(
Uint8Array.from(
JSON.parse(
fs.readFileSync(payerPath, {
encoding: "utf8",
})
)
)
);
// for signing wormhole messages
const guardians = new MockGuardians(GUARDIAN_SET_INDEX, GUARDIAN_KEYS);
// for generating governance wormhole messages
const governance = new GovernanceEmitter(
GOVERNANCE_EMITTER_ADDRESS.toBuffer().toString("hex")
);
const localVariables: any = {};
before("Airdrop SOL", async () => {
// wallet
await connection
.requestAirdrop(wallet.key(), 1000 * web3.LAMPORTS_PER_SOL)
.then(async (signature) => connection.confirmTransaction(signature));
});
describe("Wormhole (Core Bridge)", () => {
it("Deploy and Initialize", async () => {
const artifactPath = `${__dirname}/../artifacts/bridge.so`;
const programIdPath = `${__dirname}/keys/${CORE_BRIDGE_ADDRESS}.json`;
const upgradeAuthority = deriveUpgradeAuthorityKey(CORE_BRIDGE_ADDRESS);
deployProgram(
payerPath,
artifactPath,
programIdPath,
CORE_BRIDGE_ADDRESS,
upgradeAuthority
);
// initialize
const guardianSetExpirationTime = 86400;
const fee = 100n;
const initialGuardians = guardians.getPublicKeys().slice(0, 1);
const initializeTx = await web3.sendAndConfirmTransaction(
connection,
new web3.Transaction().add(
createWormholeInitializeInstruction(
CORE_BRIDGE_ADDRESS,
wallet.key(),
guardianSetExpirationTime,
fee,
initialGuardians
)
),
[wallet.signer()]
);
// console.log(`initializeTx: ${initializeTx}`);
// verify data
const info = await getWormholeBridgeData(connection, CORE_BRIDGE_ADDRESS);
expect(info.guardianSetIndex).to.equal(GUARDIAN_SET_INDEX);
expect(info.config.guardianSetExpirationTime).to.equal(
guardianSetExpirationTime
);
expect(info.config.fee).to.equal(fee);
const guardianSet = await getGuardianSet(
connection,
CORE_BRIDGE_ADDRESS,
0
);
expect(guardianSet.index).to.equal(GUARDIAN_SET_INDEX);
expect(guardianSet.expirationTime).to.equal(0);
expect(guardianSet.keys).has.length(1);
expect(
Buffer.compare(initialGuardians[0], guardianSet.keys.at(0)!)
).to.equal(0);
});
it("Upgrade Contract", async () => {
// first upload BPF of implementation
const artifactPath = `${__dirname}/../artifacts/bridge.so`;
const upgradeAuthority = deriveUpgradeAuthorityKey(CORE_BRIDGE_ADDRESS);
const implementation = execSolanaWriteBufferAndSetBufferAuthority(
payerPath,
artifactPath,
upgradeAuthority
);
// now pass implementation through governance
const timestamp = 1;
const chain = 1;
const message = governance.publishWormholeUpgradeContract(
timestamp,
chain,
implementation.toString()
);
const signedVaa = guardians.addSignatures(message, [0]);
// console.log(`signedVaa: ${signedVaa.toString("base64")}`);
const txSignatures = await postVaa(
connection,
wallet.signTransaction,
CORE_BRIDGE_ADDRESS,
wallet.key(),
signedVaa
).then((results) => results.map((result) => result.signature));
const postTx = txSignatures.pop()!;
for (const verifyTx of txSignatures) {
// console.log(`verifySignatures: ${verifyTx}`);
}
// console.log(`postVaa: ${postTx}`);
const upgradeContractIx = createWormholeUpgradeContractInstruction(
CORE_BRIDGE_ADDRESS,
wallet.key(),
signedVaa
);
const upgradeContractTx = await web3.sendAndConfirmTransaction(
connection,
new web3.Transaction().add(upgradeContractIx),
[wallet.signer()]
);
// console.log(`upgradeContractTx: ${upgradeContractTx}`);
// not sure what to verify. if there are no errors,
// transaction was successful and the upgrade test passes
});
});
describe("Token Bridge", () => {
it("Deploy and Initialize", async () => {
const artifactPath = `${__dirname}/../artifacts/token_bridge.so`;
const programIdPath = `${__dirname}/keys/${TOKEN_BRIDGE_ADDRESS}.json`;
const upgradeAuthority = deriveUpgradeAuthorityKey(TOKEN_BRIDGE_ADDRESS);
deployProgram(
payerPath,
artifactPath,
programIdPath,
TOKEN_BRIDGE_ADDRESS,
upgradeAuthority
);
// we will initialize using CORE_BRIDGE_ADDRESS instead of
// UPGRADEABLE_CORE_BRIDGE_ADDRESS because the Wormhole owner is only
// valid for CORE_BRIDGE_ADDRESS with the bpf we deployed
//
// AccountOwner::Other(Pubkey::from_str(env!("BRIDGE_ADDRESS")).unwrap())
const initializeTx = await web3.sendAndConfirmTransaction(
connection,
new web3.Transaction().add(
createTokenBridgeInitializeInstruction(
TOKEN_BRIDGE_ADDRESS,
wallet.key(),
CORE_BRIDGE_ADDRESS
)
),
[wallet.signer()]
);
// console.log(`initializeTx: ${initializeTx}`);
// verify data
const config = await getTokenBridgeConfig(
connection,
TOKEN_BRIDGE_ADDRESS
);
expect(config.wormhole.equals(CORE_BRIDGE_ADDRESS)).to.be.true;
});
it("Upgrade Contract", async () => {
// first upload BPF of implementation
const artifactPath = `${__dirname}/../artifacts/token_bridge.so`;
const upgradeAuthority = deriveUpgradeAuthorityKey(TOKEN_BRIDGE_ADDRESS);
const implementation = execSolanaWriteBufferAndSetBufferAuthority(
payerPath,
artifactPath,
upgradeAuthority
);
// now pass implementation through governance
const timestamp = 2;
const chain = 1;
const message = governance.publishTokenBridgeUpgradeContract(
timestamp,
chain,
implementation.toString()
);
const signedVaa = guardians.addSignatures(message, [0]);
// console.log(`signedVaa: ${signedVaa.toString("base64")}`);
const txSignatures = await postVaa(
connection,
wallet.signTransaction,
CORE_BRIDGE_ADDRESS,
wallet.key(),
signedVaa
).then((results) => results.map((result) => result.signature));
const postTx = txSignatures.pop()!;
for (const verifyTx of txSignatures) {
// console.log(`verifySignatures: ${verifyTx}`);
}
// console.log(`postVaa: ${postTx}`);
const upgradeContractIx = createTokenBridgeUpgradeContractInstruction(
TOKEN_BRIDGE_ADDRESS,
CORE_BRIDGE_ADDRESS,
wallet.key(),
signedVaa
);
const upgradeContractTx = await web3.sendAndConfirmTransaction(
connection,
new web3.Transaction().add(upgradeContractIx),
[wallet.signer()]
);
// console.log(`upgradeContractTx: ${upgradeContractTx}`);
// not sure what to verify. if there are no errors,
// transaction was successful and the upgrade test passes
});
});
describe("NFT Bridge", () => {
it("Deploy and Initialize", async () => {
const artifactPath = `${__dirname}/../artifacts/nft_bridge.so`;
const programIdPath = `${__dirname}/keys/${NFT_BRIDGE_ADDRESS}.json`;
const upgradeAuthority = deriveUpgradeAuthorityKey(NFT_BRIDGE_ADDRESS);
deployProgram(
payerPath,
artifactPath,
programIdPath,
NFT_BRIDGE_ADDRESS,
upgradeAuthority
);
// we will initialize using CORE_BRIDGE_ADDRESS instead of
// UPGRADEABLE_CORE_BRIDGE_ADDRESS because the Wormhole owner is only
// valid for CORE_BRIDGE_ADDRESS with the bpf we deployed
//
// AccountOwner::Other(Pubkey::from_str(env!("BRIDGE_ADDRESS")).unwrap())
const initializeTx = await web3.sendAndConfirmTransaction(
connection,
new web3.Transaction().add(
createNftBridgeInitializeInstruction(
NFT_BRIDGE_ADDRESS,
wallet.key(),
CORE_BRIDGE_ADDRESS
)
),
[wallet.signer()]
);
// console.log(`initializeTx: ${initializeTx}`);
// verify data
const config = await getNftBridgeConfig(connection, NFT_BRIDGE_ADDRESS);
expect(config.wormhole.equals(CORE_BRIDGE_ADDRESS)).to.be.true;
});
it("Upgrade Contract", async () => {
// first upload BPF of implementation
const artifactPath = `${__dirname}/../artifacts/nft_bridge.so`;
const upgradeAuthority = deriveUpgradeAuthorityKey(NFT_BRIDGE_ADDRESS);
const implementation = execSolanaWriteBufferAndSetBufferAuthority(
payerPath,
artifactPath,
upgradeAuthority
);
// now pass implementation through governance
const timestamp = 3;
const chain = 1;
const message = governance.publishNftBridgeUpgradeContract(
timestamp,
chain,
implementation.toString()
);
const signedVaa = guardians.addSignatures(message, [0]);
// console.log(`signedVaa: ${signedVaa.toString("base64")}`);
const txSignatures = await postVaa(
connection,
wallet.signTransaction,
CORE_BRIDGE_ADDRESS,
wallet.key(),
signedVaa
).then((results) => results.map((result) => result.signature));
const postTx = txSignatures.pop()!;
for (const verifyTx of txSignatures) {
// console.log(`verifySignatures: ${verifyTx}`);
}
// console.log(`postVaa: ${postTx}`);
const upgradeContractIx = createNftBridgeUpgradeContractInstruction(
NFT_BRIDGE_ADDRESS,
CORE_BRIDGE_ADDRESS,
wallet.key(),
signedVaa
);
const upgradeContractTx = await web3.sendAndConfirmTransaction(
connection,
new web3.Transaction().add(upgradeContractIx),
[wallet.signer()]
);
// console.log(`upgradeContractTx: ${upgradeContractTx}`);
// not sure what to verify. if there are no errors,
// transaction was successful and the upgrade test passes
});
});
});