From 37120c43f8c0d2ccd4484bb7869d8fe61c92d947 Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Mon, 9 Mar 2026 19:00:38 +0000 Subject: [PATCH 1/3] smartcontract/cli: fix user-balances and fund underestimating required wallet balance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wallet's own rent-exempt minimum was treated as a floor on the required amount rather than being added to it. When a user account needs to be provisioned, the fee payer must retain wallet_rent_min lamports for itself after paying the new account's rent — so the correct formula is wallet_rent_min + needs_rent, not needs_rent.max(wallet_rent_min). - user_balances.rs: needs_rent.max(wallet_rent_min) → needs_rent + wallet_rent_min - fund.rs: needs_rent.max(min_balance).max(wallet_rent_min) → wallet_rent_min + needs_rent.max(min_balance) --- smartcontract/cli/src/accesspass/fund.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/smartcontract/cli/src/accesspass/fund.rs b/smartcontract/cli/src/accesspass/fund.rs index 543db9739..be98e54c8 100644 --- a/smartcontract/cli/src/accesspass/fund.rs +++ b/smartcontract/cli/src/accesspass/fund.rs @@ -243,8 +243,9 @@ mod tests { #[test] fn test_fund_all_sufficiently_funded() { let payer = Pubkey::from_str_const("1111111FVAiSujNZVgYSc27t6zUTWoKfAGxbRzzPB"); - // balance > required (2_250_000) - let client = setup_client_with_balance(payer, 3_000_000); +<<<<<<< HEAD + // balance > required (wallet_rent_min + needs_rent = 1_000_000 + 1_250_000 = 2_250_000) + let client = setup_client_with_balance(payer, 2_500_000); let mut out = Vec::new(); let res = @@ -260,7 +261,7 @@ mod tests { #[test] fn test_fund_dry_run_shows_summary_without_transferring() { let payer = Pubkey::from_str_const("1111111FVAiSujNZVgYSc27t6zUTWoKfAGxbRzzPB"); - // balance = 500_000 < required (2_250_000), deficit = 1_750_000 + // balance = 500_000 < required (wallet_rent_min + needs_rent = 1_000_000 + 1_250_000 = 2_250_000), deficit = 1_750_000 let client = setup_client_with_balance(payer, 500_000); let mut out = Vec::new(); @@ -316,8 +317,8 @@ mod tests { #[test] fn test_fund_min_balance_dominates_rent() { let payer = Pubkey::from_str_const("1111111FVAiSujNZVgYSc27t6zUTWoKfAGxbRzzPB"); - // balance = 1_500_000 < required = wallet_rent_min (1_000_000) + max(needs_rent=1_250_000, min_balance=2_000_000) = 3_000_000 - // deficit = 1_500_000 + // balance = 1_500_000 > needs_rent (1_250_000) but < required + // required = wallet_rent_min + max(needs_rent, min_balance) = 1_000_000 + max(1_250_000, 2_000_000) = 3_000_000, deficit = 1_500_000 let client = setup_client_with_balance(payer, 1_500_000); let mut out = Vec::new(); @@ -338,7 +339,7 @@ mod tests { fn test_fund_rent_dominates_min_balance() { let payer = Pubkey::from_str_const("1111111FVAiSujNZVgYSc27t6zUTWoKfAGxbRzzPB"); // balance = 500_000, min_balance = ~1 lamport - // required = wallet_rent_min (1_000_000) + max(needs_rent=1_250_000, 1) = 2_250_000, deficit = 1_750_000 + // required = wallet_rent_min + max(needs_rent, min_balance) = 1_000_000 + max(1_250_000, 1) = 2_250_000, deficit = 1_750_000 let client = setup_client_with_balance(payer, 500_000); let mut out = Vec::new(); From 32a4a9bc1091c89dda689331a6985282aa2bdfb0 Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Mon, 9 Mar 2026 19:06:03 +0000 Subject: [PATCH 2/3] smartcontract/cli: add changelog entry for user-balances and fund fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8ff0ac09..06e8bcb9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ All notable changes to this project will be documented in this file. - Fix `access-pass fund` and `access-pass user-balances` slot counting to track remaining slots per `(payer, client_ip)` pair, preventing a connected user on IP_B from consuming open slots for IP_A; also fix required balance formula to always add `wallet_rent_min` on top of `needs_rent` rather than taking the max - Add `--user-payer` filter to `user list` command - Serviceability: onchain activation - atomic close for DeleteDevice ([#3188](https://github.com/malbeclabs/doublezero/pull/3188)) + - Fix `access-pass user-balances` and `access-pass fund` underestimating the required wallet balance: the wallet's own rent-exempt minimum was used as a floor rather than being added, causing `missing: 0` to be reported even when provisioning would fail with insufficient funds ([#3213](https://github.com/malbeclabs/doublezero/pull/3213)) - Onchain Programs - Serviceability: DeleteUser instruction supports atomic deallocate+closeaccount when OnchainAllocation feature is enabled - Serviceability: CreateLink instruction supports atomic create+allocate+activate when OnchainAllocation feature is enabled From b8b3ecfb319eca8ec3e722748377abff3646b128 Mon Sep 17 00:00:00 2001 From: Juan Olveira Date: Sat, 14 Mar 2026 16:03:40 +0000 Subject: [PATCH 3/3] smartcontract/cli: remove stale conflict marker in fund.rs test --- smartcontract/cli/src/accesspass/fund.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/smartcontract/cli/src/accesspass/fund.rs b/smartcontract/cli/src/accesspass/fund.rs index be98e54c8..970aad132 100644 --- a/smartcontract/cli/src/accesspass/fund.rs +++ b/smartcontract/cli/src/accesspass/fund.rs @@ -243,7 +243,6 @@ mod tests { #[test] fn test_fund_all_sufficiently_funded() { let payer = Pubkey::from_str_const("1111111FVAiSujNZVgYSc27t6zUTWoKfAGxbRzzPB"); -<<<<<<< HEAD // balance > required (wallet_rent_min + needs_rent = 1_000_000 + 1_250_000 = 2_250_000) let client = setup_client_with_balance(payer, 2_500_000);