gmsol_treasury/instructions/
store.rs1use anchor_lang::prelude::*;
2use anchor_spl::{
3 associated_token::AssociatedToken,
4 token_interface::{Mint, TokenAccount, TokenInterface},
5};
6use gmsol_store::{
7 cpi::{
8 accounts::{ClaimFeesFromMarket, ConfigurateGt, TransferReceiver as StoreTransferReceiver},
9 claim_fees_from_market, gt_set_referral_reward_factors, transfer_receiver,
10 },
11 program::GmsolStore,
12 utils::{CpiAuthentication, WithStore},
13 CoreError,
14};
15
16use crate::{
17 constants,
18 states::{config::ReceiverSigner, Config},
19};
20
21#[derive(Accounts)]
23pub struct TransferReceiver<'info> {
24 #[account(mut)]
26 pub authority: Signer<'info>,
27 #[account(mut)]
30 pub store: UncheckedAccount<'info>,
31 #[account(has_one = store)]
33 pub config: AccountLoader<'info, Config>,
34 #[account(
36 seeds = [constants::RECEIVER_SEED, config.key().as_ref()],
37 bump = config.load()?.receiver_bump,
38 )]
39 pub receiver: SystemAccount<'info>,
40 pub next_receiver: UncheckedAccount<'info>,
43 pub store_program: Program<'info, GmsolStore>,
45 pub system_program: Program<'info, System>,
47}
48
49pub(crate) fn unchecked_transfer_receiver(ctx: Context<TransferReceiver>) -> Result<()> {
53 let config = &ctx.accounts.config;
54 let signer = ReceiverSigner::new(config.key(), config.load()?.receiver_bump);
55 let cpi_ctx = ctx.accounts.set_receiver_ctx();
56 transfer_receiver(cpi_ctx.with_signer(&[&signer.as_seeds()]))?;
57 Ok(())
58}
59
60impl<'info> WithStore<'info> for TransferReceiver<'info> {
61 fn store_program(&self) -> AccountInfo<'info> {
62 self.store_program.to_account_info()
63 }
64
65 fn store(&self) -> AccountInfo<'info> {
66 self.store.to_account_info()
67 }
68}
69
70impl<'info> CpiAuthentication<'info> for TransferReceiver<'info> {
71 fn authority(&self) -> AccountInfo<'info> {
72 self.authority.to_account_info()
73 }
74
75 fn on_error(&self) -> Result<()> {
76 err!(CoreError::PermissionDenied)
77 }
78}
79
80impl<'info> TransferReceiver<'info> {
81 fn set_receiver_ctx(&self) -> CpiContext<'_, '_, '_, 'info, StoreTransferReceiver<'info>> {
82 CpiContext::new(
83 self.store_program.to_account_info(),
84 StoreTransferReceiver {
85 authority: self.receiver.to_account_info(),
86 store: self.store.to_account_info(),
87 next_receiver: self.next_receiver.to_account_info(),
88 },
89 )
90 }
91}
92
93#[derive(Accounts)]
95pub struct ClaimFees<'info> {
96 #[account(mut)]
98 pub authority: Signer<'info>,
99 pub store: UncheckedAccount<'info>,
102 #[account(has_one = store)]
104 pub config: AccountLoader<'info, Config>,
105 #[account(
107 seeds = [constants::RECEIVER_SEED, config.key().as_ref()],
108 bump = config.load()?.receiver_bump,
109 )]
110 pub receiver: SystemAccount<'info>,
111 #[account(mut)]
114 pub market: UncheckedAccount<'info>,
115 pub token: InterfaceAccount<'info, Mint>,
117 #[account(mut)]
120 pub vault: UncheckedAccount<'info>,
121 #[account(
123 init_if_needed,
124 payer = authority,
125 associated_token::authority = receiver,
126 associated_token::mint = token,
127 )]
128 pub receiver_vault: InterfaceAccount<'info, TokenAccount>,
129 pub event_authority: UncheckedAccount<'info>,
132 pub store_program: Program<'info, GmsolStore>,
134 pub token_program: Interface<'info, TokenInterface>,
136 pub associated_token_program: Program<'info, AssociatedToken>,
138 pub system_program: Program<'info, System>,
140}
141
142pub(crate) fn unchecked_claim_fees(ctx: Context<ClaimFees>, min_amount: u64) -> Result<()> {
146 let config = &ctx.accounts.config;
147 let signer = ReceiverSigner::new(config.key(), config.load()?.receiver_bump);
148 let cpi_ctx = ctx.accounts.claim_fees_from_market_ctx();
149 let amount = claim_fees_from_market(cpi_ctx.with_signer(&[&signer.as_seeds()]))?;
150
151 require_gte!(amount.get(), min_amount, CoreError::NotEnoughTokenAmount);
152
153 msg!("[Treasury] claimed {} tokens from the market", amount.get());
154 Ok(())
155}
156
157impl<'info> WithStore<'info> for ClaimFees<'info> {
158 fn store_program(&self) -> AccountInfo<'info> {
159 self.store_program.to_account_info()
160 }
161
162 fn store(&self) -> AccountInfo<'info> {
163 self.store.to_account_info()
164 }
165}
166
167impl<'info> CpiAuthentication<'info> for ClaimFees<'info> {
168 fn authority(&self) -> AccountInfo<'info> {
169 self.authority.to_account_info()
170 }
171
172 fn on_error(&self) -> Result<()> {
173 err!(CoreError::PermissionDenied)
174 }
175}
176
177impl<'info> ClaimFees<'info> {
178 fn claim_fees_from_market_ctx(
179 &self,
180 ) -> CpiContext<'_, '_, '_, 'info, ClaimFeesFromMarket<'info>> {
181 CpiContext::new(
182 self.store_program.to_account_info(),
183 ClaimFeesFromMarket {
184 authority: self.receiver.to_account_info(),
185 store: self.store.to_account_info(),
186 market: self.market.to_account_info(),
187 token_mint: self.token.to_account_info(),
188 vault: self.vault.to_account_info(),
189 target: self.receiver_vault.to_account_info(),
190 token_program: self.token_program.to_account_info(),
191 event_authority: self.event_authority.to_account_info(),
192 program: self.store_program.to_account_info(),
193 },
194 )
195 }
196}
197
198#[derive(Accounts)]
200pub struct SetReferralReward<'info> {
201 #[account(mut)]
203 pub authority: Signer<'info>,
204 #[account(mut)]
207 pub store: UncheckedAccount<'info>,
208 #[account(has_one = store)]
210 pub config: AccountLoader<'info, Config>,
211 pub store_program: Program<'info, GmsolStore>,
213}
214
215pub(crate) fn unchecked_set_referral_reward(
219 ctx: Context<SetReferralReward>,
220 factors: Vec<u128>,
221) -> Result<()> {
222 let signer = ctx.accounts.config.load()?.signer();
223 let cpi_ctx = ctx.accounts.configurate_gt_ctx();
224 gt_set_referral_reward_factors(cpi_ctx.with_signer(&[&signer.as_seeds()]), factors)?;
225 Ok(())
226}
227
228impl<'info> WithStore<'info> for SetReferralReward<'info> {
229 fn store_program(&self) -> AccountInfo<'info> {
230 self.store_program.to_account_info()
231 }
232
233 fn store(&self) -> AccountInfo<'info> {
234 self.store.to_account_info()
235 }
236}
237
238impl<'info> CpiAuthentication<'info> for SetReferralReward<'info> {
239 fn authority(&self) -> AccountInfo<'info> {
240 self.authority.to_account_info()
241 }
242
243 fn on_error(&self) -> Result<()> {
244 err!(CoreError::PermissionDenied)
245 }
246}
247
248impl<'info> SetReferralReward<'info> {
249 fn configurate_gt_ctx(&self) -> CpiContext<'_, '_, '_, 'info, ConfigurateGt<'info>> {
250 CpiContext::new(
251 self.store_program.to_account_info(),
252 ConfigurateGt {
253 authority: self.config.to_account_info(),
254 store: self.store.to_account_info(),
255 },
256 )
257 }
258}