Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Filter with Founder / Developer in the docs sidebar. Prefer Server Actions for UI. HTTP routes remain for MCP, webhooks, and non-React clients. Desk oracle rate lives in platform_settings / web3 via ring-token-oracle.ts — separate from fiat credit accounting.
Ring Platform wallet operations use two layers:
app/_actions/wallet.ts — type-safe, revalidatePath, works with useActionState.app/api/wallet/**/route.ts — session-cookie HTTP for external integrations and MCP.Browser calls use Auth.js session cookies on the same origin — see API reference. UI entry: /wallet (protected).
Dashboard, fiat credit points, Token Desk conversion, gasless native sends.
Store checkout debits credit points via PaymentConductor internal_credit (same fiat rate SSOT).
Social sign-in provisions custodial wallets automatically.
Superadmin sets native-token oracle rate and gas reserve — not member-facing.
| Rate | Config | Used for |
|---|---|---|
| Fiat credit accounting | ring-config.json → credit.unitToDefaultCurrency (usually 1) | Debiting/crediting points vs store defaultCurrency |
| Token Desk oracle | platform_settings.web3.oracle.ringPerUsd | Converting points ↔ native token on the desk |
Keep credit.unitToDefaultCurrency at 1 unless you intentionally scale points vs fiat. Changing the desk oracle (ringPerUsd) never changes store or ad-hoc credit spend math.
ensureUserWallets / WalletConductor.ensureNativeWallet provisions custodial address (Solana or EVM per clone).listUserWallets + getCreditBalance.transferNativeTokens (treasury-sponsored gas on Solana).initiateCreditTopupPayment → WalletConductor.initiateTopUp → PaymentConductor wallet_topup → UI followCheckoutResult(redirect) → webhook credits ledger. Card uses env processor; PayPal tab sends processor=paypal.topUpCredits / verifyTopUpTransaction.spendCredits Server Action or POST /api/wallet/credit/spend.internal_credit (PaymentConductor), not a raw UI call to /credit/spend.Custodial model: Ring signs transfers server-side for social-auth wallets. External wallets (MetaMask, Coinbase Wallet, WalletConnect via the Wagmi v3 connector picker) connect client-side — they do not use custodial server actions.
Depends-on: `credit:balance` and `wallet:list` Tunnel channels that refresh this API's UI consumers.
Deep-dive: facade methods that publish wallet-list updates after transferNative / ensure.
Next-step: member-facing wallet dashboard and credit vs native rails.
See-also: session auth model and domain API map.
Filter with Founder / Developer in the docs sidebar. Prefer Server Actions for UI. HTTP routes remain for MCP, webhooks, and non-React clients. Desk oracle rate lives in platform_settings / web3 via ring-token-oracle.ts — separate from fiat credit accounting.
Ring Platform wallet operations use two layers:
app/_actions/wallet.ts — type-safe, revalidatePath, works with useActionState.app/api/wallet/**/route.ts — session-cookie HTTP for external integrations and MCP.Browser calls use Auth.js session cookies on the same origin — see API reference. UI entry: /wallet (protected).
Dashboard, fiat credit points, Token Desk conversion, gasless native sends.
Store checkout debits credit points via PaymentConductor internal_credit (same fiat rate SSOT).
Social sign-in provisions custodial wallets automatically.
Superadmin sets native-token oracle rate and gas reserve — not member-facing.
| Rate | Config | Used for |
|---|---|---|
| Fiat credit accounting | ring-config.json → credit.unitToDefaultCurrency (usually 1) | Debiting/crediting points vs store defaultCurrency |
| Token Desk oracle | platform_settings.web3.oracle.ringPerUsd | Converting points ↔ native token on the desk |
Keep credit.unitToDefaultCurrency at 1 unless you intentionally scale points vs fiat. Changing the desk oracle (ringPerUsd) never changes store or ad-hoc credit spend math.
ensureUserWallets / WalletConductor.ensureNativeWallet provisions custodial address (Solana or EVM per clone).listUserWallets + getCreditBalance.transferNativeTokens (treasury-sponsored gas on Solana).initiateCreditTopupPayment → WalletConductor.initiateTopUp → PaymentConductor wallet_topup → UI followCheckoutResult(redirect) → webhook credits ledger. Card uses env processor; PayPal tab sends processor=paypal.topUpCredits / verifyTopUpTransaction.spendCredits Server Action or POST /api/wallet/credit/spend.internal_credit (PaymentConductor), not a raw UI call to /credit/spend.Custodial model: Ring signs transfers server-side for social-auth wallets. External wallets (MetaMask, Coinbase Wallet, WalletConnect via the Wagmi v3 connector picker) connect client-side — they do not use custodial server actions.
Depends-on: `credit:balance` and `wallet:list` Tunnel channels that refresh this API's UI consumers.
Deep-dive: facade methods that publish wallet-list updates after transferNative / ensure.
Next-step: member-facing wallet dashboard and credit vs native rails.
See-also: session auth model and domain API map.
Filter with Founder / Developer in the docs sidebar. Prefer Server Actions for UI. HTTP routes remain for MCP, webhooks, and non-React clients. Desk oracle rate lives in platform_settings / web3 via ring-token-oracle.ts — separate from fiat credit accounting.
Ring Platform wallet operations use two layers:
app/_actions/wallet.ts — type-safe, revalidatePath, works with useActionState.app/api/wallet/**/route.ts — session-cookie HTTP for external integrations and MCP.Browser calls use Auth.js session cookies on the same origin — see API reference. UI entry: /wallet (protected).
Dashboard, fiat credit points, Token Desk conversion, gasless native sends.
Store checkout debits credit points via PaymentConductor internal_credit (same fiat rate SSOT).
Social sign-in provisions custodial wallets automatically.
Superadmin sets native-token oracle rate and gas reserve — not member-facing.
| Rate | Config | Used for |
|---|---|---|
| Fiat credit accounting | ring-config.json → credit.unitToDefaultCurrency (usually 1) | Debiting/crediting points vs store defaultCurrency |
| Token Desk oracle | platform_settings.web3.oracle.ringPerUsd | Converting points ↔ native token on the desk |
Keep credit.unitToDefaultCurrency at 1 unless you intentionally scale points vs fiat. Changing the desk oracle (ringPerUsd) never changes store or ad-hoc credit spend math.
ensureUserWallets / WalletConductor.ensureNativeWallet provisions custodial address (Solana or EVM per clone).listUserWallets + getCreditBalance.transferNativeTokens (treasury-sponsored gas on Solana).initiateCreditTopupPayment → WalletConductor.initiateTopUp → PaymentConductor wallet_topup → UI followCheckoutResult(redirect) → webhook credits ledger. Card uses env processor; PayPal tab sends processor=paypal.topUpCredits / verifyTopUpTransaction.spendCredits Server Action or POST /api/wallet/credit/spend.internal_credit (PaymentConductor), not a raw UI call to /credit/spend.Custodial model: Ring signs transfers server-side for social-auth wallets. External wallets (MetaMask, Coinbase Wallet, WalletConnect via the Wagmi v3 connector picker) connect client-side — they do not use custodial server actions.
Depends-on: `credit:balance` and `wallet:list` Tunnel channels that refresh this API's UI consumers.
Deep-dive: facade methods that publish wallet-list updates after transferNative / ensure.
Next-step: member-facing wallet dashboard and credit vs native rails.
See-also: session auth model and domain API map.
executeDeskQuote |
| Credit ↔ native desk trade |
createPinAccessTokenAction | PIN-gated single-use access token |
Fiat ledger debits must use the config multiplier — never the desk oracle.
| Fact | Truth |
|---|---|
| SSOT | ring-config.json → credit.unitToDefaultCurrency (usually 1) |
| Helpers | getCreditUnitToDefaultCurrencyRate / getFiatCreditAccountingRate in lib/ring-config-core.ts + lib/payments/credit-currency.ts |
| Fallback | exchangeRates[defaultCurrency], then 1 |
| Ad-hoc debit | WalletConductor.spendCredits (Server Action omits usdRate → conductor defaults to fiat helper) |
| Store checkout | PaymentConductor internal_credit → internal-credit.processor.ts (also calls getFiatCreditAccountingRate) |
| Never | platform_settings.web3.oracle.ringPerUsd / getRingPerUsdRate for fiat usdRate |
| Desk only | ring-token-oracle / pointsPerNativeToken for points ↔ RING |
Document POST /api/wallet/credit/spend only. A GET stub may return 410 in code — it is not a capability. Use getSpendSummary or GET /api/wallet/credit/history for reads.
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/list | { wallets } via listWallets() — ?refresh=true force on-chain via refreshBalancesForUser (publishes wallet:list) |
| POST | /api/wallet/ensure | Idempotent create-if-missing — ensureWallets publishes wallet:list when provisioning changes |
| GET | /api/wallet/balance | Default wallet native-token balance |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/token/balance | { balance, address, chain, symbol } |
| POST | /api/wallet/token/transfer | Custodial native-token send; wallet_transactions row |
| POST | /api/wallet/transfer | External EVM custodial POL path when chains.enabled includes evm — not Solana native SSOT |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/activity | filter=all|credit|chain, unified feed |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/credit/balance | Balance + spend limits — live UI via Tunnel credit:balance (publishToUserTunnel after ledger mutations) |
| PUT | /api/wallet/credit/balance | Admin airdrop { user_id, amount, reason } |
| POST | /api/wallet/credit/topup | Optional tx_hash verification |
| POST | /api/wallet/credit/spend | Direct fiat debit via WalletConductor.spendCredits + unitToDefaultCurrency |
| GET | /api/wallet/credit/history | Paginated ledger |
Schemas: lib/zod/credit-schemas.ts. Service: features/wallet/services/credit-balance-service.ts.
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/desk/quote | Query side, amount |
| POST | /api/wallet/desk/execute | { idempotencyKey, quoteToken } |
| Concern | File | Key exports |
|---|---|---|
| Credit CRUD | features/wallet/services/credit-balance-service.ts | addCredits, spendCredits, getCreditHistory |
| Conductor | features/wallet/conductor/wallet-conductor.ts | spendCredits, ensureNativeWallet |
| Fiat rate | lib/ring-config-core.ts / lib/payments/credit-currency.ts | getCreditUnitToDefaultCurrencyRate, getFiatCreditAccountingRate |
| Store credit checkout | lib/payments/processors/internal-credit.processor.ts | createInternalCreditCheckout |
| Gasless transfers | features/wallet/chains/native-token-transfer-service.ts | transferNativeTokenForUser |
| Desk trades | features/wallet/chains/solana/desk-service.ts | quoteDesk, executeDesk |
| Native oracle | features/wallet/services/ring-token-oracle.ts | getRingPerUsdRate, setRingPerUsdRate |
| Wallet DB | lib/wallet/user-wallet-db.ts | getUserWallets, getNativeWallet |
| PIN tokens | lib/wallet/pin-access-token-db.ts | issueAccessToken, consumeAccessToken |
Prefer Server Action (React UI)
Form fields: amount (required), description (optional — defaults to Credit spend), orderId (optional). Conductor applies getFiatCreditAccountingRate() when usdRate is omitted.
Or HTTP POST (external / MCP)
CreditSpendRequestSchema requires amount and description. Body may include optional order_id, reference_id, metadata.
Store checkout (do not call spend HTTP from store UI)
PaymentConductor rail internal_credit → internal-credit.processor.ts → creditBalanceService.spendCredits with the same fiat rate helper.
| Variable | Required | Used by |
|---|---|---|
WALLET_ENCRYPTION_KEY | Yes | AES-256-GCM wallet secrets |
SOLANA_RPC_URL | Yes | Solana RPC |
SOLANA_TREASURY_PRIVATE_KEY | Yes | Sponsored gas / treasury ops |
WALLET_ACCESS_TOKEN_TTL_SECONDS | No (default 900) | PIN access tokens |
ORACLE_QUOTE_SECRET | Desk | Quote HMAC (falls back to WALLET_ENCRYPTION_KEY) |
RING_ORACLE_DEFAULT_RATE | No | Desk oracle fallback when DB disabled |
PLATFORM_SETTINGS_DISABLE_DB | No | Env-only oracle reads |
Admin write: setRingPerUsdRate or POST /api/admin/web3/settings.
Prerequisite: crypto wallet provider + social login that provisions custodial wallets.
executeDeskQuote |
| Credit ↔ native desk trade |
createPinAccessTokenAction | PIN-gated single-use access token |
Fiat ledger debits must use the config multiplier — never the desk oracle.
| Fact | Truth |
|---|---|
| SSOT | ring-config.json → credit.unitToDefaultCurrency (usually 1) |
| Helpers | getCreditUnitToDefaultCurrencyRate / getFiatCreditAccountingRate in lib/ring-config-core.ts + lib/payments/credit-currency.ts |
| Fallback | exchangeRates[defaultCurrency], then 1 |
| Ad-hoc debit | WalletConductor.spendCredits (Server Action omits usdRate → conductor defaults to fiat helper) |
| Store checkout | PaymentConductor internal_credit → internal-credit.processor.ts (also calls getFiatCreditAccountingRate) |
| Never | platform_settings.web3.oracle.ringPerUsd / getRingPerUsdRate for fiat usdRate |
| Desk only | ring-token-oracle / pointsPerNativeToken for points ↔ RING |
Document POST /api/wallet/credit/spend only. A GET stub may return 410 in code — it is not a capability. Use getSpendSummary or GET /api/wallet/credit/history for reads.
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/list | { wallets } via listWallets() — ?refresh=true force on-chain via refreshBalancesForUser (publishes wallet:list) |
| POST | /api/wallet/ensure | Idempotent create-if-missing — ensureWallets publishes wallet:list when provisioning changes |
| GET | /api/wallet/balance | Default wallet native-token balance |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/token/balance | { balance, address, chain, symbol } |
| POST | /api/wallet/token/transfer | Custodial native-token send; wallet_transactions row |
| POST | /api/wallet/transfer | External EVM custodial POL path when chains.enabled includes evm — not Solana native SSOT |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/activity | filter=all|credit|chain, unified feed |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/credit/balance | Balance + spend limits — live UI via Tunnel credit:balance (publishToUserTunnel after ledger mutations) |
| PUT | /api/wallet/credit/balance | Admin airdrop { user_id, amount, reason } |
| POST | /api/wallet/credit/topup | Optional tx_hash verification |
| POST | /api/wallet/credit/spend | Direct fiat debit via WalletConductor.spendCredits + unitToDefaultCurrency |
| GET | /api/wallet/credit/history | Paginated ledger |
Schemas: lib/zod/credit-schemas.ts. Service: features/wallet/services/credit-balance-service.ts.
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/desk/quote | Query side, amount |
| POST | /api/wallet/desk/execute | { idempotencyKey, quoteToken } |
| Concern | File | Key exports |
|---|---|---|
| Credit CRUD | features/wallet/services/credit-balance-service.ts | addCredits, spendCredits, getCreditHistory |
| Conductor | features/wallet/conductor/wallet-conductor.ts | spendCredits, ensureNativeWallet |
| Fiat rate | lib/ring-config-core.ts / lib/payments/credit-currency.ts | getCreditUnitToDefaultCurrencyRate, getFiatCreditAccountingRate |
| Store credit checkout | lib/payments/processors/internal-credit.processor.ts | createInternalCreditCheckout |
| Gasless transfers | features/wallet/chains/native-token-transfer-service.ts | transferNativeTokenForUser |
| Desk trades | features/wallet/chains/solana/desk-service.ts | quoteDesk, executeDesk |
| Native oracle | features/wallet/services/ring-token-oracle.ts | getRingPerUsdRate, setRingPerUsdRate |
| Wallet DB | lib/wallet/user-wallet-db.ts | getUserWallets, getNativeWallet |
| PIN tokens | lib/wallet/pin-access-token-db.ts | issueAccessToken, consumeAccessToken |
Prefer Server Action (React UI)
Form fields: amount (required), description (optional — defaults to Credit spend), orderId (optional). Conductor applies getFiatCreditAccountingRate() when usdRate is omitted.
Or HTTP POST (external / MCP)
CreditSpendRequestSchema requires amount and description. Body may include optional order_id, reference_id, metadata.
Store checkout (do not call spend HTTP from store UI)
PaymentConductor rail internal_credit → internal-credit.processor.ts → creditBalanceService.spendCredits with the same fiat rate helper.
| Variable | Required | Used by |
|---|---|---|
WALLET_ENCRYPTION_KEY | Yes | AES-256-GCM wallet secrets |
SOLANA_RPC_URL | Yes | Solana RPC |
SOLANA_TREASURY_PRIVATE_KEY | Yes | Sponsored gas / treasury ops |
WALLET_ACCESS_TOKEN_TTL_SECONDS | No (default 900) | PIN access tokens |
ORACLE_QUOTE_SECRET | Desk | Quote HMAC (falls back to WALLET_ENCRYPTION_KEY) |
RING_ORACLE_DEFAULT_RATE | No | Desk oracle fallback when DB disabled |
PLATFORM_SETTINGS_DISABLE_DB | No | Env-only oracle reads |
Admin write: setRingPerUsdRate or POST /api/admin/web3/settings.
Prerequisite: crypto wallet provider + social login that provisions custodial wallets.
executeDeskQuote |
| Credit ↔ native desk trade |
createPinAccessTokenAction | PIN-gated single-use access token |
Fiat ledger debits must use the config multiplier — never the desk oracle.
| Fact | Truth |
|---|---|
| SSOT | ring-config.json → credit.unitToDefaultCurrency (usually 1) |
| Helpers | getCreditUnitToDefaultCurrencyRate / getFiatCreditAccountingRate in lib/ring-config-core.ts + lib/payments/credit-currency.ts |
| Fallback | exchangeRates[defaultCurrency], then 1 |
| Ad-hoc debit | WalletConductor.spendCredits (Server Action omits usdRate → conductor defaults to fiat helper) |
| Store checkout | PaymentConductor internal_credit → internal-credit.processor.ts (also calls getFiatCreditAccountingRate) |
| Never | platform_settings.web3.oracle.ringPerUsd / getRingPerUsdRate for fiat usdRate |
| Desk only | ring-token-oracle / pointsPerNativeToken for points ↔ RING |
Document POST /api/wallet/credit/spend only. A GET stub may return 410 in code — it is not a capability. Use getSpendSummary or GET /api/wallet/credit/history for reads.
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/list | { wallets } via listWallets() — ?refresh=true force on-chain via refreshBalancesForUser (publishes wallet:list) |
| POST | /api/wallet/ensure | Idempotent create-if-missing — ensureWallets publishes wallet:list when provisioning changes |
| GET | /api/wallet/balance | Default wallet native-token balance |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/token/balance | { balance, address, chain, symbol } |
| POST | /api/wallet/token/transfer | Custodial native-token send; wallet_transactions row |
| POST | /api/wallet/transfer | External EVM custodial POL path when chains.enabled includes evm — not Solana native SSOT |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/activity | filter=all|credit|chain, unified feed |
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/credit/balance | Balance + spend limits — live UI via Tunnel credit:balance (publishToUserTunnel after ledger mutations) |
| PUT | /api/wallet/credit/balance | Admin airdrop { user_id, amount, reason } |
| POST | /api/wallet/credit/topup | Optional tx_hash verification |
| POST | /api/wallet/credit/spend | Direct fiat debit via WalletConductor.spendCredits + unitToDefaultCurrency |
| GET | /api/wallet/credit/history | Paginated ledger |
Schemas: lib/zod/credit-schemas.ts. Service: features/wallet/services/credit-balance-service.ts.
| Method | Path | Notes |
|---|---|---|
| GET | /api/wallet/desk/quote | Query side, amount |
| POST | /api/wallet/desk/execute | { idempotencyKey, quoteToken } |
| Concern | File | Key exports |
|---|---|---|
| Credit CRUD | features/wallet/services/credit-balance-service.ts | addCredits, spendCredits, getCreditHistory |
| Conductor | features/wallet/conductor/wallet-conductor.ts | spendCredits, ensureNativeWallet |
| Fiat rate | lib/ring-config-core.ts / lib/payments/credit-currency.ts | getCreditUnitToDefaultCurrencyRate, getFiatCreditAccountingRate |
| Store credit checkout | lib/payments/processors/internal-credit.processor.ts | createInternalCreditCheckout |
| Gasless transfers | features/wallet/chains/native-token-transfer-service.ts | transferNativeTokenForUser |
| Desk trades | features/wallet/chains/solana/desk-service.ts | quoteDesk, executeDesk |
| Native oracle | features/wallet/services/ring-token-oracle.ts | getRingPerUsdRate, setRingPerUsdRate |
| Wallet DB | lib/wallet/user-wallet-db.ts | getUserWallets, getNativeWallet |
| PIN tokens | lib/wallet/pin-access-token-db.ts | issueAccessToken, consumeAccessToken |
Prefer Server Action (React UI)
Form fields: amount (required), description (optional — defaults to Credit spend), orderId (optional). Conductor applies getFiatCreditAccountingRate() when usdRate is omitted.
Or HTTP POST (external / MCP)
CreditSpendRequestSchema requires amount and description. Body may include optional order_id, reference_id, metadata.
Store checkout (do not call spend HTTP from store UI)
PaymentConductor rail internal_credit → internal-credit.processor.ts → creditBalanceService.spendCredits with the same fiat rate helper.
| Variable | Required | Used by |
|---|---|---|
WALLET_ENCRYPTION_KEY | Yes | AES-256-GCM wallet secrets |
SOLANA_RPC_URL | Yes | Solana RPC |
SOLANA_TREASURY_PRIVATE_KEY | Yes | Sponsored gas / treasury ops |
WALLET_ACCESS_TOKEN_TTL_SECONDS | No (default 900) | PIN access tokens |
ORACLE_QUOTE_SECRET | Desk | Quote HMAC (falls back to WALLET_ENCRYPTION_KEY) |
RING_ORACLE_DEFAULT_RATE | No | Desk oracle fallback when DB disabled |
PLATFORM_SETTINGS_DISABLE_DB | No | Env-only oracle reads |
Admin write: setRingPerUsdRate or POST /api/admin/web3/settings.
Prerequisite: crypto wallet provider + social login that provisions custodial wallets.