Parcourir la source

feat(message-buffer): add init msg buffer pda to script, fix msg buffer pid (#845)

swimricky il y a 2 ans
Parent
commit
e670f57f89

+ 1 - 1
pythnet/message_buffer/Anchor.toml

@@ -2,7 +2,7 @@
 seeds = true
 skip-lint = false
 [programs.localnet]
-message_buffer = "Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM"
+message_buffer = "7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM"
 mock_cpi_caller = "Dg5PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [registry]

+ 3 - 1
pythnet/message_buffer/package.json

@@ -6,7 +6,9 @@
   },
   "dependencies": {
     "@coral-xyz/anchor": "^0.27.0",
-    "@lumina-dev/test": "^0.0.12"
+    "@lumina-dev/test": "^0.0.12",
+    "@pythnetwork/client": "^2.17.0",
+    "dotenv": "^16.0.3"
   },
   "devDependencies": {
     "@types/bn.js": "^5.1.0",

+ 1 - 1
pythnet/message_buffer/programs/message_buffer/src/lib.rs

@@ -12,7 +12,7 @@ use {
     state::*,
 };
 
-declare_id!("Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM");
+declare_id!("7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM");
 
 #[program]
 pub mod message_buffer {

+ 6 - 0
pythnet/message_buffer/scripts/.env.integration

@@ -0,0 +1,6 @@
+MESSAGE_BUFFER_PROGRAM_ID=BZZFM8qzdWvv4ysy8dxpAzjs9WJ6iy9y1ph2YNqWYzrm
+ORACLE_PROGRAM_ID=7th6GdMuo4u1zNLzFAyMY6psunHNsGjPjo8hXvcTgKei
+PAYER_KEYPAIR_PATH=/keys/funding.json
+CLUSTER=integration
+# 522 + 85(PriceFeedMessage) + 101(TwapMessage)
+INITIAL_SIZE=708

+ 6 - 0
pythnet/message_buffer/scripts/.env.local

@@ -0,0 +1,6 @@
+MESSAGE_BUFFER_PROGRAM_ID=BZZFM8qzdWvv4ysy8dxpAzjs9WJ6iy9y1ph2YNqWYzrm
+PAYER_KEYPAIR_PATH=/Users/rchen/.config/solana/id.json
+ENDPOINT=http://pythnet:8899
+CLUSTER=localnet
+# 522 + 85(PriceFeedMessage) + 101(TwapMessage)
+INITIAL_SIZE=708

+ 9 - 0
pythnet/message_buffer/scripts/.env.pythtest

@@ -0,0 +1,9 @@
+MESSAGE_BUFFER_PROGRAM_ID=7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM
+PAYER_KEYPAIR_PATH=<ABSOLUTE_PATH_TO_KEYPAIR>
+CLUSTER=pythtest-crosschain
+# Whitelist admin will be initialized to same as payer
+# then a separate txn will be used to set it to the following address
+# after the message buffers have been initialized
+# WHITELIST_ADMIN=D8y6qTbQeYQdyrgKUvZbsveQkfnUThRKZvewddr4SKNt # Pythtest Multisig authority address (PDA of executor)
+# 522 + 85(PriceFeedMessage) + 101(TwapMessage) + extra buffer
+INITIAL_SIZE=2048

+ 9 - 0
pythnet/message_buffer/scripts/.env.template

@@ -0,0 +1,9 @@
+MESSAGE_BUFFER_PROGRAM_ID=
+# absolute path to keypair
+PAYER_KEYPAIR_PATH=
+# 'devnet' | 'testnet' | 'mainnet-beta' |'integration' | 'pythtest-conformance' | 'pythnet' | 'localnet' | 'pythtest-crosschain';
+CLUSTER=
+# optional pubkey whitelist admin to set after initializing accounts
+# whitelist admin will initially be set to the payer
+WHITELIST_ADMIN=
+INITIAL_SIZE=

+ 303 - 104
pythnet/message_buffer/scripts/setup_message_buffer.ts

@@ -4,99 +4,214 @@ import { MessageBuffer } from "../target/types/message_buffer";
 import messageBuffer from "../target/idl/message_buffer.json";
 import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
 import { assert } from "chai";
+import { Connection, PublicKey } from "@solana/web3.js";
+import {
+  getPythClusterApiUrl,
+  getPythProgramKeyForCluster,
+  PythCluster,
+  parseBaseData,
+  AccountType,
+  parseProductData,
+} from "@pythnetwork/client";
 
+import path from "path";
+import dotenv from "dotenv";
+import fs from "fs";
+
+type PythClusterOrIntegration = PythCluster | "integration";
 /**
  * Script to initialize the message buffer program and whitelist admin
  * using the integration repo setup
+ *
+ * run using the following command:
+ * `NODE_ENV=<env> yarn ts-node scripts/setup_message_buffer.ts`
  */
+const MESSAGE = Buffer.from("message");
 
-const payer = anchor.web3.Keypair.fromSecretKey(
-  // Keypair at keys/funding.json
-  Uint8Array.from([
-    235, 245, 49, 124, 125, 91, 162, 107, 245, 83, 158, 7, 86, 181, 31, 252,
-    215, 200, 125, 25, 126, 55, 37, 240, 205, 171, 71, 196, 2, 11, 137, 229,
-    131, 30, 46, 220, 89, 75, 108, 173, 185, 146, 114, 253, 109, 67, 214, 133,
-    117, 79, 154, 107, 133, 193, 249, 251, 40, 171, 42, 191, 192, 60, 188, 78,
-  ])
-);
-const endpoint = "http://pythnet:8899";
-console.log(`connecting to ${endpoint}`);
-const commitment = "finalized";
-const provider = new anchor.AnchorProvider(
-  new anchor.web3.Connection(endpoint),
-  new NodeWallet(payer),
-  {
-    commitment,
-    preflightCommitment: commitment,
-    skipPreflight: true,
+function getPythClusterEndpoint(cluster: PythClusterOrIntegration): string {
+  if (cluster === "integration") {
+    return "http://pythnet:8899";
   }
-);
+  return getPythClusterApiUrl(cluster);
+}
 
-anchor.setProvider(provider);
-const messageBufferPid = new anchor.web3.PublicKey(
-  "BZZFM8qzdWvv4ysy8dxpAzjs9WJ6iy9y1ph2YNqWYzrm"
-);
+function getPythPidForCluster(
+  cluster: PythClusterOrIntegration
+): anchor.web3.PublicKey {
+  if (cluster === "integration") {
+    return new anchor.web3.PublicKey(
+      "7th6GdMuo4u1zNLzFAyMY6psunHNsGjPjo8hXvcTgKei"
+    );
+  } else {
+    return getPythProgramKeyForCluster(cluster);
+  }
+}
 
-const messageBufferProgram = new Program(
-  messageBuffer as Idl,
-  messageBufferPid,
-  provider
-) as unknown as Program<MessageBuffer>;
+const getKeypairFromFile = (keypairPath: string): anchor.web3.Keypair => {
+  const keypairBuffer = fs.readFileSync(keypairPath);
+  return anchor.web3.Keypair.fromSecretKey(
+    Uint8Array.from(JSON.parse(keypairBuffer.toString()))
+  );
+};
 
-const whitelistAdmin = payer;
+function getPythOracleCpiAuth(
+  messageBufferProgramId: anchor.web3.PublicKey,
+  pythOracleProgramId: anchor.web3.PublicKey
+): anchor.web3.PublicKey {
+  return anchor.web3.PublicKey.findProgramAddressSync(
+    [Buffer.from("upd_price_write"), messageBufferProgramId.toBuffer()],
+    pythOracleProgramId
+  )[0];
+}
 
-const MESSAGE = Buffer.from("message");
-const [whitelistPubkey, whitelistBump] =
-  anchor.web3.PublicKey.findProgramAddressSync(
-    [MESSAGE, Buffer.from("whitelist")],
-    messageBufferProgram.programId
+function getMessageBufferPubkey(
+  pythOracleCpiAuth: anchor.web3.PublicKey,
+  pythPriceAccountPk: anchor.web3.PublicKey,
+  messageBufferProgramId: anchor.web3.PublicKey
+): anchor.web3.PublicKey {
+  return anchor.web3.PublicKey.findProgramAddressSync(
+    [pythOracleCpiAuth.toBuffer(), MESSAGE, pythPriceAccountPk.toBuffer()],
+    messageBufferProgramId
+  )[0];
+}
+
+export async function getPriceAccountPubkeys(
+  connection: anchor.web3.Connection,
+  pythPublicKey: anchor.web3.PublicKey
+): Promise<PublicKey[]> {
+  const accountList = await connection.getProgramAccounts(
+    pythPublicKey,
+    connection.commitment
+  );
+  console.info(
+    `fetched ${
+      accountList.length
+    } programAccounts for pythProgram: ${pythPublicKey.toString()}`
   );
+  const priceAccountIds: PublicKey[] = [];
+  accountList.forEach((singleAccount) => {
+    const base = parseBaseData(singleAccount.account.data);
+    if (base) {
+      switch (base.type) {
+        case AccountType.Product:
+          const productData = parseProductData(singleAccount.account.data);
+          priceAccountIds.push(productData.priceAccountKey);
+          break;
+        default:
+          break;
+      }
+    }
+  });
+  return priceAccountIds;
+}
+
+async function main() {
+  let canAirdrop = false;
+  switch (process.env.NODE_ENV) {
+    case "local":
+      dotenv.config({ path: path.join(__dirname, ".env.local") });
+      canAirdrop = true;
+      break;
+    case "integration":
+      dotenv.config({ path: path.join(__dirname, ".env.integration") });
+      canAirdrop = true;
+      break;
+    case "pythtest":
+      dotenv.config({ path: path.join(__dirname, ".env.pythtest") });
+      break;
+    case "pythnet":
+      dotenv.config({ path: path.join(__dirname, ".env.pythnet") });
+      break;
+    default:
+      console.error(`Invalid NODE_ENV: ${process.env.NODE_ENV}`);
+      process.exit(1);
+  }
 
-const pythOraclePid = new anchor.web3.PublicKey(
-  "7th6GdMuo4u1zNLzFAyMY6psunHNsGjPjo8hXvcTgKei"
-);
+  const cluster = process.env.CLUSTER as PythClusterOrIntegration;
 
-const [pythOracleCpiAuth] = anchor.web3.PublicKey.findProgramAddressSync(
-  [Buffer.from("upd_price_write"), messageBufferProgram.programId.toBuffer()],
-  pythOraclePid
-);
+  const messageBufferPid = new anchor.web3.PublicKey(
+    process.env.MESSAGE_BUFFER_PROGRAM_ID
+  );
+  const pythOraclePid = getPythPidForCluster(cluster);
+  const payer = getKeypairFromFile(
+    path.resolve(process.env.PAYER_KEYPAIR_PATH)
+  );
+  const endpoint = getPythClusterEndpoint(cluster);
+  const initialSize = parseInt(process.env.INITIAL_SIZE || "", 10);
+  let whitelistAdmin = payer;
 
-const pythPriceAccountPk = new anchor.web3.PublicKey(
-  "tvNV74CEkyEhmzJYiXGgcTMLCSX8JDPVi3er5ZSTJn2"
-);
+  console.info(`
+        messageBufferPid: ${messageBufferPid.toString()}
+        pythOraclePid: ${pythOraclePid.toString()}
+        payer: ${payer.publicKey.toString()}
+        endpoint: ${endpoint}
+        whitelistAdmin: ${whitelistAdmin.publicKey.toString()}
+        initialSize: ${initialSize}
+    `);
 
-const [messageBufferPda, messageBufferBump] =
-  anchor.web3.PublicKey.findProgramAddressSync(
-    [pythOracleCpiAuth.toBuffer(), MESSAGE, pythPriceAccountPk.toBuffer()],
-    messageBufferProgram.programId
+  console.log(`connecting to ${endpoint}`);
+  const connection = new anchor.web3.Connection(endpoint);
+  const commitment = "finalized";
+
+  const provider = new anchor.AnchorProvider(
+    connection,
+    new NodeWallet(payer),
+    {
+      commitment,
+      preflightCommitment: commitment,
+      skipPreflight: true,
+    }
   );
 
-async function main() {
-  console.log("Initializing message buffer...");
+  anchor.setProvider(provider);
 
-  console.group();
-  console.log("Requesting airdrop");
+  const messageBufferProgram = new Program(
+    messageBuffer as Idl,
+    messageBufferPid,
+    provider
+  ) as unknown as Program<MessageBuffer>;
+
+  const [whitelistPubkey, whitelistBump] =
+    anchor.web3.PublicKey.findProgramAddressSync(
+      [MESSAGE, Buffer.from("whitelist")],
+      messageBufferProgram.programId
+    );
 
-  let airdropSig = await provider.connection.requestAirdrop(
-    payer.publicKey,
-    1 * anchor.web3.LAMPORTS_PER_SOL
+  const pythOracleCpiAuth = getPythOracleCpiAuth(
+    messageBufferProgram.programId,
+    pythOraclePid
   );
-  await provider.connection.confirmTransaction({
-    signature: airdropSig,
-    ...(await provider.connection.getLatestBlockhash()),
-  });
 
-  const payerBalance = await provider.connection.getBalance(payer.publicKey);
-  console.log(`payerBalance: ${payerBalance}`);
-  console.log("Airdrop complete");
-  console.groupEnd();
+  if (canAirdrop) {
+    console.group("Requesting airdrop");
+
+    let airdropSig = await provider.connection.requestAirdrop(
+      payer.publicKey,
+      1 * anchor.web3.LAMPORTS_PER_SOL
+    );
+    await provider.connection.confirmTransaction({
+      signature: airdropSig,
+      ...(await provider.connection.getLatestBlockhash()),
+    });
+
+    const payerBalance = await provider.connection.getBalance(payer.publicKey);
+    console.log(`payerBalance: ${payerBalance}`);
+    console.log("Airdrop complete");
+    console.groupEnd();
+  } else {
+    console.log("Skipping airdrop for non-local/integration environments");
+  }
+
+  console.log("Initializing message buffer whitelist admin...");
 
   let whitelist = await messageBufferProgram.account.whitelist.fetchNullable(
     whitelistPubkey
   );
 
   if (whitelist === null) {
-    console.group("No whitelist detected. Initializing message buffer");
+    console.group(
+      "No whitelist detected. Initializing message buffer whitelist & admin"
+    );
     const initializeTxnSig = await messageBufferProgram.methods
       .initialize()
       .accounts({
@@ -148,50 +263,134 @@ async function main() {
     console.log("Allowed Programs already set");
   }
 
-  let messageBufferData = await getMessageBuffer(
-    provider.connection,
-    messageBufferPda
+  let priceIds = await getPriceAccountPubkeys(connection, pythOraclePid);
+  console.info(`fetched ${priceIds.length} priceAccountIds`);
+  let errorAccounts = [];
+  let alreadyInitializedAccounts = [];
+  let newlyInitializedAccounts = [];
+
+  const messageBufferKeys = priceIds.map((priceId) => {
+    return {
+      messageBufferKey: getMessageBufferPubkey(
+        pythOracleCpiAuth,
+        priceId,
+        messageBufferPid
+      ),
+      priceAccountKey: priceId,
+    };
+  });
+
+  let accounts = await messageBufferProgram.account.messageBuffer.fetchMultiple(
+    messageBufferKeys.map((k) => k.messageBufferKey)
   );
-  if (messageBufferData === null) {
-    console.group("Creating Message Buffer");
-    const msgBufferPdaMetas = [
-      {
-        pubkey: messageBufferPda,
-        isSigner: false,
-        isWritable: true,
-      },
-    ];
-
-    await messageBufferProgram.methods
-      .createBuffer(pythOracleCpiAuth, pythPriceAccountPk, 1024 * 8)
-      .accounts({
-        whitelist: whitelistPubkey,
-        admin: whitelistAdmin.publicKey,
-        systemProgram: anchor.web3.SystemProgram.programId,
-      })
-      .signers([whitelistAdmin])
-      .remainingAccounts(msgBufferPdaMetas)
-      .rpc({ skipPreflight: true });
 
-    console.log("fetching messageBuffer");
-    const messageBufferData = await getMessageBuffer(
-      provider.connection,
-      messageBufferPda
+  const msgBufferKeysAndData = messageBufferKeys.map((k, i) => {
+    return {
+      ...k,
+      messageBufferData: accounts[i],
+    };
+  });
+
+  alreadyInitializedAccounts = msgBufferKeysAndData.filter((idAndAccount) => {
+    return idAndAccount.messageBufferData !== null;
+  });
+
+  console.log(`
+  ${
+    alreadyInitializedAccounts.length
+  } message buffer accounts already initialized.
+  alreadyInitializedAccounts: ${JSON.stringify(alreadyInitializedAccounts)}`);
+
+  const priceAccountPubkeysForNewlyInitializedMessageBuffers =
+    msgBufferKeysAndData.filter((idAndAccount) => {
+      return idAndAccount.messageBufferData === null;
+    });
+
+  if (priceAccountPubkeysForNewlyInitializedMessageBuffers.length === 0) {
+    console.info(`no new message buffers to initialize. exiting...`);
+    process.exit(1);
+  }
+  // TODO: optimize with batching
+  await Promise.all(
+    priceAccountPubkeysForNewlyInitializedMessageBuffers.map(
+      async (idAndAccount) => {
+        const priceId = idAndAccount.priceAccountKey;
+        const messageBufferPda = idAndAccount.messageBufferKey;
+        const msgBufferPdaMetas = [
+          {
+            pubkey: messageBufferPda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ];
+
+        try {
+          await messageBufferProgram.methods
+            .createBuffer(pythOracleCpiAuth, priceId, initialSize)
+            .accounts({
+              whitelist: whitelistPubkey,
+              admin: whitelistAdmin.publicKey,
+              systemProgram: anchor.web3.SystemProgram.programId,
+            })
+            .signers([whitelistAdmin])
+            .remainingAccounts(msgBufferPdaMetas)
+            .rpc({ skipPreflight: true });
+          newlyInitializedAccounts.push({
+            priceId: priceId.toString(),
+            messageBuffer: messageBufferPda.toString(),
+          });
+        } catch (e) {
+          console.error(
+            "Error creating message buffer for price account: ",
+            priceId.toString()
+          );
+          console.error(e);
+          errorAccounts.push({
+            priceId: priceId.toString(),
+            messageBuffer: messageBufferPda.toString(),
+          });
+        }
+      }
+    )
+  );
+  if (errorAccounts.length !== 0) {
+    console.error(
+      `Ran into errors when initializing ${errorAccounts.length} accounts`
     );
-    console.log(`messageBufferData: ${messageBufferData.toString("utf-8")}`);
-    console.groupEnd();
-  } else {
-    console.log("Message Buffer already created");
-    console.log(`messageBufferData: ${messageBufferData.toString("utf-8")}`);
+    console.info(`Accounts with errors: ${JSON.stringify(errorAccounts)}`);
   }
-}
+  console.log(`Initialized ${newlyInitializedAccounts.length} accounts`);
 
-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;
+  // Update whitelist admin at the end otherwise all the message buffer PDAs
+  // will have to be initialized by the whitelist admin (which could be the multisig)
+  if (process.env.WHITELIST_ADMIN) {
+    whitelist = await messageBufferProgram.account.whitelist.fetchNullable(
+      whitelistPubkey
+    );
+    let newWhitelistAdmin = new anchor.web3.PublicKey(
+      process.env.WHITELIST_ADMIN
+    );
+    if (!whitelist.admin.equals(newWhitelistAdmin)) {
+      console.info(
+        `updating whitelist admin from ${whitelist.admin.toString()} to ${newWhitelistAdmin.toString()}`
+      );
+      try {
+        await messageBufferProgram.methods
+          .updateWhitelistAdmin(newWhitelistAdmin)
+          .accounts({
+            admin: whitelistAdmin.publicKey,
+          })
+          .signers([whitelistAdmin])
+          .rpc();
+      } catch (e) {
+        console.error(`Error when attempting to update the admin: ${e}`);
+      }
+    } else {
+      console.info(
+        `whitelist admin is already ${newWhitelistAdmin.toString()}`
+      );
+    }
+  }
 }
 
 void main();

+ 44 - 1
pythnet/message_buffer/yarn.lock

@@ -30,6 +30,27 @@
   dependencies:
     regenerator-runtime "^0.13.11"
 
+"@coral-xyz/anchor@^0.26.0":
+  version "0.26.0"
+  resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.26.0.tgz#c8e4f7177e93441afd030f22d777d54d0194d7d1"
+  integrity sha512-PxRl+wu5YyptWiR9F2MBHOLLibm87Z4IMUBPreX+DYBtPM+xggvcPi0KAN7+kIL4IrIhXI8ma5V0MCXxSN1pHg==
+  dependencies:
+    "@coral-xyz/borsh" "^0.26.0"
+    "@solana/web3.js" "^1.68.0"
+    base64-js "^1.5.1"
+    bn.js "^5.1.2"
+    bs58 "^4.0.1"
+    buffer-layout "^1.2.2"
+    camelcase "^6.3.0"
+    cross-fetch "^3.1.5"
+    crypto-hash "^1.3.0"
+    eventemitter3 "^4.0.7"
+    js-sha256 "^0.9.0"
+    pako "^2.0.3"
+    snake-case "^3.0.4"
+    superstruct "^0.15.4"
+    toml "^3.0.0"
+
 "@coral-xyz/anchor@^0.27.0":
   version "0.27.0"
   resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.27.0.tgz#621e5ef123d05811b97e49973b4ed7ede27c705c"
@@ -51,6 +72,14 @@
     superstruct "^0.15.4"
     toml "^3.0.0"
 
+"@coral-xyz/borsh@^0.26.0":
+  version "0.26.0"
+  resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.26.0.tgz#d054f64536d824634969e74138f9f7c52bbbc0d5"
+  integrity sha512-uCZ0xus0CszQPHYfWAqKS5swS1UxvePu83oOF+TWpUkedsNlg6p2p4azxZNSSqwXb9uXMFgxhuMBX9r3Xoi0vQ==
+  dependencies:
+    bn.js "^5.1.2"
+    buffer-layout "^1.2.0"
+
 "@coral-xyz/borsh@^0.27.0":
   version "0.27.0"
   resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.27.0.tgz#700c647ea5262b1488957ac7fb4e8acf72c72b63"
@@ -107,6 +136,15 @@
     "@nodelib/fs.scandir" "2.1.5"
     fastq "^1.6.0"
 
+"@pythnetwork/client@^2.17.0":
+  version "2.17.0"
+  resolved "https://registry.yarnpkg.com/@pythnetwork/client/-/client-2.17.0.tgz#b155af06958f4b729bfee1c07130c556598cf168"
+  integrity sha512-hv285vehmLH6N762Z4jqvPTM+hCYnXQaUp6DMgLUpDHvE0mTbwW9PvlxYoUJZGtyeCDkgn9HrTWXPtnaXTRr+Q==
+  dependencies:
+    "@coral-xyz/anchor" "^0.26.0"
+    "@coral-xyz/borsh" "^0.26.0"
+    buffer "^6.0.1"
+
 "@solana/buffer-layout@^4.0.0":
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15"
@@ -439,7 +477,7 @@ buffer@6.0.1:
     base64-js "^1.3.1"
     ieee754 "^1.2.1"
 
-buffer@~6.0.3:
+buffer@^6.0.1, buffer@~6.0.3:
   version "6.0.3"
   resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
   integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
@@ -728,6 +766,11 @@ dot-case@^3.0.4:
     no-case "^3.0.4"
     tslib "^2.0.3"
 
+dotenv@^16.0.3:
+  version "16.0.3"
+  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
+  integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
+
 duplexer@^0.1.2:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"

+ 4 - 4
pythnet/pythnet_sdk/src/lib.rs

@@ -7,10 +7,10 @@ pub(crate) type Pubkey = [u8; 32];
 pub(crate) type PriceId = Pubkey;
 
 /// Official Message Buffer Program Id
-/// pubkey!("Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM");
+/// pubkey!("7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM");
 pub const MESSAGE_BUFFER_PID: Pubkey = [
-    7, 83, 149, 9, 30, 102, 77, 194, 50, 151, 133, 40, 118, 10, 93, 152, 174, 44, 244, 56, 27, 47,
-    234, 218, 173, 153, 254, 48, 102, 178, 128, 18,
+    96, 121, 180, 39, 141, 35, 152, 85, 128, 70, 147, 124, 128, 196, 115, 241, 86, 159, 207, 148,
+    39, 234, 137, 86, 178, 4, 238, 48, 102, 178, 128, 18,
 ];
 
 /// Pubkey::find_program_address(&[b"emitter"], &sysvar::accumulator::id());
@@ -99,7 +99,7 @@ pub(crate) mod tests {
             pythtest_accumulator_sequence_address.to_bytes()
         );
 
-        let message_buffer_program = pubkey!("Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM");
+        let message_buffer_program = pubkey!("7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM");
         assert_eq!(MESSAGE_BUFFER_PID, message_buffer_program.to_bytes());
     }
 }