Skip to content

Commit

Permalink
re-use existing CCTP serde, actually deserialize created VAA to corre…
Browse files Browse the repository at this point in the history
…ct type
  • Loading branch information
barnjamin committed Jun 25, 2024
1 parent f1bc1a7 commit a544b5f
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 293 deletions.
41 changes: 5 additions & 36 deletions solana/ts/src/cctp/messageTransmitter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import { IDL, MessageTransmitter } from "../types/message_transmitter";
import { MessageSent } from "./MessageSent";
import { MessageTransmitterConfig } from "./MessageTransmitterConfig";
import { UsedNonses } from "./UsedNonces";

export const PROGRAM_IDS = ["CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd"] as const;

export type ProgramId = (typeof PROGRAM_IDS)[number] | string;
import { CircleContracts } from "@wormhole-foundation/sdk-base/contracts";

export type ReceiveTokenMessengerMinterMessageAccounts = {
authority: PublicKey;
Expand All @@ -28,15 +25,11 @@ export type ReceiveTokenMessengerMinterMessageAccounts = {
};

export class MessageTransmitterProgram {
private _programId: ProgramId;

program: Program<MessageTransmitter>;

constructor(connection: Connection, programId?: ProgramId) {
this._programId = programId ?? testnet();
this.program = new Program(IDL, new PublicKey(this._programId), {
connection,
});
constructor(connection: Connection, private contracts: CircleContracts) {
const programId = new PublicKey(contracts.messageTransmitter);
this.program = new Program(IDL, new PublicKey(programId), { connection });
}

get ID(): PublicKey {
Expand Down Expand Up @@ -71,23 +64,7 @@ export class MessageTransmitterProgram {
}

tokenMessengerMinterProgram(): TokenMessengerMinterProgram {
switch (this._programId) {
case testnet(): {
return new TokenMessengerMinterProgram(
this.program.provider.connection,
"CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3",
);
}
case mainnet(): {
return new TokenMessengerMinterProgram(
this.program.provider.connection,
"CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3",
);
}
default: {
throw new Error("unsupported network");
}
}
return new TokenMessengerMinterProgram(this.program.provider.connection, this.contracts);
}

receiveTokenMessengerMinterMessageAccounts(
Expand Down Expand Up @@ -133,11 +110,3 @@ export class MessageTransmitterProgram {
.instruction();
}
}

export function mainnet(): ProgramId {
return "CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd";
}

export function testnet(): ProgramId {
return "CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd";
}
127 changes: 52 additions & 75 deletions solana/ts/src/cctp/messages.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ethers } from "ethers";
import { CircleBridge, UniversalAddress } from "@wormhole-foundation/sdk-definitions";

export type Cctp = {
version: number;
Expand All @@ -13,9 +13,9 @@ export type Cctp = {
// Taken from https://developers.circle.com/stablecoins/docs/message-format.
export class CctpMessage {
cctp: Cctp;
message: Buffer;
message: CctpTokenBurnMessage;

constructor(cctp: Cctp, message: Buffer) {
constructor(cctp: Cctp, message: CctpTokenBurnMessage) {
this.cctp = cctp;
this.message = message;
}
Expand All @@ -30,31 +30,60 @@ export class CctpMessage {

static decode(buf: Readonly<Buffer>): CctpMessage {
const version = buf.readUInt32BE(0);
const sourceDomain = buf.readUInt32BE(4);
const destinationDomain = buf.readUInt32BE(8);
const nonce = buf.readBigUInt64BE(12);
const sender = Array.from(buf.slice(20, 52));
const recipient = Array.from(buf.slice(52, 84));
const targetCaller = Array.from(buf.slice(84, 116));
const message = buf.subarray(116);

const [msg] = CircleBridge.deserialize(new Uint8Array(buf));
const {
sourceDomain,
destinationDomain,
nonce,
sender,
recipient,
destinationCaller,
payload,
} = msg;

const { burnToken, mintRecipient, amount, messageSender } = payload;
const header: Cctp = {
version,
sourceDomain,
destinationDomain,
nonce,
sender: Array.from(sender.toUint8Array()),
recipient: Array.from(recipient.toUint8Array()),
targetCaller: Array.from(destinationCaller.toUint8Array()),
};

return new CctpMessage(
{
header,
new CctpTokenBurnMessage(
header,
version,
sourceDomain,
destinationDomain,
nonce,
sender,
recipient,
targetCaller,
},
message,
Array.from(burnToken.toUint8Array()),
Array.from(mintRecipient.toUint8Array()),
amount,
Array.from(messageSender.toUint8Array()),
),
);
}

encode(): Buffer {
const { cctp, message } = this;
return Buffer.concat([encodeCctp(cctp), message]);
return Buffer.from(
CircleBridge.serialize({
sourceDomain: cctp.sourceDomain,
destinationDomain: cctp.destinationDomain,
nonce: cctp.nonce,
sender: new UniversalAddress(new Uint8Array(cctp.sender)),
recipient: new UniversalAddress(new Uint8Array(cctp.recipient)),
destinationCaller: new UniversalAddress(new Uint8Array(cctp.targetCaller)),
payload: {
burnToken: new UniversalAddress(new Uint8Array(message.burnTokenAddress)),
mintRecipient: new UniversalAddress(new Uint8Array(message.mintRecipient)),
amount: message.amount,
messageSender: new UniversalAddress(new Uint8Array(message.sender)),
},
}),
);
}
}

Expand Down Expand Up @@ -91,63 +120,11 @@ export class CctpTokenBurnMessage {
}

static decode(buf: Readonly<Buffer>): CctpTokenBurnMessage {
const { cctp, message } = CctpMessage.decode(buf);
const version = message.readUInt32BE(0);
const burnTokenAddress = Array.from(message.subarray(4, 36));
const mintRecipient = Array.from(message.subarray(36, 68));
const amount = BigInt(ethers.BigNumber.from(message.subarray(68, 100)).toString());
const sender = Array.from(message.subarray(100, 132));

return new CctpTokenBurnMessage(
cctp,
version,
burnTokenAddress,
mintRecipient,
amount,
sender,
);
const { message } = CctpMessage.decode(buf);
return message;
}

encode(): Buffer {
const buf = Buffer.alloc(132);

const { cctp, version, burnTokenAddress, mintRecipient, amount, sender } = this;

let offset = 0;
offset = buf.writeUInt32BE(version, offset);
buf.set(burnTokenAddress, offset);
offset += 32;
buf.set(mintRecipient, offset);
offset += 32;

// Special handling w/ uint256. This value will most likely encoded in < 32 bytes, so we
// jump ahead by 32 and subtract the length of the encoded value.
const encodedAmount = ethers.utils.arrayify(ethers.BigNumber.from(amount.toString()));
buf.set(encodedAmount, (offset += 32) - encodedAmount.length);

buf.set(sender, offset);
offset += 32;

return Buffer.concat([encodeCctp(cctp), buf]);
return new CctpMessage(this.cctp, this).encode();
}
}

function encodeCctp(cctp: Cctp): Buffer {
const buf = Buffer.alloc(116);

const { version, sourceDomain, destinationDomain, nonce, sender, recipient, targetCaller } =
cctp;

let offset = 0;
offset = buf.writeUInt32BE(version, offset);
offset = buf.writeUInt32BE(sourceDomain, offset);
offset = buf.writeUInt32BE(destinationDomain, offset);
offset = buf.writeBigUInt64BE(nonce, offset);
buf.set(sender, offset);
offset += 32;
buf.set(recipient, offset);
offset += 32;
buf.set(targetCaller, offset);

return buf;
}
43 changes: 6 additions & 37 deletions solana/ts/src/cctp/tokenMessengerMinter/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { Program } from "anchor-0.29.0";
import { Connection, PublicKey } from "@solana/web3.js";
import { CircleContracts } from "@wormhole-foundation/sdk-base/contracts";
import { Program } from "anchor-0.29.0";
import { MessageTransmitterProgram } from "../messageTransmitter";
import { IDL, TokenMessengerMinter } from "../types/token_messenger_minter";
import { RemoteTokenMessenger } from "./RemoteTokenMessenger";

export const PROGRAM_IDS = ["CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3"] as const;

export type ProgramId = (typeof PROGRAM_IDS)[number] | string;

export type DepositForBurnWithCallerAccounts = {
senderAuthority: PublicKey;
messageTransmitterConfig: PublicKey;
Expand All @@ -21,15 +18,11 @@ export type DepositForBurnWithCallerAccounts = {
};

export class TokenMessengerMinterProgram {
private _programId: ProgramId;

program: Program<TokenMessengerMinter>;

constructor(connection: Connection, programId?: ProgramId) {
this._programId = programId ?? testnet();
this.program = new Program(IDL, new PublicKey(this._programId), {
connection,
});
constructor(connection: Connection, private contracts: CircleContracts) {
const programId = new PublicKey(contracts.tokenMessenger);
this.program = new Program(IDL, programId, { connection });
}

get ID(): PublicKey {
Expand Down Expand Up @@ -89,23 +82,7 @@ export class TokenMessengerMinterProgram {
}

messageTransmitterProgram(): MessageTransmitterProgram {
switch (this._programId) {
case testnet(): {
return new MessageTransmitterProgram(
this.program.provider.connection,
"CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd",
);
}
case mainnet(): {
return new MessageTransmitterProgram(
this.program.provider.connection,
"CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd",
);
}
default: {
throw new Error("unsupported network");
}
}
return new MessageTransmitterProgram(this.program.provider.connection, this.contracts);
}

depositForBurnWithCallerAccounts(
Expand All @@ -126,11 +103,3 @@ export class TokenMessengerMinterProgram {
};
}
}

export function mainnet(): ProgramId {
return "CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3";
}

export function testnet(): ProgramId {
return "CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3";
}
30 changes: 10 additions & 20 deletions solana/ts/src/matchingEngine/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,39 +68,30 @@ import {
ReserveFastFillSequenceCompositeOpts,
} from "./types";

export const PROGRAM_IDS = [
"MatchingEngine11111111111111111111111111111",
"mPydpGUWxzERTNpyvTKdvS7v8kvw5sgwfiP8WQFrXVS",
] as const;
export type ProgramId = (typeof PROGRAM_IDS)[number] | string;
export * from "./types";

export const FEE_PRECISION_MAX = 1_000_000n;

export const CPI_EVENT_IX_SELECTOR = Uint8Array.from([228, 69, 165, 46, 81, 203, 154, 29]);

export class MatchingEngineProgram {
private _programId: ProgramId;
private _mint: PublicKey;
private _custodian?: Custodian;

pdas: ReturnType<typeof programDerivedAddresses>;

program: Program<MatchingEngineType>;

constructor(
connection: Connection,
programId: ProgramId,
private _addresses: MatchingEngine.Addresses,
) {
this._programId = programId;
constructor(connection: Connection, private _addresses: MatchingEngine.Addresses) {
const programId = _addresses.matchingEngine;
this._mint = new PublicKey(_addresses.cctp.usdcMint);
this.pdas = programDerivedAddresses(
new PublicKey(programId),
this._mint,
this.coreBridgeProgramId,
);
this.program = new Program(
{ ...(IDL as any), address: this._programId },
{ ...(IDL as any), address: programId },
{
connection,
},
Expand Down Expand Up @@ -2237,24 +2228,23 @@ export class MatchingEngineProgram {
}

upgradeManagerProgram(): UpgradeManagerProgram {
return new UpgradeManagerProgram(
this.program.provider.connection,
this._addresses.upgradeManager!,
{ ...this._addresses, tokenRouter: this._addresses.tokenRouter! },
);
return new UpgradeManagerProgram(this.program.provider.connection, {
...this._addresses,
tokenRouter: this._addresses.tokenRouter!,
});
}

tokenMessengerMinterProgram(): TokenMessengerMinterProgram {
return new TokenMessengerMinterProgram(
this.program.provider.connection,
this._addresses.cctp.tokenMessenger,
this._addresses.cctp,
);
}

messageTransmitterProgram(): MessageTransmitterProgram {
return new MessageTransmitterProgram(
this.program.provider.connection,
this._addresses.cctp.messageTransmitter,
this._addresses.cctp,
);
}

Expand Down
4 changes: 2 additions & 2 deletions solana/ts/src/protocol/matchingEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
SolanaUnsignedTransaction,
} from "@wormhole-foundation/sdk-solana";
import { vaaHash } from "../common";
import { AuctionParameters, MatchingEngineProgram, ProgramId } from "../matchingEngine";
import { AuctionParameters, MatchingEngineProgram } from "../matchingEngine";
import { SolanaWormholeCore } from "@wormhole-foundation/sdk-solana-core";

export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
Expand All @@ -44,7 +44,7 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
readonly _connection: Connection,
readonly _contracts: Contracts & MatchingEngine.Addresses,
) {
super(_connection, _contracts.matchingEngine, _contracts);
super(_connection, _contracts);

this.coreBridge = new SolanaWormholeCore(_network, _chain, _connection, {
...this._contracts,
Expand Down
Loading

0 comments on commit a544b5f

Please sign in to comment.