| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863 |
- import * as anchor from "@coral-xyz/anchor";
- import {
- IdlAccounts,
- IdlTypes,
- Program,
- BorshAccountsCoder,
- } from "@coral-xyz/anchor";
- import { MessageBuffer } from "../target/types/message_buffer";
- import { MockCpiCaller } from "../target/types/mock_cpi_caller";
- import lumina from "@lumina-dev/test";
- import { assert } from "chai";
- import { AccountMeta, ComputeBudgetProgram } from "@solana/web3.js";
- import bs58 from "bs58";
- import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
- // Enables tool that runs in local browser for easier debugging of
- // transactions in this test - https://lumina.fyi/debug
- // lumina();
- const messageBufferProgram = anchor.workspace
- .MessageBuffer as Program<MessageBuffer>;
- const mockCpiProg = anchor.workspace.MockCpiCaller as Program<MockCpiCaller>;
- const [mockCpiCallerAuth] = anchor.web3.PublicKey.findProgramAddressSync(
- [Buffer.from("upd_price_write"), messageBufferProgram.programId.toBuffer()],
- mockCpiProg.programId
- );
- const pythPriceAccountId = new anchor.BN(1);
- const addPriceParams = {
- id: pythPriceAccountId,
- price: new anchor.BN(2),
- priceExpo: new anchor.BN(3),
- ema: new anchor.BN(4),
- emaExpo: new anchor.BN(5),
- };
- const [pythPriceAccountPk] = anchor.web3.PublicKey.findProgramAddressSync(
- [
- Buffer.from("pyth"),
- Buffer.from("price"),
- pythPriceAccountId.toArrayLike(Buffer, "le", 8),
- ],
- mockCpiProg.programId
- );
- const MESSAGE = Buffer.from("message");
- const [messageBufferPda, messageBufferBump] =
- anchor.web3.PublicKey.findProgramAddressSync(
- [mockCpiCallerAuth.toBuffer(), MESSAGE, pythPriceAccountPk.toBuffer()],
- messageBufferProgram.programId
- );
- const pythPriceAccountId2 = new anchor.BN(2);
- const [pythPriceAccountPk2] = anchor.web3.PublicKey.findProgramAddressSync(
- [
- Buffer.from("pyth"),
- Buffer.from("price"),
- pythPriceAccountId2.toArrayLike(Buffer, "le", 8),
- ],
- mockCpiProg.programId
- );
- const [messageBufferPda2, messageBufferBump2] =
- anchor.web3.PublicKey.findProgramAddressSync(
- [mockCpiCallerAuth.toBuffer(), MESSAGE, pythPriceAccountPk2.toBuffer()],
- messageBufferProgram.programId
- );
- const messageBufferPdaMeta2 = {
- pubkey: messageBufferPda2,
- isSigner: false,
- isWritable: true,
- };
- const discriminator = BorshAccountsCoder.accountDiscriminator("MessageBuffer");
- const messageBufferDiscriminator = bs58.encode(discriminator);
- let provider = anchor.AnchorProvider.env();
- anchor.setProvider(provider);
- const payer = provider.wallet as NodeWallet;
- let whitelistAdmin = anchor.web3.Keypair.generate();
- const [whitelistPubkey, whitelistBump] =
- anchor.web3.PublicKey.findProgramAddressSync(
- [MESSAGE, Buffer.from("whitelist")],
- messageBufferProgram.programId
- );
- describe("message_buffer", () => {
- it("Is initialized!", async () => {
- // Add your test here.
- const tx = await messageBufferProgram.methods
- .initialize()
- .accounts({
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- })
- .signers([whitelistAdmin])
- .rpc();
- console.log("Your transaction signature", tx);
- const whitelist = await messageBufferProgram.account.whitelist.fetch(
- whitelistPubkey
- );
- assert.strictEqual(whitelist.bump, whitelistBump);
- assert.isTrue(whitelist.admin.equals(whitelistAdmin.publicKey));
- console.info(`whitelist: ${JSON.stringify(whitelist)}`);
- });
- it("Sets allowed programs to the whitelist", async () => {
- const allowedProgramAuthorities = [mockCpiCallerAuth];
- await messageBufferProgram.methods
- .setAllowedPrograms(allowedProgramAuthorities)
- .accounts({
- admin: whitelistAdmin.publicKey,
- })
- .signers([whitelistAdmin])
- .rpc();
- const whitelist = await messageBufferProgram.account.whitelist.fetch(
- whitelistPubkey
- );
- console.info(`whitelist after add: ${JSON.stringify(whitelist)}`);
- const whitelistAllowedPrograms = whitelist.allowedPrograms.map((pk) =>
- pk.toString()
- );
- assert.deepEqual(
- whitelistAllowedPrograms,
- allowedProgramAuthorities.map((p) => p.toString())
- );
- });
- it("Creates a buffer", async () => {
- const msgBufferPdaMetas = [
- {
- pubkey: messageBufferPda,
- isSigner: false,
- isWritable: true,
- },
- ];
- await messageBufferProgram.methods
- .createBuffer(mockCpiCallerAuth, pythPriceAccountPk, 1024 * 8)
- .accounts({
- whitelist: whitelistPubkey,
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- systemProgram: anchor.web3.SystemProgram.programId,
- })
- .signers([whitelistAdmin])
- .remainingAccounts(msgBufferPdaMetas)
- .rpc({ skipPreflight: true });
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda
- );
- const messageBufferHeader = deserializeMessageBufferHeader(
- messageBufferProgram,
- messageBufferAccountData
- );
- assert.equal(messageBufferHeader.version, 1);
- assert.equal(messageBufferHeader.bump, messageBufferBump);
- });
- it("Creates a buffer even if the account already has lamports", async () => {
- const minimumEmptyRent =
- await provider.connection.getMinimumBalanceForRentExemption(0);
- await provider.sendAndConfirm(
- (() => {
- const tx = new anchor.web3.Transaction();
- tx.add(
- anchor.web3.SystemProgram.transfer({
- fromPubkey: provider.wallet.publicKey,
- toPubkey: messageBufferPda2,
- lamports: minimumEmptyRent,
- })
- );
- return tx;
- })()
- );
- const accumulatorPdaBalance = await provider.connection.getBalance(
- messageBufferPda2
- );
- console.log(`accumulatorPdaBalance: ${accumulatorPdaBalance}`);
- assert.isTrue(accumulatorPdaBalance === minimumEmptyRent);
- await messageBufferProgram.methods
- .createBuffer(mockCpiCallerAuth, pythPriceAccountPk2, 1000)
- .accounts({
- whitelist: whitelistPubkey,
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- systemProgram: anchor.web3.SystemProgram.programId,
- })
- .signers([whitelistAdmin])
- .remainingAccounts([messageBufferPdaMeta2])
- .rpc({ skipPreflight: true });
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda2
- );
- const minimumMessageBufferRent =
- await provider.connection.getMinimumBalanceForRentExemption(
- messageBufferAccountData.length
- );
- const accumulatorPdaBalanceAfter = await provider.connection.getBalance(
- messageBufferPda2
- );
- assert.isTrue(accumulatorPdaBalanceAfter === minimumMessageBufferRent);
- const messageBufferHeader = deserializeMessageBufferHeader(
- messageBufferProgram,
- messageBufferAccountData
- );
- console.log(`header: ${JSON.stringify(messageBufferHeader)}`);
- assert.equal(messageBufferHeader.bump, messageBufferBump2);
- assert.equal(messageBufferAccountData[8], messageBufferBump2);
- assert.equal(messageBufferHeader.version, 1);
- });
- it("Updates the whitelist authority", async () => {
- const newWhitelistAdmin = anchor.web3.Keypair.generate();
- await messageBufferProgram.methods
- .updateWhitelistAdmin(newWhitelistAdmin.publicKey)
- .accounts({
- admin: whitelistAdmin.publicKey,
- })
- .signers([whitelistAdmin])
- .rpc();
- let whitelist = await messageBufferProgram.account.whitelist.fetch(
- whitelistPubkey
- );
- assert.isTrue(whitelist.admin.equals(newWhitelistAdmin.publicKey));
- // swap back to original authority
- await messageBufferProgram.methods
- .updateWhitelistAdmin(whitelistAdmin.publicKey)
- .accounts({
- admin: newWhitelistAdmin.publicKey,
- })
- .signers([newWhitelistAdmin])
- .rpc();
- whitelist = await messageBufferProgram.account.whitelist.fetch(
- whitelistPubkey
- );
- assert.isTrue(whitelist.admin.equals(whitelistAdmin.publicKey));
- });
- it("Mock CPI program - AddPrice", async () => {
- const mockCpiCallerAddPriceTxPubkeys = await mockCpiProg.methods
- .addPrice(addPriceParams)
- .accounts({
- systemProgram: anchor.web3.SystemProgram.programId,
- auth: mockCpiCallerAuth,
- accumulatorWhitelist: whitelistPubkey,
- messageBufferProgram: messageBufferProgram.programId,
- })
- .pubkeys();
- const accumulatorPdaMetas = [
- {
- pubkey: messageBufferPda,
- isSigner: false,
- isWritable: true,
- },
- ];
- const mockCpiCallerAddPriceTxPrep = await mockCpiProg.methods
- .addPrice(addPriceParams)
- .accounts({
- ...mockCpiCallerAddPriceTxPubkeys,
- })
- .remainingAccounts(accumulatorPdaMetas)
- .prepare();
- console.log(
- `ix: ${JSON.stringify(
- mockCpiCallerAddPriceTxPrep.instruction,
- (k, v) => {
- if (k === "data") {
- return v.toString();
- } else {
- return v;
- }
- },
- 2
- )}`
- );
- for (const prop in mockCpiCallerAddPriceTxPrep.pubkeys) {
- console.log(
- `${prop}: ${mockCpiCallerAddPriceTxPrep.pubkeys[prop].toString()}`
- );
- }
- const addPriceTx = await mockCpiProg.methods
- .addPrice(addPriceParams)
- .accounts({
- ...mockCpiCallerAddPriceTxPubkeys,
- })
- .remainingAccounts(accumulatorPdaMetas)
- .preInstructions([
- ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }),
- ])
- .rpc({
- skipPreflight: true,
- });
- console.log(`addPriceTx: ${addPriceTx}`);
- const pythPriceAccount = await provider.connection.getAccountInfo(
- mockCpiCallerAddPriceTxPubkeys.pythPriceAccount
- );
- const messageBufferAccount = await provider.connection.getAccountInfo(
- messageBufferPda
- );
- const accumulatorPriceMessages = parseMessageBuffer(
- messageBufferProgram,
- messageBufferAccount.data
- );
- console.log(
- `accumulatorPriceMessages: ${JSON.stringify(
- accumulatorPriceMessages,
- null,
- 2
- )}`
- );
- accumulatorPriceMessages.forEach((pm) => {
- assert.isTrue(pm.id.eq(addPriceParams.id));
- assert.isTrue(pm.price.eq(addPriceParams.price));
- assert.isTrue(pm.priceExpo.eq(addPriceParams.priceExpo));
- });
- });
- it("Fetches MessageBuffer using getProgramAccounts with discriminator", async () => {
- const messageBufferAccounts = await getProgramAccountsForMessageBuffers(
- provider.connection
- );
- const msgBufferAcctKeys = messageBufferAccounts.map((ai) =>
- ai.pubkey.toString()
- );
- console.log(
- `messageBufferAccounts: ${JSON.stringify(msgBufferAcctKeys, null, 2)}`
- );
- assert.isTrue(messageBufferAccounts.length === 2);
- msgBufferAcctKeys.includes(messageBufferPda.toString());
- });
- it("Mock CPI Program - UpdatePrice", async () => {
- const updatePriceParams = {
- price: new anchor.BN(5),
- priceExpo: new anchor.BN(6),
- ema: new anchor.BN(7),
- emaExpo: new anchor.BN(8),
- };
- let accumulatorPdaMeta = getAccumulatorPdaMeta(
- mockCpiCallerAuth,
- pythPriceAccountPk
- );
- await mockCpiProg.methods
- .updatePrice(updatePriceParams)
- .accounts({
- pythPriceAccount: pythPriceAccountPk,
- auth: mockCpiCallerAuth,
- accumulatorWhitelist: whitelistPubkey,
- messageBufferProgram: messageBufferProgram.programId,
- })
- .remainingAccounts([accumulatorPdaMeta])
- .preInstructions([
- ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }),
- ])
- .rpc({
- skipPreflight: true,
- });
- const pythPriceAccount = await mockCpiProg.account.priceAccount.fetch(
- pythPriceAccountPk
- );
- assert.isTrue(pythPriceAccount.price.eq(updatePriceParams.price));
- assert.isTrue(pythPriceAccount.priceExpo.eq(updatePriceParams.priceExpo));
- assert.isTrue(pythPriceAccount.ema.eq(updatePriceParams.ema));
- assert.isTrue(pythPriceAccount.emaExpo.eq(updatePriceParams.emaExpo));
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda
- );
- const updatedAccumulatorPriceMessages = parseMessageBuffer(
- messageBufferProgram,
- messageBufferAccountData
- );
- console.log(
- `updatedAccumulatorPriceMessages: ${JSON.stringify(
- updatedAccumulatorPriceMessages,
- null,
- 2
- )}`
- );
- updatedAccumulatorPriceMessages.forEach((pm) => {
- assert.isTrue(pm.id.eq(addPriceParams.id));
- assert.isTrue(pm.price.eq(updatePriceParams.price));
- assert.isTrue(pm.priceExpo.eq(updatePriceParams.priceExpo));
- });
- });
- it("Mock CPI Program - CPI Max Test", async () => {
- // with loosen CPI feature activated, max cpi instruction size len is 10KB
- let testCases = [[1024], [1024, 2048], [1024, 2048, 4096]];
- // for (let i = 1; i < 8; i++) {
- for (let i = 0; i < testCases.length; i++) {
- let testCase = testCases[i];
- console.info(`testCase: ${testCase}`);
- const updatePriceParams = {
- price: new anchor.BN(10 * (i + 5)),
- priceExpo: new anchor.BN(10 * (i + 6)),
- ema: new anchor.BN(10 * i + 7),
- emaExpo: new anchor.BN(10 * i + 8),
- };
- console.log(`updatePriceParams: ${JSON.stringify(updatePriceParams)}`);
- let accumulatorPdaMeta = getAccumulatorPdaMeta(
- mockCpiCallerAuth,
- pythPriceAccountPk
- );
- await mockCpiProg.methods
- .cpiMaxTest(updatePriceParams, testCase)
- .accounts({
- pythPriceAccount: pythPriceAccountPk,
- auth: mockCpiCallerAuth,
- accumulatorWhitelist: whitelistPubkey,
- messageBufferProgram: messageBufferProgram.programId,
- })
- .remainingAccounts([accumulatorPdaMeta])
- .preInstructions([
- ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }),
- ])
- .rpc({
- skipPreflight: true,
- });
- const pythPriceAccount = await mockCpiProg.account.priceAccount.fetch(
- pythPriceAccountPk
- );
- assert.isTrue(pythPriceAccount.price.eq(updatePriceParams.price));
- assert.isTrue(pythPriceAccount.priceExpo.eq(updatePriceParams.priceExpo));
- assert.isTrue(pythPriceAccount.ema.eq(updatePriceParams.ema));
- assert.isTrue(pythPriceAccount.emaExpo.eq(updatePriceParams.emaExpo));
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda
- );
- const messageBufferHeader = deserializeMessageBufferHeader(
- messageBufferProgram,
- messageBufferAccountData
- );
- console.log(`header: ${JSON.stringify(messageBufferHeader)}`);
- let mockCpiMessageHeaderLen = 7;
- let currentExpectedOffset = 0;
- for (let j = 0; j < testCase.length; j++) {
- currentExpectedOffset += testCase[j];
- currentExpectedOffset += mockCpiMessageHeaderLen;
- console.log(`
- header.endOffsets[${j}]: ${messageBufferHeader.endOffsets[j]}
- currentExpectedOffset: ${currentExpectedOffset}
- `);
- assert.isTrue(
- messageBufferHeader.endOffsets[j] === currentExpectedOffset
- );
- }
- }
- });
- it("Mock CPI Program - Exceed CPI Max Test ", async () => {
- // with loosen CPI feature activated, max cpi instruction size len is 10KB
- let testCases = [[1024, 2048, 4096, 8192]];
- // for (let i = 1; i < 8; i++) {
- for (let i = 0; i < testCases.length; i++) {
- let testCase = testCases[i];
- console.info(`testCase: ${testCase}`);
- const updatePriceParams = {
- price: new anchor.BN(10 * i + 5),
- priceExpo: new anchor.BN(10 * (i + 6)),
- ema: new anchor.BN(10 * i + 7),
- emaExpo: new anchor.BN(10 * i + 8),
- };
- let accumulatorPdaMeta = getAccumulatorPdaMeta(
- mockCpiCallerAuth,
- pythPriceAccountPk
- );
- let errorThrown = false;
- try {
- await mockCpiProg.methods
- .cpiMaxTest(updatePriceParams, testCase)
- .accounts({
- pythPriceAccount: pythPriceAccountPk,
- auth: mockCpiCallerAuth,
- accumulatorWhitelist: whitelistPubkey,
- messageBufferProgram: messageBufferProgram.programId,
- })
- .remainingAccounts([accumulatorPdaMeta])
- .preInstructions([
- ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }),
- ])
- .rpc({
- skipPreflight: true,
- });
- } catch (_err) {
- errorThrown = true;
- }
- assert.ok(errorThrown);
- }
- });
- it("Resizes a buffer to a valid larger size", async () => {
- const messageBufferAccountDataBefore = await getMessageBuffer(
- provider.connection,
- messageBufferPda2
- );
- const messageBufferAccountDataLenBefore =
- messageBufferAccountDataBefore.length;
- // check that header is stil the same as before
- const messageBufferHeaderBefore = deserializeMessageBufferHeader(
- messageBufferProgram,
- messageBufferAccountDataBefore
- );
- const payerBalanceBefore = await provider.connection.getBalance(
- payer.publicKey
- );
- console.log(`payerBalanceBefore: ${payerBalanceBefore}`);
- const targetSize = 10 * 1024;
- await messageBufferProgram.methods
- .resizeBuffer(mockCpiCallerAuth, pythPriceAccountPk2, targetSize)
- .accounts({
- whitelist: whitelistPubkey,
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- systemProgram: anchor.web3.SystemProgram.programId,
- })
- .signers([whitelistAdmin])
- .rpc({ skipPreflight: true });
- const payerBalanceAftger = await provider.connection.getBalance(
- payer.publicKey
- );
- assert.isTrue(payerBalanceAftger < payerBalanceBefore);
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda2
- );
- assert.equal(messageBufferAccountData.length, targetSize);
- // check that header is still the same as before
- const messageBufferHeader = deserializeMessageBufferHeader(
- messageBufferProgram,
- messageBufferAccountData
- );
- assert.deepEqual(
- messageBufferHeader.endOffsets,
- messageBufferHeaderBefore.endOffsets
- );
- assert.deepEqual(
- messageBufferAccountData.subarray(0, messageBufferAccountDataLenBefore),
- messageBufferAccountDataBefore
- );
- });
- it("Resizes a buffer to a smaller size", async () => {
- const targetSize = 4 * 1024;
- await messageBufferProgram.methods
- .resizeBuffer(mockCpiCallerAuth, pythPriceAccountPk2, targetSize)
- .accounts({
- whitelist: whitelistPubkey,
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- systemProgram: anchor.web3.SystemProgram.programId,
- messageBuffer: messageBufferPda2,
- })
- .signers([whitelistAdmin])
- .rpc({ skipPreflight: true });
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda2
- );
- assert.equal(messageBufferAccountData.length, targetSize);
- });
- it("Fails to resize buffers to invalid sizes", async () => {
- // resize more than 10KB in one txn and less than header.header_len should be fail
- const testCases = [20 * 1024, 2];
- for (const testCase of testCases) {
- let errorThrown = false;
- try {
- await messageBufferProgram.methods
- .resizeBuffer(mockCpiCallerAuth, pythPriceAccountPk2, testCase)
- .accounts({
- whitelist: whitelistPubkey,
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- systemProgram: anchor.web3.SystemProgram.programId,
- messageBuffer: messageBufferPda2,
- })
- .signers([whitelistAdmin])
- .rpc({ skipPreflight: true });
- } catch (_err) {
- errorThrown = true;
- }
- assert.ok(errorThrown);
- }
- });
- it("Deletes a buffer", async () => {
- await messageBufferProgram.methods
- .deleteBuffer(mockCpiCallerAuth, pythPriceAccountPk2)
- .accounts({
- whitelist: whitelistPubkey,
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- messageBuffer: messageBufferPda2,
- })
- .signers([whitelistAdmin])
- .remainingAccounts([messageBufferPdaMeta2])
- .rpc({ skipPreflight: true });
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda2
- );
- if (messageBufferAccountData != null) {
- assert.fail("messageBufferAccountData should be null");
- }
- const messageBufferAccounts = await getProgramAccountsForMessageBuffers(
- provider.connection
- );
- assert.equal(messageBufferAccounts.length, 1);
- assert.isFalse(
- messageBufferAccounts
- .map((a) => a.pubkey.toString())
- .includes(messageBufferPda2.toString())
- );
- });
- it("Can recreate a buffer after it's been deleted", async () => {
- await messageBufferProgram.methods
- .createBuffer(mockCpiCallerAuth, pythPriceAccountPk2, 1000)
- .accounts({
- whitelist: whitelistPubkey,
- admin: whitelistAdmin.publicKey,
- payer: payer.publicKey,
- systemProgram: anchor.web3.SystemProgram.programId,
- })
- .signers([whitelistAdmin])
- .remainingAccounts([messageBufferPdaMeta2])
- .rpc({ skipPreflight: true });
- const messageBufferAccountData = await getMessageBuffer(
- provider.connection,
- messageBufferPda2
- );
- const minimumMessageBufferRent =
- await provider.connection.getMinimumBalanceForRentExemption(
- messageBufferAccountData.length
- );
- const accumulatorPdaBalanceAfter = await provider.connection.getBalance(
- messageBufferPda2
- );
- assert.isTrue(accumulatorPdaBalanceAfter === minimumMessageBufferRent);
- const messageBufferHeader = deserializeMessageBufferHeader(
- messageBufferProgram,
- messageBufferAccountData
- );
- console.log(`header: ${JSON.stringify(messageBufferHeader)}`);
- assert.equal(messageBufferHeader.bump, messageBufferBump2);
- assert.equal(messageBufferAccountData[8], messageBufferBump2);
- assert.equal(messageBufferHeader.version, 1);
- });
- });
- export const getAccumulatorPdaMeta = (
- cpiCallerAuth: anchor.web3.PublicKey,
- pythAccount: anchor.web3.PublicKey
- ): AccountMeta => {
- const accumulatorPdaKey = anchor.web3.PublicKey.findProgramAddressSync(
- [cpiCallerAuth.toBuffer(), MESSAGE, pythAccount.toBuffer()],
- messageBufferProgram.programId
- )[0];
- return {
- pubkey: accumulatorPdaKey,
- isSigner: false,
- isWritable: true,
- };
- };
- async function getMessageBuffer(
- connection: anchor.web3.Connection,
- accountKey: anchor.web3.PublicKey
- ): Promise<Buffer | null> {
- let accountInfo = await connection.getAccountInfo(accountKey);
- return accountInfo ? accountInfo.data : null;
- }
- // Parses MessageBuffer.data into a PriceAccount or PriceOnly object based on the
- // accountType and accountSchema.
- function parseMessageBuffer(
- messageBufferProgram: Program<MessageBuffer>,
- accountData: Buffer
- ): AccumulatorPriceMessage[] {
- const msgBufferHeader = deserializeMessageBufferHeader(
- messageBufferProgram,
- accountData
- );
- const accumulatorMessages = [];
- // let dataBuffer = Buffer.from(messages);
- let dataBuffer = accountData.subarray(
- msgBufferHeader.headerLen,
- accountData.length
- );
- let start = 0;
- for (let i = 0; i < msgBufferHeader.endOffsets.length; i++) {
- const endOffset = msgBufferHeader.endOffsets[i];
- if (endOffset == 0) {
- console.log(`endOffset = 0. breaking`);
- break;
- }
- const messageBytes = dataBuffer.subarray(start, endOffset);
- const { header: msgHeader, data: msgData } =
- parseMessageBytes(messageBytes);
- console.info(`header: ${JSON.stringify(msgHeader, null, 2)}`);
- if (msgHeader.schema == 0) {
- accumulatorMessages.push(parseFullPriceMessage(msgData));
- } else if (msgHeader.schema == 1) {
- accumulatorMessages.push(parseCompactPriceMessage(msgData));
- } else {
- console.warn("unknown msgHeader.schema: " + i);
- continue;
- }
- start = endOffset;
- }
- return accumulatorMessages;
- }
- type MessageHeader = {
- schema: number;
- version: number;
- size: number;
- };
- type MessageBufferType = {
- header: MessageHeader;
- data: Buffer;
- };
- function deserializeMessageBufferHeader(
- messageBufferProgram: Program<MessageBuffer>,
- accountData: Buffer
- ): IdlAccounts<MessageBuffer>["messageBuffer"] {
- return messageBufferProgram.coder.accounts.decode(
- "MessageBuffer",
- accountData
- );
- }
- function parseMessageBytes(data: Buffer): MessageBufferType {
- let offset = 0;
- const schema = data.readInt8(offset);
- offset += 1;
- const version = data.readInt16BE(offset);
- offset += 2;
- const size = data.readUInt32BE(offset);
- offset += 4;
- const messageHeader = {
- schema,
- version,
- size,
- };
- let messageData = data.subarray(offset, offset + size);
- return {
- header: messageHeader,
- data: messageData,
- };
- }
- type AccumulatorPriceMessage = FullPriceMessage | CompactPriceMessage;
- type FullPriceMessage = {
- id: anchor.BN;
- price: anchor.BN;
- priceExpo: anchor.BN;
- ema: anchor.BN;
- emaExpo: anchor.BN;
- };
- function parseFullPriceMessage(data: Uint8Array): FullPriceMessage {
- return {
- id: new anchor.BN(data.subarray(0, 8), "be"),
- price: new anchor.BN(data.subarray(8, 16), "be"),
- priceExpo: new anchor.BN(data.subarray(16, 24), "be"),
- ema: new anchor.BN(data.subarray(24, 32), "be"),
- emaExpo: new anchor.BN(data.subarray(32, 40), "be"),
- };
- }
- type CompactPriceMessage = {
- id: anchor.BN;
- price: anchor.BN;
- priceExpo: anchor.BN;
- };
- function parseCompactPriceMessage(data: Uint8Array): CompactPriceMessage {
- return {
- id: new anchor.BN(data.subarray(0, 8), "be"),
- price: new anchor.BN(data.subarray(8, 16), "be"),
- priceExpo: new anchor.BN(data.subarray(16, 24), "be"),
- };
- }
- // fetch MessageBuffer accounts using `getProgramAccounts` and memcmp filter
- async function getProgramAccountsForMessageBuffers(
- connection: anchor.web3.Connection
- ) {
- return await connection.getProgramAccounts(messageBufferProgram.programId, {
- filters: [
- {
- memcmp: {
- offset: 0,
- bytes: messageBufferDiscriminator,
- },
- },
- ],
- });
- }
|