---
title: "Token Economics Setup"
description: "Design and operate your Ring clone economy — off-chain credit ledger, RING reference contracts, PaymentConductor rails, and referral token rewards"
locale: "en"
---
# Token Economics Setup

  Ring clones ship a **three-layer economy**: (1) an **off-chain credit ledger** in PostgreSQL for membership and store checkout, (2) optional **on-chain RING reference contracts** for treasury-grade utility tokenomics, and (3) a **referral token rail** (`ReferralRewards` + refcodes) for platform-funded growth payouts. **ring-platform.org** brands the utility token as **RING**; agricultural clones (e.g. GreenFood) may fork symbols to **DAAR** / **DAARION** via `ring-config.json`.

  
- **[Payment integration](/docs/customization/payment-integration.md)** — PaymentConductor — WayForPay, Stripe, internal credit

  
- **[Web3 wallet feature](/docs/features/wallet.md)** — Custodial wallets, balances, top-up UX

  
- **[Referral codes (refcodes)](/docs/features/refcodes.md)** — Attribution, ledger, on-chain mint

  
- **[Affiliate enablement](/docs/features/affiliate-enablement.md)** — Dual-rail ERP commission + token rewards

  
- **[Refcodes architecture](/docs/architecture/refcodes.md)** — viem minter, env contract, cron

  
- **[Customization guide](/docs/customization/customization-guide.md)** — `ring-config.json`, locales, feature flags

## Philosophy

**Traditional platforms** capture value in opaque ledgers. **Ring-powered clones** expose fee flows you control: membership utility, marketplace settlement, referral growth, and optional on-chain treasury — all configurable per white-label instance.

| Principle | Ring implementation |
|-----------|---------------------|
| Utility-first | Tokens gate features and settle platform fees — not investment promises |
| Postgres-primary | Credit balances and subscriptions live in `users.data` + `ring_subscriptions` when `DB_BACKEND_MODE=k8s-postgres-fcm` |
| Fiat + credit coexist | WayForPay/Stripe for card rails; `credit_balance` spends the same ledger |
| Per-clone branding | `ring-config.json` → `tokens.native.symbol` drives UI copy via `getNativeTokenSymbol()` |

```mermaid
flowchart TB
  subgraph App["Ring app (Next.js 16)"]
    PC[PaymentConductor]
    UCS[creditBalanceService]
    SUB[SubscriptionService]
    ORA[PriceOracleService]
  end

  subgraph Data["PostgreSQL ring_platform"]
    UB["users.data.credit_balance"]
    RS[ring_subscriptions]
    RR[referral_rewards]
  end

  subgraph Chain["Polygon (optional)"]
    RT[RingToken UUPS]
    RM[Membership UUPS]
    REF[ReferralRewards UUPS]
  end

  PC -->|credit_balance| UCS
  SUB --> UCS
  UCS --> UB
  SUB --> RS
  ORA --> UCS
  REF --> RR
  RM -.->|reference / future sync| RT
  SUB -.->|env gate| RM
```

## Layer 1 — Off-chain credit ledger (production path today)

Most membership and store flows debit an **application credit balance** — denominated in **fiat USD** (default), not the token symbol. On ring-platform.org, credits are always fiat USD. RING is a separate native token on Solana for optional on-chain operations. The [Desk widget](/docs/features/wallet.md) converts credits ↔ native tokens at the oracle rate.

### Data model

| Store | Location | Contents |
|-------|----------|----------|
| Balance | `users.data.credit_balance` | `amount`, `main_currency_equivalent`, `subscription_active`, `subscription_next_payment` |
| History | `users.data.credit_transactions` | Typed ledger entries with optional `tx_hash`, `order_id` |
| Subscriptions | `ring_subscriptions` collection | Status, `next_payment_due`, `failed_attempts`, `auto_renew` |

Schema comment: `users.data` JSONB in `data/schema.sql` v4+.

### Core services

| Service | Path | Role |
|---------|------|------|
| **creditBalanceService** | `features/wallet/services/credit-balance-service.ts` | Balance read/write, spend, top-up, membership fee debit, tunnel publish on change |
| **SubscriptionService** | `services/membership/subscription-service.ts` | Create/cancel/renew; 1 RING/month; upgrades `membership.tier` → `member` |
| **PriceOracleService** | `features/wallet/services/native-token-price-oracle.ts` | RING/USD via viem + Chainlink/CoinGecko/CMC/Binance fallbacks |
| **Internal credit checkout** | `lib/payments/processors/credit-balance.processor.ts` | PaymentConductor rail for store + membership spend |

### Membership economics (reference)

| Parameter | Value | Where enforced |
|-----------|-------|----------------|
| Monthly fee | **1** utility token | `subscription-service.ts` (`membershipFee = '1.0'`) |
| Billing period | **30 days** | `next_payment_due` timestamp math |
| Recommended buffer | **12** tokens (1 year) | `RingToken.MIN_SUBSCRIPTION_BALANCE` on-chain; UI warnings via credit limits |
| Role gate | **SUBSCRIBER+** to subscribe | `POST /api/membership/subscription/create` |

### User tops up or receives airdrop

`POST /api/wallet/credit/topup` (admin/ops) or fulfillment after `wallet_topup` PaymentConductor purpose adds credits via `creditBalanceService.addCredits()`.

### User creates subscription

`POST /api/membership/subscription/create` debits **1 RING** credit, writes `ring_subscriptions`, sets `credit_balance.subscription_active`.

This route returns **503** until `RING_TOKEN_CONTRACT_ADDRESS` and `RING_MEMBERSHIP_CONTRACT_ADDRESS` are set — even though the debit is ledger-based. Set deployed addresses (or placeholder addresses in dev) to unlock the API.

### Store checkout with credit

When `PAYMENT_STORE_ALLOW_CREDIT=true`, PaymentConductor `credit_balance` rail spends credits for orders in currencies allowed by `PAYMENT_CREDIT_BALANCE_ACCEPTED_ORDER_CURRENCIES` (defaults to `PAYMENT_FIAT_CURRENCY`).

### Credit API surface

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/api/wallet/credit/balance` | GET | Balance + subscription snapshot |
| `/api/wallet/credit/history` | GET | Paginated transaction history |
| `/api/wallet/credit/topup` | POST | Add credits |
| `/api/wallet/credit/spend` | POST | Spend credits |
| `/api/prices/ring-usd` | GET | Oracle price for UI and receipts |
| `/api/membership/subscription/create` | POST | Start membership |
| `/api/membership/subscription/status` | GET | Subscription state |
| `/api/membership/subscription/cancel` | POST | Cancel |
| `/api/membership/payment/token` | POST | Membership payment variants |

Client hook: `hooks/use-credit-balance.ts` — initial REST fetch + tunnel push updates (no polling).

## Layer 2 — On-chain RING reference contracts

Ring ships **UUPS upgradeable** reference contracts for clones that want treasury-controlled ERC-20 utility on **Polygon (chainId 137)**.

### RingToken (`contracts/RingToken.sol`)

| Constant | Value |
|----------|-------|
| `INITIAL_SUPPLY` | 1,000,000,000 RING → minted to treasury at `initialize` |
| `MEMBERSHIP_FEE` | 1 RING / month |
| `MIN_SUBSCRIPTION_BALANCE` | 12 RING |
| Decimals | 18 |

**Owner functions:** `setMembershipContract`, `setTreasury`, `creditTokens` (treasury airdrops), `pause` / `unpause`.

**Membership-only:** `deductMembershipFee(member)` — callable only by linked `Membership`.

### Membership (`contracts/Membership.sol`)

| Constant | Value |
|----------|-------|
| `SUBSCRIPTION_PERIOD` | 30 days |
| `GRACE_PERIOD` | 7 days |
| `MAX_FAILED_ATTEMPTS` | 3 → `EXPIRED` |

**Statuses:** `INACTIVE`, `ACTIVE`, `EXPIRED`, `CANCELLED`, `SUSPENDED`.

**On-chain lifecycle:** `createSubscription()` → `processBatchPayments(batchSize)` (operator/cron) → `cancelSubscription()` / admin suspend.

```mermaid
flowchart LR
  Member["Member wallet"]
  RT["RingToken"]
  RM["Membership"]
  Treasury["Treasury"]

  Member -->|"createSubscription()"| RM
  RM -->|"deductMembershipFee()"| RT
  RT -->|"1 RING / month"| Treasury
  Owner["Owner"] -->|"creditTokens()"| RT
```

  RING reference tokenomics gate **platform access**. Consult counsel before marketing yield, profit expectations, or exchange listings.

  App subscriptions today run on the **credit ledger**. On-chain `Membership` is the reference for treasury policy and future sync; wire batch renewal cron to `subscriptionService.processBatchPayments()` when you bridge both layers.

### Deploy reference contracts

Hardhat project: `contracts/`. **ReferralRewards** compiles from `contracts/contracts-src/`; **RingToken** / **Membership** live at `contracts/*.sol` — align `hardhat.config.js` `paths.sources` or copy sources before compile if factories fail.

**Install and compile**

{`cd contracts
npm install
npx hardhat compile`}

**Testnet deploy** (script references Polygon Mumbai — migrate to Amoy or fork script for current testnets)

{`RING_TREASURY_TESTNET=0xYourTreasury \\
npx hardhat run scripts/deploy-testnet.js --network polygon`}

Deploy order: `RingToken` → `Membership` → `ringToken.setMembershipContract(...)`. Output: `contracts/deployments/mumbai-deployment.json`.

**Mainnet** — `scripts/deploy-mainnet.js` after audit + multisig treasury. Fund deployer with POL; use Alchemy/Infura RPC (not anonymous `polygon-rpc.com`).

**Wire env and redeploy app**

{`RING_TOKEN_CONTRACT_ADDRESS=0x...
RING_MEMBERSHIP_CONTRACT_ADDRESS=0x...
RING_CONTRACT_ADDRESS=0x...
NEXT_PUBLIC_RING_TOKEN_ADDRESS=0x...
POLYGON_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY
NEXT_PUBLIC_POLYGON_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY
WALLET_ENCRYPTION_KEY=   # openssl rand -hex 32`}

Client metadata: `constants/web3.ts` — `TOKEN_CONFIGS`, staking scaffold (`RING_STAKING_ADDRESS`, 20% APR placeholder).

## Layer 3 — Referral token rewards (refcodes)

Growth economics are **separate** from membership fees. When a referred user completes a qualifying purchase, the platform mints or transfers reward tokens via `ReferralRewards` (UUPS).

| Piece | Path / contract |
|-------|-----------------|
| Contract | `contracts/contracts-src/ReferralRewards.sol` |
| Deploy | `npx hardhat run scripts/deploy-referral-rewards.js --network polygon` |
| Minter | `features/refcodes/services/reward-minter.ts` (viem) |
| Ops runbook | `REFERRAL-ONCHAIN-OPS.md` (repo root) |

{`REFERRAL_REWARDS_ADDRESS=0x...
REFERRAL_REWARD_TOKEN_ADDRESS=0x...
REFERRAL_MINTER_ADDRESS=0x...
REFERRAL_MINTER_PRIVATE_KEY=0x...
REFERRAL_REWARD_MODE=0          # 0=MINT, 1=TRANSFER
REFERRAL_REWARD_PERCENT=5
REFERRAL_CHAIN_ID=137`}

Clone install helper: `scripts/install-refcodes-module.sh`.

Same `orderReference` can trigger:

1. **ERP vendor commission** — vendor-funded fiat settlement (`settlements.metadata.commissionBreakdown.referralCommission`)
2. **Platform token mint** — `referral_rewards` → `payReferral` on Polygon

See [Affiliate enablement](/docs/features/affiliate-enablement.md) and [Refcodes architecture](/docs/architecture/refcodes.md).

## Payment rails — fiat, credit, native token

Token economics intersect **PaymentConductor** — one ledger (`payment_transactions`), multiple rails.

| Rail | Env | Use |
|------|-----|-----|
| `merchant_redirect` | WayForPay / Stripe / PayPal | Card checkout, membership upgrade fiat, **public_pool_contribution** jar chip-ins |
| `credit_balance` | `PAYMENT_STORE_ALLOW_CREDIT=true` | Spend `credit_balance` at store |
| `native_token` | `PAYMENT_STORE_ALLOW_TOKEN=true` | On-chain token checkout (advanced) |

**Desk oracle (shared):** Token Desk credit↔native conversion and public-pool card settle both use `getNativeTokenPerMainCurrencyRate()` (`nativeUi = fiatMajor / nativePerMainCurrency`). Do **not** confuse with `wallet_topup` (fiat credit points, 1:1 ledger). Full jar SSOT: [Public Pools & DAO Jars](/docs/features/public-pools.md).

{`PAYMENT_DEFAULT_PROCESSOR=wayforpay
PAYMENT_MEMBERSHIP_PROCESSOR=wayforpay
PAYMENT_FIAT_CURRENCY=USD
PAYMENT_STORE_ALLOW_CREDIT=true
PAYMENT_STORE_ALLOW_TOKEN=false
PAYMENT_CREDIT_BALANCE_ACCEPTED_ORDER_CURRENCIES=   # default: PAYMENT_FIAT_CURRENCY only
# Optional: PAYMENT_PUBLIC_POOL_CONTRIBUTION_PROCESSOR=wayforpay`}

Apply `data/migrations/004_payment_transactions.sql` before production payments. Full operator guide: [Payment integration](/docs/customization/payment-integration.md).

## White-label token branding

### `ring-config.json`

{`"tokens": {
  "nativeToken": {
    "symbol": "RING",
    "name": "RING Governance Token",
    "decimals": 18
  }
}`}

`getNativeTokenSymbol()` and `getNativeTokenConfig()` read this for checkout labels, wallet UI, and payment copy. Fork the symbol/name for vertical clones (e.g. `GFT`, `DAAR`) without renaming Solidity unless you deploy a new ERC-20.

### Sidebar and public pages

`ring-config.json` → `sidebar.quickLinks` includes `about.sidebar.tokenEconomy` → `/token-economy` on your clone's marketing site.

### Staking and vendor gates

`constants/web3.ts` defines a **RING staking pool scaffold** (20% APR, 100 RING minimum) — configure addresses per clone or disable in UI.

`components/vendor/staking-card.tsx` supports per-product **vendor stake** requirements (`tokenSymbol`, `requiredStake`) — use for agent/vendor activation flows, not global protocol rules.

## Design your clone economy

### Classify the token

**Utility token** — listings, membership, marketplace fees. No profit promises.

Security tokens and multi-token splits need legal review before launch.

### Set parameters

{`export const cloneToken = {
  name: 'Acme Platform Token',
  symbol: 'APT',
  totalSupply: 100_000_000,
  decimals: 18,
  membershipFee: 1,
  minSubscriptionBalance: 12,
  treasuryShare: 1.0,
}`}

Map fees in `constants/store.ts` / ERP commission helpers for marketplace cuts.

### Integrate with Ring services

1. Deploy or fork `RingToken.sol` / `Membership.sol` (optional)
2. Update `ring-config.json` + `constants/web3.ts` addresses
3. Set `RING_TOKEN_CONTRACT_ADDRESS` + membership env vars
4. Enable `PAYMENT_STORE_ALLOW_CREDIT` if store should spend credits
5. Deploy `ReferralRewards` when refcodes on-chain rewards are live
6. Smoke: `npm run smoke:pipelines` (see `scripts/PIPELINES.md`)

## Health metrics

| Metric | Signal |
|--------|--------|
| Active subscriptions / failed payment rate | `ring_subscriptions` + credit history |
| Credit ledger vs treasury | Reconcile `users.data.credit_balance` with on-chain treasury movements |
| Referral mint queue | `referral_rewards` status + `/admin/refcodes` |
| Oracle freshness | `PriceOracleService` cache TTL and fallback usage |
| Payment ledger | `payment_transactions` by `rail` and `processor` |

## Legal and launch checklist

  Token launches have jurisdiction-specific consequences. Engage counsel before public sale, exchange listing, or yield marketing. See the dedicated guide: [Token launch jurisdictions](/docs/web3/token-launch-jurisdictions.md) (EU MiCA, US SEC/CFTC, UK FCA, Ukraine, FATF, official sources).

### Immediate

- [ ] Choose: RING reference vs branded ERC-20 fork
- [ ] Set `ring-config.json` token symbol + public token economy page
- [ ] Multisig treasury and contract owner keys
- [ ] Tokenomics paper (utility, fees, treasury — no investment claims)

### Development

- [ ] Postgres migrations through `004_payment_transactions` + `005_refcodes_schema`
- [ ] Wire credit + PaymentConductor env vars
- [ ] Deploy testnet contracts; run `contracts/test`
- [ ] Smoke membership create + store credit checkout

### Launch

- [ ] Mainnet deploy after audit
- [ ] Verify contracts on Polygonscan
- [ ] Enable refcodes minter (`REFERRAL-ONCHAIN-OPS.md`)
- [ ] Monitor subscription metrics and treasury alerts

  
- **[Payment integration](/docs/customization/payment-integration.md)** — Webhooks, WayForPay, Stripe setup

  
- **[Database migrations](/docs/getting-started/migrations.md)** — `refcodes`, `payment_transactions`, schema order

  
- **[Ring customization opportunities](/opportunities?type=ring_customization)** — Web3 specialists on the platform
