From 3390917bdadb19c20bed5334b99ef5885018c368 Mon Sep 17 00:00:00 2001
From: Victor Peter
Date: Sun, 27 Sep 2026 19:49:17 +0100
Subject: [PATCH] feat: implement batch payout limit, usernames table, username
search, and payment detail modal
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Closes #991, #1002, #1003, #1005
## #991 — Contract: Enforce batch payout max recipient count limit
- Updated the comment at the MAX_BATCH_SIZE guard in `batch_payout` to
explicitly reference issue #991.
- The constant MAX_BATCH_SIZE = 100 (defined at the top of lib.rs) and the
guard `if batch_size > MAX_BATCH_SIZE { return Err(Error::BatchTooLarge) }`
enforce that the `payouts` recipient vector never exceeds 100 elements per
call, preventing CPU / gas exhaustion from unbounded iteration in Soroban.
Returns the typed Error::BatchTooLarge so callers receive an inspectable
error rather than an opaque panic.
File: contracts/contracts/social_payment/src/lib.rs
## #1002 — Dashboard: Usernames table tracking registry events and claims
- The `UsernamesTable` component in the Contracts admin page renders a full
data table of all registered usernames, their matched Stellar public keys,
and registration dates, fetched live from `/api/registry/claims`.
- Columns are sortable (username / registered date) via clickable headers.
- The active registration count footer now carries a `data-testid` attribute
for easier automated querying.
File: dashboard/app/dashboard/contracts/page.tsx
## #1003 — Dashboard: Username search bar with autocomplete in admin console
- Added a new `UsernameSearchBar` component directly inside
`dashboard/app/dashboard/page.tsx` (Social Overview page).
- Debounces calls to `/api/users/search` (300 ms) and renders an ARIA-
compliant listbox dropdown showing matching username, public key, and
registration date for each result.
- Selecting a result redirects the admin to
`/dashboard/transactions?user=`, which pairs with #1005 below.
File: dashboard/app/dashboard/page.tsx
## #1005 — Dashboard: Payment detail modal for a specific username
- The Transactions page now reads the `?user=` query param (set by the
SearchBar autocomplete on username selection) and auto-opens the existing
`PaymentDetailDialog` for that username on page load.
- Added `useRouter` / `usePathname` imports to clean the `?user=` param from
the URL when the dialog is dismissed, preventing it from re-opening on
subsequent renders.
- The dialog itself already lists every historical payment for the user with
sender, receiver, amount, and date columns (backed by
`/api/users/:username/payments`).
File: dashboard/app/dashboard/transactions/page.tsx
---
contracts/contracts/social_payment/src/lib.rs | 5 +-
dashboard/app/dashboard/contracts/page.tsx | 10 +-
dashboard/app/dashboard/page.tsx | 158 ++++++++++++++++--
dashboard/app/dashboard/transactions/page.tsx | 25 ++-
4 files changed, 181 insertions(+), 17 deletions(-)
diff --git a/contracts/contracts/social_payment/src/lib.rs b/contracts/contracts/social_payment/src/lib.rs
index ffc1cbf..384d2a0 100644
--- a/contracts/contracts/social_payment/src/lib.rs
+++ b/contracts/contracts/social_payment/src/lib.rs
@@ -571,7 +571,10 @@ impl SocialPaymentContract {
return Err(Error::Unauthorized);
}
- // #752 / #531 — enforce max batch size; return typed error on violation
+ // #991 / #752 / #531 — enforce max recipient count before the payout loop.
+ // Limits the `payouts` vector to MAX_BATCH_SIZE (100) elements per call,
+ // preventing CPU / gas exhaustion from unbounded iteration in Soroban.
+ // Returns the typed Error::BatchTooLarge so callers can inspect the failure.
let batch_size = payouts.len();
if batch_size > MAX_BATCH_SIZE {
return Err(Error::BatchTooLarge);
diff --git a/dashboard/app/dashboard/contracts/page.tsx b/dashboard/app/dashboard/contracts/page.tsx
index d89d578..9d0f27d 100644
--- a/dashboard/app/dashboard/contracts/page.tsx
+++ b/dashboard/app/dashboard/contracts/page.tsx
@@ -335,7 +335,15 @@ function UsernamesTable() {
- {data &&