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

Commit 681ecd4

Browse files
authored
token-2022: [I-03] Clarify calculate_inverse_fee math (#6874)
#### Problem According to the Certora audit report: > Description: The function calculate_inverse_fee is not exactly an inverse operation of calculate_fee. That is, it is not the case that calculate_inverse_fee(x + calculate_fee(x)) == calculate_fee(x). > Recommendation: Document that calculate_inverse_fee is not an exact inverse and instead that only the relationship calculate_fee(x) <= calculate_inverse_fee(x + calculate_fee(x)) holds in order to avoid confusion with the potential users of calculate_inverse_fee. #### Solution Do the recommended thing. I don't think the math in the comment is correct, so I've added a test to make sure the relationship is correct.
1 parent d9a6ee8 commit 681ecd4

File tree

1 file changed

+28
-0
lines changed
  • token/program-2022/src/extension/transfer_fee

1 file changed

+28
-0
lines changed

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ impl TransferFee {
113113
}
114114

115115
/// Calculate the fee that would produce the given output
116+
///
117+
/// Note: this function is not an exact inverse operation of
118+
/// `calculate_fee`. Meaning, it is not the case that:
119+
///
120+
/// `calculate_fee(x) == calculate_inverse_fee(x - calculate_fee(x))`
121+
///
122+
/// Only the following relationship holds:
123+
///
124+
/// `calculate_fee(x) >= calculate_inverse_fee(x - calculate_fee(x))`
116125
pub fn calculate_inverse_fee(&self, post_fee_amount: u64) -> Option<u64> {
117126
let pre_fee_amount = self.calculate_pre_fee_amount(post_fee_amount)?;
118127
self.calculate_fee(pre_fee_amount)
@@ -444,4 +453,23 @@ pub(crate) mod test {
444453
assert!(diff < precision, "diff is {} for precision {}", diff, precision);
445454
}
446455
}
456+
457+
proptest! {
458+
#[test]
459+
fn inverse_fee_relationship(
460+
transfer_fee_basis_points in 0u16..MAX_FEE_BASIS_POINTS,
461+
maximum_fee in u64::MIN..=u64::MAX,
462+
amount_in in 0..=u64::MAX
463+
) {
464+
let transfer_fee = TransferFee {
465+
epoch: PodU64::from(0),
466+
maximum_fee: PodU64::from(maximum_fee),
467+
transfer_fee_basis_points: PodU16::from(transfer_fee_basis_points),
468+
};
469+
let fee = transfer_fee.calculate_fee(amount_in).unwrap();
470+
let amount_out = amount_in.checked_sub(fee).unwrap();
471+
let fee_exact_out = transfer_fee.calculate_inverse_fee(amount_out).unwrap();
472+
assert!(fee >= fee_exact_out);
473+
}
474+
}
447475
}

0 commit comments

Comments
 (0)