Skip to content

Commit 809e17c

Browse files
committed
reclaim tdas
1 parent 83ea7fe commit 809e17c

File tree

3 files changed

+270
-5
lines changed

3 files changed

+270
-5
lines changed

priority_fee_distribution_sdk/src/instruction.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,32 @@ pub fn close_claim_status_ix(
140140
}
141141
}
142142

143+
pub fn close_priority_fee_distribution_account_ix(
144+
config: Pubkey,
145+
priority_fee_distribution_account: Pubkey,
146+
expired_funds_account: Pubkey,
147+
validator_vote_account: Pubkey,
148+
signer: Pubkey,
149+
epoch: u64,
150+
) -> Instruction {
151+
Instruction {
152+
program_id: jito_priority_fee_distribution::ID,
153+
accounts:
154+
jito_priority_fee_distribution::client::accounts::ClosePriorityFeeDistributionAccount {
155+
config,
156+
priority_fee_distribution_account,
157+
expired_funds_account,
158+
validator_vote_account,
159+
signer,
160+
}
161+
.to_account_metas(None),
162+
data: jito_priority_fee_distribution::client::args::ClosePriorityFeeDistributionAccount {
163+
_epoch: epoch,
164+
}
165+
.data(),
166+
}
167+
}
168+
143169
pub fn migrate_tda_merkle_root_upload_authority_ix(
144170
priority_fee_distribution_account: Pubkey,
145171
merkle_root_upload_config: Pubkey,

tip-router-operator-cli/src/reclaim.rs

Lines changed: 221 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@ use std::{sync::Arc, time::Instant};
33
use anchor_lang::{AccountDeserialize, Discriminator};
44
use anyhow::Result;
55
use jito_priority_fee_distribution_sdk::{
6-
instruction::close_claim_status_ix as close_pf_claim_status_ix,
6+
instruction::{
7+
close_claim_status_ix as close_pf_claim_status_ix,
8+
close_priority_fee_distribution_account_ix,
9+
},
710
jito_priority_fee_distribution::accounts::ClaimStatus as PriorityFeeDistributionClaimStatus,
11+
jito_priority_fee_distribution::accounts::Config as PriorityFeeDistributionConfig,
812
PriorityFeeDistributionAccount,
913
};
1014
use jito_tip_distribution_sdk::{
11-
instruction::close_claim_status_ix as close_tip_claim_status_ix,
15+
instruction::{
16+
close_claim_status_ix as close_tip_claim_status_ix, close_tip_distribution_account_ix,
17+
},
1218
jito_tip_distribution::accounts::ClaimStatus as TipDistributionClaimStatus,
19+
jito_tip_distribution::accounts::Config as TipDistributionConfig,
1320
TipDistributionAccount,
1421
};
1522
use log::{error, info};
@@ -34,6 +41,32 @@ pub async fn close_expired_accounts(
3441
priority_fee_distribution_program_id: Pubkey,
3542
signer: Arc<Keypair>,
3643
num_monitored_epochs: u64,
44+
) -> Result<()> {
45+
close_expired_distribution_accounts(
46+
rpc_url,
47+
tip_distribution_program_id,
48+
priority_fee_distribution_program_id,
49+
signer.clone(),
50+
num_monitored_epochs,
51+
)
52+
.await?;
53+
close_expired_claims(
54+
rpc_url,
55+
tip_distribution_program_id,
56+
priority_fee_distribution_program_id,
57+
signer.clone(),
58+
num_monitored_epochs,
59+
)
60+
.await?;
61+
Ok(())
62+
}
63+
64+
pub async fn close_expired_claims(
65+
rpc_url: &str,
66+
tip_distribution_program_id: Pubkey,
67+
priority_fee_distribution_program_id: Pubkey,
68+
signer: Arc<Keypair>,
69+
num_monitored_epochs: u64,
3770
) -> Result<()> {
3871
let epochs_to_process = {
3972
// Use default timeout and commitment config for fetching the current epoch
@@ -56,7 +89,6 @@ pub async fn close_expired_accounts(
5689
let duration = start.elapsed();
5790
datapoint_info!(
5891
"tip_router_cli.expired_claim_statuses",
59-
("epoch", epoch, i64),
6092
(
6193
"expired_tip_claim_statuses",
6294
tip_distribution_claim_accounts.len(),
@@ -68,6 +100,7 @@ pub async fn close_expired_accounts(
68100
i64
69101
),
70102
("duration", duration.as_secs(), i64),
103+
"epoch" => epoch.to_string(),
71104
);
72105

73106
let close_tip_claim_transactions = close_tip_claim_transactions(
@@ -112,6 +145,100 @@ pub async fn close_expired_accounts(
112145
Ok(())
113146
}
114147

148+
pub async fn close_expired_distribution_accounts(
149+
rpc_url: &str,
150+
tip_distribution_program_id: Pubkey,
151+
priority_fee_distribution_program_id: Pubkey,
152+
signer: Arc<Keypair>,
153+
num_monitored_epochs: u64,
154+
) -> Result<()> {
155+
let epochs_to_process = {
156+
// Use default timeout and commitment config for fetching the current epoch
157+
let rpc_client = rpc_utils::new_rpc_client(rpc_url);
158+
let current_epoch = rpc_client.get_epoch_info().await?.epoch;
159+
(current_epoch - num_monitored_epochs)..current_epoch
160+
};
161+
for epoch in epochs_to_process {
162+
let rpc_client = rpc_utils::new_high_timeout_rpc_client(rpc_url);
163+
info!("Fetching distribution accounts expiring in epoch {}", epoch);
164+
let start = Instant::now();
165+
let (tip_distribution_accounts, priority_fee_distribution_accounts) =
166+
fetch_expired_distribution_accounts(
167+
&rpc_client,
168+
tip_distribution_program_id,
169+
priority_fee_distribution_program_id,
170+
epoch,
171+
)
172+
.await?;
173+
let duration = start.elapsed();
174+
datapoint_info!(
175+
"tip_router_cli.expired_distribution_accounts",
176+
(
177+
"expired_tip_distribution_accounts",
178+
tip_distribution_accounts.len(),
179+
i64
180+
),
181+
(
182+
"expired_priority_fee_distribution_accounts",
183+
priority_fee_distribution_accounts.len(),
184+
i64
185+
),
186+
("duration", duration.as_secs(), i64),
187+
"epoch" => epoch.to_string(),
188+
);
189+
190+
let close_tip_claim_transactions = close_tip_distribution_account_transactions(
191+
&rpc_client,
192+
&tip_distribution_accounts,
193+
tip_distribution_program_id,
194+
signer.pubkey(),
195+
epoch,
196+
)
197+
.await?;
198+
let close_priority_fee_claim_transactions =
199+
close_priority_fee_distribution_account_transactions(
200+
&rpc_client,
201+
&priority_fee_distribution_accounts,
202+
priority_fee_distribution_program_id,
203+
signer.pubkey(),
204+
epoch,
205+
)
206+
.await?;
207+
let mut transactions = [
208+
close_tip_claim_transactions,
209+
close_priority_fee_claim_transactions,
210+
]
211+
.concat();
212+
213+
info!(
214+
"Processing {} close distribution account transactions",
215+
transactions.len()
216+
);
217+
let rpc_client = rpc_utils::new_rpc_client(rpc_url);
218+
transactions.shuffle(&mut rand::thread_rng());
219+
for batch in transactions.chunks_mut(100_000) {
220+
let start = Instant::now();
221+
let mut blockhash = rpc_client.get_latest_blockhash().await?;
222+
for transaction in batch.iter_mut() {
223+
transaction.sign(&[&signer], blockhash);
224+
let maybe_signature = rpc_client.send_transaction(transaction).await;
225+
if let Err(e) = maybe_signature {
226+
// Fetch a new blockhash if the transaction failed
227+
blockhash = rpc_client.get_latest_blockhash().await?;
228+
error!("Error sending transaction: {:?}", e);
229+
}
230+
}
231+
let duration = start.elapsed();
232+
info!(
233+
"Processed batch of {} close distribution account transactions in {:?} seconds",
234+
batch.len(),
235+
duration.as_secs()
236+
);
237+
}
238+
}
239+
Ok(())
240+
}
241+
115242
fn close_tip_claim_transactions(
116243
accounts: &[(Pubkey, TipDistributionClaimStatus)],
117244
tip_distribution_program_id: Pubkey,
@@ -150,6 +277,91 @@ fn close_priority_fee_claim_transactions(
150277
pack_transactions(instructions, payer, MAX_TRANSACTION_SIZE)
151278
}
152279

280+
async fn close_tip_distribution_account_transactions(
281+
rpc_client: &RpcClient,
282+
accounts: &[(Pubkey, TipDistributionAccount)],
283+
tip_distribution_program_id: Pubkey,
284+
payer: Pubkey,
285+
target_epoch: u64,
286+
) -> Result<Vec<Transaction>> {
287+
let config_pubkey =
288+
jito_tip_distribution_sdk::derive_config_account_address(&tip_distribution_program_id).0;
289+
290+
let config_account = rpc_client
291+
.get_account_with_config(
292+
&config_pubkey,
293+
RpcAccountInfoConfig {
294+
encoding: Some(UiAccountEncoding::Base64),
295+
..RpcAccountInfoConfig::default()
296+
},
297+
)
298+
.await?
299+
.value
300+
.ok_or(anyhow::anyhow!("Config account not found"))?;
301+
302+
let tip_distribution_config =
303+
TipDistributionConfig::try_deserialize(&mut config_account.data.as_slice())?;
304+
305+
let instructions: Vec<_> = accounts
306+
.iter()
307+
.map(|(pubkey, account)| {
308+
close_tip_distribution_account_ix(
309+
config_pubkey,
310+
*pubkey,
311+
tip_distribution_config.expired_funds_account,
312+
account.validator_vote_account,
313+
payer,
314+
account.epoch_created_at,
315+
)
316+
})
317+
.collect();
318+
319+
Ok(pack_transactions(instructions, payer, MAX_TRANSACTION_SIZE))
320+
}
321+
322+
async fn close_priority_fee_distribution_account_transactions(
323+
rpc_client: &RpcClient,
324+
accounts: &[(Pubkey, PriorityFeeDistributionAccount)],
325+
priority_fee_distribution_program_id: Pubkey,
326+
payer: Pubkey,
327+
target_epoch: u64,
328+
) -> Result<Vec<Transaction>> {
329+
let config_pubkey = jito_priority_fee_distribution_sdk::derive_config_account_address(
330+
&priority_fee_distribution_program_id,
331+
)
332+
.0;
333+
let config_account = rpc_client
334+
.get_account_with_config(
335+
&config_pubkey,
336+
RpcAccountInfoConfig {
337+
encoding: Some(UiAccountEncoding::Base64),
338+
..RpcAccountInfoConfig::default()
339+
},
340+
)
341+
.await?
342+
.value
343+
.ok_or(anyhow::anyhow!("Config account not found"))?;
344+
345+
let priority_fee_distribution_config =
346+
PriorityFeeDistributionConfig::try_deserialize(&mut config_account.data.as_slice())?;
347+
348+
let instructions: Vec<_> = accounts
349+
.iter()
350+
.map(|(pubkey, account)| {
351+
close_priority_fee_distribution_account_ix(
352+
config_pubkey,
353+
*pubkey,
354+
priority_fee_distribution_config.expired_funds_account,
355+
account.validator_vote_account,
356+
payer,
357+
account.epoch_created_at,
358+
)
359+
})
360+
.collect();
361+
362+
Ok(pack_transactions(instructions, payer, MAX_TRANSACTION_SIZE))
363+
}
364+
153365
pub async fn fetch_expired_distribution_accounts(
154366
rpc_client: &RpcClient,
155367
tip_distribution_program_id: Pubkey,
@@ -173,7 +385,9 @@ pub async fn fetch_expired_distribution_accounts(
173385
+ 8 // merkle_root.max_total_claim
174386
+ 8 // merkle_root.max_num_nodes
175387
+ 8 // merkle_root.total_funds_claimed
176-
+ 8, // merkle_root.num_nodes_claimed
388+
+ 8 // merkle_root.num_nodes_claimed
389+
+ 8 // epoch_created_at
390+
+ 2, // commission_bps
177391
target_epoch.to_le_bytes().to_vec(),
178392
)),
179393
];
@@ -203,7 +417,9 @@ pub async fn fetch_expired_distribution_accounts(
203417
+ 8 // merkle_root.max_total_claim
204418
+ 8 // merkle_root.max_num_nodes
205419
+ 8 // merkle_root.total_funds_claimed
206-
+ 8, // merkle_root.num_nodes_claimed
420+
+ 8 // merkle_root.num_nodes_claimed
421+
+ 8 // epoch_created_at
422+
+ 2, // commission_bps
207423
target_epoch.to_le_bytes().to_vec(),
208424
)),
209425
];

tip_distribution_sdk/src/instruction.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,29 @@ pub fn close_claim_status_ix(
140140
}
141141
}
142142

143+
pub fn close_tip_distribution_account_ix(
144+
config: Pubkey,
145+
tip_distribution_account: Pubkey,
146+
expired_funds_account: Pubkey,
147+
validator_vote_account: Pubkey,
148+
signer: Pubkey,
149+
epoch: u64,
150+
) -> Instruction {
151+
Instruction {
152+
program_id: jito_tip_distribution::ID,
153+
accounts: jito_tip_distribution::client::accounts::CloseTipDistributionAccount {
154+
config,
155+
tip_distribution_account,
156+
expired_funds_account,
157+
validator_vote_account,
158+
signer,
159+
}
160+
.to_account_metas(None),
161+
data: jito_tip_distribution::client::args::CloseTipDistributionAccount { _epoch: epoch }
162+
.data(),
163+
}
164+
}
165+
143166
pub fn migrate_tda_merkle_root_upload_authority_ix(
144167
tip_distribution_account: Pubkey,
145168
merkle_root_upload_config: Pubkey,

0 commit comments

Comments
 (0)