-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathcall_handler.rs
More file actions
127 lines (118 loc) · 3.63 KB
/
call_handler.rs
File metadata and controls
127 lines (118 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use borsh::BorshDeserialize;
use solana_program::{
account_info::AccountInfo,
entrypoint::ProgramResult,
instruction::{AccountMeta, Instruction},
program::invoke_signed,
program_error::ProgramError,
pubkey::Pubkey,
system_program,
};
use crate::{
args::CallHandlerArgs,
ephemeral_balance_seeds_from_payer,
error::{INVALID_ESCROW_OWNER, INVALID_ESCROW_PDA},
processor::utils::loaders::{
load_initialized_validator_fees_vault, load_owned_pda, load_pda,
load_signer,
},
};
/// Calls a handler on user specified program
///
/// Accounts:
/// 0: `[signer]` validator
/// 1: `[]` validator fee vault to verify its registration
/// 2: `[]` destination program of an action
/// 3: `[]` escrow authority account which created escrow account
/// 4: `[writable]` non delegated escrow pda created from 3
/// 5: `[readonly/writable]` other accounts needed for action
/// 6: `[readonly/writable]` other accounts needed for action
/// 7: ...
///
/// Requirements:
///
/// - escrow account initialized
/// - escrow account not delegated
/// - validator as a caller
///
/// Steps:
/// 1. Verify that signer is a valid registered validator
/// 2. Verify escrow pda exists and not delegated
/// 3. Invoke signed on behalf of escrow pda user specified action
///
/// Usage:
///
/// This instruction is meant to be called via CPI with the owning program signing for the
/// delegated account.
pub fn process_call_handler(
_program_id: &Pubkey,
accounts: &[AccountInfo],
data: &[u8],
) -> ProgramResult {
const OTHER_ACCOUNTS_OFFSET: usize = 5;
let (
[validator, validator_fees_vault, destination_program, escrow_authority_account, escrow_account],
other_accounts,
) = accounts.split_at(OTHER_ACCOUNTS_OFFSET)
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
let args = CallHandlerArgs::try_from_slice(data)?;
// verify account is a signer
load_signer(validator, "validator")?;
// verify signer is a registered validator
load_initialized_validator_fees_vault(
validator,
validator_fees_vault,
true,
)?;
// verify passed escrow_account derived from escrow authority
let escrow_seeds: &[&[u8]] = ephemeral_balance_seeds_from_payer!(
escrow_authority_account.key,
args.escrow_index
);
let escrow_bump = load_pda(
escrow_account,
escrow_seeds,
&crate::id(),
true,
INVALID_ESCROW_PDA,
)?;
load_owned_pda(
escrow_account,
&system_program::id(),
INVALID_ESCROW_OWNER,
)?;
// deduce necessary accounts for CPI
let (accounts_meta, handler_accounts): (
Vec<AccountMeta>,
Vec<AccountInfo>,
) = other_accounts
.iter()
.chain([escrow_authority_account, escrow_account])
.filter(|account| account.key != validator.key)
.map(|account| {
(
// We enable only escrow to be a signer
AccountMeta {
pubkey: *account.key,
is_writable: account.is_writable,
is_signer: account.key == escrow_account.key,
},
account.clone(),
)
})
.collect();
let handler_instruction = Instruction {
program_id: *destination_program.key,
data: args.data,
accounts: accounts_meta,
};
let bump_slice = &[escrow_bump];
let escrow_signer_seeds = [escrow_seeds, &[bump_slice]].concat();
invoke_signed(
&handler_instruction,
&handler_accounts,
&[&escrow_signer_seeds],
)
}