Skip to content
This repository was archived by the owner on Jun 16, 2025. It is now read-only.

Commit 3026ec7

Browse files
committed
Refactor how vaas are posted
1 parent ac625b5 commit 3026ec7

File tree

8 files changed

+155
-165
lines changed

8 files changed

+155
-165
lines changed

solana/ts/src/common/index.ts

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
22
import { MessageTransmitterProgram } from "../cctp";
33
import { BN } from "@coral-xyz/anchor";
4+
import { VAA, keccak256 } from "@wormhole-foundation/sdk-definitions";
45

56
export * from "./messages";
67
export * from "./state";
78

89
export type Uint64 = bigint | BN | number;
910

10-
export function isUint64(value: Uint64): boolean {
11-
return (
12-
typeof value === "bigint" ||
13-
(typeof value === "object" && value instanceof BN) ||
14-
typeof value === "number"
15-
);
16-
}
17-
1811
export function uint64ToBigInt(value: Uint64): bigint {
1912
if (typeof value === "bigint") {
2013
return value;
@@ -38,32 +31,7 @@ export function uint64ToBN(value: Uint64): BN {
3831
}
3932

4033
export type VaaHash = Array<number> | Buffer | Uint8Array;
41-
42-
export function vaaHashToUint8Array(vaaHash: VaaHash): Uint8Array {
43-
if (Array.isArray(vaaHash)) {
44-
return Uint8Array.from(vaaHash);
45-
} else if (Buffer.isBuffer(vaaHash)) {
46-
return Uint8Array.from(vaaHash);
47-
} else {
48-
return vaaHash;
49-
}
50-
}
51-
52-
export function vaaHashToBuffer(vaaHash: VaaHash): Buffer {
53-
if (Buffer.isBuffer(vaaHash)) {
54-
return vaaHash;
55-
} else {
56-
return Buffer.from(vaaHashToUint8Array(vaaHash));
57-
}
58-
}
59-
60-
export function vaaHashToArray(vaaHash: VaaHash): Array<number> {
61-
if (Array.isArray(vaaHash)) {
62-
return vaaHash;
63-
} else {
64-
return Array.from(vaaHashToUint8Array(vaaHash));
65-
}
66-
}
34+
export const vaaHash = (vaa: VAA<any>): VaaHash => keccak256(vaa.hash);
6735

6836
export async function reclaimCctpMessageIx(
6937
messageTransmitter: MessageTransmitterProgram,

solana/ts/src/matchingEngine/index.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import {
5353
ReservedFastFillSequence,
5454
RouterEndpoint,
5555
} from "./state";
56+
import { VAA, keccak256 } from "@wormhole-foundation/sdk-definitions";
5657

5758
export const PROGRAM_IDS = [
5859
"MatchingEngine11111111111111111111111111111",
@@ -225,7 +226,11 @@ export class MatchingEngineProgram {
225226
constructor(connection: Connection, programId: ProgramId, mint: PublicKey) {
226227
this._programId = programId;
227228
this._mint = mint;
228-
this.pdas = programDerivedAddresses(new PublicKey(programId), mint);
229+
this.pdas = programDerivedAddresses(
230+
new PublicKey(programId),
231+
mint,
232+
this.coreBridgeProgramId(),
233+
);
229234
this.program = new Program(
230235
{ ...(IDL as any), address: this._programId },
231236
{
@@ -388,13 +393,11 @@ export class MatchingEngineProgram {
388393

389394
async fetchAuction(input: VaaHash | { address: PublicKey }): Promise<Auction> {
390395
const addr = "address" in input ? input.address : this.auctionAddress(input);
391-
// @ts-ignore This is BS. This is correct.
392396
return this.program.account.auction.fetch(addr);
393397
}
394398

395399
async fetchProposal(input?: { address: PublicKey }): Promise<Proposal> {
396400
const addr = input === undefined ? await this.proposalAddress() : input.address;
397-
// @ts-ignore This is BS. This is correct.
398401
return this.program.account.proposal.fetch(addr);
399402
}
400403

@@ -2495,7 +2498,7 @@ export class MatchingEngineProgram {
24952498
fastFillSequencerAddress = (sourceChain: ChainId, sender: Array<number>): PublicKey =>
24962499
this.pdas.fastFillSequencer(sourceChain, sender);
24972500
reservedFastFillSequenceAddress = (fastVaaHash: VaaHash): PublicKey =>
2498-
this.pdas.reservedFastFillSequenceAddress(fastVaaHash);
2501+
this.pdas.reservedFastFillSequence(fastVaaHash);
24992502
transferAuthorityAddress = (auction: PublicKey, offerPrice: Uint64): PublicKey =>
25002503
this.pdas.transferAuthority(auction, offerPrice);
25012504
auctionHistoryAddress = (id: Uint64): PublicKey => this.pdas.auctionHistory(id);

solana/ts/src/matchingEngine/pdas.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as splToken from "@solana/spl-token";
22
import { PublicKey } from "@solana/web3.js";
33
import { ChainId } from "@wormhole-foundation/sdk-base";
4+
import { utils as coreUtils } from "@wormhole-foundation/sdk-solana-core";
45
import { Uint64, VaaHash, cctpMessageAddress, coreMessageAddress, writeUint64BE } from "../common";
56
import {
67
Auction,
@@ -14,9 +15,9 @@ import {
1415
ReservedFastFillSequence,
1516
RouterEndpoint,
1617
} from "./state";
17-
import { VAA } from "@wormhole-foundation/sdk-definitions";
18+
import { VAA, keccak256 } from "@wormhole-foundation/sdk-definitions";
1819

19-
export function programDerivedAddresses(ID: PublicKey, mint: PublicKey) {
20+
export function programDerivedAddresses(ID: PublicKey, mint: PublicKey, coreId: PublicKey) {
2021
return {
2122
auctionConfig: (id: number) => AuctionConfig.address(ID, id),
2223
auction: (vaaHash: VaaHash) => Auction.address(ID, vaaHash),
@@ -54,7 +55,7 @@ export function programDerivedAddresses(ID: PublicKey, mint: PublicKey) {
5455
FastFill.address(ID, sourceChain, orderSender, sequence),
5556
fastFillSequencer: (sourceChain: ChainId, sender: Array<number>) =>
5657
FastFillSequencer.address(ID, sourceChain, sender),
57-
reservedFastFillSequenceAddress: (fastVaaHash: VaaHash) =>
58+
reservedFastFillSequence: (fastVaaHash: VaaHash) =>
5859
ReservedFastFillSequence.address(ID, fastVaaHash),
5960
transferAuthority: (auction: PublicKey, offerPrice: Uint64) => {
6061
const encodedOfferPrice = Buffer.alloc(8);
@@ -65,5 +66,8 @@ export function programDerivedAddresses(ID: PublicKey, mint: PublicKey) {
6566
)[0];
6667
},
6768
auctionHistory: (id: Uint64) => AuctionHistory.address(ID, id),
69+
70+
//
71+
postedVaa: (vaa: VAA<any>) => coreUtils.derivePostedVaaKey(coreId, Buffer.from(vaa.hash)),
6872
};
6973
}

solana/ts/src/protocol/matchingEngine.ts

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
CircleAttestation,
1919
CircleBridge,
2020
Contracts,
21-
UnsignedTransaction,
2221
VAA,
2322
keccak256,
2423
} from "@wormhole-foundation/sdk-definitions";
@@ -30,8 +29,9 @@ import {
3029
SolanaTransaction,
3130
SolanaUnsignedTransaction,
3231
} from "@wormhole-foundation/sdk-solana";
33-
import { utils as coreUtils } from "@wormhole-foundation/sdk-solana-core";
32+
import { vaaHash } from "../common";
3433
import { AuctionParameters, MatchingEngineProgram, ProgramId } from "../matchingEngine";
34+
import { SolanaWormholeCore } from "@wormhole-foundation/sdk-solana-core";
3535

3636
export interface SolanaMatchingEngineContracts {
3737
matchingEngine: string;
@@ -42,6 +42,8 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
4242
extends MatchingEngineProgram
4343
implements MatchingEngine<N, C>
4444
{
45+
coreBridge: SolanaWormholeCore<N, C>;
46+
4547
constructor(
4648
readonly _network: N,
4749
readonly _chain: C,
@@ -54,6 +56,11 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
5456
_contracts.matchingEngine as ProgramId,
5557
new PublicKey(_contracts.usdcMint),
5658
);
59+
60+
this.coreBridge = new SolanaWormholeCore(_network, _chain, _connection, {
61+
coreBridge: this.coreBridgeProgramId().toBase58(),
62+
...this._contracts,
63+
});
5764
}
5865

5966
static async fromRpc<N extends Network>(
@@ -160,6 +167,10 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
160167
throw new Error("Method not implemented.");
161168
}
162169

170+
async *postVaa(sender: AnySolanaAddress, vaa: FastTransfer.VAA) {
171+
yield* this.coreBridge.postVaa(sender, vaa);
172+
}
173+
163174
async *placeInitialOffer(
164175
sender: AnySolanaAddress,
165176
vaa: VAA<"FastTransfer:FastMarketOrder">,
@@ -168,10 +179,7 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
168179
) {
169180
const payer = new SolanaAddress(sender).unwrap();
170181

171-
const vaaAddress = coreUtils.derivePostedVaaKey(
172-
this.coreBridgeProgramId(),
173-
Buffer.from(vaa.hash),
174-
);
182+
const vaaAddress = this.pdas.postedVaa(vaa);
175183

176184
const ixs = await this.placeInitialOfferCctpIx(
177185
{ payer, fastVaa: vaaAddress },
@@ -196,6 +204,10 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
196204
yield this.createUnsignedTx({ transaction }, "MatchingEngine.improveOffer");
197205
}
198206

207+
async *reserveFastFillSequence() {
208+
throw new Error("Method not implemented.");
209+
}
210+
199211
async *executeFastOrder(
200212
sender: AnySolanaAddress,
201213
vaa: VAA<"FastTransfer:FastMarketOrder">,
@@ -207,16 +219,15 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
207219
? new SolanaAddress(participant).unwrap()
208220
: undefined;
209221

210-
const fastVaa = coreUtils.derivePostedVaaKey(
211-
this.coreBridgeProgramId(),
212-
Buffer.from(vaa.hash),
213-
);
222+
const fastVaa = this.pdas.postedVaa(vaa);
214223

215-
const digest = keccak256(vaa.hash);
216-
const auction = this.auctionAddress(digest);
224+
const digest = vaaHash(vaa);
225+
const auction = this.pdas.auction(digest);
226+
227+
const reservedSequence = this.pdas.reservedFastFillSequence(digest);
217228

218229
// TODO: make sure this has already been done, or do it here
219-
const reservedSequence = this.reservedFastFillSequenceAddress(digest);
230+
// yield* this.reserveFastFillSequence();
220231

221232
const { targetChain } = vaa.payload;
222233

@@ -258,15 +269,8 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
258269
) {
259270
const payer = new SolanaAddress(sender).unwrap();
260271

261-
const fastVaa = coreUtils.derivePostedVaaKey(
262-
this.coreBridgeProgramId(),
263-
Buffer.from(fast.hash),
264-
);
265-
266-
const finalizedVaa = coreUtils.derivePostedVaaKey(
267-
this.coreBridgeProgramId(),
268-
Buffer.from(finalized.hash),
269-
);
272+
const fastVaa = this.pdas.postedVaa(fast);
273+
const finalizedVaa = this.pdas.postedVaa(finalized);
270274

271275
const preparedAddress = this.preparedOrderResponseAddress(keccak256(fast.hash));
272276

@@ -340,10 +344,7 @@ export class SolanaMatchingEngine<N extends Network, C extends SolanaChains>
340344
const digest = keccak256(fast.hash);
341345
const preparedOrderResponse = this.preparedOrderResponseAddress(digest);
342346
const auction = this.auctionAddress(digest);
343-
const fastVaa = coreUtils.derivePostedVaaKey(
344-
this.coreBridgeProgramId(),
345-
Buffer.from(fast.hash),
346-
);
347+
const fastVaa = this.pdas.postedVaa(fast);
347348

348349
const settleIx = await (async () => {
349350
if (finalized && !cctp) {

solana/ts/src/testing/mock.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Connection, Keypair } from "@solana/web3.js";
22
import { Chain, Network } from "@wormhole-foundation/sdk-base";
3-
import { SignAndSendSigner, toUniversal } from "@wormhole-foundation/sdk-definitions";
3+
import { toUniversal } from "@wormhole-foundation/sdk-definitions";
4+
import { signAndSendWait } from "@wormhole-foundation/sdk-connect";
45
import { mocks } from "@wormhole-foundation/sdk-definitions/testing";
56
import { SolanaAddress, SolanaSendSigner } from "@wormhole-foundation/sdk-solana";
67
import { utils as coreUtils } from "@wormhole-foundation/sdk-solana-core";
@@ -9,12 +10,18 @@ import { LiquidityLayerMessage } from "../common";
910
import { VaaAccount } from "../wormhole";
1011
import { CORE_BRIDGE_PID, GUARDIAN_KEY, MOCK_GUARDIANS } from "./consts";
1112
import { getBlockTime, postVaa } from "./utils";
13+
import { FastTransfer } from "@wormhole-foundation/example-liquidity-layer-definitions";
14+
import { SolanaMatchingEngine } from "../protocol";
1215

1316
export class SDKSigner<N extends Network> extends SolanaSendSigner<N, "Solana"> {
1417
unwrap(): Keypair {
1518
// @ts-ignore
1619
return this._keypair;
1720
}
21+
connection(): Connection {
22+
// @ts-ignore
23+
return this._rpc;
24+
}
1825
}
1926

2027
export function getSdkSigner<N extends Network>(
@@ -31,21 +38,20 @@ export function unwrapSigners(signers: SDKSigner<Network>[]): Keypair[] {
3138
return signers.map((signer) => signer.unwrap());
3239
}
3340

34-
export async function postLiquidityLayerVaav2(
41+
export async function createLiquidityLayerVaa(
3542
connection: Connection,
36-
payer: Keypair | SignAndSendSigner<Network, "Solana">,
3743
foreignEmitterAddress: Array<number>,
3844
sequence: bigint,
3945
message: LiquidityLayerMessage | Buffer,
4046
args: { sourceChain?: Chain; timestamp?: number } = {},
41-
) {
47+
): Promise<FastTransfer.VAA> {
4248
let { sourceChain, timestamp } = args;
4349
sourceChain ??= "Ethereum";
4450
timestamp ??= await getBlockTime(connection);
4551

4652
const foreignEmitter = new mocks.MockEmitter(
4753
toUniversal(sourceChain, new Uint8Array(foreignEmitterAddress)),
48-
sourceChain ?? "Ethereum",
54+
sourceChain,
4955
sequence - 1n,
5056
);
5157

@@ -58,8 +64,20 @@ export async function postLiquidityLayerVaav2(
5864

5965
const vaa = MOCK_GUARDIANS.addSignatures(published, [0]);
6066

61-
const { address } = await postVaa(connection, payer, vaa);
62-
const account = await VaaAccount.fetch(connection, address);
67+
// @ts-ignore -- lie
68+
return vaa;
69+
}
70+
71+
export async function postLiquidityLayerVaav2<N extends Network>(
72+
signer: SDKSigner<N>,
73+
engine: SolanaMatchingEngine<N, "Solana">,
74+
vaa: FastTransfer.VAA,
75+
) {
76+
const txs = engine.postVaa(signer.address(), vaa);
77+
await signAndSendWait(txs, signer);
78+
79+
const address = engine.pdas.postedVaa(vaa);
80+
const account = await VaaAccount.fetch(signer.connection(), address);
6381

6482
return { address, account };
6583
}

solana/ts/src/testing/utils.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import { UniversalAddress, VAA } from "@wormhole-foundation/sdk-definitions";
1717
import { SolanaSendSigner, SolanaUnsignedTransaction } from "@wormhole-foundation/sdk-solana";
1818
import { SolanaWormholeCore, utils as coreUtils } from "@wormhole-foundation/sdk-solana-core";
1919
import { expect } from "chai";
20-
import { execSync } from "child_process";
2120
import { Err, Ok } from "ts-results";
2221
import { CORE_BRIDGE_PID, USDC_MINT_ADDRESS } from "./consts";
2322

@@ -219,22 +218,6 @@ export async function postVaa(
219218
return { txids, address };
220219
}
221220

222-
export function loadProgramBpf(artifactPath: string, keypath: string): PublicKey {
223-
// Invoke BPF Loader Upgradeable `write-buffer` instruction.
224-
const buffer = (() => {
225-
const output = execSync(`solana -u l -k ${keypath} program write-buffer ${artifactPath}`);
226-
return new PublicKey(output.toString().match(/^Buffer: ([A-Za-z0-9]+)/)![1]);
227-
})();
228-
229-
// Return the pubkey for the buffer (our new program implementation).
230-
return buffer;
231-
}
232-
233-
export async function waitBySlots(connection: Connection, numSlots: number) {
234-
const targetSlot = await connection.getSlot().then((slot) => slot + numSlots);
235-
return waitUntilSlot(connection, targetSlot);
236-
}
237-
238221
export async function waitUntilSlot(connection: Connection, targetSlot: number) {
239222
return new Promise((resolve, _) => {
240223
const sub = connection.onSlotChange((slot) => {

solana/ts/src/wormhole/index.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,7 @@ export class VaaAccount {
102102

103103
emitterInfo(): EmitterInfo {
104104
const { emitterChain: chain, emitterAddress: address, sequence } = this.vaa();
105-
return {
106-
chain: toChainId(chain),
107-
address: Array.from(address.toUint8Array()),
108-
sequence,
109-
};
105+
return { chain: toChainId(chain), address: Array.from(address.toUint8Array()), sequence };
110106
}
111107

112108
timestamp(): number {

0 commit comments

Comments
 (0)