Skip to content

💰 Currency / Exchange

🎯 Purpose

The Exchange layer provides optional, data-driven currency conversion.

It defines how one currency can be converted into another using authored rules and a runtime implementation that delegates all mutations to a provided currency service.

This layer does not own balances or wallet state.


⚠️ Important Notes

  • Exchange does not own or persist wallet state
  • All mutations are delegated to a provided ICurrencyService
  • Atomicity is not guaranteed
  • Rollback is best-effort only
  • Behaviour depends on the composed service stack

🧩 What Lives Here

CurrencyExchangeTable

ScriptableObject containing exchange rules between currency pairs.

Each rule defines:

  • rate — multiplier applied to the source amount
  • feePct — percentage fee (0–100)
  • minSrc — minimum source amount
  • maxSrc — maximum source amount (0 = no cap)
  • roundDown — rounding behaviour

Behaviour:

  • Currency identifiers are normalized before lookup
  • Rules are stored as (from, to) pairs
  • When duplicates exist, the last rule is used
  • Table rebuilds on OnEnable and OnValidate

Example:

if (table.TryGetRule(src, dst, out var rule))
{
    // inspect rule
}

TableCurrencyExchange

Runtime implementation of ICurrencyExchange backed by a CurrencyExchangeTable.

  • Uses the table for quoting
  • Delegates mutations to a provided ICurrencyService
  • Attempts rollback if credit fails after debit

🧠 Usage Guidance

TryQuote

Non-mutating preview of an exchange.

Returns:

  • true when a quote is produced
  • false when inputs are invalid or a rule is missing

Flow:

  • Validate inputs
  • Lookup rule
  • Apply min/max constraints
  • Apply fee
  • Apply rounding
  • Reject if result is non-positive

TryQuote does not inspect wallet state or authority.


TryExchange

Applies an exchange using a provided ICurrencyService.

Flow:

  1. Validate inputs
  2. Ensure rule exists
  3. Recompute quote
  4. Debit source currency
  5. Credit destination currency
  6. Attempt rollback if credit fails

Returns:

  • CurOpResult.Ok on success
  • Failure codes from underlying operations
  • NotFound when no rule exists
  • InvalidArgs when quoting fails

🧠 Usage Guidance

Mental model

  • Exchange defines conversion rules, not balances
  • Execution depends on the provided service
  • Service composition (caps, authority, etc.) still applies

🚫 Internal Use Only

This folder provides optional conversion behaviour.

Do not:

  • Store wallet state here
  • Assume transactional guarantees
  • Depend on specific service composition order

🧹 Safe to Remove

This folder may be removed if currency conversion is not required.

Core Currency functionality will continue to operate without it.


  • Abstractions — ICurrencyExchange, ICurrencyService
  • Policies — caps and transfer rules
  • Definitions — formatting and presentation
  • Core — composition and service resolution