---
title: "Архітектура WalletConductor"
description: "Методи фасаду, тонкі адаптери, курси кредитів і native, передача до PaymentConductor та перевірені маршрути /api/wallet — грошовий аналог архітектури PaymentConductor"
locale: "uk"
---
# Архітектура WalletConductor

WalletConductor — це **server-only грошовий фасад** Ring Platform для кастодіальних гаманців native token і фіатного кредитного ledger. Тонкі адаптери викликають conductor; PaymentConductor володіє checkout PSP для `wallet_topup` і `native_token_onramp`. Передача браузера після top-up — це `redirect` Conductor + `followCheckoutResult` — див. [Архітектура PaymentConductor](/docs/architecture/payment-conductor.md).

**Гайд для оператора / продукту:** [WalletConductor](/docs/features/wallet-conductor.md) · [Wallet](/docs/features/wallet.md) · [PaymentConductor](/docs/architecture/payment-conductor.md)

> **Info**
> Використовуйте вкладки **Founder** / **Developer** на бічній панелі документації, щоб відфільтрувати цю сторінку. Огляд функції (цінність + чекліст): [WalletConductor](/docs/features/wallet-conductor.md). Інвентар HTTP/actions: [Wallet API](/docs/api/wallet.md).

  
- **[Огляд функції](/docs/features/wallet-conductor.md)** — Можливості, SSOT двох курсів, чекліст оператора

  
- **[Архітектура PaymentConductor](/docs/architecture/payment-conductor.md)** — Ledger, webhooks, обробники purpose

  
- **[Wallet API](/docs/api/wallet.md)** — Actions і HTTP-поверхня

### For founders

## Чому ця архітектура важлива

- **Єдиний грошовий стрижень** — top-up, Token Desk, кастодіальне надсилання, разове витрачання кредитів і купівля на NFT market використовують один фасад замість розрізнених викликів PSP/ledger.
- **Чіткий поділ продукту** — поповнення карткою купує **credit points**; desk конвертує points ↔ **native**; onramp confidential+ купує treasury native без додавання points.
- **Безпечні ручки оператора** — desk oracle (`nativePerMainCurrency`) ніколи не переписує математику store checkout або разового витрачання кредитів (`credit.creditBalanceUnitToMainCurrency`).
- **Межа за задумом** — checkout store/membership і зовнішній EVM `POST /api/wallet/transfer` залишаються поза WalletConductor, щоб клони випадково не змішували рейки.

### For developers

## Потік запиту

```mermaid
flowchart LR
  subgraph adapters["Тонкі адаптери"]
    SA["app/_actions/wallet.ts"]
    API["/api/wallet/*"]
    NFT["nft-market actions"]
    AUTH["auth.ts OAuth"]
  end

  WC["WalletConductor\nfeatures/wallet/conductor"]

  subgraph deps["Делегати"]
    PC["PaymentConductor"]
    CBS["creditBalanceService"]
    DESK["desk-service"]
    XFER["native-token-transfer-service"]
    EW["ensure-wallet"]
    SOL["SolanaMarketClient"]
  end

  SA --> WC
  API --> WC
  NFT --> WC
  AUTH --> WC
  WC --> PC
  WC --> CBS
  WC --> DESK
  WC --> XFER
  WC --> EW
  WC --> SOL
```

## Основні модулі

| Модуль | Шлях | Відповідальність |
|--------|------|----------------|
| Фасад | `features/wallet/conductor/wallet-conductor.ts` | Усі публічні методи оркестрації |
| Provision | `features/wallet/services/ensure-wallet.ts` | Атомарне створення гаманця в кількох мережах (використовується `ensureNativeWallet`) |
| Credit ledger | `features/wallet/services/credit-balance-service.ts` | Додавання/витрачання фіатних points |
| Fiat rate | `lib/payments/credit-balance.ts` → `getFiatCreditAccountingRate` | SSOT `credit.creditBalanceUnitToMainCurrency` |
| Desk | `features/wallet/chains/solana/desk-service.ts` | Котирування + виконання (subscriber+) |
| Desk oracle | `features/wallet/services/native-token-oracle.ts` | `nativePerMainCurrency` лише для desk |
| Custodial send | `features/wallet/chains/native-token-transfer-service.ts` | Gasless надсилання native |
| PSP checkout | `lib/payments/conductor/payment-conductor.ts` | `wallet_topup`, `native_token_onramp` |
| Onramp gate | `lib/payments/confidential-token-onramp.ts` | `assertNativeTokenOnrampAllowed` |
| Actions | `app/_actions/wallet.ts` | Обгортки для сесії |
| NFT buy | `features/nft-market/services/solana-market-client.ts` | Розрахунок купівлі на market |

### API фасаду

| Метод | Auth / gates | Делегує до |
|--------|--------------|--------------|
| `initiateTopUp` | Сесія; amount 25–2000 | PaymentConductor `wallet_topup`; повертає `redirect` |
| `initiateNativeOnramp` | Сесія + confidential+ + onramp flag | PaymentConductor `native_token_onramp` |
| `quoteDesk` / `executeDesk` | `assertTokenDeskSubscriberAccess` | desk-service + oracle |
| `getNativeBalance` | Caller `userId` | native-token-transfer-service |
| `transferNative` | Caller `userId` | transfer service + `wallet_transactions` + **`publishWalletListUpdate(userId, 'updated')`** |
| `spendCredits` | Caller `userId` | creditBalanceService + fiat rate (+ `credit:balance` tunnel через service) |
| `ensureNativeWallet` | Caller supplies `id` (OAuth-safe) | ensure-wallet (+ `wallet:list` коли wallets змінюються) |
| `ensureFunded` | Сесія | ensure + необов’язковий credit floor |
| `purchaseNftListing` | Idempotency key | SolanaMarketClient |

Також експортується: `getWalletConductorNativeChain()` → `getNativeChain()`.

{`import { WalletConductor } from '@/features/wallet/conductor/wallet-conductor'

// OAuth / events — no session required
await WalletConductor.ensureNativeWallet({ id: userId, role })

// Prefer Server Actions from UI (app/_actions/wallet.ts)
await WalletConductor.spendCredits({
  userId,
  amount: '10.00',
  description: 'API debit',
  // usdRate defaults to getFiatCreditAccountingRate()
})`}

## Два курси — не змішуйте

| Курс | SSOT | Використовується в |
|------|------|---------|
| Облік фіатних кредитів | `credit.creditBalanceUnitToMainCurrency` через `getFiatCreditAccountingRate()` | `spendCredits`, debit side desk, PaymentConductor `credit_balance` |
| Oracle Token Desk | `platform_settings.web3.oracle.nativePerMainCurrency` | лише `quoteDesk` / `executeDesk` |

**Не належить WalletConductor:** checkout store/membership (`store_order`, `membership_upgrade`, рейки `credit_balance` / `native_token`), життєвий цикл membership SubscriptionConductor і зовнішній EVM `POST /api/wallet/transfer` (Polygon POL / SupportedCrypto). Для кастодіальних надсилань native платформи надавайте перевагу `/api/wallet/token/transfer`.

## Тонкі адаптери (перевірено)

### Server Actions (`app/_actions/wallet.ts`)

| Дія | Метод Conductor |
|--------|------------------|
| `ensureUserWallets` | `ensureNativeWallet` |
| `getNativeTokenBalanceAction` | `getNativeBalance` |
| `spendCredits` | `spendCredits` |
| `transferNativeTokens` | `transferNative` |
| `executeDeskQuote` | `executeDesk` |
| `initiateCreditTopupPayment` | `initiateTopUp` |
| `initiateNativeTokenOnrampPayment` | `initiateNativeOnramp` |
| `createPinAccessTokenAction` | `ensureNativeWallet` |

Desk **quote** не має action-обгортки — лише HTTP (`POST /api/wallet/desk/quote`). Купівля NFT: `app/_actions/nft-market.ts` → `purchaseNftListing`. OAuth: `auth.ts` → `ensureNativeWallet`.

### HTTP-маршрути, які викликають WalletConductor

| Метод | Path | Метод Conductor |
|--------|------|------------------|
| `POST` | `/api/wallet/desk/quote` | `quoteDesk` |
| `POST` | `/api/wallet/desk/execute` | `executeDesk` |
| `POST` | `/api/wallet/ensure` | `ensureNativeWallet` |
| `GET` | `/api/wallet/token/balance` | `getNativeBalance` |
| `POST` | `/api/wallet/token/transfer` | `transferNative` |
| `POST` | `/api/wallet/credit/spend` | `spendCredits` (fiat rate SSOT) |

### Явно поза фасадом

| Шлях / поверхня | Чому |
|----------------|-----|
| `POST /api/wallet/transfer` | Шлях EVM SupportedCrypto — не Solana custodial SSOT |
| `POST /api/wallet/credit/topup` | Chain-proof додавання кредитів через `creditBalanceService` (не card top-up) |
| `GET /api/wallet/credit/spend` | **410 deprecated** — використовуйте `getSpendSummary` / `GET /api/wallet/credit/history` |
| Store / membership purposes PaymentConductor | Checkout-рейки, а не фасад wallet |

## Послідовність — картка → credit points

```mermaid
sequenceDiagram
  participant UI as CreditAddFsModal
  participant WC as WalletConductor
  participant PC as PaymentConductor
  participant PSP as WayForPay_or_Stripe_or_PayPal
  participant WH as wallet_topup_webhook
  participant CBS as creditBalanceService
  UI->>WC: initiateTopUp formData
  WC->>PC: createCheckout purpose=wallet_topup
  PC-->>UI: redirect navigate_or_form_post
  UI->>PSP: followCheckoutResult
  Note over UI,PSP: returnUrl browser UX only
  PSP->>WH: webhook Approved_or_capture
  WH->>CBS: addFiatUsd fiat points
```

Див. [Архітектура PaymentConductor](/docs/architecture/payment-conductor.md) щодо `CheckoutRedirect` і [WayForPay](/docs/features/wayforpay-integration.md) щодо HPP POST.

## Послідовність — разове витрачання кредитів

```mermaid
sequenceDiagram
  participant API as POST /api/wallet/credit/spend
  participant WC as WalletConductor.spendCredits
  participant RATE as getFiatCreditAccountingRate
  participant CBS as creditBalanceService
  API->>WC: amount, description
  WC->>RATE: creditBalanceUnitToMainCurrency
  WC->>CBS: spendCredits(..., usdRate)
  CBS-->>API: newBalance, transactionId
```

## Середовище й конфігурація (перевірено)

| Ключ | Роль |
|-----|------|
| `WALLET_ENCRYPTION_KEY` | Шифрування кастодіальних ключів |
| `SOLANA_RPC_URL` / `SOLANA_TREASURY_PRIVATE_KEY` | Кастодіальний Solana + спонсорування gas |
| `CONFIDENTIAL_TOKEN_ONRAMP` / `NEXT_PUBLIC_CONFIDENTIAL_TOKEN_ONRAMP` / desk `nativeTokenOnramp` | Gate native card onramp (`isNativeTokenOnrampEnabled`) |
| `credit.creditBalanceUnitToMainCurrency` | Множник обліку фіатного ledger |
| `ORACLE_QUOTE_SECRET` / `RING_ORACLE_DEFAULT_RATE` | HMAC котирування desk + fallback |

Server SSOT для onramp: `lib/ring-config-chain.ts` → `isNativeTokenOnrampEnabled()`. Runtime role gate: `assertNativeTokenOnrampAllowed` (confidential/admin/superadmin + flag).

## Нотатки з безпеки

- Кастодіальні ключі ніколи не залишають сервер; UI використовує Server Actions / автентифіковані маршрути
- Desk потребує subscriber+; native onramp потребує confidential+ і feature flag
- Фіатне витрачання має використовувати `getFiatCreditAccountingRate()` — ніколи не передавайте desk `nativePerMainCurrency` у дебети кредитного ledger
- Надавайте перевагу `/api/wallet/token/*` — застарілі псевдоніми `/api/wallet/ring/*` видалено

## Пов’язана документація

  
- [features/tunnel-protocol](/docs/features/tunnel-protocol.md) — Залежність: після transferNative / ensure conductor розсилає `wallet:list` через publishWalletListUpdate.

  
- [features/wallet-conductor](/docs/features/wallet-conductor.md) — Наступний крок: продуктовий гайд для операторів із двома аудиторіями.

  
- [architecture/payment-conductor](/docs/architecture/payment-conductor.md) — Той самий процес: PSP ledger і webhooks для wallet_topup / native_token_onramp.

  
- [features/wallet](/docs/features/wallet.md) — Див. також: потоки dashboard гаманця для учасника.

  
- [api/wallet](/docs/api/wallet.md) — Поглиблення: Server Actions та інвентар HTTP.
