gmsol_treasury/instructions/
config.rs

1use anchor_lang::prelude::*;
2use gmsol_store::{
3    cpi::{accept_receiver, accounts::AcceptReceiver},
4    program::GmsolStore,
5    states::{Seed, Store},
6    utils::{CpiAuthentication, WithStore},
7};
8use gmsol_utils::InitSpace;
9
10use crate::{
11    constants,
12    states::{
13        config::{Config, ReceiverSigner},
14        treasury::TreasuryVaultConfig,
15    },
16};
17
18/// The accounts definition for [`initialize_config`](crate::gmsol_treasury::initialize_config).
19#[derive(Accounts)]
20pub struct InitializeConfig<'info> {
21    /// Payer.
22    #[account(mut)]
23    pub payer: Signer<'info>,
24    /// The store that controls this config.
25    #[account(mut)]
26    pub store: AccountLoader<'info, Store>,
27    /// The config account.
28    #[account(
29        init,
30        payer = payer,
31        space = 8 + Config::INIT_SPACE,
32        seeds = [Config::SEED, store.key().as_ref()],
33        bump,
34    )]
35    pub config: AccountLoader<'info, Config>,
36    /// Receiver.
37    #[account(
38        seeds = [constants::RECEIVER_SEED, config.key().as_ref()],
39        bump,
40    )]
41    pub receiver: SystemAccount<'info>,
42    /// The store program.
43    pub store_program: Program<'info, GmsolStore>,
44    /// The system program.
45    pub system_program: Program<'info, System>,
46}
47
48pub(crate) fn initialize_config(ctx: Context<InitializeConfig>) -> Result<()> {
49    let receiver_bump = ctx.bumps.receiver;
50
51    ctx.accounts.accept_receiver(receiver_bump)?;
52
53    let mut config = ctx.accounts.config.load_init()?;
54    let store = ctx.accounts.store.key();
55    config.init(ctx.bumps.config, receiver_bump, &store);
56
57    msg!("[Treasury] initialized the treasury config for {}", store);
58    Ok(())
59}
60
61impl InitializeConfig<'_> {
62    fn accept_receiver(&self, receiver_bump: u8) -> Result<()> {
63        if self.store.load()?.receiver() != self.receiver.key() {
64            let signer = ReceiverSigner::new(self.config.key(), receiver_bump);
65            accept_receiver(
66                CpiContext::new(
67                    self.store_program.to_account_info(),
68                    AcceptReceiver {
69                        next_receiver: self.receiver.to_account_info(),
70                        store: self.store.to_account_info(),
71                    },
72                )
73                .with_signer(&[&signer.as_seeds()]),
74            )?;
75        }
76        Ok(())
77    }
78}
79
80/// The accounts definition for [`set_treasury_vault_config`](crate::gmsol_treasury::set_treasury_vault_config).
81#[derive(Accounts)]
82pub struct SetTreasuryVaultConfig<'info> {
83    /// Authority.
84    pub authority: Signer<'info>,
85    /// Store.
86    /// CHECK: check by CPI.
87    pub store: UncheckedAccount<'info>,
88    /// Config to update.
89    #[account(mut, has_one = store)]
90    pub config: AccountLoader<'info, Config>,
91    /// Treasury vault config.
92    #[account(has_one = config)]
93    pub treasury_vault_config: AccountLoader<'info, TreasuryVaultConfig>,
94    /// Store program.
95    pub store_program: Program<'info, GmsolStore>,
96}
97
98/// Set treasury vault config address.
99/// # CHECK
100/// Only [`TREASURY_ADMIN`](crate::roles::TREASURY_ADMIN) can use.
101pub(crate) fn unchecked_set_treasury_vault_config(
102    ctx: Context<SetTreasuryVaultConfig>,
103) -> Result<()> {
104    let address = ctx.accounts.treasury_vault_config.key();
105    let previous = ctx
106        .accounts
107        .config
108        .load_mut()?
109        .set_treasury_vault_config(address)?;
110    msg!(
111        "[Treasury] the treasury address has been updated from {} to {}",
112        previous,
113        address
114    );
115    Ok(())
116}
117
118impl<'info> WithStore<'info> for SetTreasuryVaultConfig<'info> {
119    fn store_program(&self) -> AccountInfo<'info> {
120        self.store_program.to_account_info()
121    }
122
123    fn store(&self) -> AccountInfo<'info> {
124        self.store.to_account_info()
125    }
126}
127
128impl<'info> CpiAuthentication<'info> for SetTreasuryVaultConfig<'info> {
129    fn authority(&self) -> AccountInfo<'info> {
130        self.authority.to_account_info()
131    }
132
133    fn on_error(&self) -> Result<()> {
134        err!(gmsol_store::CoreError::PermissionDenied)
135    }
136}
137
138/// The accounts definition for updating [`Config`].
139#[derive(Accounts)]
140pub struct UpdateConfig<'info> {
141    /// Authority.
142    pub authority: Signer<'info>,
143    /// Store.
144    /// CHECK: check by CPI.
145    pub store: UncheckedAccount<'info>,
146    /// Config to update.
147    #[account(mut, has_one = store)]
148    pub config: AccountLoader<'info, Config>,
149    /// Store program.
150    pub store_program: Program<'info, GmsolStore>,
151}
152
153impl<'info> WithStore<'info> for UpdateConfig<'info> {
154    fn store_program(&self) -> AccountInfo<'info> {
155        self.store_program.to_account_info()
156    }
157
158    fn store(&self) -> AccountInfo<'info> {
159        self.store.to_account_info()
160    }
161}
162
163impl<'info> CpiAuthentication<'info> for UpdateConfig<'info> {
164    fn authority(&self) -> AccountInfo<'info> {
165        self.authority.to_account_info()
166    }
167
168    fn on_error(&self) -> Result<()> {
169        err!(gmsol_store::CoreError::PermissionDenied)
170    }
171}
172
173/// Set config's gt factor.
174/// # CHECK
175/// Only [`TREASURY_ADMIN`](crate::roles::TREASURY_ADMIN) can use.
176pub(crate) fn unchecked_set_gt_factor(ctx: Context<UpdateConfig>, factor: u128) -> Result<()> {
177    let previous = ctx.accounts.config.load_mut()?.set_gt_factor(factor)?;
178    msg!(
179        "[Treasury] the GT factor has been updated from {} to {}",
180        previous,
181        factor
182    );
183    Ok(())
184}
185
186/// Set config's buyback factor.
187/// # CHECK
188/// Only [`TREASURY_ADMIN`](crate::roles::TREASURY_ADMIN) can use.
189pub(crate) fn unchecked_set_buyback_factor(ctx: Context<UpdateConfig>, factor: u128) -> Result<()> {
190    let previous = ctx.accounts.config.load_mut()?.set_buyback_factor(factor)?;
191    msg!(
192        "[Treasury] the buyback factor has been updated from {} to {}",
193        previous,
194        factor
195    );
196    Ok(())
197}