Pro Access
Pro Access is the subscription system for MonoHub, Monolythium's DeFi application. Users pay LYTH on-chain to unlock premium features. The payment is routed through the ProAccessRouter contract, which emits events for the indexer and forwards funds to the treasury.
Overview
Pro Access operates as a hybrid on-chain/off-chain system:
- The backend defines subscription tiers (offer IDs, pricing, duration).
- The user pays the exact LYTH amount on-chain via the ProAccessRouter.
- The indexer listens for
ProAccessPaidevents and updates the user's subscription status in the database. - The frontend queries the indexer API to check if the connected wallet has an active subscription.
This design keeps tier logic flexible (off-chain) while payment attribution remains verifiable (on-chain).
Subscription Tiers
Pro Access offers tiered subscriptions priced in native LYTH:
| Tier | Price | Duration |
|---|---|---|
| Basic | 10 LYTH | 30 days |
| Standard | 30 LYTH | 30 days |
| Premium | 50 LYTH | 30 days |
| Elite | 80 LYTH | 30 days |
Exact tier pricing and features are managed by the backend and can be adjusted without redeploying the contract. The contract itself is tier-agnostic -- it only validates that msg.value matches the expectedAmountWei parameter.
On-Chain Payment Flow
The pay() Function
function pay(bytes32 offerId, uint256 expectedAmountWei) external payable
| Parameter | Description |
|---|---|
offerId | Unique identifier for the offer, generated by the backend |
expectedAmountWei | The exact payment amount in wei (must match msg.value) |
The function enforces an exactness guard: msg.value must equal expectedAmountWei exactly. This prevents accidental overpayment and makes indexer accounting deterministic.
Payment Execution
When pay() is called:
- The contract validates that
msg.value > 0,offerIdis non-zero, andmsg.value == expectedAmountWei. - A
ProAccessPaidevent is emitted with theofferId, payer address, amount, and expected amount. - The full payment is forwarded immediately to the treasury address.
User Wallet ProAccessRouter Treasury
| | |
|--- pay(offerId, amount) ->| |
| |-- emit ProAccessPaid --->|
| |-- forward LYTH --------->|
| | |
The contract rejects direct transfers (via receive()) -- all payments must go through the pay() function.
Event Structure
event ProAccessPaid(
bytes32 indexed offerId,
address indexed payer,
uint256 amount,
uint256 expectedAmount
);
The indexer listens for this event to attribute payments to wallets and activate subscriptions.
Treasury Routing
All Pro Access payments are forwarded immediately to the treasury. The treasury address is set at deployment and can be updated by the contract owner:
function setTreasury(address newTreasury) external onlyOwner
A withdrawStuck() safety valve exists for the owner to recover any funds that might accumulate in the contract if a treasury transfer fails.
Frontend Integration
The MonoHub frontend handles Pro Access subscriptions through this flow:
-
Check Status: On page load, the frontend queries the indexer API (
/api/pro-access/status?wallet=0x...) to determine if the connected wallet has an active subscription. -
Display Tiers: If no active subscription exists, the UI displays available tiers with pricing.
-
Payment: When a user selects a tier, the frontend:
- Requests an
offerIdfrom the backend. - Prompts the wallet to send a transaction to
ProAccessRouter.pay()with the exact LYTH amount. - Waits for transaction confirmation.
- Requests an
-
Activation: The indexer picks up the
ProAccessPaidevent and activates the subscription. The frontend polls for updated status.
Contract Administration
| Function | Description |
|---|---|
setTreasury(address) | Update the treasury address |
transferOwnership(address) | Transfer contract ownership |
withdrawStuck() | Recover stuck funds to treasury |