💰 Currency -- Core¶
Namespace: RevGaming.RevFramework.Currency
The Core layer contains the primary runtime building blocks of the Currency system. These are the services, helpers, and utilities you interact with during normal gameplay, UI wiring, and tooling.
Core is where you use Currency --- not where you define contracts (see Abstractions) or wire scene composition (see Bootstrap).
Multiplayer note (netcode-agnostic): Currency is designed to support server/host-authoritative flows. Use Authority (
ICurrencyAuthority) and Idempotency (|rid:<token>insourceId) when building multiplayer systems.
🔎 Core Design Principle¶
Core exposes capability-based composition.
Features such as:
- Caps\
- Audit\
- Authority\
- Idempotency\
- Escrow\
- Batch emission
are added via decorators composed through CurrencyFactories.
Core helpers automatically detect these optional capabilities when
present --- without expanding the public ICurrencyService contract.
What lives in Core¶
Core includes:
- The default in-scene currency service (
SceneCurrencyService) - Public factories for composing stacks (
CurrencyFactories) - Resolvers (
CurrencyResolve) to access the active service - High-level helpers for common gameplay patterns:
- Transactions
- Hold Transactions
- Purchases
- Awaiters
- Audit helpers
Everything here depends only on Abstractions and optional capabilities. Concrete decorators remain internal.
Core types¶
SceneCurrencyService¶
The default in-scene implementation of ICurrencyService.
- Stores balances in a dictionary keyed by
GameObject → CurrencyId → long - Emits
OnWalletChangedfor every mutation - Optionally prunes destroyed owners over time
- Predictable and allocation-light
- Suitable as the inner layer for all decorator stacks
Important\
SceneCurrencyService.Instanceis the raw inner service (no caps, audit, authority, idempotency, etc.).\ Gameplay code should preferCurrencyResolveto ensure the composed stack is used.
Recommended usage:
var svc = CurrencyResolve.ServiceFrom(this);
svc.Credit(player, new CurrencyId("gold"), 100);
CurrencyResolve¶
Runtime resolver for the active ICurrencyService.
Resolution order:
- Published override (via
CurrencyBootstrap.Publish) - Cached per-scene resolve
- One-time scene-local search for
SceneCurrencyService
Resolution is scene-aware: in additive or multi-scene setups, the service is resolved from the caller's scene.
var svc = CurrencyResolve.ServiceFrom(this);
This is the recommended entry point for gameplay and UI code.
CurrencyFactories¶
Public factory helpers for composing currency service stacks.
Core helpers:
WithCapsWithAuditWithAuthorityWithEscrowWithIdempotencyWithBatchEvents
Factories ensure:
- Decorator ordering is explicit
- Concrete decorator types remain internal
Example:
svc = CurrencyFactories.WithCapsAuditAuthorityIdemBatch(
svc, policy, this);
Factories define composition order but do not guarantee transactional safety across multi-step workflows.
CurrencyTxn¶
Best-effort multi-operation transactions.
- Stages multiple
Credit,Debit,Set, orTransferoperations - Performs a simulated precheck before committing (funds/overflow only)
- Applies operations sequentially
- Attempts rollback automatically on the first failure
- Emits a single batch event when supported
Note Rollback is best-effort. Final atomicity depends on the composed service stack (policy, authority, escrow, idempotency, etc. may block rollback). For stronger guarantees when escrow is available, use
CurrencyHoldTxn.
CurrencyHoldTxn¶
Two-phase, escrow-backed hold transactions.
Designed for flows where currency must be reserved before final confirmation, such as:
- Auction bids
- Crafting queues
- Matchmaking entry fees
- Delayed purchases
- Time-limited offers
CurrencyHoldTxn:
- Places escrow holds for one or more debits
- Supports staged commit / cancel
- Integrates with escrow TTL when enabled
- Emits batched events when supported
- Performs rollback on failure
Use CurrencyHoldTxn when currency must be reserved first --- not
immediately spent.
CurrencyPurchase¶
Convenience helpers for affordability checks and best-effort multi-currency spends/grants.
Internally applies operations sequentially and attempts rollback on failure. Final atomicity depends on the composed service stack.
CurrencyAwaiters¶
Task-based and coroutine-based awaiters that complete when wallet conditions change.
- Subscribes to
OnWalletChanged(event-driven) - Includes safe cancellation, timeout handling, and owner/service invalidation detection
Prefer awaiters over manual polling.
CurrencyAudit & CurrencyAuditLive¶
Helpers for working with audit-enabled stacks.
CurrencyAuditprovides query helpers when auditing is presentCurrencyAuditLiveprovides safe subscription to live audit events
Stacks without auditing simply return empty results.
CurrencyServiceExtensions¶
Extension helpers layered on top of ICurrencyService.
- Audit-aware overloads
- Cap-aware preview helpers
- Affordability helpers
These helpers detect optional capabilities without expanding the public contract.
CurrencyRequestId¶
Utility for generating idempotency tokens.
var rid = CurrencyRequestId.New();
Idempotency convention:
"VendorA|rid:<token>"(recommended)"rid:<token>"(also valid)
Idempotency is enforced only by stacks that include the idempotency decorator.
CurrencyEscrowExpiryPump¶
Scene component that periodically calls ExpireStale() on
escrow-enabled services.
Relevant only when escrow is enabled and TTLs are used.
Attach when you want automatic cleanup of expired holds.
Best practices¶
- Resolve services via
CurrencyResolve - Avoid direct use of
SceneCurrencyService.Instance - Compose stacks using
CurrencyFactories - Use
CurrencyTxnfor immediate multi-step actions - Use
CurrencyHoldTxnfor reservation flows - Prefer awaiters over polling
- Enable audit during development
- Ensure an expiry pump exists when using escrow TTL
- Route multiplayer mutations through authority
Related¶
- Abstractions --- contracts and primitives
- Bootstrap --- scene-level composition and publishing
- Internal --- decorator implementations
- Authority --- authority contracts and binders
- Persistence --- snapshot capture