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

Commit 7a9bc69

Browse files
committed
replace postVaa with method that takes signer and no guardian args
1 parent 79cc198 commit 7a9bc69

File tree

3 files changed

+108
-77
lines changed

3 files changed

+108
-77
lines changed

solana/ts/src/testing/mock.ts

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,68 @@
11
import { Connection, Keypair } from "@solana/web3.js";
22
import { ethers } from "ethers";
33
import { LiquidityLayerMessage } from "../common";
4-
import { CORE_BRIDGE_PID, GUARDIAN_KEY } from "./consts";
4+
import { CORE_BRIDGE_PID, GUARDIAN_KEY, MOCK_GUARDIANS } from "./consts";
55
import { postVaa, getBlockTime } from "./utils";
66
import { mocks } from "@wormhole-foundation/sdk-definitions/testing";
7-
import { utils as coreUtils } from "@wormhole-foundation/sdk-solana-core";
8-
import { Chain } from "@wormhole-foundation/sdk-base";
9-
import { serialize, toUniversal } from "@wormhole-foundation/sdk-definitions";
7+
import { signAndSendWait } from "@wormhole-foundation/sdk-connect";
8+
import { SolanaWormholeCore, utils as coreUtils } from "@wormhole-foundation/sdk-solana-core";
9+
import { Chain, Network, contracts } from "@wormhole-foundation/sdk-base";
10+
import {
11+
SignAndSendSigner,
12+
buildConfig,
13+
serialize,
14+
toUniversal,
15+
} from "@wormhole-foundation/sdk-definitions";
16+
import { SolanaAddress, SolanaSendSigner } from "@wormhole-foundation/sdk-solana";
17+
import { VaaAccount } from "../wormhole";
18+
19+
export type SDKSigner<N extends Network> = SolanaSendSigner<N, "Solana">;
20+
21+
export function getSdkSigner<N extends Network>(
22+
connection: Connection,
23+
key: Keypair,
24+
debug: boolean = false,
25+
): { signer: SDKSigner<N>; address: SolanaAddress } {
26+
const signer = new SolanaSendSigner(connection, "Solana", key, debug, {});
27+
const address = new SolanaAddress(key.publicKey);
28+
return { signer, address };
29+
}
30+
31+
// TODO: return VaaAccount, too
32+
export async function postLiquidityLayerVaav2(
33+
connection: Connection,
34+
payer: Keypair | SignAndSendSigner<Network, "Solana">,
35+
foreignEmitterAddress: Array<number>,
36+
sequence: bigint,
37+
message: LiquidityLayerMessage | Buffer,
38+
args: { sourceChain?: Chain; timestamp?: number } = {},
39+
) {
40+
let { sourceChain, timestamp } = args;
41+
sourceChain ??= "Ethereum";
42+
timestamp ??= await getBlockTime(connection);
43+
44+
const foreignEmitter = new mocks.MockEmitter(
45+
toUniversal(sourceChain, new Uint8Array(foreignEmitterAddress)),
46+
sourceChain ?? "Ethereum",
47+
sequence - 1n,
48+
);
49+
50+
const published = foreignEmitter.publishMessage(
51+
0, // nonce,
52+
Buffer.isBuffer(message) ? message : message.encode(),
53+
0, // consistencyLevel
54+
timestamp,
55+
);
56+
57+
const vaa = MOCK_GUARDIANS.addSignatures(published, [0]);
58+
59+
await postVaa(connection, payer, Buffer.from(serialize(vaa)));
60+
61+
const address = coreUtils.derivePostedVaaKey(CORE_BRIDGE_PID, Buffer.from(vaa.hash));
62+
const account = await VaaAccount.fetch(connection, address);
63+
64+
return { address, account };
65+
}
1066

1167
// TODO: return VaaAccount, too
1268
export async function postLiquidityLayerVaa(

solana/ts/src/testing/utils.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,22 @@ async function debugSendAndConfirmTransaction(
197197

198198
export async function postVaa(
199199
connection: Connection,
200-
payer: Keypair,
200+
payer: Keypair | SdkSigner<Network, "Solana">,
201201
vaaBuf: Buffer,
202202
coreBridgeAddress?: PublicKey,
203203
) {
204204
const core = new SolanaWormholeCore("Devnet", "Solana", connection, {
205205
coreBridge: (coreBridgeAddress ?? CORE_BRIDGE_PID).toString(),
206206
});
207-
const txs = core.postVaa(payer.publicKey, deserialize("Uint8Array", vaaBuf));
208-
const signer = new SolanaSendSigner(connection, "Solana", payer, false, {});
209-
await signAndSendWait(txs, signer);
207+
208+
const signer =
209+
payer instanceof Keypair
210+
? new SolanaSendSigner(connection, "Solana", payer, false, {})
211+
: payer;
212+
213+
const txs = core.postVaa(signer.address(), deserialize("Uint8Array", vaaBuf));
214+
215+
return await signAndSendWait(txs, signer);
210216
}
211217

212218
export function loadProgramBpf(artifactPath: string, keypath: string): PublicKey {

solana/ts/tests/01__matchingEngine.ts

Lines changed: 38 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ import {
6868
toUniversalAddress,
6969
waitUntilSlot,
7070
waitUntilTimestamp,
71+
getSdkSigner,
72+
SDKSigner,
73+
postLiquidityLayerVaav2,
7174
} from "../src/testing";
7275
import { VaaAccount } from "../src/wormhole";
7376

@@ -78,32 +81,21 @@ chai.config.truncateThreshold = 0;
7881
// Set to true to add debug logs for Signer
7982
const SIGNER_DEBUG = false;
8083

81-
type SDKSigner = SolanaSendSigner<"Devnet", "Solana">;
82-
83-
function getSdkStuff(
84-
connection: Connection,
85-
key: Keypair,
86-
): { signer: SDKSigner; address: SolanaAddress } {
87-
const signer = new SolanaSendSigner(connection, "Solana", key, SIGNER_DEBUG, {});
88-
const address = new SolanaAddress(key.publicKey);
89-
return { signer, address };
90-
}
91-
9284
describe("Matching Engine", function () {
9385
const connection = new Connection(LOCALHOST, "processed");
9486

9587
// owner is also the recipient in all tests
9688
const payer = PAYER_KEYPAIR;
97-
const { signer: payerSigner, address: payerAddress } = getSdkStuff(connection, payer);
89+
const { signer: payerSigner, address: payerAddress } = getSdkSigner(connection, payer);
9890

9991
const owner = OWNER_KEYPAIR;
100-
const { signer: ownerSigner, address: ownerAddress } = getSdkStuff(connection, owner);
92+
const { signer: ownerSigner, address: ownerAddress } = getSdkSigner(connection, owner);
10193

10294
const relayer = Keypair.generate();
103-
const { signer: relayerSigner, address: relayerAddress } = getSdkStuff(connection, relayer);
95+
const { signer: relayerSigner, address: relayerAddress } = getSdkSigner(connection, relayer);
10496

10597
const ownerAssistant = OWNER_ASSISTANT_KEYPAIR;
106-
const { signer: ownerAssistantSigner, address: ownerAssistantAddress } = getSdkStuff(
98+
const { signer: ownerAssistantSigner, address: ownerAssistantAddress } = getSdkSigner(
10799
connection,
108100
ownerAssistant,
109101
);
@@ -116,17 +108,17 @@ describe("Matching Engine", function () {
116108
);
117109
const newFeeRecipient = Keypair.generate().publicKey;
118110
const playerOne = PLAYER_ONE_KEYPAIR;
119-
const { signer: playerOneSigner, address: playerOneAddress } = getSdkStuff(
111+
const { signer: playerOneSigner, address: playerOneAddress } = getSdkSigner(
120112
connection,
121113
playerOne,
122114
);
123115
const playerTwo = Keypair.generate();
124-
const { signer: playerTwoSigner, address: playerTwoAddress } = getSdkStuff(
116+
const { signer: playerTwoSigner, address: playerTwoAddress } = getSdkSigner(
125117
connection,
126118
playerTwo,
127119
);
128120
const liquidator = Keypair.generate();
129-
const { signer: liquidatorSigner, address: liquidatorAddress } = getSdkStuff(
121+
const { signer: liquidatorSigner, address: liquidatorAddress } = getSdkSigner(
130122
connection,
131123
liquidator,
132124
);
@@ -1447,18 +1439,15 @@ describe("Matching Engine", function () {
14471439
});
14481440

14491441
it("Cannot Place Initial Offer (Invalid VAA)", async function () {
1450-
const fastVaa = await postLiquidityLayerVaa(
1442+
const { address: fastVaa, account: account } = await postLiquidityLayerVaav2(
14511443
connection,
1452-
playerOne,
1453-
MOCK_GUARDIANS,
1444+
playerOneSigner,
14541445
ethRouter,
14551446
wormholeSequence++,
14561447
Buffer.from("deadbeef", "hex"),
14571448
);
14581449

1459-
const auction = await VaaAccount.fetch(connection, fastVaa).then((vaa) =>
1460-
engine.auctionAddress(vaa.digest()),
1461-
);
1450+
const auction = engine.auctionAddress(account.digest());
14621451
await placeInitialOfferCctpForTest(
14631452
{
14641453
payer: playerOne.publicKey,
@@ -1559,10 +1548,9 @@ describe("Matching Engine", function () {
15591548
});
15601549

15611550
it("Cannot Place Initial Offer (Invalid Payload)", async function () {
1562-
const fastVaa = await postLiquidityLayerVaa(
1551+
const { address: fastVaa, account } = await postLiquidityLayerVaav2(
15631552
connection,
1564-
playerOne,
1565-
MOCK_GUARDIANS,
1553+
playerOneSigner,
15661554
ethRouter,
15671555
wormholeSequence++,
15681556
new LiquidityLayerMessage({
@@ -1585,9 +1573,7 @@ describe("Matching Engine", function () {
15851573
}),
15861574
);
15871575

1588-
const auction = await VaaAccount.fetch(connection, fastVaa).then((vaa) =>
1589-
engine.auctionAddress(vaa.digest()),
1590-
);
1576+
const auction = engine.auctionAddress(account.digest());
15911577
await placeInitialOfferCctpForTest(
15921578
{
15931579
payer: playerOne.publicKey,
@@ -2438,7 +2424,7 @@ describe("Matching Engine", function () {
24382424

24392425
it("Execute Fast Order After Grace Period with Liquidator (Initial Offer Token is Closed)", async function () {
24402426
const tmpOwner = Keypair.generate();
2441-
const { signer: tmpOwnerSiner } = getSdkStuff(connection, tmpOwner);
2427+
const { signer: tmpOwnerSiner } = getSdkSigner(connection, tmpOwner);
24422428
const transferLamportsToTmpOwnerIx = SystemProgram.transfer({
24432429
fromPubkey: payer.publicKey,
24442430
toPubkey: tmpOwner.publicKey,
@@ -4369,13 +4355,13 @@ describe("Matching Engine", function () {
43694355
});
43704356

43714357
interface TestOptions {
4372-
signers?: SDKSigner[];
4358+
signers?: SDKSigner<"Devnet">[];
43734359
errorMsg?: string | null;
43744360
}
43754361

43764362
function addDefaultOptions<T extends TestOptions>(
43774363
opts: T,
4378-
): [{ signers: SDKSigner[]; errorMsg: string | null }, Omit<T, keyof TestOptions>] {
4364+
): [{ signers: SDKSigner<"Devnet">[]; errorMsg: string | null }, Omit<T, keyof TestOptions>] {
43794365
let { signers, errorMsg } = opts;
43804366
signers ??= [payerSigner];
43814367
delete opts.signers;
@@ -4445,6 +4431,7 @@ describe("Matching Engine", function () {
44454431
// Place the initial offer.
44464432
const txs = engine.placeInitialOffer(
44474433
new SolanaAddress(accounts.payer),
4434+
// @ts-expect-error may be Uint8Array typed for payload
44484435
fastMarketOrderVAA,
44494436
args.offerPrice,
44504437
args.totalDeposit,
@@ -4454,6 +4441,10 @@ describe("Matching Engine", function () {
44544441
return expectTxsErr(signers[0], txs, errorMsg);
44554442
}
44564443

4444+
// If we still have a Uint8Array, we failed to deserialize it earlier but it was accepted
4445+
// and not caught by the above error check. Why?
4446+
if (fastMarketOrderVAA.payloadLiteral === "Uint8Array") throw "Invalid VAA";
4447+
44574448
const offerToken =
44584449
accounts.offerToken ??
44594450
splToken.getAssociatedTokenAddressSync(USDC_MINT_ADDRESS, accounts.payer);
@@ -4486,7 +4477,7 @@ describe("Matching Engine", function () {
44864477

44874478
const auctionCustodyBalanceAfter = await engine.fetchAuctionCustodyTokenBalance(auction);
44884479

4489-
const { fastMarketOrder } = LiquidityLayerMessage.decode(fast.vaaAccount.payload());
4480+
const fastMarketOrder = fastMarketOrderVAA.payload;
44904481
expect(fastMarketOrder).is.not.undefined;
44914482
const { amountIn, maxFee, targetChain, redeemerMessage } = fastMarketOrder!;
44924483

@@ -5172,20 +5163,6 @@ describe("Matching Engine", function () {
51725163
};
51735164
}
51745165

5175-
type VaaResult = {
5176-
vaa: PublicKey;
5177-
vaaAccount: VaaAccount;
5178-
};
5179-
5180-
type FastObservedResult = VaaResult & {
5181-
fastMarketOrder: FastMarketOrder;
5182-
};
5183-
5184-
type FinalizedObservedResult = VaaResult & {
5185-
slowOrderResponse: SlowOrderResponse;
5186-
cctp: CctpMessageArgs;
5187-
};
5188-
51895166
type ObserveCctpOrderVaasOpts = {
51905167
sourceChain?: Chain;
51915168
emitter?: Array<number>;
@@ -5199,10 +5176,7 @@ describe("Matching Engine", function () {
51995176
finalizedVaaTimestamp?: number;
52005177
};
52015178

5202-
async function observeCctpOrderVaas(opts: ObserveCctpOrderVaasOpts = {}): Promise<{
5203-
fast: FastObservedResult;
5204-
finalized?: FinalizedObservedResult;
5205-
}> {
5179+
async function observeCctpOrderVaas(opts: ObserveCctpOrderVaasOpts = {}) {
52065180
let {
52075181
sourceChain,
52085182
emitter,
@@ -5231,18 +5205,14 @@ describe("Matching Engine", function () {
52315205
throw new Error(`Invalid source chain: ${sourceChain}`);
52325206
}
52335207

5234-
const fastVaa = await postLiquidityLayerVaa(
5208+
const { address: fastVaa, account: fastVaaAccount } = await postLiquidityLayerVaav2(
52355209
connection,
5236-
payer,
5237-
MOCK_GUARDIANS,
5210+
payerSigner,
52385211
emitter,
52395212
wormholeSequence++,
5240-
new LiquidityLayerMessage({
5241-
fastMarketOrder,
5242-
}),
5213+
new LiquidityLayerMessage({ fastMarketOrder }),
52435214
{ sourceChain, timestamp: vaaTimestamp },
52445215
);
5245-
const fastVaaAccount = await VaaAccount.fetch(connection, fastVaa);
52465216
const fast = { fastMarketOrder, vaa: fastVaa, vaaAccount: fastVaaAccount };
52475217

52485218
if (finalized) {
@@ -5266,16 +5236,15 @@ describe("Matching Engine", function () {
52665236
}),
52675237
});
52685238

5269-
const finalizedVaa = await postLiquidityLayerVaa(
5270-
connection,
5271-
payer,
5272-
MOCK_GUARDIANS,
5273-
finalizedEmitter,
5274-
finalizedSequence,
5275-
finalizedMessage,
5276-
{ sourceChain: finalizedSourceChain, timestamp: finalizedVaaTimestamp },
5277-
);
5278-
const finalizedVaaAccount = await VaaAccount.fetch(connection, finalizedVaa);
5239+
const { address: finalizedVaa, account: finalizedVaaAccount } =
5240+
await postLiquidityLayerVaav2(
5241+
connection,
5242+
payerSigner,
5243+
finalizedEmitter,
5244+
finalizedSequence,
5245+
finalizedMessage,
5246+
{ sourceChain: finalizedSourceChain, timestamp: finalizedVaaTimestamp },
5247+
);
52795248
return {
52805249
fast,
52815250
finalized: {

0 commit comments

Comments
 (0)