From 847dad8d4c13bd7b5eb738647dae49737b857450 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Thu, 27 Oct 2022 17:32:13 +0000 Subject: [PATCH] sdk/js: add SequenceTracker testing: add emitter sequence check --- .../src/solana/wormhole/accounts/emitter.ts | 36 +++++++++---- sdk/js/src/solana/wormhole/accounts/index.ts | 1 + .../src/solana/wormhole/accounts/sequence.ts | 50 +++++++++++++++++++ .../sdk-tests/2_token_bridge.ts | 36 +++++++++++++ 4 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 sdk/js/src/solana/wormhole/accounts/sequence.ts diff --git a/sdk/js/src/solana/wormhole/accounts/emitter.ts b/sdk/js/src/solana/wormhole/accounts/emitter.ts index 0d44a5d0b..268a16fac 100644 --- a/sdk/js/src/solana/wormhole/accounts/emitter.ts +++ b/sdk/js/src/solana/wormhole/accounts/emitter.ts @@ -1,5 +1,15 @@ -import { PublicKey, PublicKeyInitData } from "@solana/web3.js"; +import { + Commitment, + Connection, + PublicKey, + PublicKeyInitData, +} from "@solana/web3.js"; import { deriveAddress } from "../../utils"; +import { + deriveEmitterSequenceKey, + getSequenceTracker, + SequenceTracker, +} from "./sequence"; export interface EmitterAccounts { emitter: PublicKey; @@ -12,16 +22,6 @@ export function deriveWormholeEmitterKey( return deriveAddress([Buffer.from("emitter")], emitterProgramId); } -export function deriveEmitterSequenceKey( - emitter: PublicKeyInitData, - wormholeProgramId: PublicKeyInitData -): PublicKey { - return deriveAddress( - [Buffer.from("Sequence"), new PublicKey(emitter).toBytes()], - wormholeProgramId - ); -} - export function getEmitterKeys( emitterProgramId: PublicKeyInitData, wormholeProgramId: PublicKeyInitData @@ -32,3 +32,17 @@ export function getEmitterKeys( sequence: deriveEmitterSequenceKey(emitter, wormholeProgramId), }; } + +export async function getProgramSequenceTracker( + connection: Connection, + emitterProgramId: PublicKeyInitData, + wormholeProgramId: PublicKeyInitData, + commitment?: Commitment +): Promise { + return getSequenceTracker( + connection, + deriveWormholeEmitterKey(emitterProgramId), + wormholeProgramId, + commitment + ); +} diff --git a/sdk/js/src/solana/wormhole/accounts/index.ts b/sdk/js/src/solana/wormhole/accounts/index.ts index 3330f5f57..dc960d2d6 100644 --- a/sdk/js/src/solana/wormhole/accounts/index.ts +++ b/sdk/js/src/solana/wormhole/accounts/index.ts @@ -4,5 +4,6 @@ export * from "./emitter"; export * from "./feeCollector"; export * from "./guardianSet"; export * from "./postedVaa"; +export * from "./sequence"; export * from "./signatureSet"; export * from "./upgrade"; diff --git a/sdk/js/src/solana/wormhole/accounts/sequence.ts b/sdk/js/src/solana/wormhole/accounts/sequence.ts new file mode 100644 index 000000000..ad9ba80d0 --- /dev/null +++ b/sdk/js/src/solana/wormhole/accounts/sequence.ts @@ -0,0 +1,50 @@ +import { + Connection, + PublicKey, + Commitment, + PublicKeyInitData, +} from "@solana/web3.js"; +import { deriveAddress, getAccountData } from "../../utils"; + +export function deriveEmitterSequenceKey( + emitter: PublicKeyInitData, + wormholeProgramId: PublicKeyInitData +): PublicKey { + return deriveAddress( + [Buffer.from("Sequence"), new PublicKey(emitter).toBytes()], + wormholeProgramId + ); +} + +export async function getSequenceTracker( + connection: Connection, + emitter: PublicKeyInitData, + wormholeProgramId: PublicKeyInitData, + commitment?: Commitment +): Promise { + return connection + .getAccountInfo( + deriveEmitterSequenceKey(emitter, wormholeProgramId), + commitment + ) + .then((info) => SequenceTracker.deserialize(getAccountData(info))); +} + +export class SequenceTracker { + sequence: bigint; + + constructor(sequence: bigint) { + this.sequence = sequence; + } + + static deserialize(data: Buffer): SequenceTracker { + if (data.length != 8) { + throw new Error("data.length != 8"); + } + return new SequenceTracker(data.readBigUInt64LE(0)); + } + + value(): bigint { + return this.sequence; + } +} diff --git a/testing/solana-test-validator/sdk-tests/2_token_bridge.ts b/testing/solana-test-validator/sdk-tests/2_token_bridge.ts index a50057190..134d2cac1 100644 --- a/testing/solana-test-validator/sdk-tests/2_token_bridge.ts +++ b/testing/solana-test-validator/sdk-tests/2_token_bridge.ts @@ -58,6 +58,7 @@ import { deriveWormholeEmitterKey, getPostedMessage, getPostedVaa, + getProgramSequenceTracker, } from "../../../sdk/js/src/solana/wormhole"; import { parseGovernanceVaa, @@ -1082,6 +1083,13 @@ describe("Token Bridge", () => { expect(assetMeta.decimals).to.equal(9); expect(assetMeta.symbol).to.equal(""); expect(assetMeta.name).to.equal(""); + + const sequenceTracker = await getProgramSequenceTracker( + connection, + TOKEN_BRIDGE_ADDRESS, + CORE_BRIDGE_ADDRESS + ); + expect(sequenceTracker.value()).to.equal(messageData.sequence + 1n); }); // it("Attest Mint With Metadata", async () => { @@ -1183,6 +1191,13 @@ describe("Token Bridge", () => { Buffer.compare(tokenTransfer.tokenAddress, mint.toBuffer()) ).to.equal(0); expect(tokenTransfer.tokenChain).to.equal(1); + + const sequenceTracker = await getProgramSequenceTracker( + connection, + TOKEN_BRIDGE_ADDRESS, + CORE_BRIDGE_ADDRESS + ); + expect(sequenceTracker.value()).to.equal(messageData.sequence + 1n); }); it("Receive Token", async () => { @@ -1409,6 +1424,13 @@ describe("Token Bridge", () => { expect( Buffer.compare(tokenTransfer.tokenTransferPayload, transferPayload) ).to.equal(0); + + const sequenceTracker = await getProgramSequenceTracker( + connection, + TOKEN_BRIDGE_ADDRESS, + CORE_BRIDGE_ADDRESS + ); + expect(sequenceTracker.value()).to.equal(messageData.sequence + 1n); }); }); @@ -1744,6 +1766,13 @@ describe("Token Bridge", () => { Buffer.compare(tokenTransfer.tokenAddress, tokenAddress) ).to.equal(0); expect(tokenTransfer.tokenChain).to.equal(tokenChain); + + const sequenceTracker = await getProgramSequenceTracker( + connection, + TOKEN_BRIDGE_ADDRESS, + CORE_BRIDGE_ADDRESS + ); + expect(sequenceTracker.value()).to.equal(messageData.sequence + 1n); }); it("Send Token With Payload", async () => { @@ -1846,6 +1875,13 @@ describe("Token Bridge", () => { expect( Buffer.compare(tokenTransfer.tokenTransferPayload, transferPayload) ).to.equal(0); + + const sequenceTracker = await getProgramSequenceTracker( + connection, + TOKEN_BRIDGE_ADDRESS, + CORE_BRIDGE_ADDRESS + ); + expect(sequenceTracker.value()).to.equal(messageData.sequence + 1n); }); }); });