💱 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 — even if it’s accessible in code.
Audience: Developers integrating Currency into gameplay, UI, or persistence Scope: Runtime public API only (Editor / Teaching helpers excluded)
🚀 Quick Start (Ignore everything else if you want)¶
var svc = CurrencyResolve.ServiceFrom(this);
svc.Credit(player, new CurrencyId("gold"), 100);
That’s it.
Everything else on this page is optional.
📌 Core Concepts¶
- Currency is service-first and stack-composed.
- All interaction happens via
ICurrencyServiceand 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
CurOpResultwith 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:
- Published override (bootstrappers / tests / teachables)
- Scene-local
SceneCurrencyService
SceneCurrencyService is the default scene implementation, but gameplay code must not depend on it directly.
Always resolve services via CurrencyResolve.
🧩 Composition & Factories¶
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 helpers enforce recommended ordering, but if composing manually you are responsible for decorator order.
📦 Batching¶
CurrencyBatching¶
Public batching wrapper that allows multi-operation work to emit a single batch event.
using var batch = CurrencyBatching.BeginBatch(svc);
// perform multiple operations
batch.Emit();
Batching:
- captures deltas during a block
- emits a single batch event on success
- detaches subscriptions automatically via
Dispose()
Batch emission only occurs when the service stack includes:
CurrencyFactories.WithBatchEvents(...)
Otherwise batching is a safe no-op.
📏 Policies & Caps¶
CurrencyPolicy¶
Authoritative asset defining per-currency caps and global rules.
Supported runtime surface:
TryGetCapRule(CurrencyId, out CurrencyCapRule)RequireEscrow
CurrencyCapRule¶
Stable primitive returned by policies.
Fields:
minmax(0 = unlimited)mode(ClamporFail)
Runtime code must rely on this primitive rather than authoring rule containers.
🔍 Operation Results¶
CurOpResult¶
Returned by all currency mutations.
Fields:
SuccessCodeMessage(optional)
CurOpCode¶
Stable outcome codes including:
OkInvalidArgsInsufficientFundsBelowMinimumAboveMaximumUnauthorizedServiceMissingNotFound
These codes are intended for:
- UI feedback
- analytics
- deterministic branching
📊 Events¶
CurrencyDelta¶
Emitted after a successful mutation.
Contains:
ownercurrencybeforeafter
Event Surfaces¶
Supported event surfaces:
ICurrencyService.OnWalletChangedICurrencyBatchEvents.OnWalletBatchChanged
Batch events emit once per successful multi-operation block when batching is enabled.
🧾 Audit (Optional Capability)¶
CurrencyAudit¶
Helpers for reading audit history when auditing is present.
CurrencyAudit.Get(svc, owner);
If auditing is not present, helpers return empty results.
Live Audit¶
using var sub = CurrencyAuditLive.Subscribe(svc, entry => { });
This only activates when the service stack implements ICurrencyAuditEvents.
⏱ Awaiters¶
CurrencyAwaiters¶
Async and coroutine helpers that wait for currency state changes without polling.
Examples:
WaitForBalanceAtLeastAsyncWaitForAnyChangeAsyncWaitForDeltaAsync- predicate-based waits
Async continuations may resume off the Unity thread.
Coroutine versions always resume on the Unity thread.
🔄 Transactions¶
CurrencyTxn¶
Fluent transaction builder.
var r = CurrencyTxn.Begin(svc)
.Debit(player, gold, 250)
.Credit(player, gems, 5)
.Commit();
Guarantees:
- ordered multi-operation execution
- best-effort rollback on first failure
- optional single batch event
Rollback may be blocked by:
- policy
- authority
- escrow requirements
- idempotency
🔐 Escrow¶
ICurrencyEscrow¶
Optional capability that enables hard-hold escrow.
Operations:
TryHoldCommitReleaseExpireStale
Escrow behaviour:
TryHolddebits immediatelyCommitfinalizes the holdReleaserefunds
If CurrencyPolicy.RequireEscrow is enabled and the guard is present,
direct Debit and Transfer operations fail unless the stack includes escrow.
ICurrencyEscrowReadOnly¶
Inspection surface for UI and debugging.
Allows querying active holds without mutation.
🔁 Exchange¶
ICurrencyExchange¶
Stable interface for currency conversion.
Built via:
ICurrencyExchange ex = CurrencyFactories.BuildExchange(table);
Supports:
TryQuoteTryExchange
Execution performs debit then credit with best-effort rollback.
💾 Persistence¶
ICurrencyPersistence¶
Abstract persistence contract.
Helper utilities:
CurrencyPersistence.CaptureCurrencyPersistence.Restore
Scene utilities (JSON save etc.) may implement this interface but are not required.
🧱 Value Types¶
Stable primitives safe for storage and serialization:
CurrencyIdMoneyCurrencyDeltaWalletSnapshotWalletSnapshotLine
🧰 Supported Extensions¶
CurrencyServiceExtensions¶
Public extension helpers that do not expand the core interface.
Includes:
- audit-aware overloads with
reasonandsourceId - affordability helpers
- deficit helpers
- transfer preview helpers
These extensions are part of the supported public API.
❌ Explicitly Not Supported¶
The following are not public API:
- concrete service implementations (
SceneCurrencyService, decorators) - internal namespaces (
RevGaming.RevFramework.Currency.Internal) - internal batching types
- 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 activate only when composed.
Not Guaranteed¶
- Full transactional atomicity across arbitrary decorator stacks
- Network replication
- automatic escrow usage
- automatic rollback when policy/authority blocks an operation
TL;DR¶
If it’s not on this page, it’s not part of the supported Currency API.