wormhole-circle-integration/solana/ts/scripts/setupTestnet.ts

185 lines
5.7 KiB
TypeScript

import {
ChainName,
coalesceChainId,
parseVaa,
tryNativeToUint8Array,
} from "@certusone/wormhole-sdk";
import { MockEmitter, MockGuardians } from "@certusone/wormhole-sdk/lib/cjs/mock";
import { NodeWallet, postVaaSolana } from "@certusone/wormhole-sdk/lib/cjs/solana";
import { derivePostedVaaKey } from "@certusone/wormhole-sdk/lib/cjs/solana/wormhole";
import { Connection, Keypair, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
import "dotenv/config";
import { CircleIntegrationProgram } from "../src";
const PROGRAM_ID = "wCCTPvsyeL9qYqbHTv3DUAyzEfYcyHoYw5c4mgcbBeW";
// Here we go.
main();
// impl
async function main() {
let govSequence = 6900n;
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const circleIntegration = new CircleIntegrationProgram(connection, PROGRAM_ID);
if (process.env.SOLANA_PRIVATE_KEY === undefined) {
throw new Error("SOLANA_PRIVATE_KEY is undefined");
}
const payer = Keypair.fromSecretKey(Buffer.from(process.env.SOLANA_PRIVATE_KEY, "hex"));
// Set up CCTP Program.
// await intialize(connection, payer);
// Register emitter and domain.
{
const foreignChain = "ethereum";
const foreignEmitter = "0x0a69146716b3a21622287efa1607424c663069a4";
const cctpDomain = 0;
await registerEmitterAndDomain(
circleIntegration,
payer,
govSequence++,
foreignChain,
foreignEmitter,
cctpDomain,
);
}
{
const foreignChain = "avalanche";
const foreignEmitter = "0x58f4C17449c90665891C42E14D34aae7a26A472e";
const cctpDomain = 1;
await registerEmitterAndDomain(
circleIntegration,
payer,
govSequence++,
foreignChain,
foreignEmitter,
cctpDomain,
);
}
{
const foreignChain = "optimism";
const foreignEmitter = "0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c";
const cctpDomain = 2;
await registerEmitterAndDomain(
circleIntegration,
payer,
govSequence++,
foreignChain,
foreignEmitter,
cctpDomain,
);
}
{
const foreignChain = "arbitrum";
const foreignEmitter = "0x2E8F5E00a9C5D450A72700546B89E2b70DfB00f2";
const cctpDomain = 3;
await registerEmitterAndDomain(
circleIntegration,
payer,
govSequence++,
foreignChain,
foreignEmitter,
cctpDomain,
);
}
}
async function intialize(circleIntegration: CircleIntegrationProgram, payer: Keypair) {
console.log("custodian", circleIntegration.custodianAddress().toString());
const ix = await circleIntegration.initializeIx(payer.publicKey);
const connection = circleIntegration.program.provider.connection;
const txSig = await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
console.log("intialize", txSig);
}
async function registerEmitterAndDomain(
circleIntegration: CircleIntegrationProgram,
payer: Keypair,
govSequence: bigint,
foreignChain: ChainName,
foreignEmitter: string,
cctpDomain: number,
) {
const connection = circleIntegration.program.provider.connection;
const registeredEmitter = circleIntegration.registeredEmitterAddress(
coalesceChainId(foreignChain),
);
const emitterAddress = Array.from(tryNativeToUint8Array(foreignEmitter, foreignChain));
const exists = await connection.getAccountInfo(registeredEmitter).then((acct) => acct != null);
if (exists) {
const registered = await circleIntegration.fetchRegisteredEmitter(registeredEmitter);
if (Buffer.from(registered.address).equals(Buffer.from(emitterAddress))) {
console.log("already registered", foreignChain, foreignEmitter, cctpDomain);
return;
}
}
const govEmitter = new MockEmitter(
"0000000000000000000000000000000000000000000000000000000000000004",
1,
Number(govSequence),
);
const payload = Buffer.alloc(32 + 1 + 2 + 2 + 32 + 4);
// Action.
payload.writeUInt8(2, 32);
// Data.
payload.writeUInt16BE(1, 33); // targetChain
payload.writeUInt16BE(coalesceChainId(foreignChain), 35);
payload.set(tryNativeToUint8Array(foreignEmitter, foreignChain), 37);
payload.writeUInt32BE(cctpDomain, 69);
const moduleName = "CircleIntegration";
payload.set(Buffer.from(moduleName), 32 - moduleName.length);
const published = govEmitter.publishMessage(
0, // nonce,
payload,
0, // consistencyLevel
12345678, // timestamp
);
if (process.env.GUARDIAN_PRIVATE_KEY === undefined) {
throw new Error("GUARDIAN_PRIVATE_KEY is undefined");
}
const guardians = new MockGuardians(0, [process.env.GUARDIAN_PRIVATE_KEY]);
const vaaBuf = guardians.addSignatures(published, [0]);
await postVaaSolana(
connection,
new NodeWallet(payer).signTransaction,
circleIntegration.coreBridgeProgramId(),
payer.publicKey,
vaaBuf,
);
const vaa = derivePostedVaaKey(circleIntegration.coreBridgeProgramId(), parseVaa(vaaBuf).hash);
const ix = await circleIntegration.registerEmitterAndDomainIx({
payer: payer.publicKey,
vaa,
});
const txSig = await sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
console.log(
"register emitter and domain",
txSig,
"chain",
foreignChain,
"addr",
foreignEmitter,
"domain",
cctpDomain,
);
}