Skip to content

💱 Currency System — Public API

This page defines the supported, stable public API for the RevFramework Currency System.

If something is not listed here, it is not supported as a public integration point — even if it appears accessible in code.

Audience: Developers integrating Currency into gameplay, UI, or persistence
Scope: Runtime public API only (Editor / Teaching helpers excluded)
Stability: Breaking changes to items listed here are avoided or clearly versioned


📌 Core Concepts

  • Currency is service-first and stack-composed.
  • All interaction happens via ICurrencyService and related capability interfaces.
  • Currency values are stored as integer minor units (long), never floats.
  • Cross-cutting behaviour (caps, audit, escrow, authority, idempotency, batching) is added via composition, not inheritance.
  • All mutations return a CurOpResult with an explicit outcome code.

🧱 Service Entry Points

ICurrencyService

The canonical runtime interface for all currency interaction.

Supported operations:

  • EnsureWallet(owner)
  • GetBalance(owner, currencyId)
  • Credit(owner, currencyId, amount)
  • Debit(owner, currencyId, amount)
  • SetBalance(owner, currencyId, absoluteAmount)
  • Transfer(from, to, currencyId, amount)

All amounts are minor units (long).

Resolution

Currency services are resolved via:

ICurrencyService svc = CurrencyResolve.ServiceFrom(context);

Resolution order: 1. Published override (bootstrappers / tests / teachables) 2. Scene-local SceneCurrencyService

SceneCurrencyService is a required scene component for the default runtime setup,
but gameplay code should never depend on it directly. Always resolve via CurrencyResolve.


🧩 Composition & Factories (Supported)

CurrencyFactories

The supported way to build and extend a currency stack without referencing internal types.

Common decorators:

  • WithCaps(inner, policy)
  • WithAudit(inner)
  • WithAuthority(inner, context)
  • WithEscrow(inner)
  • WithIdempotency(inner)
  • WithBatchEvents(inner)

Recommended multiplayer stack:

svc = CurrencyFactories.WithCapsAuditAuthority(
    baseSvc,
    policy,
    context
);

Order matters. Combined factory helpers enforce a safe, recommended ordering. If composing manually, you are responsible for maintaining correct decorator order.


📦 Batching (Public Wrapper)

CurrencyBatching

Public batching API that allows multi-operation work to emit a single batch event without exposing internal batching types.

using var batch = CurrencyBatching.BeginBatch(svc);

// perform multiple operations...

batch.Emit();   // or batch.Cancel();
  • Safe no-op when the service does not support batching
  • Guarantees event unsubscription via Dispose()

📏 Policies & Caps

CurrencyPolicy

Authoritative asset defining per-currency caps and global rules.

Supported runtime surface:

  • TryGetCapRule(CurrencyId, out CurrencyCapRule)
  • RequireEscrow (global toggle)

CurrencyCapRule

Stable primitive returned by policies:

  • min
  • max (0 = no max)
  • mode (Clamp or Fail)

No runtime code should depend on authoring rule shapes.


🔍 Operation Results

CurOpResult

Returned by all currency mutations.

Fields: - Success - Code - Message (optional, best-effort)

CurOpCode

Stable outcome codes, including:

  • Ok
  • InvalidArgs
  • InsufficientFunds
  • BelowMinimum
  • AboveMaximum
  • Unauthorized
  • ServiceMissing
  • NotFound

These codes are intended for: - UI feedback - analytics - deterministic branching


📊 Events & Observation

CurrencyDelta

Emitted after a successful mutation.

Contains: - owner - currency - before - after

Events

Supported event surfaces:

  • ICurrencyService.OnWalletChanged
  • ICurrencyBatchEvents.OnWalletBatchChanged (when batching is enabled)

Batch events emit once per successful multi-op commit when batching is enabled and a batch scope is emitted.


🧾 Audit (Optional Capability)

CurrencyAudit (Helpers)

Safe helper API for reading audit history when supported:

CurrencyAudit.Get(svc, owner, lastN);

If auditing is not present, helpers return empty results.

Live Audit

using var sub = CurrencyAuditLive.Subscribe(svc, entry => { ... });

Only active when the service stack supports audit events.


⏱ Awaiters & Async Helpers

CurrencyAwaiters

Supported async / coroutine helpers that subscribe to events instead of polling:

  • WaitForBalanceAtLeastAsync
  • WaitForAnyChangeAsync
  • WaitForDeltaAsync
  • Predicate-based waits

Async continuations may resume off the Unity main thread.
Coroutine variants always resume on the Unity thread.


🔄 Transactions

CurrencyTxn

Fluent transaction builder for orchestrated atomic multi-operation commits.

var r = CurrencyTxn.Begin(svc, "ShopPurchase", sourceId)
    .Debit(player, gold, 250)
    .Credit(player, gems, 5)
    .Commit();

Guarantees: - Orchestrated multi-operation commit - Best-effort rollback on first failure - Single batch event when supported

Note: True transactional atomicity across all decorator stacks is not guaranteed. Authority, RequireEscrow, idempotency, or policy rules may block rollback operations.


🔐 Escrow (Optional Capability)

ICurrencyEscrow

Hard-hold escrow for debits and transfers.

Supported operations: - TryHold - Commit - Release - ExpireStale

When CurrencyPolicy.RequireEscrow is enabled and the RequireEscrow guard is composed, direct Debit and Transfer operations fail unless the service stack includes escrow.

ICurrencyEscrowReadOnly

Read-only inspection surface for UI/debug tooling.


🔁 Exchange

ICurrencyExchange

Stable interface for currency conversion.

Built via:

ICurrencyExchange ex = CurrencyFactories.BuildExchange(table);

Supports: - TryQuote - TryExchange (orchestrated debit + credit)

TransferPolicyProviders

Helper for building ITransferPolicyProvider instances without exposing authoring types.

ITransferPolicyProvider provider = TransferPolicyProviders.FromPolicy(policy);

💾 Persistence

ICurrencyPersistence

Abstract persistence contract.

Supported helpers: - CurrencyPersistence.Capture - CurrencyPersistence.Restore

Scene tools (JSON save, etc.) implement this interface but are not required for gameplay.


🧱 Value Types (Stable)

  • CurrencyId
  • Money
  • CurrencyDelta
  • WalletSnapshot
  • WalletSnapshotLine

These types are safe to store, serialize, and compare.


🧰 Supported Convenience Extensions

CurrencyServiceExtensions

Public extension helpers that do not expand the core service interface:

  • Credit / Debit / Transfer overloads with reason and sourceId
  • Deficit and affordability helpers
  • Transfer preview helpers
  • Formatting helpers for UI

These extensions are part of the supported public API.


❌ Explicitly Not Supported

The following are not part of the supported public API:

  • Concrete service implementations (SceneCurrencyService, decorators)
  • Internal decorators or helpers
  • Internal namespaces (RevGaming.RevFramework.Currency.Internal.*)
  • Casting to internal capability interfaces
  • Authoring rule containers
  • Direct access to audit buffers or escrow internals

Runtime Guarantees

  • Single currency operations are atomic.
  • All mutations return a deterministic CurOpResult.
  • Successful mutations emit OnWalletChanged.
  • Optional capabilities (audit, escrow, idempotency, batching) activate only when composed.

Not Guaranteed

  • Cross-operation transactional atomicity across arbitrary decorator stacks.
  • Network replication or prediction.
  • Implicit escrow usage.
  • Automatic rollback under authority or policy denial.

TL;DR

If it’s not on this page, it’s not part of the supported Currency API.