Repository: solana-labs/solana-program-library
Pull request #6171 (2024-01-24 09:45:57)

build(deps): bump serde_with from 3.5.0 to 3.5.1
Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.5.0 to 3.5.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/jonasbb/serde_with/releases">serde_with's releases</a>.</em></p>
<blockquote>
<h2>serde_with v3.5.1</h2>
<h3>Fixed</h3>
<ul>
<li>The <code>serde_as</code> macro now better detects existing <code>schemars</code> attributes on fields and incorporates them by <a href="https://github.com/swlynch99"><code>@​swlynch99</code></a> (<a href="https://redirect.github.com/jonasbb/serde_with/issues/682">#682</a>)
This avoids errors on existing <code>#[schemars(with = ...)]</code> annotations.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/jonasbb/serde_with/commit/88e98795dc164b1ca8a1e8978402f0656ff4ca07"><code>88e9879</code></a> Merge pull request <a href="https://redirect.github.com/jonasbb/serde_with/issues/682">#682</a> from swlynch99/schemars-custom-with</li>
<li><a href="https://github.com/jonasbb/serde_with/commit/1c9131ff64d52c47e260f898ab9ef7051f10085c"><code>1c9131f</code></a> Bump version to 3.5.1</li>
<li><a href="https://github.com/jonasbb/serde_with/commit/bceb16e27fcac603ddc1712c4065dc45c43ef6c3"><code>bceb16e</code></a> Add changelog</li>
<li><a href="https://github.com/jonasbb/serde_with/commit/215d77a5fe7b82735514a420be1e9e7a44edc9e4"><code>215d77a</code></a> Use #[serde_as] from import without crate name</li>
<li><a href="https://github.com/jonasbb/serde_with/commit/b2afd766b761d016a68bc49968b4b114b90821a9"><code>b2afd76</code></a> Extend the test with an always existing condition</li>
<li><a href="https://github.com/jonasbb/serde_with/commit/c09f33b394979c9370c7fffced3379e3652ac1f2"><code>c09f33b</code></a> Avoid emitting a #[schemars] annotation when one already exists</li>
<li>See full diff in <a href="https://github.com/jonasbb/serde_with/compare/v3.5.0...v3.5.1">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=serde_with&package-manager=cargo&previous-version=3.5.0&new-version=3.5.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 5740b79b8..8ff5732bc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4568,9 +4568,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "3.5.0"
+version = "3.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f58c3a1b3e418f61c25b2aeb43fc6c95eaa252b8cecdda67f401943e9e08d33f"
+checksum = "f5c9fdb6b00a489875b22efd4b78fe2b363b72265cc5f6eb2e2b9ee270e6140c"
 dependencies = [
  "base64 0.21.7",
  "chrono",
@@ -4579,7 +4579,7 @@ dependencies = [
  "indexmap 2.0.2",
  "serde",
  "serde_json",
- "serde_with_macros 3.5.0",
+ "serde_with_macros 3.5.1",
  "time",
 ]
 
@@ -4597,9 +4597,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with_macros"
-version = "3.5.0"
+version = "3.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2068b437a31fc68f25dd7edc296b078f04b45145c199d8eed9866e45f1ff274"
+checksum = "dbff351eb4b33600a2e138dfa0b10b65a238ea8ff8fb2387c422c5022a3e8298"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -7177,7 +7177,7 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "serde_with 3.5.0",
+ "serde_with 3.5.1",
  "serial_test",
  "solana-account-decoder",
  "solana-clap-v3-utils",
@@ -7353,7 +7353,7 @@ dependencies = [
  "proptest",
  "serde",
  "serde_json",
- "serde_with 3.5.0",
+ "serde_with 3.5.1",
  "serial_test",
  "solana-program",
  "solana-program-test",
diff --git a/single-pool/cli/Cargo.toml b/single-pool/cli/Cargo.toml
index 7a84be6e3..4d5870732 100644
--- a/single-pool/cli/Cargo.toml
+++ b/single-pool/cli/Cargo.toml
@@ -16,7 +16,7 @@ bincode = "1.3.1"
 serde = "1.0.195"
 serde_derive = "1.0.103"
 serde_json = "1.0.111"
-serde_with = "3.5.0"
+serde_with = "3.5.1"
 solana-account-decoder = "=1.17.13"
 solana-clap-v3-utils = "=1.17.13"
 solana-cli-config = "=1.17.13"
diff --git a/stake-pool/program/src/state.rs b/stake-pool/program/src/state.rs
index 31c2ef946..b453b1b5a 100644
--- a/stake-pool/program/src/state.rs
+++ b/stake-pool/program/src/state.rs
@@ -942,9 +942,13 @@ impl Fee {
         if self.denominator == 0 {
             return Some(0);
         }
-        (amt as u128)
-            .checked_mul(self.numerator as u128)?
-            .checked_div(self.denominator as u128)
+        let numerator = (amt as u128).checked_mul(self.numerator as u128)?;
+        // ceiling the calculation by adding (denominator - 1) to the numerator
+        let denominator = self.denominator as u128;
+        numerator
+            .checked_add(denominator)?
+            .checked_sub(1)?
+            .checked_div(denominator)
     }
 
     /// Withdrawal fees have some additional restrictions,
diff --git a/token/program-2022/Cargo.toml b/token/program-2022/Cargo.toml
index 58143c353..8b74c8f7e 100644
--- a/token/program-2022/Cargo.toml
+++ b/token/program-2022/Cargo.toml
@@ -38,7 +38,7 @@ spl-type-length-value = { version = "0.3.0", path = "../../libraries/type-length
 spl-pod = { version = "0.1.0", path = "../../libraries/pod" }
 thiserror = "1.0"
 serde = { version = "1.0.195", optional = true }
-serde_with = { version = "3.5.0", optional = true }
+serde_with = { version = "3.5.1", optional = true }
 base64 = { version = "0.21.7", optional = true }
 
 [dev-dependencies]


Test patch:
diff --git a/stake-pool/program/tests/helpers/mod.rs b/stake-pool/program/tests/helpers/mod.rs
index d82dbe5ad..23f146578 100644
--- a/stake-pool/program/tests/helpers/mod.rs
+++ b/stake-pool/program/tests/helpers/mod.rs
@@ -897,15 +897,17 @@ impl StakePoolAccounts {
     }
 
     pub fn calculate_fee(&self, amount: u64) -> u64 {
-        amount * self.epoch_fee.numerator / self.epoch_fee.denominator
+        (amount * self.epoch_fee.numerator + self.epoch_fee.denominator - 1)
+            / self.epoch_fee.denominator
     }
 
     pub fn calculate_withdrawal_fee(&self, pool_tokens: u64) -> u64 {
-        pool_tokens * self.withdrawal_fee.numerator / self.withdrawal_fee.denominator
+        (pool_tokens * self.withdrawal_fee.numerator + self.withdrawal_fee.denominator - 1)
+            / self.withdrawal_fee.denominator
     }
 
     pub fn calculate_inverse_withdrawal_fee(&self, pool_tokens: u64) -> u64 {
-        pool_tokens * self.withdrawal_fee.denominator
+        (pool_tokens * self.withdrawal_fee.denominator + self.withdrawal_fee.denominator - 1)
             / (self.withdrawal_fee.denominator - self.withdrawal_fee.numerator)
     }
 
@@ -914,7 +916,8 @@ impl StakePoolAccounts {
     }
 
     pub fn calculate_sol_deposit_fee(&self, pool_tokens: u64) -> u64 {
-        pool_tokens * self.sol_deposit_fee.numerator / self.sol_deposit_fee.denominator
+        (pool_tokens * self.sol_deposit_fee.numerator + self.sol_deposit_fee.denominator - 1)
+            / self.sol_deposit_fee.denominator
     }
 
     pub fn calculate_sol_referral_fee(&self, deposit_fee_collected: u64) -> u64 {
diff --git a/stake-pool/program/tests/withdraw_sol.rs b/stake-pool/program/tests/withdraw_sol.rs
index 67b60a7a2..e8eb2423a 100644
--- a/stake-pool/program/tests/withdraw_sol.rs
+++ b/stake-pool/program/tests/withdraw_sol.rs
@@ -214,7 +214,7 @@ async fn fail_overdraw_reserve() {
         .await;
     assert!(error.is_none(), "{:?}", error);
 
-    // try to withdraw one lamport, will overdraw
+    // try to withdraw one lamport after fees, will overdraw
     let error = stake_pool_accounts
         .withdraw_sol(
             &mut context.banks_client,
@@ -222,7 +222,7 @@ async fn fail_overdraw_reserve() {
             &context.last_blockhash,
             &user,
             &pool_token_account,
-            1,
+            2,
             None,
         )
         .await
diff --git a/stake-pool/program/tests/withdraw_with_fee.rs b/stake-pool/program/tests/withdraw_with_fee.rs
index b55283fbd..7a8e000c1 100644
--- a/stake-pool/program/tests/withdraw_with_fee.rs
+++ b/stake-pool/program/tests/withdraw_with_fee.rs
@@ -6,10 +6,10 @@ mod helpers;
 use {
     bincode::deserialize,
     helpers::*,
-    solana_program::{borsh0_10::try_from_slice_unchecked, pubkey::Pubkey, stake},
+    solana_program::{pubkey::Pubkey, stake},
     solana_program_test::*,
     solana_sdk::signature::{Keypair, Signer},
-    spl_stake_pool::{minimum_stake_lamports, state},
+    spl_stake_pool::minimum_stake_lamports,
 };
 
 #[tokio::test]
@@ -183,20 +183,8 @@ async fn success_empty_out_stake_with_fee() {
             .await;
     let lamports_to_withdraw =
         validator_stake_account.lamports - minimum_stake_lamports(&meta, stake_minimum_delegation);
-    let stake_pool_account = get_account(
-        &mut context.banks_client,
-        &stake_pool_accounts.stake_pool.pubkey(),
-    )
-    .await;
-    let stake_pool =
-        try_from_slice_unchecked::<state::StakePool>(stake_pool_account.data.as_slice()).unwrap();
-    let fee = stake_pool.stake_withdrawal_fee;
-    let inverse_fee = state::Fee {
-        numerator: fee.denominator - fee.numerator,
-        denominator: fee.denominator,
-    };
     let pool_tokens_to_withdraw =
-        lamports_to_withdraw * inverse_fee.denominator / inverse_fee.numerator;
+        stake_pool_accounts.calculate_inverse_withdrawal_fee(lamports_to_withdraw);
 
     let last_blockhash = context
         .banks_client