💰 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 amountfeePct— percentage fee (0–100)minSrc— minimum source amountmaxSrc— 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
OnEnableandOnValidate
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:
truewhen a quote is producedfalsewhen 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:
- Validate inputs
- Ensure rule exists
- Recompute quote
- Debit source currency
- Credit destination currency
- Attempt rollback if credit fails
Returns:
CurOpResult.Okon success- Failure codes from underlying operations
NotFoundwhen no rule existsInvalidArgswhen 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.
🔗 Related Documentation¶
- Abstractions —
ICurrencyExchange,ICurrencyService - Policies — caps and transfer rules
- Definitions — formatting and presentation
- Core — composition and service resolution