gmsol_timelock/instructions/
config.rs1use anchor_lang::prelude::*;
2use gmsol_store::{
3 program::GmsolStore,
4 states::{Seed, Store, MAX_ROLE_NAME_LEN},
5 utils::{fixed_str::fixed_str_to_bytes, CpiAuthenticate, CpiAuthentication, WithStore},
6 CoreError,
7};
8use gmsol_utils::InitSpace;
9
10use crate::{
11 roles,
12 states::{config::TimelockConfig, Executor, ExecutorWalletSigner},
13};
14
15#[derive(Accounts)]
17pub struct InitializeConfig<'info> {
18 #[account(mut)]
20 pub authority: Signer<'info>,
21 #[account(mut)]
24 pub store: AccountLoader<'info, Store>,
25 #[account(
27 init,
28 payer = authority,
29 space = 8 + TimelockConfig::INIT_SPACE,
30 seeds = [TimelockConfig::SEED, store.key().as_ref()],
31 bump,
32 )]
33 pub timelock_config: AccountLoader<'info, TimelockConfig>,
34 #[account(
36 has_one = store,
37 constraint = executor.load()?.role_name()? == roles::ADMIN @ CoreError::InvalidArgument,
38 seeds = [
39 Executor::SEED,
40 store.key().as_ref(),
41 &fixed_str_to_bytes::<MAX_ROLE_NAME_LEN>(roles::ADMIN)?,
42 ],
43 bump = executor.load()?.bump,
44 )]
45 pub executor: AccountLoader<'info, Executor>,
46 #[account(
48 seeds = [Executor::WALLET_SEED, executor.key().as_ref()],
49 bump,
50 )]
51 pub wallet: SystemAccount<'info>,
52 pub store_program: Program<'info, GmsolStore>,
54 pub system_program: Program<'info, System>,
56}
57
58pub(crate) fn unchecked_initialize_config(
62 ctx: Context<InitializeConfig>,
63 delay: u32,
64) -> Result<()> {
65 CpiAuthenticate::only(&ctx, roles::TIMELOCK_KEEPER)?;
67 CpiAuthenticate::only(&ctx, roles::TIMELOCKED_ADMIN)?;
70
71 let admin_executor_wallet_bump = ctx.bumps.wallet;
72
73 ctx.accounts
74 .accept_store_authority(admin_executor_wallet_bump)?;
75
76 ctx.accounts.timelock_config.load_init()?.init(
77 ctx.bumps.timelock_config,
78 delay,
79 ctx.accounts.store.key(),
80 );
81 msg!(
82 "[Timelock] Initialized timelock config with delay = {}",
83 delay
84 );
85 Ok(())
86}
87
88impl<'info> WithStore<'info> for InitializeConfig<'info> {
89 fn store_program(&self) -> AccountInfo<'info> {
90 self.store_program.to_account_info()
91 }
92
93 fn store(&self) -> AccountInfo<'info> {
94 self.store.to_account_info()
95 }
96}
97
98impl<'info> CpiAuthentication<'info> for InitializeConfig<'info> {
99 fn authority(&self) -> AccountInfo<'info> {
100 self.authority.to_account_info()
101 }
102
103 fn on_error(&self) -> Result<()> {
104 err!(CoreError::PermissionDenied)
105 }
106}
107
108impl InitializeConfig<'_> {
109 fn accept_store_authority(&self, admin_executor_wallet_bump: u8) -> Result<()> {
110 use gmsol_store::cpi::{accept_store_authority, accounts::AcceptStoreAuthority};
111
112 if !self.store.load()?.is_authority(self.wallet.key) {
113 let signer = ExecutorWalletSigner::new(self.executor.key(), admin_executor_wallet_bump);
114 accept_store_authority(
115 CpiContext::new(
116 self.store_program.to_account_info(),
117 AcceptStoreAuthority {
118 next_authority: self.wallet.to_account_info(),
119 store: self.store.to_account_info(),
120 },
121 )
122 .with_signer(&[&signer.as_seeds()]),
123 )?;
124 }
125
126 Ok(())
127 }
128}
129
130#[derive(Accounts)]
132pub struct IncreaseDelay<'info> {
133 #[account(mut)]
135 pub authority: Signer<'info>,
136 pub store: UncheckedAccount<'info>,
139 #[account(mut, has_one = store)]
140 pub timelock_config: AccountLoader<'info, TimelockConfig>,
141 pub store_program: Program<'info, GmsolStore>,
143}
144
145pub(crate) fn unchecked_increase_delay(ctx: Context<IncreaseDelay>, delta: u32) -> Result<()> {
149 require_neq!(delta, 0, CoreError::InvalidArgument);
150 let new_delay = ctx
151 .accounts
152 .timelock_config
153 .load_mut()?
154 .increase_delay(delta)?;
155 msg!(
156 "[Timelock] Timelock delay increased, new delay = {}",
157 new_delay
158 );
159 Ok(())
160}
161
162impl<'info> WithStore<'info> for IncreaseDelay<'info> {
163 fn store_program(&self) -> AccountInfo<'info> {
164 self.store_program.to_account_info()
165 }
166
167 fn store(&self) -> AccountInfo<'info> {
168 self.store.to_account_info()
169 }
170}
171
172impl<'info> CpiAuthentication<'info> for IncreaseDelay<'info> {
173 fn authority(&self) -> AccountInfo<'info> {
174 self.authority.to_account_info()
175 }
176
177 fn on_error(&self) -> Result<()> {
178 err!(CoreError::PermissionDenied)
179 }
180}