gmsol_timelock/instructions/bypass/
set_expected_price_provider.rs

1use anchor_lang::prelude::*;
2use gmsol_store::{
3    cpi::{accounts::SetExpectedProvider, set_expected_provider},
4    program::GmsolStore,
5    states::{PriceProviderKind, RoleKey, Seed, MAX_ROLE_NAME_LEN},
6    utils::{fixed_str::fixed_str_to_bytes, CpiAuthentication, WithStore},
7    CoreError,
8};
9
10use crate::states::{Executor, ExecutorWalletSigner};
11
12/// The accounts definition for [`set_expected_price_provider`](crate::gmsol_timelock::set_expected_price_provider).
13#[derive(Accounts)]
14pub struct SetExpectedPriceProvider<'info> {
15    /// Authority.
16    pub authority: Signer<'info>,
17    /// Store.
18    /// CHECK: check by CPI.
19    #[account(mut)]
20    pub store: UncheckedAccount<'info>,
21    /// Token map.
22    /// CHECK: check by CPI.
23    #[account(mut)]
24    pub token_map: UncheckedAccount<'info>,
25    /// Executor.
26    #[account(
27        has_one = store,
28        constraint = executor.load()?.role_name()? == RoleKey::MARKET_KEEPER @ CoreError::InvalidArgument,
29        seeds = [
30            Executor::SEED,
31            store.key.as_ref(),
32            &fixed_str_to_bytes::<MAX_ROLE_NAME_LEN>(RoleKey::MARKET_KEEPER)?,
33        ],
34        bump = executor.load()?.bump,
35    )]
36    pub executor: AccountLoader<'info, Executor>,
37    /// Executor Wallet.
38    #[account(
39        mut,
40        seeds = [Executor::WALLET_SEED, executor.key().as_ref()],
41        bump,
42    )]
43    pub wallet: SystemAccount<'info>,
44    /// Token to update.
45    /// CHECK: only used as an identifier.
46    pub token: UncheckedAccount<'info>,
47    /// Store program.
48    pub store_program: Program<'info, GmsolStore>,
49    /// System program.
50    pub system_program: Program<'info, System>,
51}
52
53/// Revoke a role. This instruction will bypass the timelock check.
54/// # CHECK
55/// Only [`TIMELOCKED_MARKET_KEEPER`](crate::roles::TIMELOCKED_MARKET_KEEPER) can use.
56pub(crate) fn unchecked_set_expected_price_provider(
57    ctx: Context<SetExpectedPriceProvider>,
58    new_expected_price_provider: PriceProviderKind,
59) -> Result<()> {
60    let token = ctx.accounts.token.key;
61    let signer = ExecutorWalletSigner::new(ctx.accounts.executor.key(), ctx.bumps.wallet);
62    let ctx = ctx.accounts.set_expected_provider_ctx();
63
64    set_expected_provider(
65        ctx.with_signer(&[&signer.as_seeds()]),
66        *token,
67        new_expected_price_provider.into(),
68    )?;
69
70    Ok(())
71}
72
73impl<'info> WithStore<'info> for SetExpectedPriceProvider<'info> {
74    fn store_program(&self) -> AccountInfo<'info> {
75        self.store_program.to_account_info()
76    }
77
78    fn store(&self) -> AccountInfo<'info> {
79        self.store.to_account_info()
80    }
81}
82
83impl<'info> CpiAuthentication<'info> for SetExpectedPriceProvider<'info> {
84    fn authority(&self) -> AccountInfo<'info> {
85        self.authority.to_account_info()
86    }
87
88    fn on_error(&self) -> Result<()> {
89        err!(CoreError::PermissionDenied)
90    }
91}
92
93impl<'info> SetExpectedPriceProvider<'info> {
94    fn set_expected_provider_ctx(
95        &self,
96    ) -> CpiContext<'_, '_, '_, 'info, SetExpectedProvider<'info>> {
97        CpiContext::new(
98            self.store_program.to_account_info(),
99            SetExpectedProvider {
100                authority: self.wallet.to_account_info(),
101                store: self.store.to_account_info(),
102                token_map: self.token_map.to_account_info(),
103            },
104        )
105    }
106}