Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit e59a0dc

Browse files
authored
token-2022: Set transfer fee two epochs ahead (#3120)
1 parent 51ece68 commit e59a0dc

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

token/program-2022-test/tests/transfer_fee.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,18 @@ async fn set_fee() {
267267
}])
268268
.await
269269
.unwrap();
270+
271+
// warp to first normal slot to easily calculate epochs
272+
let epoch_schedule = context.context.lock().await.genesis_config().epoch_schedule;
273+
let first_normal_slot = epoch_schedule.first_normal_slot;
274+
let slots_per_epoch = epoch_schedule.slots_per_epoch;
275+
context
276+
.context
277+
.lock()
278+
.await
279+
.warp_to_slot(first_normal_slot)
280+
.unwrap();
281+
270282
let token = context.token_context.unwrap().token;
271283

272284
// set to something new, old fee not touched
@@ -315,9 +327,43 @@ async fn set_fee() {
315327
);
316328
assert_eq!(extension.older_transfer_fee, newer_transfer_fee);
317329

318-
// warp forward one epoch, new fee becomes old fee during set
330+
// warp forward one epoch, old fee still not touched when set
331+
let new_transfer_fee_basis_points = 10;
332+
let new_maximum_fee = 10;
333+
context
334+
.context
335+
.lock()
336+
.await
337+
.warp_to_slot(first_normal_slot + slots_per_epoch)
338+
.unwrap();
339+
token
340+
.set_transfer_fee(
341+
&transfer_fee_config_authority,
342+
new_transfer_fee_basis_points,
343+
new_maximum_fee,
344+
)
345+
.await
346+
.unwrap();
347+
let state = token.get_mint_info().await.unwrap();
348+
let extension = state.get_extension::<TransferFeeConfig>().unwrap();
349+
assert_eq!(
350+
extension.newer_transfer_fee.transfer_fee_basis_points,
351+
new_transfer_fee_basis_points.into()
352+
);
353+
assert_eq!(
354+
extension.newer_transfer_fee.maximum_fee,
355+
new_maximum_fee.into()
356+
);
357+
assert_eq!(extension.older_transfer_fee, newer_transfer_fee);
358+
359+
// warp forward two epochs, old fee is replaced on set
319360
let newer_transfer_fee = extension.newer_transfer_fee;
320-
context.context.lock().await.warp_to_slot(10_000).unwrap();
361+
context
362+
.context
363+
.lock()
364+
.await
365+
.warp_to_slot(first_normal_slot + 3 * slots_per_epoch)
366+
.unwrap();
321367
let new_transfer_fee_basis_points = MAX_FEE_BASIS_POINTS;
322368
let new_maximum_fee = u64::MAX;
323369
token

token/program-2022/src/extension/transfer_fee/processor.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,16 @@ fn process_set_transfer_fee(
9191
// When setting the transfer fee, we have two situations:
9292
// * newer transfer fee epoch <= current epoch:
9393
// newer transfer fee is the active one, so overwrite older transfer fee with newer, then overwrite newer transfer fee
94-
// * newer transfer fee epoch == next epoch:
94+
// * newer transfer fee epoch >= next epoch:
9595
// it was never used, so just overwrite next transfer fee
9696
let epoch = Clock::get()?.epoch;
97-
let next_epoch = epoch.saturating_add(1);
9897
if u64::from(extension.newer_transfer_fee.epoch) <= epoch {
9998
extension.older_transfer_fee = extension.newer_transfer_fee;
10099
}
100+
// set two epochs ahead to avoid rug pulls at the end of an epoch
101+
let newer_fee_start_epoch = epoch.saturating_add(2);
101102
let transfer_fee = TransferFee {
102-
epoch: next_epoch.into(),
103+
epoch: newer_fee_start_epoch.into(),
103104
transfer_fee_basis_points: transfer_fee_basis_points.into(),
104105
maximum_fee: maximum_fee.into(),
105106
};

0 commit comments

Comments
 (0)