feat(revenue): add protocol revenue dashboard for treasury tracking (#807) - #1033
Merged
sanmipaul merged 1 commit intoAug 5, 2026
Merged
Conversation
|
@ykhalid218 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
ykhalid218
force-pushed
the
feat/protocol-revenue-dashboard
branch
from
August 2, 2026 03:32
9acbd2b to
2f30f80
Compare
…stera-hq#807) Add an admin revenue dashboard at /admin/revenue that surfaces the protocol factoring-fee revenue, treasury status, and funded-volume metrics previously only visible by querying the blockchain directly. - Revenue overview: cumulative fees (all-time, by token), pending fees, average fee per invoice, and current fee rate from live pool + token contract state. - Charts: monthly (12-month) and weekly (8-week) fee revenue trends plus a fee-rate-vs-funded-volume composed chart, rendered with recharts. - Treasury status: per-token treasury balances read directly from the token contracts for the on-chain treasury address, refreshed every 30s; last withdrawal reconstructed from rev_wdraw events. - Volume metrics: all-time funded volume, active today/week/month, and unique borrowers + lenders from invoice records and deposit events. - Data service in lib/revenue.ts with 5-min TTL caching and unit tests.
ykhalid218
force-pushed
the
feat/protocol-revenue-dashboard
branch
from
August 2, 2026 03:36
2f30f80 to
ba4fe10
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Astera collects a factoring fee on every funded invoice (
pool.factoring_fee_bps, locked at funding time and charged at repayment), yet until now there has been no dashboard showing protocol revenue over time. The treasury address balance and fee accumulation were only visible by querying the blockchain directly — poor transparency for stakeholders and investors.This PR introduces a Protocol Revenue Dashboard at
/admin/revenuethat turns that raw on-chain state into a real-time, chart-driven treasury & revenue view. It is implemented as a new data service (frontend/lib/revenue.ts) plus a recharts-based admin page, following the exact conventions already established byfrontend/lib/analytics.tsand the existing/admin/analyticsdashboard (5-minute TTL caching, skeleton loading states, brand styling, i18n keys inen+fr).No smart-contract changes are required. Everything is read through public Soroban view functions and pool events already emitted by
contracts/pool/src/lib.rs(get_treasury,get_protocol_revenue,get_token_totals, and therev_wdraw/deposit/fundedevents).Related Issue
Closes #807 — feat: add protocol revenue dashboard for treasury tracking
What This PR Delivers
1. Revenue Overview (all-time, per token)
get_token_totals(...).total_fee_revenueper accepted token, then aggregated across tokens.get_protocol_revenue(token)on the pool contract, i.e. the fee balance still held in the pool and eligible forwithdraw_revenue.get_config().factoring_fee_bpsrendered as a percentage.2. Revenue Trends (charts, past 12 months)
BarChart.BarChart+Line(volume on the left axis, fee-rate % on the right axis) so stakeholders can see pricing against throughput.3. Treasury Status (30s real-time polling)
balance) for the on-chain treasury address, refreshed every 30 seconds via an uncachedfetchTreasurySnapshot().get_treasury()on the pool; the panel degrades to a clear "not configured" state when unset.rev_wdrawpool event.4. Volume Metrics
amount+fundedAt) across all funded statuses (Funded,Paid,Defaulted,Disputed).depositevents.5. Access Control
/adminand is therefore gated by the existinguseAdminGuard(admin wallet must match the on-chain pooladmin), satisfying the issue's "detailed fee breakdown — admin only" requirement.Files Changed
frontend/lib/revenue.tsfetchRevenueData()+ uncachedfetchTreasurySnapshot()frontend/lib/contracts.tsgetTreasuryAddress()(get_treasury),getProtocolRevenue(token)(get_protocol_revenue),getTokenBalanceOf(token, address)(tokenbalance)frontend/app/admin/revenue/page.tsxfrontend/components/analytics/RevenueTrendChart.tsxfrontend/components/analytics/FeeVolumeChart.tsxfrontend/components/analytics/index.tsfrontend/components/AdminNav.tsxfrontend/locales/en/common.jsonAdmin.revenue.*+Admin.nav.revenuekeysfrontend/locales/fr/common.jsonfrontend/__tests__/lib/revenue.test.tsArchitecture & Data Flow
Deterministic historical series. Like
lib/analytics.ts(which explicitly derives historical charts from current on-chain state until a time-series store exists), the monthly/weekly series are anchored to the live cumulative fee and volume totals using a deterministic growth allocation (no RNG), so the sum of the buckets always reconciles to the real on-chain cumulative figures. The companion event-indexer issue will provide the full time-series store to replace this derivation later.Event schemas parsed (confirmed against
contracts/pool/src/lib.rs):rev_wdraw→(token, amount, treasury)— last treasury withdrawal.deposit→(investor, token, received, shares, timestamp)— unique lender count.funded→(invoice_id, sme, principal, token, timestamp)— funded-volume buckets (invoice records are used for volume in this PR; the event stream feeds lender/withdrawal metrics).Key Implementation Details
fetchRevenueData()caches for 5 minutes (getRevenueCacheTTL()), and the page's 5-minute interval callsclearRevenueCache()before refetching — identical to/admin/analytics.fetchTreasurySnapshot()is deliberately not cached and is polled every 30s; it also skips RPC polling entirely when the pool reports no configured treasury (avoids pointless churn on an unconfigured pool)..catch(...)fallbacks — an RPC outage renders the dashboard with zeroed KPIs and a banner, never a crash.getTreasuryAddress()returnsnullonly forTreasuryNotConfigured(a simulation error) or transport failures, matching the repo'sStellarRpc.Api.isSimulationErrorpattern used bygetCurrentRate.useTranslations('Admin.revenue'); keys are mirrored inenandfr, and both files were validated as parseable JSON.bg-brand-card,border-brand-border,text-brand-gold, skeleton loaders) and theuseAdminGuard-gated admin layout.Verification Results
npx tsc --noEmitnpx eslint <changed files>any-type warnings, consistent with repo tolerance)npx jest __tests__/lib/revenue.test.tsnpx jestnode -e JSON.parse(...)en+frboth validFull-suite failures are pre-existing on
upstream/main(verified by running the same suites against the pristine tree viagit stash):__tests__/admin-invoices-batch.test.tsxapp/admin/exchange-rates/page.test.tsxPre-existing typecheck failure (also reproduced on pristine
upstream/main):app/invoice/[id]/page.tsx— JSX parse errors at ~lines 1044+; unrelated to this PR and out of scope.Acceptance Criteria
/admin/revenuefrontend/app/admin/revenue/page.tsx, admin-guardedfetchTreasurySnapshot()polled every 30sTesting Notes (for Reviewers)
cd frontend && npx jest __tests__/lib/revenue.test.ts— covers series math, event decoding, cache TTL, and treasury snapshot behavior.NEXT_PUBLIC_POOL_CONTRACT_IDset, open/admin/revenueas the pool admin → confirm KPI cards populate, charts render 12 monthly bars, and the treasury panel updates within ~30s. With no treasury configured, confirm the panel shows the "not configured" state and stops polling.Known Limitations & Future Work
fetchKycInvestors):lastWithdrawalanduniqueLendersreflect trailing 30-day activity; the UIdataNotediscloses this./statsroute exposing only the basic public metrics (volume, fee rate) could be added later if the maintainers prefer public access without the admin route — the issue permits either location.