Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Commit

Permalink
token-2022: [I-03] Clarify calculate_inverse_fee math (#6874)
Browse files Browse the repository at this point in the history
#### 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.
  • Loading branch information
joncinque authored Jun 20, 2024
1 parent d9a6ee8 commit 681ecd4
Showing 1 changed file with 28 additions and 0 deletions.
28 changes: 28 additions & 0 deletions token/program-2022/src/extension/transfer_fee/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ impl TransferFee {
}

/// Calculate the fee that would produce the given output
///
/// Note: this function is not an exact inverse operation of
/// `calculate_fee`. Meaning, it is not the case that:
///
/// `calculate_fee(x) == calculate_inverse_fee(x - calculate_fee(x))`
///
/// Only the following relationship holds:
///
/// `calculate_fee(x) >= calculate_inverse_fee(x - calculate_fee(x))`
pub fn calculate_inverse_fee(&self, post_fee_amount: u64) -> Option<u64> {
let pre_fee_amount = self.calculate_pre_fee_amount(post_fee_amount)?;
self.calculate_fee(pre_fee_amount)
Expand Down Expand Up @@ -444,4 +453,23 @@ pub(crate) mod test {
assert!(diff < precision, "diff is {} for precision {}", diff, precision);
}
}

proptest! {
#[test]
fn inverse_fee_relationship(
transfer_fee_basis_points in 0u16..MAX_FEE_BASIS_POINTS,
maximum_fee in u64::MIN..=u64::MAX,
amount_in in 0..=u64::MAX
) {
let transfer_fee = TransferFee {
epoch: PodU64::from(0),
maximum_fee: PodU64::from(maximum_fee),
transfer_fee_basis_points: PodU16::from(transfer_fee_basis_points),
};
let fee = transfer_fee.calculate_fee(amount_in).unwrap();
let amount_out = amount_in.checked_sub(fee).unwrap();
let fee_exact_out = transfer_fee.calculate_inverse_fee(amount_out).unwrap();
assert!(fee >= fee_exact_out);
}
}
}

0 comments on commit 681ecd4

Please sign in to comment.