1use anchor_lang::prelude::*;
2use anchor_spl::token::{self, Burn, Mint, MintTo, Token, TokenAccount, Transfer};
3
4declare_id!("2Wvo8b4oF63csMU45z6qHCN9EZ1qV2ifBb3dwnWow6Ub");
7
8#[program]
9pub mod restaking_programs{
10 use super::*;
11
12 pub fn initialize_state_account(
13 ctx: Context<InitializeStateAccount>,
14 msol_mint: Pubkey,
15 jitoSol_mint: Pubkey,
16 rm_sol_mint: Pubkey,
17 rjito_sol_mint: Pubkey,
18 ) -> Result<()> {
19 let state = &mut ctx.accounts.state;
20 state.authority = ctx.accounts.authority.key();
21 state.msol_mint = msol_mint;
22 state.jitosol_mint = jitoSol_mint;
23 state.rm_sol_mint = rm_sol_mint;
24 state.rjito_sol_mint = rjito_sol_mint;
25 state.bump = ctx.bumps.state;
26 Ok(())
27 }
28
29 pub fn initialize_vault_account(
30 ctx: Context<InitializeVault>,
31 token_mint: Pubkey,
32 ) -> Result<()> {
33 let vault_account = &mut ctx.accounts.vault_account;
34 vault_account.token_mint = token_mint;
35 vault_account.vault = ctx.accounts.vault.key();
36 vault_account.bump = ctx.bumps.vault_account;
37 vault_account.total_deposited = 0;
38 Ok(())
39 }
40
41 pub fn initialize_mint_account(
42 ctx: Context<InitializeMintAccount>,
43 base_mint: Pubkey,
44 restaked_mint: Pubkey,
45 ) -> Result<()> {
46 let mint_account = &mut ctx.accounts.mint_account;
47 let vault_account = &ctx.accounts.vault_account;
48
49 mint_account.base_mint = base_mint;
50 mint_account.restaked_mint = restaked_mint;
51 mint_account.vault = vault_account.key();
52 mint_account.bump = ctx.bumps.mint_account;
53 mint_account.total_minted = 0;
54 mint_account.exchange_rate = 1_000_000_000;
55 mint_account.last_update_slot = Clock::get()?.slot;
56
57 Ok(())
58 }
59
60 pub fn restake(ctx: Context<Restake>, amount: u64) -> Result<()> {
61 let vault_account = &mut ctx.accounts.vault_account;
62 let mint_account = &mut ctx.accounts.mint_account;
63 let user_account = &mut ctx.accounts.user_restaking_account;
64
65 user_account.bump = ctx.bumps.user_restaking_account;
66
67 let cpi_ctx = CpiContext::new(
68 ctx.accounts.token_program.to_account_info(),
69 Transfer {
70 from: ctx.accounts.user_base_token.to_account_info(),
71 to: ctx.accounts.vault.to_account_info(),
72 authority: ctx.accounts.user.to_account_info(),
73 },
74 );
75 token::transfer(cpi_ctx, amount)?;
76
77 let restaked_amount = amount
78 .checked_mul(1_000_000_000) .unwrap()
80 .checked_div(mint_account.exchange_rate)
81 .unwrap();
82
83 let seeds = &[
84 b"mint_account",
85 mint_account.base_mint.as_ref(),
86 &[mint_account.bump],
87 ];
88 let signer = &[&seeds[..]];
89
90 let cpi_ctx_mint = CpiContext::new_with_signer(
91 ctx.accounts.token_program.to_account_info(),
92 MintTo {
93 mint: ctx.accounts.restaked_mint.to_account_info(),
94 to: ctx.accounts.user_restaked_token.to_account_info(),
95 authority: mint_account.to_account_info(),
96 },
97 signer,
98 );
99 token::mint_to(cpi_ctx_mint, restaked_amount)?;
100
101 vault_account.total_deposited = vault_account.total_deposited.checked_add(amount).unwrap();
102
103 mint_account.total_minted = mint_account
104 .total_minted
105 .checked_add(restaked_amount)
106 .unwrap();
107
108 user_account.user = ctx.accounts.user.key();
109 user_account.deposited_mint = mint_account.base_mint;
110 user_account.restaked_mint = mint_account.restaked_mint;
111
112 user_account.deposited_amount = user_account.deposited_amount.checked_add(amount).unwrap();
113
114 user_account.restaked_amount = user_account
115 .restaked_amount
116 .checked_add(restaked_amount)
117 .unwrap();
118
119 emit!(RestakeEvent{
120 user: ctx.accounts.user.key(),
121 base_mint: mint_account.base_mint,
122 restaked_mint: mint_account.restaked_mint,
123 amount_deposited: amount,
124 restaked_amount,
125 exchange_rate: mint_account.exchange_rate,
126 });
127
128 Ok(())
129 }
130
131 pub fn request_unstake(ctx: Context<RequestUnstake>, restaked_amount: u64) -> Result<()> {
132 let user_account = &mut ctx.accounts.user_restaking_account;
133 let _mint_account = &ctx.accounts.mint_account;
134
135 require!(restaked_amount > 0, CustomError::InvalidAmount);
136 require!(user_account.restaked_amount >= restaked_amount, CustomError::InsufficientRestakeBalance);
137
138
139 let cpi_ctx_burn = CpiContext::new(
140 ctx.accounts.token_program.to_account_info(),
141 Burn {
142 mint: ctx.accounts.restaked_mint.to_account_info(),
143 from: ctx.accounts.user_restaked_token.to_account_info(),
144 authority: ctx.accounts.user.to_account_info(),
145 },
146 );
147 token::burn(cpi_ctx_burn, restaked_amount)?;
148
149 user_account.pending_unstake = restaked_amount;
150 user_account.cooldown_end_timestamp = Clock::get()?.unix_timestamp + 300; emit!(UnstakeRequestedEvent{
153 user: ctx.accounts.user.key(),
154 restaked_mint: ctx.accounts.mint_account.restaked_mint,
155 restaked_amount,
156 cooldown_end_timestamp: user_account.cooldown_end_timestamp ,
157 });
158
159 Ok(())
160 }
161
162 pub fn claim_unstake(ctx: Context<ClaimUnstake>) -> Result<()> {
163 let vault_account = &mut ctx.accounts.vault_account;
164 let mint_account = &mut ctx.accounts.mint_account;
165 let user_account = &mut ctx.accounts.user_restaking_account;
166
167 let current_timestamp = Clock::get()?.unix_timestamp;
168 require!(
169 current_timestamp >= user_account.cooldown_end_timestamp,
170 CustomError::CooldownNotFinished
171 );
172
173 let restaked_amount = user_account.pending_unstake;
174 require!(restaked_amount > 0, CustomError::NothingToClaim);
175
176 let base_amount = restaked_amount
177 .checked_mul(mint_account.exchange_rate)
178 .unwrap()
179 .checked_div(1_000_000_000)
180 .unwrap();
181
182 let fee = base_amount / 1000;
183 let withdraw_amount = base_amount.checked_sub(fee).unwrap();
184
185 let seeds = &[
186 b"vault_account",
187 mint_account.base_mint.as_ref(),
188 &[vault_account.bump],
189 ];
190 let signer = &[&seeds[..]];
191
192 let cpi_ctx_transfer = CpiContext::new_with_signer(
193 ctx.accounts.token_program.to_account_info(),
194 anchor_spl::token::Transfer {
195 from: ctx.accounts.vault.to_account_info(),
196 to: ctx.accounts.user_base_token.to_account_info(),
197 authority: vault_account.to_account_info(),
198 },
199 signer,
200 );
201 anchor_spl::token::transfer(cpi_ctx_transfer, withdraw_amount)?;
202
203 vault_account.total_deposited = vault_account
204 .total_deposited
205 .checked_sub(base_amount)
206 .unwrap();
207 mint_account.total_minted = mint_account
208 .total_minted
209 .checked_sub(restaked_amount)
210 .unwrap();
211 user_account.pending_unstake = 0;
212 user_account.last_claimed_slot = Clock::get()?.slot;emit!(UnstakeClaimedEvent{
215 user: ctx.accounts.user.key(),
216 base_mint: mint_account.base_mint,
217 base_amount,
218 fee,
219 withdraw_amount,
220 });
221
222
223 Ok(())
224 }
225
226 pub fn claim_rewards(ctx: Context<ClaimRewards>) -> Result<()> {
227 let user_account = &mut ctx.accounts.user_restaking_account;
228 let treasury = &mut ctx.accounts.treasury;
229
230 let current_slot = Clock::get()?.slot;
231
232
233 let elapsed_slots = current_slot
234 .checked_sub(user_account.last_claimed_slot)
235 .unwrap();
236
237 require!(elapsed_slots > 0, CustomError::NothingToClaim);
238
239 let reward_rate: u64 = 1; let rewards = elapsed_slots
241 .checked_mul(user_account.restaked_amount)
242 .unwrap()
243 .checked_mul(reward_rate)
244 .unwrap();
245
246 require!(
247 **treasury.to_account_info().lamports.borrow() >= rewards,
248 CustomError::InsufficientTreasuryBalance
249 );
250
251 **treasury.to_account_info().try_borrow_mut_lamports()? -= rewards;
252 **ctx.accounts.user.to_account_info().try_borrow_mut_lamports()? += rewards;
253
254
255 user_account.last_claimed_slot = current_slot;
256
257 emit!(RewardsClaimedEvent{
258 user: ctx.accounts.user.key(),
259 rewards,
260 elapsed_slots,
261 });
262
263 Ok(())
264 }
265 pub fn initialize_operator(ctx: Context<RegisterOperator>, bond_amount: u64, metadata: String) -> Result<()> {
266 let operator_account = &mut ctx.accounts.operator_account;
267 let vault = &mut ctx.accounts.vault; require!(bond_amount >= 2_000_000_000, CustomError::NotEnoughToken);
270
271 operator_account.owner = ctx.accounts.operator_key.key();
272 operator_account.bond_amount = bond_amount;
273 operator_account.metadata = metadata;
274 operator_account.active = true;
275 operator_account.avs_count = 0;
276 operator_account.bump = ctx.bumps.operator_account;
277 operator_account.vault_bump = ctx.bumps.vault;
278
279
280 vault.bump = ctx.bumps.vault;
281
282
283 let transfer_ix = anchor_lang::solana_program::system_instruction::transfer(
284 &ctx.accounts.operator_key.key(),
285 &ctx.accounts.vault.key(),
286 bond_amount,
287 );
288
289 anchor_lang::solana_program::program::invoke(
290 &transfer_ix,
291 &[
292 ctx.accounts.operator_key.to_account_info(),
293 ctx.accounts.vault.to_account_info(),
294 ],
295 )?;
296
297 emit!(OperatorRegisteredEvent{
298 owner : operator_account.owner,
299 bond_amount,
300 metadata: operator_account.metadata.clone(),
301 active : true,
302 avs_count : operator_account.avs_count,
303 });
304
305 Ok(())
306 }
307
308
309 pub fn update_operator_metadata( ctx: Context<UpdateOperatorMetadata>, metadata : String)->Result<()>{
310
311 let operator_account = &mut ctx.accounts.operator_account;
312 require!(operator_account.owner== ctx.accounts.owner.key(), CustomError::Unauthorized);
313
314 operator_account.metadata = metadata;
315
316 emit!(OperatorMetadataUpdatedEvent{
317 owner: operator_account.owner,
318 metadata: operator_account.metadata.clone(),
319 });
320
321 Ok(())
322 }
323
324 pub fn de_register_operator(ctx: Context<DeRegisterOperator>) -> Result<()> {
325 require!(
326 ctx.accounts.operator_account.owner == ctx.accounts.operator_key.key(),
327 CustomError::Unauthorized
328 );
329
330 let bond_amount = ctx.accounts.operator_account.bond_amount;
331
332 **ctx.accounts.operator_key.to_account_info().try_borrow_mut_lamports()? += bond_amount;
333 **ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= bond_amount;
334
335 let operator_account = &mut ctx.accounts.operator_account;
336 operator_account.active = false;
337
338 emit!(OperatorDeRegisteredEvent{
339 owner: operator_account.owner,
340 bond_returned: bond_amount,
341 active: false,
342 });
343
344 Ok(())
345 }
346
347 pub fn slash_operator(ctx: Context<SlashOperator>, operator_owner: Pubkey,amount: u64) -> Result<()> {
348 let operator_account = &mut ctx.accounts.operator_account;
349
350 require!(
351 operator_account.bond_amount >= amount,
352 CustomError::InsufficientBond
353 );
354
355 operator_account.bond_amount = operator_account
356 .bond_amount
357 .checked_sub(amount)
358 .unwrap();
359
360 **ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= amount;
361 **ctx.accounts.treasury.to_account_info().try_borrow_mut_lamports()? += amount;
362
363 emit!(OperatorSlashedEvent{
364 operator_owner,
365 slashed_amount: amount,
366 remaining_bond: operator_account.bond_amount,
367 });
368
369 Ok(())
370 }
371
372 pub fn initialize_reward_treasury(ctx: Context<InitializeRewardTreasury>) -> Result<()> {
373 let treasury = &mut ctx.accounts.treasury;
374 treasury.authority = ctx.accounts.authority.key();
375 treasury.bump = ctx.bumps.treasury;
376 treasury.total_rewards_distributed = 0;
377 Ok(())
378 }
379
380 pub fn register_avs(ctx: Context<RegisterAvs>, metadata:String , registration_fee: u64)->Result<()>{
381 let avs_owner_ai = ctx.accounts.avs_owner.to_account_info();
383 let avs_account_ai = ctx.accounts.avs_account.to_account_info();
384
385 require!(registration_fee >= 3_000_000_000, CustomError::NotEnoughToken);
386
387 let transfer_sol = anchor_lang::solana_program::system_instruction::transfer(
388 &ctx.accounts.avs_owner.key(),
389 &ctx.accounts.avs_account.key(),
390 registration_fee,
391 );
392
393 anchor_lang::solana_program::program::invoke(
394 &transfer_sol,
395 &[avs_owner_ai.clone(), avs_account_ai.clone()],
396 )?;
397
398
399 let avs_account = &mut ctx.accounts.avs_account;
400 let treasury = &mut ctx.accounts.treasury;
401
402 let treasury_share = registration_fee / 2;
403 **avs_account.to_account_info().try_borrow_mut_lamports()? -= treasury_share;
404 **treasury.to_account_info().try_borrow_mut_lamports()? += treasury_share;
405
406 avs_account.owner = ctx.accounts.avs_owner.key();
407 avs_account.metadata = metadata.clone();
408 avs_account.registration_fee = registration_fee;
409 avs_account.active = true;
410 avs_account.registered_slot = Clock::get()?.slot;
411 avs_account.bump = ctx.bumps.avs_account;
412
413 emit!(AvsRegisteredEvent{
414 owner: avs_account.owner,
415 registration_fee,
416 metadata: avs_account.metadata.clone(),
417 registered_slot: avs_account.registered_slot,
418 });
419
420 Ok(())
421 }
422
423 pub fn update_avs_metadata(ctx: Context<UpdateAvsMetadata>, metadata: String )-> Result<()>{
424 let avs_account = &mut ctx.accounts.avs_account;
425
426 require!(avs_account.owner == ctx.accounts.avs_owner.key(), CustomError::Unauthorized);
427 avs_account.metadata = metadata;
428
429 emit!(AvsMetadatUpdatedEvent{
430 owner: avs_account.owner,
431 metadata: avs_account.metadata.clone() ,
432 });
433
434 Ok(())
435 }
436
437
438 pub fn de_register_avs(ctx: Context<DeRegisterAvs>) -> Result<()> {
439 let avs_account = &mut ctx.accounts.avs_account;
440 require!(avs_account.owner == ctx.accounts.avs_owner.key(), CustomError::Unauthorized);
441
442 avs_account.active = false;
443
444 emit!(AvsDeRegisterEvent{
445 owner: avs_account.owner,
446 active : false,
447 });
448
449 Ok(())
450 }
451
452 pub fn operator_opt_in_avs(ctx: Context<OptInAvs>, avs_owner: Pubkey ) -> Result<()> {
453 let operator_account = &mut ctx.accounts.operator_account;
454 let operator_avs_reg = &mut ctx.accounts.operator_avs_registration;
455 let avs_account = &ctx.accounts.avs_account;
456
457
458 require!(
459 operator_account.active,
460 CustomError::OperatorNotActive
461 );
462
463
464 require!(
465 avs_account.active,
466 CustomError::AvsNotActive
467 );
468
469
470 operator_avs_reg.operator = ctx.accounts.operator_key.key();
471 operator_avs_reg.avs = avs_account.key();
472 operator_avs_reg.opted_in_slot = Clock::get()?.slot;
473 operator_avs_reg.active = true;
474 operator_avs_reg.tasks_completed = 0;
475 operator_avs_reg.tasks_failed = 0;
476 operator_avs_reg.bump = ctx.bumps.operator_avs_registration;
477
478
479 operator_account.avs_count = operator_account
480 .avs_count
481 .checked_add(1)
482 .unwrap();
483
484 emit!(OperatorOptedInEvent{
485 operator: operator_avs_reg.operator,
486 avs: avs_account.key(),
487 avs_owner,
488 opted_in_slot: operator_avs_reg.opted_in_slot,
489 });
490
491 msg!(
492 "✅ Operator {} opted into AVS {} (owner: {})",
493 operator_avs_reg.operator,
494 avs_account.key(),
495 avs_owner
496 );
497
498 Ok(())
499 }
500
501
502}
503
504#[derive(Accounts)]
505pub struct InitializeStateAccount<'info> {
506 #[account(mut)]
507 pub authority: Signer<'info>,
508
509 #[account(
510 init,
511 payer = authority,
512 space = 8 + StateAccount::INIT_SPACE,
513 seeds = [b"state"],
514 bump
515 )]
516 pub state: Account<'info, StateAccount>,
517
518 pub system_program: Program<'info, System>,
519}
520
521#[derive(Accounts)]
522#[instruction(token_mint: Pubkey)]
523pub struct InitializeVault<'info> {
524 #[account(mut)]
525 pub authority: Signer<'info>,
526
527 #[account(
528 init,
529 payer = authority,
530 space = 8 + VaultAccount::INIT_SPACE,
531 seeds = [b"vault_account", token_mint.key().as_ref()],
532 bump
533 )]
534 pub vault_account: Account<'info, VaultAccount>,
535
536 #[account(
537 init,
538 payer = authority,
539 token::mint = token_mint,
540 token::authority = vault_account,
541 seeds = [b"vault_token", token_mint.key().as_ref()],
542 bump
543 )]
544 pub vault: Account<'info, TokenAccount>,
545
546 pub token_mint: Account<'info, Mint>,
547 pub system_program: Program<'info, System>,
548 pub token_program: Program<'info, Token>,
549 pub rent: Sysvar<'info, Rent>,
550}
551
552#[derive(Accounts)]
553#[instruction(base_mint: Pubkey, restaked_mint: Pubkey)]
554pub struct InitializeMintAccount<'info> {
555 #[account(mut)]
556 pub authority: Signer<'info>,
557
558 #[account(
559 init,
560 payer = authority,
561 space = 8 + MintAccount::INIT_SPACE,
562 seeds = [b"mint_account", base_mint.key().as_ref()],
563 bump
564 )]
565 pub mint_account: Account<'info, MintAccount>,
566
567 #[account(mut)]
568 pub vault_account: Account<'info, VaultAccount>,
569
570 pub system_program: Program<'info, System>,
571}
572
573#[derive(Accounts)]
574pub struct Restake<'info> {
575 #[account(mut)]
576 pub user: Signer<'info>,
577
578 #[account(mut)]
579 pub user_base_token: Account<'info, TokenAccount>,
580
581 #[account(
582 mut,
583 seeds = [b"vault_account", mint_account.base_mint.as_ref()],
584 bump = vault_account.bump
585 )]
586 pub vault_account: Account<'info, VaultAccount>,
587
588 #[account(mut)]
589 pub vault: Account<'info, TokenAccount>,
590
591 #[account(
592 mut,
593 seeds = [b"mint_account", mint_account.base_mint.as_ref()],
594 bump = mint_account.bump
595 )]
596 pub mint_account: Account<'info, MintAccount>,
597
598 #[account(mut)]
599 pub restaked_mint: Account<'info, Mint>,
600
601 #[account(mut)]
602 pub user_restaked_token: Account<'info, TokenAccount>,
603
604 #[account(
605 init_if_needed,
606 payer = user,
607 space = 8 + UserRestakingAccount::INIT_SPACE,
608 seeds = [b"user_restaking", user.key().as_ref(), mint_account.restaked_mint.as_ref()],
609 bump
610 )]
611 pub user_restaking_account: Account<'info, UserRestakingAccount>,
612
613 pub token_program: Program<'info, Token>,
614 pub system_program: Program<'info, System>,
615}
616
617
618#[derive(Accounts)]
619pub struct RequestUnstake<'info> {
620 #[account(mut)]
621 pub user: Signer<'info>,
622
623 #[account(
624 mut,
625 constraint = user_restaked_token.owner == user.key(),
626 constraint = user_restaked_token.mint == mint_account.restaked_mint
627 )]
628 pub user_restaked_token: Account<'info, TokenAccount>,
629
630 #[account(
631 mut,
632 constraint = user_restaking_account.user == user.key(),
633 constraint = user_restaking_account.restaked_mint == mint_account.restaked_mint
634 )]
635 pub user_restaking_account: Account<'info, UserRestakingAccount>,
636
637 #[account(mut)]
638 pub restaked_mint: Account<'info, Mint>,
639
640 #[account(mut)]
641 pub mint_account: Account<'info, MintAccount>,
642
643 pub token_program: Program<'info, Token>,
644 pub system_program: Program<'info, System>,
645}
646
647#[derive(Accounts)]
648pub struct ClaimUnstake<'info> {
649 #[account(mut)]
650 pub user: Signer<'info>,
651
652 #[account(
653 mut,
654 constraint = user_base_token.owner == user.key(),
655 constraint = user_base_token.mint == mint_account.base_mint
656 )]
657 pub user_base_token: Account<'info, TokenAccount>,
658
659 #[account(
660 mut,
661 constraint = user_restaking_account.user == user.key(),
662 constraint = user_restaking_account.restaked_mint == mint_account.restaked_mint
663 )]
664 pub user_restaking_account: Account<'info, UserRestakingAccount>,
665
666 #[account(mut)]
667 pub vault_account: Account<'info, VaultAccount>,
668
669 #[account(
670 mut,
671 constraint = vault.mint == mint_account.base_mint
672 )]
673 pub vault: Account<'info, TokenAccount>,
674
675 #[account(mut)]
676 pub mint_account: Account<'info, MintAccount>,
677
678 pub token_program: Program<'info, Token>,
679}
680
681
682#[derive(Accounts)]
683pub struct RegisterOperator<'info> {
684 #[account(mut)]
685 pub operator_key: Signer<'info>,
686
687 #[account(
688 init,
689 payer = operator_key,
690 space = 8 + OperatorAccount::INIT_SPACE,
691 seeds = [b"operator", operator_key.key().as_ref()],
692 bump
693 )]
694 pub operator_account: Account<'info, OperatorAccount>,
695
696 #[account(
697 init,
698 payer = operator_key,
699 space = 8 + OperatorVault::INIT_SPACE,
700 seeds = [b"vault", operator_key.key().as_ref()],
701 bump
702 )]
703 pub vault: Account<'info, OperatorVault>,
704
705 pub system_program: Program<'info, System>,
706}
707
708
709#[derive(Accounts)]
710pub struct UpdateOperatorMetadata<'info>{
711 #[account(mut)]
712 pub owner: Signer<'info>,
713
714 #[account(
715 mut ,
716 seeds = [b"operator", owner.key().as_ref()],
717 bump = operator_account.bump,
718 has_one = owner @ CustomError::Unauthorized
719 )]
720 pub operator_account: Account<'info , OperatorAccount>
721}
722
723#[derive(Accounts)]
724pub struct DeRegisterOperator<'info> {
725 #[account(mut)]
726 pub operator_key: Signer<'info>,
727
728 #[account(
729 mut,
730 seeds = [b"operator", operator_key.key().as_ref()],
731 bump = operator_account.bump,
732 close = operator_key
733 )]
734 pub operator_account: Account<'info, OperatorAccount>,
735
736 #[account(
738 mut,
739 seeds = [b"vault", operator_key.key().as_ref()],
740 bump = operator_account.vault_bump,
741 close = operator_key )]
743 pub vault: Account<'info, OperatorVault>,
744
745 pub system_program: Program<'info, System>,
746}
747#[derive(Accounts)]
748#[instruction(operator_owner: Pubkey)]
749pub struct SlashOperator<'info> {
750 #[account(mut)]
751 pub authority: Signer<'info>,
752
753 #[account(
754 mut,
755 seeds = [b"operator", operator_owner.as_ref()],
756 bump = operator_account.bump,
757 )]
758 pub operator_account: Account<'info, OperatorAccount>,
759
760 #[account(
761 mut,
762 seeds = [b"vault", operator_owner.as_ref()],
763 bump = operator_account.vault_bump
764 )]
765 pub vault: Account<'info, OperatorVault>,
766
767 #[account(
768 mut,
769 seeds = [b"reward_treasury"],
770 bump = treasury.bump
771 )]
772 pub treasury: Account<'info, RewardTreasury>,
773
774 pub system_program: Program<'info, System>,
775}
776#[derive(Accounts)]
777pub struct InitializeRewardTreasury<'info> {
778 #[account(mut)]
779 pub authority: Signer<'info>,
780
781 #[account(
782 init,
783 payer = authority,
784 space = 8 + RewardTreasury::INIT_SPACE,
785 seeds = [b"reward_treasury"],
786 bump
787 )]
788 pub treasury: Account<'info, RewardTreasury>,
789
790 pub system_program: Program<'info, System>,
791}
792
793#[derive(Accounts)]
794pub struct ClaimRewards<'info> {
795 #[account(mut)]
796 pub user: Signer<'info>,
797
798 #[account(
799 mut,
800 constraint = user_restaking_account.user == user.key()
801 )]
802 pub user_restaking_account: Account<'info, UserRestakingAccount>,
803
804 #[account(
805 mut,
806 seeds = [b"reward_treasury"],
807 bump = treasury.bump
808 )]
809 pub treasury: Account<'info, RewardTreasury>,
810}
811
812#[derive(Accounts)]
813pub struct RegisterAvs<'info>{
814
815 #[account(mut)]
816 pub avs_owner : Signer<'info>,
817
818 #[account(
819 init ,
820 payer = avs_owner,
821 space = 8 + AvsAccount::INIT_SPACE,
822 seeds = [b"avs" , avs_owner.key().as_ref()],
823 bump
824 )]
825 pub avs_account : Account<'info , AvsAccount>,
826
827 #[account(
828 mut ,
829 seeds = [b"reward_treasury"],
830 bump = treasury.bump
831 )]
832 pub treasury: Account<'info , RewardTreasury>,
833
834 pub system_program : Program<'info , System>
835}
836
837#[derive(Accounts)]
838pub struct UpdateAvsMetadata<'info>{
839 #[account(mut)]
840 pub avs_owner: Signer<'info>,
841
842 #[account(
843 mut ,
844 seeds = [b"avs", avs_owner.key().as_ref()],
845 bump = avs_account.bump,
846 )]
847 pub avs_account: Account<'info , AvsAccount>
848}
849
850#[derive(Accounts)]
851pub struct DeRegisterAvs<'info>{
852 #[account(mut)]
853 pub avs_owner : Signer<'info>,
854
855 #[account(
856 mut,
857 seeds = [b"avs", avs_owner.key().as_ref()],
858 bump = avs_account.bump,
859 close = avs_owner
860 )]
861 pub avs_account : Account<'info , AvsAccount>
862}
863
864#[derive(Accounts)]
865pub struct GetUserData<'info> {
866 pub user: Signer<'info>,
867
868 #[account(
869 seeds = [b"user_restaking", user.key().as_ref(), restaked_mint.key().as_ref()],
870 bump = user_restaking_account.bump,
871 constraint = user_restaking_account.user == user.key()
872 )]
873 pub user_restaking_account: Account<'info, UserRestakingAccount>,
874
875 pub restaked_mint: Account<'info, Mint>,
876}
877
878
879#[derive(Accounts)]
880#[instruction(avs_owner: Pubkey)] pub struct OptInAvs<'info> {
882 #[account(mut)]
883 pub operator_key: Signer<'info>,
884
885
886 #[account(
887 mut,
888 seeds = [b"operator", operator_key.key().as_ref()],
889 bump = operator_account.bump,
890 constraint = operator_account.active @ CustomError::OperatorNotActive,
891 constraint = operator_account.owner == operator_key.key() @ CustomError::Unauthorized
892 )]
893 pub operator_account: Account<'info, OperatorAccount>,
894
895 #[account(
897 seeds = [b"avs", avs_owner.as_ref()], bump = avs_account.bump,
899 constraint = avs_account.active @ CustomError::AvsNotActive,
900 constraint = avs_account.owner == avs_owner @ CustomError::Unauthorized
901 )]
902 pub avs_account: Account<'info, AvsAccount>,
903
904 #[account(
906 init,
907 payer = operator_key,
908 space = 8 + OperatorAvsRegistration::INIT_SPACE,
909 seeds = [
910 b"operator_avs",
911 operator_key.key().as_ref(),
912 avs_owner.as_ref()
913 ],
914 bump
915 )]
916 pub operator_avs_registration: Account<'info, OperatorAvsRegistration>,
917
918 pub system_program: Program<'info, System>,
919}
920
921
922#[account]
923#[derive(InitSpace, Debug)]
924pub struct StateAccount {
925 pub authority: Pubkey,
926 pub msol_mint: Pubkey,
927 pub jitosol_mint: Pubkey,
928 pub rm_sol_mint: Pubkey,
929 pub rjito_sol_mint: Pubkey,
930 pub bump: u8,
931}
932
933#[account]
934#[derive(InitSpace, Debug)]
935pub struct VaultAccount {
936 pub token_mint: Pubkey,
937 pub vault: Pubkey,
938 pub bump: u8,
939 pub total_deposited: u64,
940}
941
942#[account]
943#[derive(InitSpace, Debug)]
944pub struct MintAccount {
945 pub base_mint: Pubkey,
946 pub restaked_mint: Pubkey,
947 pub vault: Pubkey,
948 pub bump: u8,
949 pub total_minted: u64,
950 pub exchange_rate: u64,
951 pub last_update_slot: u64,
952}
953#[account]
954#[derive(InitSpace, Debug)]
955pub struct UserRestakingAccount {
956 pub user: Pubkey,
957 pub deposited_mint: Pubkey,
958 pub restaked_mint: Pubkey,
959 pub deposited_amount: u64,
960 pub restaked_amount: u64,
961 pub bump: u8,
962 pub cooldown_end_timestamp: i64,
963 pub pending_unstake: u64,
964 pub reward_debt: u64,
965 pub last_claimed_slot: u64,
966}
967
968#[account]
969#[derive(InitSpace, Debug)]
970pub struct OperatorAccount {
971 pub owner: Pubkey,
972 pub bond_amount: u64,
973 #[max_len(100)]
974 pub metadata: String,
975 pub active: bool,
976 pub avs_count: u32,
977 pub bump: u8,
978 pub vault_bump: u8,
979}
980
981#[account]
982#[derive(InitSpace, Debug)]
983pub struct OperatorVault {
984 pub bump: u8,
985}
986
987
988#[account]
989#[derive(InitSpace, Debug)]
990pub struct RewardTreasury {
991 pub authority: Pubkey,
992 pub bump: u8,
993 pub total_rewards_distributed: u64,
994}
995
996
997#[account]
998#[derive(InitSpace, Debug)]
999pub struct AvsAccount{
1000 pub owner: Pubkey,
1001 #[max_len(100)]
1002 pub metadata: String,
1003 pub registration_fee : u64,
1004 pub active : bool,
1005 pub slashing_policy : Pubkey,
1006 pub registered_slot : u64,
1007 pub bump: u8,
1008}
1009
1010pub struct SlashingPolicy {
1011 pub misbehavior_type: u8, pub penalty_percent: u8,
1013}
1014
1015#[account]
1016#[derive(InitSpace, Debug)]
1017pub struct OperatorAvsRegistration {
1018 pub operator: Pubkey,
1019 pub avs: Pubkey,
1020 pub opted_in_slot: u64,
1021 pub active: bool,
1022 pub tasks_completed: u64,
1023 pub tasks_failed: u64,
1024 pub bump: u8,
1025}
1026
1027#[event]
1028pub struct OperatorRegisteredEvent{
1029 pub owner : Pubkey,
1030 pub bond_amount: u64,
1031 pub metadata : String,
1032 pub active: bool,
1033 pub avs_count: u32,
1034}
1035
1036#[event]
1037pub struct OperatorMetadataUpdatedEvent{
1038 pub owner: Pubkey,
1039 pub metadata: String,
1040}
1041
1042#[event]
1043pub struct OperatorDeRegisteredEvent{
1044 pub owner: Pubkey,
1045 pub bond_returned: u64,
1046 pub active: bool
1047}
1048
1049#[event]
1050pub struct OperatorSlashedEvent{
1051 pub operator_owner: Pubkey,
1052 pub slashed_amount: u64,
1053 pub remaining_bond: u64,
1054}
1055
1056
1057#[event]
1058pub struct AvsRegisteredEvent{
1059 pub owner: Pubkey,
1060 pub registration_fee: u64,
1061 pub metadata: String,
1062 pub registered_slot: u64,
1063}
1064
1065#[event]
1066pub struct AvsMetadatUpdatedEvent{
1067 pub owner: Pubkey,
1068 pub metadata: String,
1069}
1070
1071#[event]
1072pub struct AvsDeRegisterEvent{
1073 pub owner: Pubkey,
1074 pub active : bool,
1075}
1076
1077#[event]
1078pub struct OperatorOptedInEvent{
1079 pub operator: Pubkey,
1080 pub avs: Pubkey,
1081 pub avs_owner: Pubkey,
1082 pub opted_in_slot: u64,
1083}
1084
1085#[event]
1086pub struct RestakeEvent{
1087 pub user: Pubkey,
1088 pub base_mint: Pubkey,
1089 pub restaked_mint: Pubkey,
1090 pub amount_deposited: u64,
1091 pub restaked_amount: u64,
1092 pub exchange_rate: u64,
1093}
1094
1095#[event]
1096pub struct UnstakeRequestedEvent{
1097 pub user: Pubkey,
1098 pub restaked_mint: Pubkey,
1099 pub restaked_amount: u64,
1100 pub cooldown_end_timestamp: i64,
1101}
1102
1103#[event]
1104pub struct UnstakeClaimedEvent{
1105 pub user: Pubkey,
1106 pub base_mint: Pubkey,
1107 pub base_amount: u64,
1108 pub fee: u64,
1109 pub withdraw_amount: u64,
1110}
1111
1112#[event]
1113pub struct RewardsClaimedEvent{
1114 pub user: Pubkey,
1115 pub rewards: u64,
1116 pub elapsed_slots: u64,
1117}
1118
1119
1120
1121
1122#[error_code]
1123pub enum CustomError {
1124 #[msg("Cooldown not finished yet")]
1125 CooldownNotFinished,
1126 #[msg("No pending unstake to claim")]
1127 NothingToClaim,
1128 #[msg("Not enough tokens supplied")]
1129 NotEnoughToken,
1130 #[msg("Unauthorized action")]
1131 Unauthorized,
1132 #[msg("Insufficient bond to slash")]
1133 InsufficientBond,
1134 #[msg("Not enough lamports in treasury")]
1135 InsufficientTreasuryBalance,
1136 #[msg("Avs not active to opt")]
1137 AvsNotActive,
1138 #[msg("Operator not active to run nodes")]
1139 OperatorNotActive,
1140 #[msg("Operator not opted into this AVS")]
1141 OperatorNotOptedIn,
1142 #[msg("Task not completed")]
1143 TaskNotCompleted,
1144 #[msg("Challenge already resolved")]
1145 ChallengeAlreadyResolved,
1146 #[msg("Amount must be greater than 0")]
1147 InvalidAmount,
1148 #[msg("Insufficient restaked balance in account")]
1149 InsufficientRestakeBalance,
1150}