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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use {
crate::objects::*,
anchor_lang::prelude::*,
clockwork_utils::{anchor_sighash, AccountMetaData, ExecResponse, InstructionData},
};
#[derive(Accounts)]
pub struct WorkerDistributeFees<'info> {
#[account(address = Config::pubkey())]
pub config: Account<'info, Config>,
#[account(
mut,
seeds = [
SEED_FEE,
fee.worker.as_ref(),
],
bump,
has_one = worker,
)]
pub fee: Account<'info, Fee>,
#[account(address = Registry::pubkey())]
pub registry: Account<'info, Registry>,
#[account(
address = snapshot.pubkey(),
constraint = snapshot.id.eq(®istry.current_epoch)
)]
pub snapshot: Account<'info, Snapshot>,
#[account(
address = snapshot_frame.pubkey(),
has_one = snapshot,
has_one = worker,
)]
pub snapshot_frame: Account<'info, SnapshotFrame>,
#[account(address = config.epoch_thread)]
pub thread: Signer<'info>,
#[account(mut)]
pub worker: Account<'info, Worker>,
}
pub fn handler(ctx: Context<WorkerDistributeFees>) -> Result<ExecResponse> {
let config = &ctx.accounts.config;
let fee = &mut ctx.accounts.fee;
let registry = &ctx.accounts.registry;
let snapshot = &ctx.accounts.snapshot;
let snapshot_frame = &ctx.accounts.snapshot_frame;
let thread = &ctx.accounts.thread;
let worker = &mut ctx.accounts.worker;
let fee_lamport_balance = fee.to_account_info().lamports();
let fee_data_len = 8 + fee.try_to_vec()?.len();
let fee_rent_balance = Rent::get().unwrap().minimum_balance(fee_data_len);
let fee_usable_balance = fee_lamport_balance.checked_sub(fee_rent_balance).unwrap();
let commission_balance = fee_usable_balance
.checked_mul(worker.commission_rate)
.unwrap()
.checked_div(100)
.unwrap();
**fee.to_account_info().try_borrow_mut_lamports()? = fee
.to_account_info()
.lamports()
.checked_sub(commission_balance)
.unwrap();
**worker.to_account_info().try_borrow_mut_lamports()? = worker
.to_account_info()
.lamports()
.checked_add(commission_balance)
.unwrap();
worker.commission_balance = worker
.commission_balance
.checked_add(commission_balance)
.unwrap();
fee.distributable_balance = fee_usable_balance.checked_sub(commission_balance).unwrap();
let next_instruction = if snapshot_frame.total_entries.gt(&0) {
let delegation_pubkey = Delegation::pubkey(worker.key(), 0);
let snapshot_entry_pubkey = SnapshotEntry::pubkey(snapshot_frame.key(), 0);
Some(InstructionData {
program_id: crate::ID,
accounts: vec![
AccountMetaData::new_readonly(config.key(), false),
AccountMetaData::new(delegation_pubkey, false),
AccountMetaData::new(fee.key(), false),
AccountMetaData::new_readonly(registry.key(), false),
AccountMetaData::new_readonly(snapshot.key(), false),
AccountMetaData::new_readonly(snapshot_frame.key(), false),
AccountMetaData::new_readonly(snapshot_entry_pubkey.key(), false),
AccountMetaData::new_readonly(thread.key(), true),
AccountMetaData::new_readonly(worker.key(), false),
],
data: anchor_sighash("fee_distribute").to_vec(),
})
} else if snapshot_frame
.id
.checked_add(1)
.unwrap()
.lt(&snapshot.total_frames)
{
let next_worker_pubkey = Worker::pubkey(worker.id.checked_add(1).unwrap());
let next_snapshot_frame_pubkey =
SnapshotFrame::pubkey(snapshot.key(), snapshot_frame.id.checked_add(1).unwrap());
Some(InstructionData {
program_id: crate::ID,
accounts: vec![
AccountMetaData::new_readonly(config.key(), false),
AccountMetaData::new(Fee::pubkey(next_worker_pubkey), false),
AccountMetaData::new_readonly(registry.key(), false),
AccountMetaData::new_readonly(snapshot.key(), false),
AccountMetaData::new_readonly(next_snapshot_frame_pubkey, false),
AccountMetaData::new_readonly(thread.key(), true),
AccountMetaData::new(next_worker_pubkey, false),
],
data: anchor_sighash("worker_fees_distribute").to_vec(),
})
} else if registry.total_unstakes.gt(&0) {
Some(InstructionData {
program_id: crate::ID,
accounts: vec![
AccountMetaData::new_readonly(config.key(), false),
AccountMetaData::new_readonly(registry.key(), false),
AccountMetaData::new_readonly(thread.key(), true),
AccountMetaData::new_readonly(Unstake::pubkey(0), false),
],
data: anchor_sighash("unstake_preprocess").to_vec(),
})
} else {
Some(InstructionData {
program_id: crate::ID,
accounts: vec![
AccountMetaData::new_readonly(config.key(), false),
AccountMetaData::new_readonly(registry.key(), false),
AccountMetaData::new_readonly(thread.key(), true),
AccountMetaData::new_readonly(Worker::pubkey(0), false),
],
data: anchor_sighash("worker_delegations_stake").to_vec(),
})
};
Ok(ExecResponse {
next_instruction,
..ExecResponse::default()
})
}