跳到主要内容

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:

  1. The backend defines subscription tiers (offer IDs, pricing, duration).
  2. The user pays the exact LYTH amount on-chain via the ProAccessRouter.
  3. The indexer listens for ProAccessPaid events and updates the user's subscription status in the database.
  4. 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:

TierPriceDuration
Basic10 LYTH30 days
Standard30 LYTH30 days
Premium50 LYTH30 days
Elite80 LYTH30 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
ParameterDescription
offerIdUnique identifier for the offer, generated by the backend
expectedAmountWeiThe 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:

  1. The contract validates that msg.value > 0, offerId is non-zero, and msg.value == expectedAmountWei.
  2. A ProAccessPaid event is emitted with the offerId, payer address, amount, and expected amount.
  3. 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:

  1. 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.

  2. Display Tiers: If no active subscription exists, the UI displays available tiers with pricing.

  3. Payment: When a user selects a tier, the frontend:

    • Requests an offerId from the backend.
    • Prompts the wallet to send a transaction to ProAccessRouter.pay() with the exact LYTH amount.
    • Waits for transaction confirmation.
  4. Activation: The indexer picks up the ProAccessPaid event and activates the subscription. The frontend polls for updated status.

Contract Administration

FunctionDescription
setTreasury(address)Update the treasury address
transferOwnership(address)Transfer contract ownership
withdrawStuck()Recover stuck funds to treasury