155 lines
4.2 KiB
TypeScript
155 lines
4.2 KiB
TypeScript
import { Idl, InstructionCoder } from "@project-serum/anchor";
|
|
import { ETHEREUM_KEY_LENGTH } from "../../utils";
|
|
|
|
export class WormholeInstructionCoder implements InstructionCoder {
|
|
constructor(_: Idl) {}
|
|
|
|
encode(ixName: string, ix: any): Buffer {
|
|
switch (ixName) {
|
|
case "initialize": {
|
|
return encodeInitialize(ix);
|
|
}
|
|
case "postVaa": {
|
|
return encodePostVaa(ix);
|
|
}
|
|
case "setFees": {
|
|
return encodeSetFees(ix);
|
|
}
|
|
case "transferFees": {
|
|
return encodeTransferFees(ix);
|
|
}
|
|
case "upgradeContract": {
|
|
return encodeUpgradeContract(ix);
|
|
}
|
|
case "upgradeGuardianSet": {
|
|
return encodeUpgradeGuardianSet(ix);
|
|
}
|
|
case "verifySignatures": {
|
|
return encodeVerifySignatures(ix);
|
|
}
|
|
default: {
|
|
throw new Error(`Invalid instruction: ${ixName}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
encodeState(_ixName: string, _ix: any): Buffer {
|
|
throw new Error("Wormhole program does not have state");
|
|
}
|
|
}
|
|
|
|
/** Solitaire enum of existing the Core Bridge's instructions.
|
|
*
|
|
* https://github.com/certusone/wormhole/blob/main/solana/bridge/program/src/lib.rs#L92
|
|
*/
|
|
export enum WormholeInstruction {
|
|
Initialize,
|
|
PostMessage,
|
|
PostVAA,
|
|
SetFees,
|
|
TransferFees,
|
|
UpgradeContract,
|
|
UpgradeGuardianSet,
|
|
VerifySignatures,
|
|
PostMessageUnreliable, // sounds useful
|
|
}
|
|
|
|
function encodeInitialize({
|
|
guardianSetExpirationTime,
|
|
fee,
|
|
initialGuardians,
|
|
}: any): Buffer {
|
|
if (typeof fee != "bigint") {
|
|
fee = BigInt(fee);
|
|
}
|
|
const initialGuardiansLen = initialGuardians.length;
|
|
const serialized = Buffer.alloc(
|
|
16 + initialGuardiansLen * ETHEREUM_KEY_LENGTH
|
|
);
|
|
serialized.writeUInt32LE(guardianSetExpirationTime, 0);
|
|
serialized.writeBigUInt64LE(fee, 4);
|
|
serialized.writeUInt32LE(initialGuardiansLen, 12);
|
|
for (let i = 0; i < initialGuardiansLen; ++i) {
|
|
const key = initialGuardians.at(i)!;
|
|
if (!Buffer.isBuffer(key)) {
|
|
throw new Error("key must be Buffer");
|
|
}
|
|
serialized.write(key.toString("hex"), 16 + i * ETHEREUM_KEY_LENGTH, "hex");
|
|
}
|
|
return encodeWormholeInstructionData(
|
|
WormholeInstruction.Initialize,
|
|
serialized
|
|
);
|
|
}
|
|
|
|
function encodeWormholeInstructionData(
|
|
instructionType: WormholeInstruction,
|
|
data?: Buffer
|
|
): Buffer {
|
|
const instructionData = Buffer.alloc(
|
|
1 + (data === undefined ? 0 : data.length)
|
|
);
|
|
instructionData.writeUInt8(instructionType, 0);
|
|
if (data !== undefined) {
|
|
instructionData.write(data.toString("hex"), 1, "hex");
|
|
}
|
|
return instructionData;
|
|
}
|
|
|
|
function encodePostVaa({
|
|
version,
|
|
guardianSetIndex,
|
|
timestamp,
|
|
nonce,
|
|
emitterChain,
|
|
emitterAddress,
|
|
sequence,
|
|
consistencyLevel,
|
|
payload,
|
|
}: any) {
|
|
if (!Buffer.isBuffer(emitterAddress)) {
|
|
throw new Error("emitterAddress must be Buffer");
|
|
}
|
|
if (!Buffer.isBuffer(payload)) {
|
|
throw new Error("payload must be Buffer");
|
|
}
|
|
if (typeof sequence != "bigint") {
|
|
sequence = BigInt(sequence);
|
|
}
|
|
const serialized = Buffer.alloc(60 + payload.length);
|
|
serialized.writeUInt8(version, 0);
|
|
serialized.writeUInt32LE(guardianSetIndex, 1);
|
|
serialized.writeUInt32LE(timestamp, 5);
|
|
serialized.writeUInt32LE(nonce, 9);
|
|
serialized.writeUInt16LE(emitterChain, 13);
|
|
serialized.write(emitterAddress.toString("hex"), 15, "hex");
|
|
serialized.writeBigInt64LE(sequence, 47);
|
|
serialized.writeUInt8(consistencyLevel, 55);
|
|
serialized.writeUInt32LE(payload.length, 56);
|
|
serialized.write(payload.toString("hex"), 60, "hex");
|
|
return encodeWormholeInstructionData(WormholeInstruction.PostVAA, serialized);
|
|
}
|
|
|
|
function encodeSetFees({}: any) {
|
|
return encodeWormholeInstructionData(WormholeInstruction.SetFees);
|
|
}
|
|
|
|
function encodeTransferFees({}: any) {
|
|
return encodeWormholeInstructionData(WormholeInstruction.TransferFees);
|
|
}
|
|
|
|
function encodeUpgradeContract({}: any) {
|
|
return encodeWormholeInstructionData(WormholeInstruction.UpgradeContract);
|
|
}
|
|
|
|
function encodeUpgradeGuardianSet({}: any) {
|
|
return encodeWormholeInstructionData(WormholeInstruction.UpgradeGuardianSet);
|
|
}
|
|
|
|
function encodeVerifySignatures({ signatureStatus }: any) {
|
|
return encodeWormholeInstructionData(
|
|
WormholeInstruction.VerifySignatures,
|
|
Buffer.from(signatureStatus, "hex")
|
|
);
|
|
}
|