Problem
PR #14 (open upstream as PR #31) shipped the dashboard wallet-card "Gas Sponsor" cell with the dot + Enabled/Off status indicator on the wallet home. The issue title also asked for a "daily budget consumption progress" fill-bar, but that bar cannot render today: GET /v1/wallets/:id/sponsorship does not return how much of the daily budget has been spent. The frontend already reserves the slot -- SponsorshipConfig.fees_spent_today_stroops?: number is typed as optional in frontend/src/lib/sponsorship.ts, and the cell in frontend/src/app/dashboard/page.tsx carries an inline comment explaining it will swap the cap-label for a fill-bar the moment the API exposes the value.
This issue tracks that backend change.
What the API should return
Extend crates/api/src/routes/sponsorship.rs::SponsorshipResponse with a field:
fees_spent_today_stroops: i64 -- actual stroops the sponsor has paid today (UTC day boundary) for this wallet, summed over rows in sponsored_transactions where status = 'confirmed' and created_at >= today_utc. Use 0 when no rows exist (cheaper than Option<i64> and easier to consume).
The store crate already exposes Store::sum_sponsored_fees_today(wallet_id) -- reuse it inside get_sponsorship to populate the new field. The migrations gas_sponsorship_configs and sponsored_transactions continue to flow through unchanged.
Acceptance criteria
Frontend change needed
After this lands, a PR #31 followup can simply replace the cap-label in frontend/src/app/dashboard/page.tsx:
{typeof dailyBudget === "number" && dailyBudget > 0 && (
<p className="mt-0.5 text-[10px] text-muted">
{formatXlm(dailyBudget)} XLM/day cap
</p>
)}
with a small fill-bar showing min(100, spentToday / dailyBudget * 100)% width plus a fees_spent_today / dailyBudget XLM today label, gated on typeof spentToday === "number". Drop the optional ? from the type in frontend/src/lib/sponsorship.ts at the same time.
References
Problem
PR #14 (open upstream as PR #31) shipped the dashboard wallet-card "Gas Sponsor" cell with the dot + Enabled/Off status indicator on the wallet home. The issue title also asked for a "daily budget consumption progress" fill-bar, but that bar cannot render today:
GET /v1/wallets/:id/sponsorshipdoes not return how much of the daily budget has been spent. The frontend already reserves the slot --SponsorshipConfig.fees_spent_today_stroops?: numberis typed as optional infrontend/src/lib/sponsorship.ts, and the cell infrontend/src/app/dashboard/page.tsxcarries an inline comment explaining it will swap the cap-label for a fill-bar the moment the API exposes the value.This issue tracks that backend change.
What the API should return
Extend
crates/api/src/routes/sponsorship.rs::SponsorshipResponsewith a field:fees_spent_today_stroops: i64-- actual stroops the sponsor has paid today (UTC day boundary) for this wallet, summed over rows insponsored_transactionswherestatus = 'confirmed'andcreated_at >= today_utc. Use0when no rows exist (cheaper thanOption<i64>and easier to consume).The store crate already exposes
Store::sum_sponsored_fees_today(wallet_id)-- reuse it insideget_sponsorshipto populate the new field. The migrationsgas_sponsorship_configsandsponsored_transactionscontinue to flow through unchanged.Acceptance criteria
SponsorshipResponsegainsfees_spent_today_stroops: i64, defaulting to0when no rows exist today.Store::sum_sponsored_fees_today(wallet_id)is invoked fromget_sponsorshipand the result is plugged in.confirmedsponsored_transaction for the wallet, callsGET /v1/wallets/:id/sponsorship, and asserts the new field equals the insertedfee_stroops. A pending row should not be counted.sponsored_transactionsquery plan does not fall back to a full table scan -- the existingwallet_id, status, created_atcovering index should serve the SUM.Frontend change needed
After this lands, a PR #31 followup can simply replace the cap-label in
frontend/src/app/dashboard/page.tsx:with a small fill-bar showing
min(100, spentToday / dailyBudget * 100)%width plus afees_spent_today / dailyBudget XLM todaylabel, gated ontypeof spentToday === "number". Drop the optional?from the type infrontend/src/lib/sponsorship.tsat the same time.References
crates/api/src/routes/sponsorship.rs::SponsorshipResponse-- current response shape (no consumption field).crates/store/src/lib.rs::Store::sum_sponsored_fees_today-- primitive already present; just call it.crates/store/src/models.rs::SponsorshipConfig-- store-side row model.frontend/src/lib/sponsorship.ts-- reservedfees_spent_today_stroops?: number.frontend/src/app/dashboard/page.tsx-- the cell + inline comment about the future fill-bar.