1use anchor_lang::{prelude::*, solana_program::clock::Clock};
2#[cfg(not(feature = "no-entrypoint"))]
3use solana_security_txt::security_txt;
4
5use crate::{
6 state::{
7 ClaimStatus, Config, MerkleRoot, MerkleRootUploadConfig, PriorityFeeDistributionAccount,
8 },
9 ErrorCode::Unauthorized,
10};
11
12#[cfg(not(feature = "no-entrypoint"))]
13security_txt! {
14 name: "Jito Priority Fee Program",
16 project_url: "https://jito.network/",
17 contacts: "email:support@jito.network",
18 policy: "https://github.com/jito-foundation/jito-programs",
19 preferred_languages: "en",
21 source_code: "https://github.com/jito-foundation/jito-programs",
22 source_revision: std::env!("GIT_SHA"),
23 source_release: std::env!("GIT_REF_NAME")
24}
25
26pub mod merkle_proof;
27pub mod state;
28
29declare_id!("Priority6weCZ5HwDn29NxLFpb7TDp2iLZ6XKc5e8d3");
30
31#[program]
32pub mod jito_priority_fee_distribution {
33 use jito_programs_vote_state::VoteState;
34 use solana_program::native_token::lamports_to_sol;
35
36 use super::*;
37 use crate::ErrorCode::*;
38
39 pub fn initialize(
41 ctx: Context<Initialize>,
42 authority: Pubkey,
43 expired_funds_account: Pubkey,
44 num_epochs_valid: u64,
45 max_validator_commission_bps: u16,
46 bump: u8,
47 ) -> Result<()> {
48 let cfg = &mut ctx.accounts.config;
49 cfg.authority = authority;
50 cfg.expired_funds_account = expired_funds_account;
51 cfg.num_epochs_valid = num_epochs_valid;
52 cfg.max_validator_commission_bps = max_validator_commission_bps;
53 cfg.go_live_epoch = u64::MAX;
54 cfg.bump = bump;
55 cfg.validate()?;
56
57 Ok(())
58 }
59
60 pub fn initialize_priority_fee_distribution_account(
63 ctx: Context<InitializePriorityFeeDistributionAccount>,
64 merkle_root_upload_authority: Pubkey,
65 validator_commission_bps: u16,
66 bump: u8,
67 ) -> Result<()> {
68 if validator_commission_bps > ctx.accounts.config.max_validator_commission_bps {
69 return Err(MaxValidatorCommissionFeeBpsExceeded.into());
70 }
71
72 let validator_vote_account_node_pubkey =
73 VoteState::deserialize_node_pubkey(&ctx.accounts.validator_vote_account)?;
74 if validator_vote_account_node_pubkey != *ctx.accounts.signer.key {
75 return Err(Unauthorized.into());
76 }
77
78 let current_epoch = Clock::get()?.epoch;
79
80 let distribution_acc = &mut ctx.accounts.priority_fee_distribution_account;
81 distribution_acc.validator_vote_account = ctx.accounts.validator_vote_account.key();
82 distribution_acc.epoch_created_at = current_epoch;
83 distribution_acc.validator_commission_bps = validator_commission_bps;
84 distribution_acc.merkle_root_upload_authority = merkle_root_upload_authority;
85 distribution_acc.merkle_root = None;
86 distribution_acc.expires_at = current_epoch
87 .checked_add(ctx.accounts.config.num_epochs_valid)
88 .ok_or(ArithmeticError)?;
89 distribution_acc.bump = bump;
90 distribution_acc.validate()?;
91
92 emit!(PriorityFeeDistributionAccountInitializedEvent {
93 priority_fee_distribution_account: distribution_acc.key(),
94 });
95
96 Ok(())
97 }
98
99 pub fn update_config(ctx: Context<UpdateConfig>, new_config: Config) -> Result<()> {
101 UpdateConfig::auth(&ctx)?;
102
103 let config = &mut ctx.accounts.config;
104 config.authority = new_config.authority;
105 config.expired_funds_account = new_config.expired_funds_account;
106 config.num_epochs_valid = new_config.num_epochs_valid;
107 config.max_validator_commission_bps = new_config.max_validator_commission_bps;
108 config.go_live_epoch = new_config.go_live_epoch;
109 config.validate()?;
110
111 emit!(ConfigUpdatedEvent {
112 authority: ctx.accounts.authority.key(),
113 });
114
115 Ok(())
116 }
117
118 pub fn upload_merkle_root(
123 ctx: Context<UploadMerkleRoot>,
124 root: [u8; 32],
125 max_total_claim: u64,
126 max_num_nodes: u64,
127 ) -> Result<()> {
128 UploadMerkleRoot::auth(&ctx)?;
129
130 let current_epoch = Clock::get()?.epoch;
131 let distribution_acc = &mut ctx.accounts.priority_fee_distribution_account;
132
133 if let Some(merkle_root) = &distribution_acc.merkle_root {
134 if merkle_root.num_nodes_claimed > 0 {
135 return Err(Unauthorized.into());
136 }
137 }
138 if current_epoch <= distribution_acc.epoch_created_at {
139 return Err(PrematureMerkleRootUpload.into());
140 }
141
142 if current_epoch > distribution_acc.expires_at {
143 return Err(ExpiredPriorityFeeDistributionAccount.into());
144 }
145
146 distribution_acc.merkle_root = Some(MerkleRoot {
147 root,
148 max_total_claim,
149 max_num_nodes,
150 total_funds_claimed: 0,
151 num_nodes_claimed: 0,
152 });
153 distribution_acc.validate()?;
154
155 emit!(MerkleRootUploadedEvent {
156 merkle_root_upload_authority: ctx.accounts.merkle_root_upload_authority.key(),
157 priority_fee_distribution_account: distribution_acc.key(),
158 });
159
160 Ok(())
161 }
162
163 pub fn close_claim_status(ctx: Context<CloseClaimStatus>) -> Result<()> {
166 let claim_status = &ctx.accounts.claim_status;
167
168 if Clock::get()?.epoch <= claim_status.expires_at {
170 return Err(PrematureCloseClaimStatus.into());
171 }
172
173 emit!(ClaimStatusClosedEvent {
174 claim_status_payer: ctx.accounts.claim_status_payer.key(),
175 claim_status_account: claim_status.key(),
176 });
177
178 Ok(())
179 }
180
181 pub fn close_priority_fee_distribution_account(
185 ctx: Context<ClosePriorityFeeDistributionAccount>,
186 _epoch: u64,
187 ) -> Result<()> {
188 ClosePriorityFeeDistributionAccount::auth(&ctx)?;
189
190 let priority_fee_distribution_account = &mut ctx.accounts.priority_fee_distribution_account;
191
192 if Clock::get()?.epoch <= priority_fee_distribution_account.expires_at {
193 return Err(PrematureClosePriorityFeeDistributionAccount.into());
194 }
195
196 let expired_amount = PriorityFeeDistributionAccount::claim_expired(
197 priority_fee_distribution_account.to_account_info(),
198 ctx.accounts.expired_funds_account.to_account_info(),
199 )?;
200 priority_fee_distribution_account.validate()?;
201
202 emit!(PriorityFeeDistributionAccountClosedEvent {
203 expired_funds_account: ctx.accounts.expired_funds_account.key(),
204 priority_fee_distribution_account: priority_fee_distribution_account.key(),
205 expired_amount,
206 });
207
208 Ok(())
209 }
210
211 pub fn claim(ctx: Context<Claim>, _bump: u8, amount: u64, proof: Vec<[u8; 32]>) -> Result<()> {
213 Claim::auth(&ctx)?;
214
215 let claim_status = &mut ctx.accounts.claim_status;
216
217 let claimant_account = &mut ctx.accounts.claimant;
218 let priority_fee_distribution_account = &mut ctx.accounts.priority_fee_distribution_account;
219
220 let clock = Clock::get()?;
221 if clock.epoch > priority_fee_distribution_account.expires_at {
222 return Err(ExpiredPriorityFeeDistributionAccount.into());
223 }
224
225 let tip_distribution_info = priority_fee_distribution_account.to_account_info();
226 let tip_distribution_epoch_expires_at = priority_fee_distribution_account.expires_at;
227 let merkle_root = priority_fee_distribution_account
228 .merkle_root
229 .as_mut()
230 .ok_or(RootNotUploaded)?;
231
232 let node = &solana_program::hash::hashv(&[
234 &[0u8],
235 &solana_program::hash::hashv(&[
236 &claimant_account.key().to_bytes(),
237 &amount.to_le_bytes(),
238 ])
239 .to_bytes(),
240 ]);
241
242 if !merkle_proof::verify(proof, merkle_root.root, node.to_bytes()) {
243 return Err(InvalidProof.into());
244 }
245
246 PriorityFeeDistributionAccount::claim(
247 tip_distribution_info,
248 claimant_account.to_account_info(),
249 amount,
250 )?;
251
252 claim_status.claim_status_payer = ctx.accounts.payer.key();
254 claim_status.expires_at = tip_distribution_epoch_expires_at;
255
256 merkle_root.total_funds_claimed = merkle_root
257 .total_funds_claimed
258 .checked_add(amount)
259 .ok_or(ArithmeticError)?;
260 if merkle_root.total_funds_claimed > merkle_root.max_total_claim {
261 return Err(ExceedsMaxClaim.into());
262 }
263
264 merkle_root.num_nodes_claimed = merkle_root
265 .num_nodes_claimed
266 .checked_add(1)
267 .ok_or(ArithmeticError)?;
268 if merkle_root.num_nodes_claimed > merkle_root.max_num_nodes {
269 return Err(ExceedsMaxNumNodes.into());
270 }
271
272 emit!(ClaimedEvent {
273 priority_fee_distribution_account: priority_fee_distribution_account.key(),
274 payer: ctx.accounts.payer.key(),
275 claimant: claimant_account.key(),
276 amount
277 });
278
279 priority_fee_distribution_account.validate()?;
280
281 Ok(())
282 }
283
284 pub fn initialize_merkle_root_upload_config(
285 ctx: Context<InitializeMerkleRootUploadConfig>,
286 authority: Pubkey,
287 original_authority: Pubkey,
288 ) -> Result<()> {
289 InitializeMerkleRootUploadConfig::auth(&ctx)?;
291
292 let merkle_root_upload_config = &mut ctx.accounts.merkle_root_upload_config;
294 merkle_root_upload_config.override_authority = authority;
295 merkle_root_upload_config.original_upload_authority = original_authority;
296 merkle_root_upload_config.bump = ctx.bumps.merkle_root_upload_config;
297 Ok(())
298 }
299
300 pub fn update_merkle_root_upload_config(
301 ctx: Context<UpdateMerkleRootUploadConfig>,
302 authority: Pubkey,
303 original_authority: Pubkey,
304 ) -> Result<()> {
305 UpdateMerkleRootUploadConfig::auth(&ctx)?;
307
308 let merkle_root_upload_config = &mut ctx.accounts.merkle_root_upload_config;
310 merkle_root_upload_config.override_authority = authority;
311 merkle_root_upload_config.original_upload_authority = original_authority;
312
313 Ok(())
314 }
315
316 pub fn migrate_tda_merkle_root_upload_authority(
317 ctx: Context<MigrateTdaMerkleRootUploadAuthority>,
318 ) -> Result<()> {
319 let distribution_account = &mut ctx.accounts.priority_fee_distribution_account;
320 if distribution_account.merkle_root.is_some() {
322 return Err(InvalidTdaForMigration.into());
323 }
324 if distribution_account.merkle_root_upload_authority
326 != ctx
327 .accounts
328 .merkle_root_upload_config
329 .original_upload_authority
330 {
331 return Err(InvalidTdaForMigration.into());
332 }
333
334 distribution_account.merkle_root_upload_authority =
336 ctx.accounts.merkle_root_upload_config.override_authority;
337
338 Ok(())
339 }
340
341 pub fn transfer_priority_fee_tips(
342 ctx: Context<TransferPriorityFeeTips>,
343 lamports: u64,
344 ) -> Result<()> {
345 let epoch = Clock::get()?.epoch;
346 require!(
348 ctx.accounts
349 .priority_fee_distribution_account
350 .epoch_created_at
351 == epoch,
352 ErrorCode::AccountValidationFailure
353 );
354
355 ctx.accounts
356 .priority_fee_distribution_account
357 .increment_total_lamports_transferred(lamports)?;
358
359 let go_live_epoch = ctx.accounts.config.go_live_epoch;
360 if go_live_epoch > epoch {
361 msg!(
362 "Priority fee transfer is not live yet. {}/{} - ({:.5})",
363 epoch,
364 go_live_epoch,
365 lamports_to_sol(lamports)
366 );
367
368 return Ok(());
369 }
370
371 let ix = solana_program::system_instruction::transfer(
373 ctx.accounts.from.key,
374 &ctx.accounts.priority_fee_distribution_account.key(),
375 lamports,
376 );
377 solana_program::program::invoke(
378 &ix,
379 &[
380 ctx.accounts.from.to_account_info(),
381 ctx.accounts
382 .priority_fee_distribution_account
383 .to_account_info(),
384 ],
385 )
386 .map_err(Into::into)
387 }
388}
389
390#[error_code]
391pub enum ErrorCode {
392 #[msg("Account failed validation.")]
393 AccountValidationFailure,
394
395 #[msg("Encountered an arithmetic under/overflow error.")]
396 ArithmeticError,
397
398 #[msg("The maximum number of funds to be claimed has been exceeded.")]
399 ExceedsMaxClaim,
400
401 #[msg("The maximum number of claims has been exceeded.")]
402 ExceedsMaxNumNodes,
403
404 #[msg("The given PriorityFeeDistributionAccount has expired.")]
405 ExpiredPriorityFeeDistributionAccount,
406
407 #[msg("The funds for the given index and PriorityFeeDistributionAccount have already been claimed.")]
408 FundsAlreadyClaimed,
409
410 #[msg("Supplied invalid parameters.")]
411 InvalidParameters,
412
413 #[msg("The given proof is invalid.")]
414 InvalidProof,
415
416 #[msg("Failed to deserialize the supplied vote account data.")]
417 InvalidVoteAccountData,
418
419 #[msg("Validator's commission basis points must be less than or equal to the Config account's max_validator_commission_bps.")]
420 MaxValidatorCommissionFeeBpsExceeded,
421
422 #[msg("The given PriorityFeeDistributionAccount is not ready to be closed.")]
423 PrematureClosePriorityFeeDistributionAccount,
424
425 #[msg("The given ClaimStatus account is not ready to be closed.")]
426 PrematureCloseClaimStatus,
427
428 #[msg("Must wait till at least one epoch after the tip distribution account was created to upload the merkle root.")]
429 PrematureMerkleRootUpload,
430
431 #[msg("No merkle root has been uploaded to the given PriorityFeeDistributionAccount.")]
432 RootNotUploaded,
433
434 #[msg("Unauthorized signer.")]
435 Unauthorized,
436
437 #[msg("TDA not valid for migration.")]
438 InvalidTdaForMigration,
439}
440
441#[derive(Accounts)]
442pub struct CloseClaimStatus<'info> {
443 #[account(
446 mut,
447 close = claim_status_payer,
448 constraint = claim_status_payer.key() == claim_status.claim_status_payer
449 )]
450 pub claim_status: Account<'info, ClaimStatus>,
451
452 #[account(mut)]
455 pub claim_status_payer: UncheckedAccount<'info>,
456}
457
458#[derive(Accounts)]
459pub struct Initialize<'info> {
460 #[account(
461 init,
462 seeds = [Config::SEED],
463 bump,
464 payer = initializer,
465 space = Config::SIZE,
466 rent_exempt = enforce
467 )]
468 pub config: Account<'info, Config>,
469
470 pub system_program: Program<'info, System>,
471
472 #[account(mut)]
473 pub initializer: Signer<'info>,
474}
475
476#[derive(Accounts)]
477#[instruction(
478 _merkle_root_upload_authority: Pubkey,
479 _validator_commission_bps: u16,
480 _bump: u8
481)]
482pub struct InitializePriorityFeeDistributionAccount<'info> {
483 pub config: Account<'info, Config>,
484
485 #[account(
486 init,
487 seeds = [
488 PriorityFeeDistributionAccount::SEED,
489 validator_vote_account.key().as_ref(),
490 Clock::get().unwrap().epoch.to_le_bytes().as_ref(),
491 ],
492 bump,
493 payer = signer,
494 space = PriorityFeeDistributionAccount::SIZE,
495 rent_exempt = enforce
496 )]
497 pub priority_fee_distribution_account: Account<'info, PriorityFeeDistributionAccount>,
498
499 pub validator_vote_account: AccountInfo<'info>,
502
503 #[account(mut)]
505 pub signer: Signer<'info>,
506
507 pub system_program: Program<'info, System>,
508}
509
510#[derive(Accounts)]
511pub struct UpdateConfig<'info> {
512 #[account(mut, rent_exempt = enforce)]
513 pub config: Account<'info, Config>,
514
515 #[account(mut)]
516 pub authority: Signer<'info>,
517}
518
519impl UpdateConfig<'_> {
520 fn auth(ctx: &Context<UpdateConfig>) -> Result<()> {
521 if ctx.accounts.config.authority != ctx.accounts.authority.key() {
522 Err(Unauthorized.into())
523 } else {
524 Ok(())
525 }
526 }
527}
528
529#[derive(Accounts)]
530#[instruction(epoch: u64)]
531pub struct ClosePriorityFeeDistributionAccount<'info> {
532 pub config: Account<'info, Config>,
533
534 #[account(mut)]
536 pub expired_funds_account: AccountInfo<'info>,
537
538 #[account(
539 mut,
540 close = validator_vote_account,
541 seeds = [
542 PriorityFeeDistributionAccount::SEED,
543 validator_vote_account.key().as_ref(),
544 epoch.to_le_bytes().as_ref(),
545 ],
546 bump = priority_fee_distribution_account.bump,
547 )]
548 pub priority_fee_distribution_account: Account<'info, PriorityFeeDistributionAccount>,
549
550 #[account(mut)]
552 pub validator_vote_account: AccountInfo<'info>,
553
554 #[account(mut)]
556 pub signer: Signer<'info>,
557}
558
559impl ClosePriorityFeeDistributionAccount<'_> {
560 fn auth(ctx: &Context<ClosePriorityFeeDistributionAccount>) -> Result<()> {
561 if ctx.accounts.config.expired_funds_account != ctx.accounts.expired_funds_account.key() {
562 Err(Unauthorized.into())
563 } else {
564 Ok(())
565 }
566 }
567}
568
569#[derive(Accounts)]
570#[instruction(_bump: u8, _amount: u64, _proof: Vec<[u8; 32]>)]
571pub struct Claim<'info> {
572 pub config: Account<'info, Config>,
573
574 #[account(mut, rent_exempt = enforce)]
575 pub priority_fee_distribution_account: Account<'info, PriorityFeeDistributionAccount>,
576
577 pub merkle_root_upload_authority: Signer<'info>,
578
579 #[account(
581 init,
582 rent_exempt = enforce,
583 seeds = [
584 ClaimStatus::SEED,
585 claimant.key().as_ref(),
586 priority_fee_distribution_account.key().as_ref()
587 ],
588 bump,
589 space = ClaimStatus::SIZE,
590 payer = payer
591 )]
592 pub claim_status: Account<'info, ClaimStatus>,
593
594 #[account(mut)]
597 pub claimant: AccountInfo<'info>,
598
599 #[account(mut)]
601 pub payer: Signer<'info>,
602
603 pub system_program: Program<'info, System>,
604}
605impl Claim<'_> {
606 fn auth(ctx: &Context<Claim>) -> Result<()> {
607 if ctx.accounts.merkle_root_upload_authority.key()
608 != ctx
609 .accounts
610 .priority_fee_distribution_account
611 .merkle_root_upload_authority
612 {
613 Err(Unauthorized.into())
614 } else {
615 Ok(())
616 }
617 }
618}
619
620#[derive(Accounts)]
621pub struct UploadMerkleRoot<'info> {
622 pub config: Account<'info, Config>,
623
624 #[account(mut, rent_exempt = enforce)]
625 pub priority_fee_distribution_account: Account<'info, PriorityFeeDistributionAccount>,
626
627 #[account(mut)]
628 pub merkle_root_upload_authority: Signer<'info>,
629}
630
631impl UploadMerkleRoot<'_> {
632 fn auth(ctx: &Context<UploadMerkleRoot>) -> Result<()> {
633 if ctx.accounts.merkle_root_upload_authority.key()
634 != ctx
635 .accounts
636 .priority_fee_distribution_account
637 .merkle_root_upload_authority
638 {
639 Err(Unauthorized.into())
640 } else {
641 Ok(())
642 }
643 }
644}
645
646#[derive(Accounts)]
647pub struct InitializeMerkleRootUploadConfig<'info> {
648 #[account(mut, rent_exempt = enforce)]
649 pub config: Account<'info, Config>,
650
651 #[account(
652 init,
653 rent_exempt = enforce,
654 seeds = [
655 MerkleRootUploadConfig::SEED,
656 ],
657 bump,
658 space = MerkleRootUploadConfig::SIZE,
659 payer = payer
660 )]
661 pub merkle_root_upload_config: Account<'info, MerkleRootUploadConfig>,
662
663 pub authority: Signer<'info>,
664
665 #[account(mut)]
666 pub payer: Signer<'info>,
667
668 pub system_program: Program<'info, System>,
669}
670
671impl InitializeMerkleRootUploadConfig<'_> {
672 fn auth(ctx: &Context<InitializeMerkleRootUploadConfig>) -> Result<()> {
673 if ctx.accounts.config.authority != ctx.accounts.authority.key() {
674 Err(Unauthorized.into())
675 } else {
676 Ok(())
677 }
678 }
679}
680
681#[derive(Accounts)]
682pub struct UpdateMerkleRootUploadConfig<'info> {
683 #[account(rent_exempt = enforce)]
684 pub config: Account<'info, Config>,
685
686 #[account(
687 mut,
688 seeds = [MerkleRootUploadConfig::SEED],
689 bump,
690 rent_exempt = enforce,
691 )]
692 pub merkle_root_upload_config: Account<'info, MerkleRootUploadConfig>,
693
694 pub authority: Signer<'info>,
695
696 pub system_program: Program<'info, System>,
697}
698
699impl UpdateMerkleRootUploadConfig<'_> {
700 fn auth(ctx: &Context<UpdateMerkleRootUploadConfig>) -> Result<()> {
701 if ctx.accounts.config.authority != ctx.accounts.authority.key() {
702 Err(Unauthorized.into())
703 } else {
704 Ok(())
705 }
706 }
707}
708
709#[derive(Accounts)]
710pub struct MigrateTdaMerkleRootUploadAuthority<'info> {
711 #[account(mut, rent_exempt = enforce)]
712 pub priority_fee_distribution_account: Account<'info, PriorityFeeDistributionAccount>,
713
714 #[account(
715 seeds = [MerkleRootUploadConfig::SEED],
716 bump,
717 rent_exempt = enforce,
718 )]
719 pub merkle_root_upload_config: Account<'info, MerkleRootUploadConfig>,
720}
721
722#[derive(Accounts)]
723pub struct TransferPriorityFeeTips<'info> {
724 #[account(rent_exempt = enforce)]
725 pub config: Account<'info, Config>,
726
727 #[account(
728 mut,
729 rent_exempt = enforce
730 )]
731 pub priority_fee_distribution_account: Account<'info, PriorityFeeDistributionAccount>,
732
733 #[account(mut)]
734 pub from: Signer<'info>,
735 pub system_program: Program<'info, System>,
736}
737
738#[event]
741pub struct PriorityFeeDistributionAccountInitializedEvent {
742 pub priority_fee_distribution_account: Pubkey,
743}
744
745#[event]
746pub struct ValidatorCommissionBpsUpdatedEvent {
747 pub priority_fee_distribution_account: Pubkey,
748 pub old_commission_bps: u16,
749 pub new_commission_bps: u16,
750}
751
752#[event]
753pub struct MerkleRootUploadAuthorityUpdatedEvent {
754 pub old_authority: Pubkey,
755 pub new_authority: Pubkey,
756}
757
758#[event]
759pub struct ConfigUpdatedEvent {
760 authority: Pubkey,
762}
763
764#[event]
765pub struct ClaimedEvent {
766 pub priority_fee_distribution_account: Pubkey,
768
769 pub payer: Pubkey,
771
772 pub claimant: Pubkey,
774
775 pub amount: u64,
777}
778
779#[event]
780pub struct MerkleRootUploadedEvent {
781 pub merkle_root_upload_authority: Pubkey,
783
784 pub priority_fee_distribution_account: Pubkey,
786}
787
788#[event]
789pub struct PriorityFeeDistributionAccountClosedEvent {
790 pub expired_funds_account: Pubkey,
792
793 pub priority_fee_distribution_account: Pubkey,
795
796 pub expired_amount: u64,
798}
799
800#[event]
801pub struct ClaimStatusClosedEvent {
802 pub claim_status_payer: Pubkey,
804
805 pub claim_status_account: Pubkey,
807}