0

I am writing a smart contract that take price values from a switchboard(Oracle Service) save these prices in vec and calculate volatility but everytime I run test on smart contract it reset vector length to zero

#[program]
pub mod volatility {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let volatility_account = &mut ctx.accounts.volatility_account;
        volatility_account.total = volatility_account.prices.len() as u64;
        msg!("Total Prices {}!", volatility_account.total);
        Ok(())
    }

    pub fn add_price(ctx: Context<AddPrice>) -> Result<()> {
        let volatility_account = &mut ctx.accounts.volatility_account;
        let feed = &ctx.accounts.aggregator.load()?;
        let val: f64 = feed.get_result()?.try_into()?;
        volatility_account.prices.push(val);
        volatility_account.total = volatility_account.prices.len() as u64;
        msg!("Current feed result is {}!", val);
        msg!("Total Prices {}!", volatility_account.total);
        Ok(())
    }

    pub fn calculate_volatility(ctx: Context<CalculateVolatility>) -> Result<()> {
        let volatility_account = &mut ctx.accounts.volatility_account;
        let mut sum: f64 = 0.0;
        for price in &volatility_account.prices {
            sum = sum + price;
        }
        let mean = sum / volatility_account.prices.len() as f64;
        let mut square_sum: f64 = 0.0;
        for price in &volatility_account.prices {
            square_sum = square_sum + (price - mean).mul(price - mean);
        }

        let variance = square_sum / (volatility_account.prices.len() - 1) as f64;
        let standard_deviation = f64::sqrt(variance);
        let volatility = standard_deviation.mul(f64::sqrt(volatility_account.prices.len() as f64));

        volatility_account.volatility = volatility;
        msg!("Volatility is {}!", volatility);
        msg!("Total Prices {}!", volatility_account.prices.len());
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(
    init,
    payer = user,
    space = 200000
    )]
    pub volatility_account: Account<'info, Volatility>,

    #[account(mut)]
    pub user: Signer<'info>,

    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct AddPrice<'info> {
    #[account(
    constraint =
    *aggregator.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ FeedErrorCode::InvalidSwitchboardAccount
    )]
    pub aggregator: AccountLoader<'info, AggregatorAccountData>,

    #[account(mut)]
    pub volatility_account: Account<'info, Volatility>,
}

#[derive(Accounts)]
pub struct CalculateVolatility<'info> {
    #[account(mut)]
    pub volatility_account: Account<'info, Volatility>,
}

#[account]
pub struct Volatility {
    pub prices: Vec<f64>,
    pub total: u64,
    pub volatility: f64,
}

and test I have written is below

describe("volatility", () => {
    // Configure the client to use the local cluster.
    const provider = anchor.AnchorProvider.env()
    anchor.setProvider(provider);

    const BTC_PRICE_FEED = new PublicKey(
        "uXp9uaJFFPiQQmPH4UaXTWfeV9M59AvGwNSS6BppbQ3"
    );
    const PROGRAM_ID = new PublicKey(
        "FKLzkEN4iBf9dPFuxUjvVFZGtEqYXLZgdFn9hxa2sKKq"
    );

    const program = new anchor.Program(
        IDL,
        PROGRAM_ID,
        provider,
        new anchor.BorshCoder(IDL)
    ) as anchor.Program<Volatility>;

    const volatilityKeypair = anchor.web3.Keypair.generate();


    it("Is initialized!", async () => {
        // The Account to create.

        // Create the new account and initialize it with the program.
        const signature = await program.methods
            .initialize()
            .accounts({
                volatilityAccount: volatilityKeypair.publicKey,
                user: provider.wallet.publicKey,
                systemProgram: anchor.web3.SystemProgram.programId,
            })
            .signers([volatilityKeypair])
            .rpc();

        const logs = await provider.connection.getParsedTransaction(
            signature,
            "confirmed"
        );

        console.log(JSON.stringify(logs?.meta?.logMessages, undefined, 2));
    });

     it("Add 1st price", async () => {
         const signature = await program.methods
             .addPrice()
             .accounts({
                 aggregator: BTC_PRICE_FEED,
                 volatilityAccount: volatilityKeypair.publicKey,
             })
             .rpc();

         const logs = await provider.connection.getParsedTransaction(
             signature,
             "confirmed"
         );

         console.log(JSON.stringify(logs?.meta?.logMessages, undefined, 2));
     });

    it("Add 2nd price", async () => {
        const signature = await program.methods
            .addPrice()
            .accounts({
                aggregator: BTC_PRICE_FEED,
                volatilityAccount: volatilityKeypair.publicKey,
            })
            .rpc();

        const logs = await provider.connection.getParsedTransaction(
            signature,
            "confirmed"
        );

        console.log(JSON.stringify(logs?.meta?.logMessages, undefined, 2));
    });

    it("Add 3rd price", async () => {
        const signature = await program.methods
            .addPrice()
            .accounts({
                aggregator: BTC_PRICE_FEED,
                volatilityAccount: volatilityKeypair.publicKey,
            })
            .rpc();

        const logs = await provider.connection.getParsedTransaction(
            signature,
            "confirmed"
        );

        console.log(JSON.stringify(logs?.meta?.logMessages, undefined, 2));
    });

    it("Calculate volatility", async () => {
        const signature = await program.methods
               .calculateVolatility()
               .accounts({
                   volatilityAccount: volatilityKeypair.publicKey,
               })
               .rpc();


        const logs = await provider.connection.getParsedTransaction(
            signature,
            "confirmed"
        );

        console.log(JSON.stringify(logs?.meta?.logMessages, undefined, 2));
       });

     /*it("Can read feed", async () => {
         const signature = await program.methods
             .readResult({maxConfidenceInterval: 0.25})
             .accounts({
                 aggregator: BTC_PRICE_FEED
             })
             .rpc();
         const logs = await provider.connection.getParsedTransaction(
             signature,
             "confirmed"
         );

         console.log(JSON.stringify(logs?.meta?.logMessages, undefined, 2));
     });*/
});

Link for github repo Solana Volatility

I want to add functionality when every I call add_price method it update and add new value in price vector and that array will be used in calculate_volatility methods.

1
  • Do you mean that between add 1st, add 2nd... It always logs "Current feed result is 0!" ?
    – Arowana
    Commented Nov 24, 2022 at 8:38

2 Answers 2

0

Not typically a good idea to use a Vec for your on-chain structs because it occupies an unknown amount of space. Better to use a fixed size array like: pub prices: [u64; 20],

You can insert with something like:

    let mut idx = 0;
    while idx < prices_len {
        if prices[idx] == 0 {
           break;
        }
        idx += 1;
    }
    // Insert at idx, or do whatever you want to do when the array is full.

On the front end this can annoying because it must initialized an array of 20 BN.

1
  • ok but why that vector size is zero every time I run the test
    – rana_sadam
    Commented Nov 22, 2022 at 10:36
0
const volatilityKeypair = anchor.web3.Keypair.generate();

This line is problem everytime I create a new keypair and previous data is lost now I have used a keypair and save in json file now the problem is solved for reference please check code repo solana contract

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.