1use anchor_lang::prelude::*;
2use anchor_spl::token::{self, Burn, Mint, MintTo, Token, TokenAccount, Transfer};
3
4declare_id!("6UqcKJ3U7zfr5JkhzjDZQsunbJeFBxgCKYbuMw8Scv6B");
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 Ok(())
120 }
121
122 pub fn request_unstake(ctx: Context<RequestUnstake>, restaked_amount: u64) -> Result<()> {
123 let user_account = &mut ctx.accounts.user_restaking_account;
124 let _mint_account = &ctx.accounts.mint_account;
125
126 let cpi_ctx_burn = CpiContext::new(
127 ctx.accounts.token_program.to_account_info(),
128 Burn {
129 mint: ctx.accounts.restaked_mint.to_account_info(),
130 from: ctx.accounts.user_restaked_token.to_account_info(),
131 authority: ctx.accounts.user.to_account_info(),
132 },
133 );
134 token::burn(cpi_ctx_burn, restaked_amount)?;
135
136 user_account.pending_unstake = restaked_amount;
137 user_account.cooldown_end_slot = Clock::get()?.slot + 500; Ok(())
140 }
141
142 pub fn claim_unstake(ctx: Context<ClaimUnstake>) -> Result<()> {
143 let vault_account = &mut ctx.accounts.vault_account;
144 let mint_account = &mut ctx.accounts.mint_account;
145 let user_account = &mut ctx.accounts.user_restaking_account;
146
147 let current_slot = Clock::get()?.slot;
148 require!(
149 current_slot >= user_account.cooldown_end_slot,
150 CustomError::CooldownNotFinished
151 );
152
153 let restaked_amount = user_account.pending_unstake;
154 require!(restaked_amount > 0, CustomError::NothingToClaim);
155
156 let base_amount = restaked_amount
157 .checked_mul(mint_account.exchange_rate)
158 .unwrap()
159 .checked_div(1_000_000_000)
160 .unwrap();
161
162 let fee = base_amount / 1000;
163 let withdraw_amount = base_amount.checked_sub(fee).unwrap();
164
165 let seeds = &[
166 b"vault_account",
167 mint_account.base_mint.as_ref(),
168 &[vault_account.bump],
169 ];
170 let signer = &[&seeds[..]];
171
172 let cpi_ctx_transfer = CpiContext::new_with_signer(
173 ctx.accounts.token_program.to_account_info(),
174 anchor_spl::token::Transfer {
175 from: ctx.accounts.vault.to_account_info(),
176 to: ctx.accounts.user_base_token.to_account_info(),
177 authority: vault_account.to_account_info(),
178 },
179 signer,
180 );
181 anchor_spl::token::transfer(cpi_ctx_transfer, withdraw_amount)?;
182
183 vault_account.total_deposited = vault_account
184 .total_deposited
185 .checked_sub(base_amount)
186 .unwrap();
187 mint_account.total_minted = mint_account
188 .total_minted
189 .checked_sub(restaked_amount)
190 .unwrap();
191 user_account.pending_unstake = 0;
192 user_account.last_claimed_slot = Clock::get()?.slot;Ok(())
195 }
196
197 pub fn claim_rewards(ctx: Context<ClaimRewards>) -> Result<()> {
198 let user_account = &mut ctx.accounts.user_restaking_account;
199 let treasury = &mut ctx.accounts.treasury;
200
201 let current_slot = Clock::get()?.slot;
202
203
204 let elapsed_slots = current_slot
205 .checked_sub(user_account.last_claimed_slot)
206 .unwrap();
207
208 require!(elapsed_slots > 0, CustomError::NothingToClaim);
209
210 let reward_rate: u64 = 1; let rewards = elapsed_slots
212 .checked_mul(user_account.restaked_amount)
213 .unwrap()
214 .checked_mul(reward_rate)
215 .unwrap();
216
217 require!(
218 **treasury.to_account_info().lamports.borrow() >= rewards,
219 CustomError::InsufficientTreasuryBalance
220 );
221
222 **treasury.to_account_info().try_borrow_mut_lamports()? -= rewards;
223 **ctx.accounts.user.to_account_info().try_borrow_mut_lamports()? += rewards;
224
225
226 user_account.last_claimed_slot = current_slot;
227
228 Ok(())
229 }
230
231 pub fn get_cooldown_end_slot(ctx: Context<GetUserData>,) -> Result<u64> {
232 let user_account = &ctx.accounts.user_restaking_account;
233 Ok(user_account.cooldown_end_slot)
234 }
235
236 pub fn get_pending_unstake(ctx: Context<GetUserData>) -> Result<u64> {
237 let user_account = &ctx.accounts.user_restaking_account;
238 let value = user_account.pending_unstake;
239 Ok(value)
240 }
241
242 pub fn get_reward_debt(ctx: Context<GetUserData>,) -> Result<u64> {
243 let user_account = &ctx.accounts.user_restaking_account;
244 let value = user_account.reward_debt;
245 Ok(value)
246 }
247
248
249
250 pub fn initialize_operator(ctx: Context<RegisterOperator>, bond_amount: u64, metadata: String) -> Result<()> {
251 let operator_account = &mut ctx.accounts.operator_account;
252 let vault = &mut ctx.accounts.vault; require!(bond_amount >= 2_000_000_000, CustomError::NotEnoughToken);
255
256
257 operator_account.owner = ctx.accounts.operator_key.key();
258 operator_account.bond_amount = bond_amount;
259 operator_account.metadata = metadata;
260 operator_account.active = true;
261 operator_account.avs_count = 0;
262 operator_account.bump = ctx.bumps.operator_account;
263 operator_account.vault_bump = ctx.bumps.vault;
264
265
266 vault.bump = ctx.bumps.vault;
267
268
269 let transfer_ix = anchor_lang::solana_program::system_instruction::transfer(
270 &ctx.accounts.operator_key.key(),
271 &ctx.accounts.vault.key(),
272 bond_amount,
273 );
274
275 anchor_lang::solana_program::program::invoke(
276 &transfer_ix,
277 &[
278 ctx.accounts.operator_key.to_account_info(),
279 ctx.accounts.vault.to_account_info(),
280 ],
281 )?;
282
283 Ok(())
284 }
285
286
287 pub fn update_operator_metadata( ctx: Context<UpdateOperatorMetadata>, metadata : String)->Result<()>{
288
289 let operator_account = &mut ctx.accounts.operator_account;
290 require!(operator_account.owner== ctx.accounts.owner.key(), CustomError::Unauthorized);
291
292 operator_account.metadata = metadata;
293
294 Ok(())
295 }
296
297 pub fn de_register_operator(ctx: Context<DeRegisterOperator>) -> Result<()> {
298 require!(
299 ctx.accounts.operator_account.owner == ctx.accounts.operator_key.key(),
300 CustomError::Unauthorized
301 );
302
303 let bond_amount = ctx.accounts.operator_account.bond_amount;
304
305 **ctx.accounts.operator_key.to_account_info().try_borrow_mut_lamports()? += bond_amount;
306 **ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= bond_amount;
307
308 let operator_account = &mut ctx.accounts.operator_account;
309 operator_account.active = false;
310
311 Ok(())
312 }
313
314 pub fn slash_operator(ctx: Context<SlashOperator>, operator_owner: Pubkey,amount: u64) -> Result<()> {
315 let operator_account = &mut ctx.accounts.operator_account;
316
317 require!(
318 operator_account.bond_amount >= amount,
319 CustomError::InsufficientBond
320 );
321
322 operator_account.bond_amount = operator_account
323 .bond_amount
324 .checked_sub(amount)
325 .unwrap();
326
327 **ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= amount;
328 **ctx.accounts.treasury.to_account_info().try_borrow_mut_lamports()? += amount;
329
330 Ok(())
331 }
332
333 pub fn initialize_reward_treasury(ctx: Context<InitializeRewardTreasury>) -> Result<()> {
334 let treasury = &mut ctx.accounts.treasury;
335 treasury.authority = ctx.accounts.authority.key();
336 treasury.bump = ctx.bumps.treasury;
337 treasury.total_rewards_distributed = 0;
338 Ok(())
339 }
340
341 pub fn register_avs(ctx: Context<RegisterAvs>, metadata:String , registration_fee: u64)->Result<()>{
342 let avs_owner_ai = ctx.accounts.avs_owner.to_account_info();
344 let avs_account_ai = ctx.accounts.avs_account.to_account_info();
345
346 require!(registration_fee >= 3_000_000_000, CustomError::NotEnoughToken);
347
348 let transfer_sol = anchor_lang::solana_program::system_instruction::transfer(
349 &ctx.accounts.avs_owner.key(),
350 &ctx.accounts.avs_account.key(),
351 registration_fee,
352 );
353
354 anchor_lang::solana_program::program::invoke(
355 &transfer_sol,
356 &[avs_owner_ai.clone(), avs_account_ai.clone()],
357 )?;
358
359
360 let avs_account = &mut ctx.accounts.avs_account;
361 let treasury = &mut ctx.accounts.treasury;
362
363 let treasury_share = registration_fee / 2;
364 **avs_account.to_account_info().try_borrow_mut_lamports()? -= treasury_share;
365 **treasury.to_account_info().try_borrow_mut_lamports()? += treasury_share;
366
367 avs_account.owner = ctx.accounts.avs_owner.key();
368 avs_account.metadata = metadata;
369 avs_account.registration_fee = registration_fee;
370 avs_account.active = true;
371 avs_account.registered_slot = Clock::get()?.slot;
372 avs_account.bump = ctx.bumps.avs_account;
373
374 Ok(())
375 }
376
377 pub fn update_avs_metadata(ctx: Context<UpdateAvsMetadata>, metadata: String )-> Result<()>{
378 let avs_account = &mut ctx.accounts.avs_account;
379
380 require!(avs_account.owner == ctx.accounts.avs_owner.key(), CustomError::Unauthorized);
381 avs_account.metadata = metadata;
382
383 Ok(())
384 }
385
386
387 pub fn de_register_avs(ctx: Context<DeRegisterAvs>) -> Result<()> {
388 let avs_account = &mut ctx.accounts.avs_account;
389 require!(avs_account.owner == ctx.accounts.avs_owner.key(), CustomError::Unauthorized);
390
391 avs_account.active = false;
392 Ok(())
393 }
394
395 pub fn operator_opt_in_avs(ctx: Context<OptInAvs>, avs_owner: Pubkey ) -> Result<()> {
396 let operator_account = &mut ctx.accounts.operator_account;
397 let operator_avs_reg = &mut ctx.accounts.operator_avs_registration;
398 let avs_account = &ctx.accounts.avs_account;
399
400
401 require!(
402 operator_account.active,
403 CustomError::OperatorNotActive
404 );
405
406
407 require!(
408 avs_account.active,
409 CustomError::AvsNotActive
410 );
411
412
413 operator_avs_reg.operator = ctx.accounts.operator_key.key();
414 operator_avs_reg.avs = avs_account.key();
415 operator_avs_reg.opted_in_slot = Clock::get()?.slot;
416 operator_avs_reg.active = true;
417 operator_avs_reg.tasks_completed = 0;
418 operator_avs_reg.tasks_failed = 0;
419 operator_avs_reg.bump = ctx.bumps.operator_avs_registration;
420
421
422 operator_account.avs_count = operator_account
423 .avs_count
424 .checked_add(1)
425 .unwrap();
426
427 msg!(
428 "✅ Operator {} opted into AVS {} (owner: {})",
429 operator_avs_reg.operator,
430 avs_account.key(),
431 avs_owner
432 );
433
434 Ok(())
435 }
436}
437
438#[derive(Accounts)]
439pub struct InitializeStateAccount<'info> {
440 #[account(mut)]
441 pub authority: Signer<'info>,
442
443 #[account(
444 init,
445 payer = authority,
446 space = 8 + StateAccount::INIT_SPACE,
447 seeds = [b"state"],
448 bump
449 )]
450 pub state: Account<'info, StateAccount>,
451
452 pub system_program: Program<'info, System>,
453}
454
455#[derive(Accounts)]
456#[instruction(token_mint: Pubkey)]
457pub struct InitializeVault<'info> {
458 #[account(mut)]
459 pub authority: Signer<'info>,
460
461 #[account(
462 init,
463 payer = authority,
464 space = 8 + VaultAccount::INIT_SPACE,
465 seeds = [b"vault_account", token_mint.key().as_ref()],
466 bump
467 )]
468 pub vault_account: Account<'info, VaultAccount>,
469
470 #[account(
471 init,
472 payer = authority,
473 token::mint = token_mint,
474 token::authority = vault_account,
475 seeds = [b"vault_token", token_mint.key().as_ref()],
476 bump
477 )]
478 pub vault: Account<'info, TokenAccount>,
479
480 pub token_mint: Account<'info, Mint>,
481 pub system_program: Program<'info, System>,
482 pub token_program: Program<'info, Token>,
483 pub rent: Sysvar<'info, Rent>,
484}
485
486#[derive(Accounts)]
487#[instruction(base_mint: Pubkey, restaked_mint: Pubkey)]
488pub struct InitializeMintAccount<'info> {
489 #[account(mut)]
490 pub authority: Signer<'info>,
491
492 #[account(
493 init,
494 payer = authority,
495 space = 8 + MintAccount::INIT_SPACE,
496 seeds = [b"mint_account", base_mint.key().as_ref()],
497 bump
498 )]
499 pub mint_account: Account<'info, MintAccount>,
500
501 #[account(mut)]
502 pub vault_account: Account<'info, VaultAccount>,
503
504 pub system_program: Program<'info, System>,
505}
506
507#[derive(Accounts)]
508pub struct Restake<'info> {
509 #[account(mut)]
510 pub user: Signer<'info>,
511
512 #[account(mut)]
513 pub user_base_token: Account<'info, TokenAccount>,
514
515 #[account(
516 mut,
517 seeds = [b"vault_account", mint_account.base_mint.as_ref()],
518 bump = vault_account.bump
519 )]
520 pub vault_account: Account<'info, VaultAccount>,
521
522 #[account(mut)]
523 pub vault: Account<'info, TokenAccount>,
524
525 #[account(
526 mut,
527 seeds = [b"mint_account", mint_account.base_mint.as_ref()],
528 bump = mint_account.bump
529 )]
530 pub mint_account: Account<'info, MintAccount>,
531
532 #[account(mut)]
533 pub restaked_mint: Account<'info, Mint>,
534
535 #[account(mut)]
536 pub user_restaked_token: Account<'info, TokenAccount>,
537
538 #[account(
539 init_if_needed,
540 payer = user,
541 space = 8 + UserRestakingAccount::INIT_SPACE,
542 seeds = [b"user_restaking", user.key().as_ref(), mint_account.restaked_mint.as_ref()],
543 bump
544 )]
545 pub user_restaking_account: Account<'info, UserRestakingAccount>,
546
547 pub token_program: Program<'info, Token>,
548 pub system_program: Program<'info, System>,
549}
550
551
552#[derive(Accounts)]
553pub struct RequestUnstake<'info> {
554 #[account(mut)]
555 pub user: Signer<'info>,
556
557 #[account(
558 mut,
559 constraint = user_restaked_token.owner == user.key(),
560 constraint = user_restaked_token.mint == mint_account.restaked_mint
561 )]
562 pub user_restaked_token: Account<'info, TokenAccount>,
563
564 #[account(
565 mut,
566 constraint = user_restaking_account.user == user.key(),
567 constraint = user_restaking_account.restaked_mint == mint_account.restaked_mint
568 )]
569 pub user_restaking_account: Account<'info, UserRestakingAccount>,
570
571 #[account(mut)]
572 pub restaked_mint: Account<'info, Mint>,
573
574 #[account(mut)]
575 pub mint_account: Account<'info, MintAccount>,
576
577 pub token_program: Program<'info, Token>,
578 pub system_program: Program<'info, System>,
579}
580
581#[derive(Accounts)]
582pub struct ClaimUnstake<'info> {
583 #[account(mut)]
584 pub user: Signer<'info>,
585
586 #[account(
587 mut,
588 constraint = user_base_token.owner == user.key(),
589 constraint = user_base_token.mint == mint_account.base_mint
590 )]
591 pub user_base_token: Account<'info, TokenAccount>,
592
593 #[account(
594 mut,
595 constraint = user_restaking_account.user == user.key(),
596 constraint = user_restaking_account.restaked_mint == mint_account.restaked_mint
597 )]
598 pub user_restaking_account: Account<'info, UserRestakingAccount>,
599
600 #[account(mut)]
601 pub vault_account: Account<'info, VaultAccount>,
602
603 #[account(
604 mut,
605 constraint = vault.mint == mint_account.base_mint
606 )]
607 pub vault: Account<'info, TokenAccount>,
608
609 #[account(mut)]
610 pub mint_account: Account<'info, MintAccount>,
611
612 pub token_program: Program<'info, Token>,
613}
614
615
616#[derive(Accounts)]
617pub struct RegisterOperator<'info> {
618 #[account(mut)]
619 pub operator_key: Signer<'info>,
620
621 #[account(
622 init,
623 payer = operator_key,
624 space = 8 + OperatorAccount::INIT_SPACE,
625 seeds = [b"operator", operator_key.key().as_ref()],
626 bump
627 )]
628 pub operator_account: Account<'info, OperatorAccount>,
629
630 #[account(
631 init,
632 payer = operator_key,
633 space = 8 + OperatorVault::INIT_SPACE,
634 seeds = [b"vault", operator_key.key().as_ref()],
635 bump
636 )]
637 pub vault: Account<'info, OperatorVault>,
638
639 pub system_program: Program<'info, System>,
640}
641
642
643#[derive(Accounts)]
644pub struct UpdateOperatorMetadata<'info>{
645 #[account(mut)]
646 pub owner: Signer<'info>,
647
648 #[account(
649 mut ,
650 seeds = [b"operator", owner.key().as_ref()],
651 bump = operator_account.bump,
652 has_one = owner @ CustomError::Unauthorized
653 )]
654 pub operator_account: Account<'info , OperatorAccount>
655}
656
657#[derive(Accounts)]
658pub struct DeRegisterOperator<'info> {
659 #[account(mut)]
660 pub operator_key: Signer<'info>,
661
662 #[account(
663 mut,
664 seeds = [b"operator", operator_key.key().as_ref()],
665 bump = operator_account.bump,
666 close = operator_key
667 )]
668 pub operator_account: Account<'info, OperatorAccount>,
669
670 #[account(
672 mut,
673 seeds = [b"vault", operator_key.key().as_ref()],
674 bump = operator_account.vault_bump,
675 close = operator_key )]
677 pub vault: Account<'info, OperatorVault>,
678
679 pub system_program: Program<'info, System>,
680}
681#[derive(Accounts)]
682#[instruction(operator_owner: Pubkey)]
683pub struct SlashOperator<'info> {
684 #[account(mut)]
685 pub authority: Signer<'info>,
686
687 #[account(
688 mut,
689 seeds = [b"operator", operator_owner.as_ref()],
690 bump = operator_account.bump,
691 )]
692 pub operator_account: Account<'info, OperatorAccount>,
693
694 #[account(
695 mut,
696 seeds = [b"vault", operator_owner.as_ref()],
697 bump = operator_account.vault_bump
698 )]
699 pub vault: Account<'info, OperatorVault>,
700
701 #[account(
702 mut,
703 seeds = [b"reward_treasury"],
704 bump = treasury.bump
705 )]
706 pub treasury: Account<'info, RewardTreasury>,
707
708 pub system_program: Program<'info, System>,
709}
710#[derive(Accounts)]
711pub struct InitializeRewardTreasury<'info> {
712 #[account(mut)]
713 pub authority: Signer<'info>,
714
715 #[account(
716 init,
717 payer = authority,
718 space = 8 + RewardTreasury::INIT_SPACE,
719 seeds = [b"reward_treasury"],
720 bump
721 )]
722 pub treasury: Account<'info, RewardTreasury>,
723
724 pub system_program: Program<'info, System>,
725}
726
727#[derive(Accounts)]
728pub struct ClaimRewards<'info> {
729 #[account(mut)]
730 pub user: Signer<'info>,
731
732 #[account(
733 mut,
734 constraint = user_restaking_account.user == user.key()
735 )]
736 pub user_restaking_account: Account<'info, UserRestakingAccount>,
737
738 #[account(
739 mut,
740 seeds = [b"reward_treasury"],
741 bump = treasury.bump
742 )]
743 pub treasury: Account<'info, RewardTreasury>,
744}
745
746#[derive(Accounts)]
747pub struct RegisterAvs<'info>{
748
749 #[account(mut)]
750 pub avs_owner : Signer<'info>,
751
752 #[account(
753 init ,
754 payer = avs_owner,
755 space = 8 + AvsAccount::INIT_SPACE,
756 seeds = [b"avs" , avs_owner.key().as_ref()],
757 bump
758 )]
759 pub avs_account : Account<'info , AvsAccount>,
760
761 #[account(
762 mut ,
763 seeds = [b"reward_treasury"],
764 bump = treasury.bump
765 )]
766 pub treasury: Account<'info , RewardTreasury>,
767
768 pub system_program : Program<'info , System>
769}
770
771#[derive(Accounts)]
772pub struct UpdateAvsMetadata<'info>{
773 #[account(mut)]
774 pub avs_owner: Signer<'info>,
775
776 #[account(
777 mut ,
778 seeds = [b"avs", avs_owner.key().as_ref()],
779 bump = avs_account.bump,
780 )]
781 pub avs_account: Account<'info , AvsAccount>
782}
783
784#[derive(Accounts)]
785pub struct DeRegisterAvs<'info>{
786 #[account(mut)]
787 pub avs_owner : Signer<'info>,
788
789 #[account(
790 mut,
791 seeds = [b"avs", avs_owner.key().as_ref()],
792 bump = avs_account.bump,
793 close = avs_owner
794 )]
795 pub avs_account : Account<'info , AvsAccount>
796}
797
798#[derive(Accounts)]
799pub struct GetUserData<'info> {
800 pub user: Signer<'info>,
801
802 #[account(
803 seeds = [b"user_restaking", user.key().as_ref(), restaked_mint.key().as_ref()],
804 bump = user_restaking_account.bump,
805 constraint = user_restaking_account.user == user.key()
806 )]
807 pub user_restaking_account: Account<'info, UserRestakingAccount>,
808
809 pub restaked_mint: Account<'info, Mint>,
810}
811
812
813#[derive(Accounts)]
814#[instruction(avs_owner: Pubkey)] pub struct OptInAvs<'info> {
816 #[account(mut)]
817 pub operator_key: Signer<'info>,
818
819
820 #[account(
821 mut,
822 seeds = [b"operator", operator_key.key().as_ref()],
823 bump = operator_account.bump,
824 constraint = operator_account.active @ CustomError::OperatorNotActive,
825 constraint = operator_account.owner == operator_key.key() @ CustomError::Unauthorized
826 )]
827 pub operator_account: Account<'info, OperatorAccount>,
828
829 #[account(
831 seeds = [b"avs", avs_owner.as_ref()], bump = avs_account.bump,
833 constraint = avs_account.active @ CustomError::AvsNotActive,
834 constraint = avs_account.owner == avs_owner @ CustomError::Unauthorized
835 )]
836 pub avs_account: Account<'info, AvsAccount>,
837
838 #[account(
840 init,
841 payer = operator_key,
842 space = 8 + OperatorAvsRegistration::INIT_SPACE,
843 seeds = [
844 b"operator_avs",
845 operator_key.key().as_ref(),
846 avs_owner.as_ref()
847 ],
848 bump
849 )]
850 pub operator_avs_registration: Account<'info, OperatorAvsRegistration>,
851
852 pub system_program: Program<'info, System>,
853}
854
855
856#[account]
857#[derive(InitSpace, Debug)]
858pub struct StateAccount {
859 pub authority: Pubkey,
860 pub msol_mint: Pubkey,
861 pub jitosol_mint: Pubkey,
862 pub rm_sol_mint: Pubkey,
863 pub rjito_sol_mint: Pubkey,
864 pub bump: u8,
865}
866
867#[account]
868#[derive(InitSpace, Debug)]
869pub struct VaultAccount {
870 pub token_mint: Pubkey,
871 pub vault: Pubkey,
872 pub bump: u8,
873 pub total_deposited: u64,
874}
875
876#[account]
877#[derive(InitSpace, Debug)]
878pub struct MintAccount {
879 pub base_mint: Pubkey,
880 pub restaked_mint: Pubkey,
881 pub vault: Pubkey,
882 pub bump: u8,
883 pub total_minted: u64,
884 pub exchange_rate: u64,
885 pub last_update_slot: u64,
886}
887#[account]
888#[derive(InitSpace, Debug)]
889pub struct UserRestakingAccount {
890 pub user: Pubkey,
891 pub deposited_mint: Pubkey,
892 pub restaked_mint: Pubkey,
893 pub deposited_amount: u64,
894 pub restaked_amount: u64,
895 pub bump: u8,
896 pub cooldown_end_slot: u64,
897 pub pending_unstake: u64,
898 pub reward_debt: u64,
899 pub last_claimed_slot: u64,
900}
901
902#[account]
903#[derive(InitSpace, Debug)]
904pub struct OperatorAccount {
905 pub owner: Pubkey,
906 pub bond_amount: u64,
907 #[max_len(100)]
908 pub metadata: String,
909 pub active: bool,
910 pub avs_count: u32,
911 pub bump: u8,
912 pub vault_bump: u8,
913}
914
915#[account]
916#[derive(InitSpace, Debug)]
917pub struct OperatorVault {
918 pub bump: u8,
919}
920
921
922#[account]
923#[derive(InitSpace, Debug)]
924pub struct RewardTreasury {
925 pub authority: Pubkey,
926 pub bump: u8,
927 pub total_rewards_distributed: u64,
928}
929
930
931#[account]
932#[derive(InitSpace, Debug)]
933pub struct AvsAccount{
934 pub owner: Pubkey,
935 #[max_len(100)]
936 pub metadata: String,
937 pub registration_fee : u64,
938 pub active : bool,
939 pub slashing_policy : Pubkey,
940 pub registered_slot : u64,
941 pub bump: u8,
942}
943
944pub struct SlashingPolicy {
945 pub misbehavior_type: u8, pub penalty_percent: u8,
947}
948
949#[account]
950#[derive(InitSpace, Debug)]
951pub struct OperatorAvsRegistration {
952 pub operator: Pubkey,
953 pub avs: Pubkey,
954 pub opted_in_slot: u64,
955 pub active: bool,
956 pub tasks_completed: u64,
957 pub tasks_failed: u64,
958 pub bump: u8,
959}
960
961#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
962pub struct UserUnstakeInfo {
963 pub cooldown_end_slot: u64,
964 pub pending_unstake: u64,
965 pub reward_debt: u64,
966}
967
968
969#[error_code]
970pub enum CustomError {
971 #[msg("Cooldown not finished yet")]
972 CooldownNotFinished,
973 #[msg("No pending unstake to claim")]
974 NothingToClaim,
975 #[msg("Not enough tokens supplied")]
976 NotEnoughToken,
977 #[msg("Unauthorized action")]
978 Unauthorized,
979 #[msg("Insufficient bond to slash")]
980 InsufficientBond,
981 #[msg("Not enough lamports in treasury")]
982 InsufficientTreasuryBalance,
983 #[msg("Avs not active to opt")]
984 AvsNotActive,
985 #[msg("Operator not active to run nodes")]
986 OperatorNotActive,
987 #[msg("Operator not opted into this AVS")]
988 OperatorNotOptedIn,
989 #[msg("Task not completed")]
990 TaskNotCompleted,
991 #[msg("Challenge already resolved")]
992 ChallengeAlreadyResolved,
993}