Skip to content

Commit 4d45bec

Browse files
committed
add CarryOverRequestedUndelegation
1 parent bf93ac1 commit 4d45bec

14 files changed

Lines changed: 1066 additions & 17 deletions

‎dlp-api/src/consts.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ pub const COMMIT_FEE_LAMPORTS: u64 = 100_000;
1414
/// Fixed fee per delegation session (0.0003 SOL).
1515
pub const SESSION_FEE_LAMPORTS: u64 = 300_000;
1616

17+
/// Default and minimum timeout for requested undelegation.
18+
pub const DEFAULT_UNDELEGATION_REQUEST_TIMEOUT_SLOTS: u64 = 300;
19+
1720
/// The discriminator for the external undelegate instruction.
1821
pub const EXTERNAL_UNDELEGATE_DISCRIMINATOR: [u8; 8] =
1922
[196, 28, 41, 206, 48, 37, 51, 167];

‎dlp-api/src/discriminator.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ pub enum DlpDiscriminator {
6565

6666
/// See [crate::processor::process_request_undelegation] for docs.
6767
RequestUndelegation = 26,
68+
69+
/// See [crate::processor::process_carry_over_requested_undelegation] for docs.
70+
CarryOverRequestedUndelegation = 27,
6871
}
6972

7073
impl DlpDiscriminator {

‎dlp-api/src/error.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,15 @@ pub enum DlpError {
173173
#[error("Request undelegation is only supported for off-curve delegated accounts")]
174174
RequestUndelegationOnCurveAccount = 49,
175175

176+
#[error("Undelegation request timeout is below the minimum")]
177+
UndelegationRequestTimeoutTooShort = 50,
178+
179+
#[error("Undelegation request has not expired")]
180+
UndelegationRequestNotExpired = 51,
181+
182+
#[error("Invalid pending commit state for timeout carry-over")]
183+
InvalidPendingCommitState = 52,
184+
176185
#[error("An infallible error is encountered possibly due to logic error")]
177186
InfallibleError = 100,
178187
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use dlp::{
2+
discriminator::DlpDiscriminator,
3+
pda::{
4+
commit_record_pda_from_delegated_account,
5+
commit_state_pda_from_delegated_account,
6+
delegation_metadata_pda_from_delegated_account,
7+
delegation_record_pda_from_delegated_account,
8+
undelegate_buffer_pda_from_delegated_account,
9+
undelegation_request_pda_from_delegated_account,
10+
},
11+
total_size_budget, AccountSizeClass, DLP_PROGRAM_DATA_SIZE_CLASS,
12+
};
13+
use solana_program::{
14+
instruction::{AccountMeta, Instruction},
15+
pubkey::Pubkey,
16+
};
17+
use solana_sdk_ids::system_program;
18+
19+
use crate::compat::{Compatize, Modernize};
20+
21+
/// Builds a timeout carry-over instruction for a requested undelegation.
22+
/// See [dlp::processor::process_carry_over_requested_undelegation] for docs.
23+
#[allow(clippy::too_many_arguments)]
24+
pub fn carry_over_requested_undelegation(
25+
caller: Pubkey,
26+
delegated_account: Pubkey,
27+
owner_program: Pubkey,
28+
request_rent_payer: Pubkey,
29+
delegation_rent_payer: Pubkey,
30+
commit_reimbursement: Pubkey,
31+
) -> Instruction {
32+
let delegated_account_compat = delegated_account.compatize();
33+
let undelegate_buffer_pda =
34+
undelegate_buffer_pda_from_delegated_account(&delegated_account_compat)
35+
.modernize();
36+
let request_pda = undelegation_request_pda_from_delegated_account(
37+
&delegated_account_compat,
38+
)
39+
.modernize();
40+
let delegation_record_pda =
41+
delegation_record_pda_from_delegated_account(&delegated_account_compat)
42+
.modernize();
43+
let delegation_metadata_pda =
44+
delegation_metadata_pda_from_delegated_account(
45+
&delegated_account_compat,
46+
)
47+
.modernize();
48+
let commit_state_pda =
49+
commit_state_pda_from_delegated_account(&delegated_account_compat)
50+
.modernize();
51+
let commit_record_pda =
52+
commit_record_pda_from_delegated_account(&delegated_account_compat)
53+
.modernize();
54+
55+
Instruction {
56+
program_id: dlp::id().modernize(),
57+
accounts: vec![
58+
AccountMeta::new(caller, true),
59+
AccountMeta::new(delegated_account, false),
60+
AccountMeta::new_readonly(owner_program, false),
61+
AccountMeta::new(undelegate_buffer_pda, false),
62+
AccountMeta::new(request_pda, false),
63+
AccountMeta::new(delegation_record_pda, false),
64+
AccountMeta::new(delegation_metadata_pda, false),
65+
AccountMeta::new(request_rent_payer, false),
66+
AccountMeta::new(delegation_rent_payer, false),
67+
AccountMeta::new(commit_state_pda, false),
68+
AccountMeta::new(commit_record_pda, false),
69+
AccountMeta::new(commit_reimbursement, false),
70+
AccountMeta::new_readonly(system_program::id(), false),
71+
],
72+
data: DlpDiscriminator::CarryOverRequestedUndelegation.to_vec(),
73+
}
74+
}
75+
76+
///
77+
/// Returns accounts-data-size budget for requested undelegation carry-over.
78+
///
79+
/// This value can be used with ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit
80+
///
81+
pub fn carry_over_requested_undelegation_size_budget(
82+
delegated_account: AccountSizeClass,
83+
) -> u32 {
84+
total_size_budget(&[
85+
DLP_PROGRAM_DATA_SIZE_CLASS,
86+
AccountSizeClass::Tiny, // caller
87+
delegated_account, // delegated_account
88+
AccountSizeClass::Tiny, // owner_program
89+
delegated_account, // undelegate_buffer_pda
90+
AccountSizeClass::Tiny, // undelegation_request_pda
91+
AccountSizeClass::Tiny, // delegation_record_pda
92+
AccountSizeClass::Tiny, // delegation_metadata_pda
93+
AccountSizeClass::Tiny, // request_rent_payer
94+
AccountSizeClass::Tiny, // delegation_rent_payer
95+
delegated_account, // commit_state_pda
96+
AccountSizeClass::Tiny, // commit_record_pda
97+
AccountSizeClass::Tiny, // commit_reimbursement
98+
AccountSizeClass::Tiny, // system_program
99+
])
100+
}

‎dlp-api/src/instruction_builder/mod.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod call_handler;
22
mod call_handler_v2;
3+
mod carry_over_requested_undelegation;
34
mod close_ephemeral_balance;
45
mod close_validator_fees_vault;
56
mod commit_diff;
@@ -28,6 +29,7 @@ mod whitelist_validator_for_program;
2829

2930
pub use call_handler::*;
3031
pub use call_handler_v2::*;
32+
pub use carry_over_requested_undelegation::*;
3133
pub use close_ephemeral_balance::*;
3234
pub use close_validator_fees_vault::*;
3335
pub use commit_diff::*;

‎dlp-api/src/instruction_builder/request_undelegation.rs‎

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,31 @@ pub fn request_undelegation(
2121
payer: Pubkey,
2222
delegated_account: Pubkey,
2323
owner_program: Pubkey,
24+
) -> Instruction {
25+
build_request_undelegation(payer, delegated_account, owner_program, None)
26+
}
27+
28+
/// Builds a request undelegation instruction with a custom timeout.
29+
/// See [dlp::processor::process_request_undelegation] for docs.
30+
pub fn request_undelegation_with_timeout(
31+
payer: Pubkey,
32+
delegated_account: Pubkey,
33+
owner_program: Pubkey,
34+
timeout_slots: u64,
35+
) -> Instruction {
36+
build_request_undelegation(
37+
payer,
38+
delegated_account,
39+
owner_program,
40+
Some(timeout_slots),
41+
)
42+
}
43+
44+
fn build_request_undelegation(
45+
payer: Pubkey,
46+
delegated_account: Pubkey,
47+
owner_program: Pubkey,
48+
timeout_slots: Option<u64>,
2449
) -> Instruction {
2550
let delegated_account_compat = delegated_account.compatize();
2651
let undelegation_request_pda =
@@ -36,6 +61,10 @@ pub fn request_undelegation(
3661
&delegated_account_compat,
3762
)
3863
.modernize();
64+
let mut data = DlpDiscriminator::RequestUndelegation.to_vec();
65+
if let Some(timeout_slots) = timeout_slots {
66+
data.extend_from_slice(&timeout_slots.to_le_bytes());
67+
}
3968

4069
Instruction {
4170
program_id: dlp::id().modernize(),
@@ -48,7 +77,7 @@ pub fn request_undelegation(
4877
AccountMeta::new_readonly(delegation_metadata_pda, false),
4978
AccountMeta::new_readonly(system_program::id(), false),
5079
],
51-
data: DlpDiscriminator::RequestUndelegation.to_vec(),
80+
data,
5281
}
5382
}
5483

‎dlp-api/src/state/undelegation_request.rs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ pub struct UndelegationRequest {
2323

2424
/// The slot at which the request was created.
2525
pub created_slot: u64,
26+
27+
/// The first slot at which timeout carry-over is allowed.
28+
pub expires_at_slot: u64,
29+
30+
/// Delegation metadata nonce observed when the request was created.
31+
pub delegation_nonce_at_request: u64,
32+
33+
/// PDA bump for this request.
34+
pub bump: u8,
35+
36+
/// Explicit padding keeps this type Pod-safe with repr(C).
37+
pub _padding: [u8; 7],
2638
}
2739

2840
impl AccountWithDiscriminator for UndelegationRequest {

‎src/lib.rs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ pub fn fast_process_instruction(
154154
program_id, accounts, data,
155155
))
156156
}
157+
DlpDiscriminator::CarryOverRequestedUndelegation => {
158+
Some(processor::fast::process_carry_over_requested_undelegation(
159+
program_id, accounts, data,
160+
))
161+
}
157162
_ => None,
158163
}
159164
}

0 commit comments

Comments
 (0)