Просмотр исходного кода

feat(accumulator-updater): add funding account for AccumulatorInput creation (#771)

swimricky 2 лет назад
Родитель
Сommit
9fea461174

+ 27 - 7
accumulator_updater/programs/accumulator_updater/src/instructions/put_all.rs

@@ -14,6 +14,7 @@ use {
 
 
 pub const ACCUMULATOR: &[u8; 11] = b"accumulator";
+pub const FUND: &[u8; 4] = b"fund";
 
 pub fn put_all<'info>(
     ctx: Context<'_, '_, '_, 'info, PutAll<'info>>,
@@ -39,17 +40,23 @@ pub fn put_all<'info>(
                 &crate::ID,
             );
             require_keys_eq!(accumulator_input_ai.key(), pda);
-            let signer_seeds = &[
+            let signer_seeds = [
                 cpi_caller.as_ref(),
                 ACCUMULATOR.as_ref(),
                 base_account_key.as_ref(),
                 &[bump],
             ];
+            let fund_pda_bump = *ctx
+                .bumps
+                .get("fund")
+                .ok_or(AccumulatorUpdaterError::FundBumpNotFound)?;
+            let fund_signer_seeds = [ACCUMULATOR.as_ref(), FUND.as_ref(), &[fund_pda_bump]];
             PutAll::create_account(
                 accumulator_input_ai,
                 8 + AccumulatorInput::INIT_SPACE,
-                &ctx.accounts.payer,
-                signer_seeds,
+                &ctx.accounts.fund,
+                // seeds,
+                &[signer_seeds.as_slice(), fund_signer_seeds.as_slice()],
                 &ctx.accounts.system_program,
             )?;
             loader = AccountLoader::<AccumulatorInput>::try_from_unchecked(
@@ -86,22 +93,35 @@ pub fn is_uninitialized_account(ai: &AccountInfo) -> bool {
     ai.data_is_empty() && ai.owner == &system_program::ID
 }
 
+
 #[derive(Accounts)]
 #[instruction( base_account_key: Pubkey)]
 pub struct PutAll<'info> {
-    #[account(mut)]
-    pub payer:              Signer<'info>,
+    /// `Fund` is a system account that holds
+    /// the lamports that will be used to fund
+    /// `AccumulatorInput` account initialization
+    #[account(
+        mut,
+        seeds = [
+            b"accumulator".as_ref(),
+            b"fund".as_ref(),
+        ],
+        owner = system_program::System::id(),
+        bump,
+    )]
+    pub fund:               SystemAccount<'info>,
     pub whitelist_verifier: WhitelistVerifier<'info>,
     pub system_program:     Program<'info, System>,
     // remaining_accounts:  - [AccumulatorInput PDA]
 }
 
+
 impl<'info> PutAll<'info> {
     fn create_account<'a>(
         account_info: &AccountInfo<'a>,
         space: usize,
         payer: &AccountInfo<'a>,
-        seeds: &[&[u8]],
+        seeds: &[&[&[u8]]],
         system_program: &AccountInfo<'a>,
     ) -> Result<()> {
         let lamports = Rent::get()?.minimum_balance(space);
@@ -113,7 +133,7 @@ impl<'info> PutAll<'info> {
                     from: payer.to_account_info(),
                     to:   account_info.to_account_info(),
                 },
-                &[seeds],
+                seeds,
             ),
             lamports,
             space.try_into().unwrap(),

+ 3 - 2
accumulator_updater/programs/accumulator_updater/src/lib.rs

@@ -88,8 +88,7 @@ pub mod accumulator_updater {
 #[derive(Accounts)]
 pub struct Initialize<'info> {
     #[account(mut)]
-    pub payer: Signer<'info>,
-
+    pub payer:          Signer<'info>,
     #[account(
         init,
         payer = payer,
@@ -142,4 +141,6 @@ pub enum AccumulatorUpdaterError {
     AccumulatorInputNotWritable,
     #[msg("Accumulator Input not provided")]
     AccumulatorInputNotProvided,
+    #[msg("Fund Bump not found")]
+    FundBumpNotFound,
 }

+ 2 - 0
accumulator_updater/programs/accumulator_updater/src/state/accumulator_input.rs

@@ -6,6 +6,7 @@ use {
     anchor_lang::prelude::*,
 };
 
+
 /// `AccumulatorInput` is an arbitrary set of bytes
 /// that will be included in the AccumulatorSysvar
 ///
@@ -42,6 +43,7 @@ pub struct AccumulatorHeader {
     pub end_offsets: [u16; 255], // 510
 }
 
+
 impl AccumulatorHeader {
     // HEADER_LEN allows for append-only forward-compatibility for the header.
     // this is the number of bytes from the beginning of the account_info.data

+ 3 - 1
accumulator_updater/programs/mock-cpi-caller/src/instructions/add_price.rs

@@ -61,7 +61,7 @@ impl<'info> AddPrice<'info> {
         inputs: Vec<Vec<u8>>,
     ) -> anchor_lang::Result<()> {
         let mut accounts = vec![
-            AccountMeta::new(ctx.accounts.payer.key(), true),
+            AccountMeta::new(ctx.accounts.fund.key(), false),
             AccountMeta::new_readonly(ctx.accounts.accumulator_whitelist.key(), false),
             AccountMeta::new_readonly(ctx.accounts.ixs_sysvar.key(), false),
             AccountMeta::new_readonly(ctx.accounts.system_program.key(), false),
@@ -113,6 +113,8 @@ pub struct AddPrice<'info> {
     pub pyth_price_account:    AccountLoader<'info, PriceAccount>,
     #[account(mut)]
     pub payer:                 Signer<'info>,
+    #[account(mut)]
+    pub fund:                  SystemAccount<'info>,
     /// also needed for accumulator_updater
     pub system_program:        Program<'info, System>,
     /// CHECK: whitelist

+ 4 - 2
accumulator_updater/programs/mock-cpi-caller/src/instructions/update_price.rs

@@ -45,8 +45,10 @@ pub struct UpdatePrice<'info> {
     bump,
     )]
     pub pyth_price_account:    AccountLoader<'info, PriceAccount>,
+    // #[account(mut)]
+    // pub payer:                 Signer<'info>,
     #[account(mut)]
-    pub payer:                 Signer<'info>,
+    pub fund:                  SystemAccount<'info>,
     /// Needed for accumulator_updater
     pub system_program:        Program<'info, System>,
     /// CHECK: whitelist
@@ -91,7 +93,7 @@ impl<'info> UpdatePrice<'info> {
         values: Vec<Vec<u8>>,
     ) -> anchor_lang::Result<()> {
         let mut accounts = vec![
-            AccountMeta::new(ctx.accounts.payer.key(), true),
+            AccountMeta::new(ctx.accounts.fund.key(), false),
             AccountMeta::new_readonly(ctx.accounts.accumulator_whitelist.key(), false),
             AccountMeta::new_readonly(ctx.accounts.ixs_sysvar.key(), false),
             AccountMeta::new_readonly(ctx.accounts.system_program.key(), false),

+ 14 - 0
accumulator_updater/tests/accumulator_updater.ts

@@ -15,6 +15,10 @@ const accumulatorUpdaterProgram = anchor.workspace
   .AccumulatorUpdater as Program<AccumulatorUpdater>;
 const mockCpiProg = anchor.workspace.MockCpiCaller as Program<MockCpiCaller>;
 let whitelistAuthority = anchor.web3.Keypair.generate();
+const [fundPda] = anchor.web3.PublicKey.findProgramAddressSync(
+  [Buffer.from("accumulator"), Buffer.from("fund")],
+  accumulatorUpdaterProgram.programId
+);
 
 const pythPriceAccountId = new anchor.BN(1);
 const addPriceParams = {
@@ -33,6 +37,7 @@ const [pythPriceAccountPk] = anchor.web3.PublicKey.findProgramAddressSync(
   mockCpiProg.programId
 );
 
+let fundBalance = 100 * anchor.web3.LAMPORTS_PER_SOL;
 describe("accumulator_updater", () => {
   // Configure the client to use the local cluster.
   let provider = anchor.AnchorProvider.env();
@@ -44,6 +49,10 @@ describe("accumulator_updater", () => {
       accumulatorUpdaterProgram.programId
     );
 
+  before("transfer lamports to the fund", async () => {
+    await provider.connection.requestAirdrop(fundPda, fundBalance);
+  });
+
   it("Is initialized!", async () => {
     // Add your test here.
     const tx = await accumulatorUpdaterProgram.methods
@@ -104,6 +113,7 @@ describe("accumulator_updater", () => {
     const mockCpiCallerAddPriceTxPubkeys = await mockCpiProg.methods
       .addPrice(addPriceParams)
       .accounts({
+        fund: fundPda,
         systemProgram: anchor.web3.SystemProgram.programId,
         ixsSysvar: anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY,
         accumulatorWhitelist: whitelistPubkey,
@@ -219,6 +229,9 @@ describe("accumulator_updater", () => {
     accumulatorAccounts
       .map((a) => a.toString())
       .includes(accumulatorPdaKey.toString());
+
+    const fundBalanceAfter = await provider.connection.getBalance(fundPda);
+    assert.isTrue(fundBalance > fundBalanceAfter);
   });
 
   it("Mock CPI Program - UpdatePrice", async () => {
@@ -233,6 +246,7 @@ describe("accumulator_updater", () => {
     await mockCpiProg.methods
       .updatePrice(updatePriceParams)
       .accounts({
+        fund: fundPda,
         pythPriceAccount: pythPriceAccountPk,
         ixsSysvar: anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY,
         accumulatorWhitelist: whitelistPubkey,