62: Add AssetAZ Currency Identity Service and migrate CurrencyType
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-08-07
|
||||
@@ -0,0 +1,62 @@
|
||||
## Context
|
||||
|
||||
See `proposal.md` for motivation. Currency metadata currently lives in `WellKnownCurrencyTypes`, while `WellKnownTradingPairs` captures static pairs and `RaydiumImpl` hardcodes one of them. The repository temporarily hosts both logical AssetAZ API and implementation packages, and Nenjim runtime discovery is outside this issue.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- Separate the public identity API from its hardcoded implementation package.
|
||||
- Make UUID identity robust across service instances and metadata revisions.
|
||||
- Migrate every production caller in one step so no parallel authoritative registry remains.
|
||||
- Let Raydium translate the pool response's actual mint identities into its returned pair.
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- Moving value types other than `CurrencyType`.
|
||||
- Runtime service discovery, remote/database catalogues, public registration, or constructor restriction.
|
||||
- Unit tests or Nenjim Test Tool changes.
|
||||
|
||||
## Decisions
|
||||
|
||||
### External identity is a private composite key
|
||||
|
||||
`ExternalCurrencyReference` is the public immutable carrier and explicitly implements equality and hashing from `namespace + externalId`; optional symbol metadata is excluded. The implementation may retain a private composite key for indexing and conflict diagnostics, but public value equality has the same semantic identity. The hardcoded catalogue separately compares supplied symbol metadata so conflicting catalogue entries are still rejected.
|
||||
|
||||
### Canonical and external metadata have different completeness rules
|
||||
|
||||
Every `CurrencyType` has a non-null UUID, name, and canonical symbol, even though only its UUID participates in equality. An external reference may omit its observed symbol because integrations can provide a valid namespace and external identifier without display metadata. A currency may also have zero external references; reverse lookup then returns an immutable empty set. Evelyn IOU is not such an example because its Solana mint is configured explicitly.
|
||||
|
||||
### Catalogue construction validates before freezing
|
||||
|
||||
The hardcoded implementation builds local maps, detects duplicate UUIDs with conflicting metadata and duplicate external identities targeting different UUIDs, then stores immutable copies. Reverse-reference sets are also immutable. This gives lock-free concurrent reads and contains mutation entirely within construction. A public registration API was rejected because version 1 is deliberately read-only.
|
||||
|
||||
### NenjimHub owns the service instance
|
||||
|
||||
`NenjimHubImpl.startAutoRunProcesses()` is the temporary Cauldron composition root. It creates exactly one `HardcodedCurrencyIdentityService`, then passes the interface-typed instance through constructors to the ticker source, Solana, Jupiter, Raydium, Evelyn, and any other autorun component that needs currency identities. Identity consumers never instantiate the hardcoded implementation themselves and do not use a global singleton. Multiple local service instances were rejected because they create independent lifecycles and prevent Nenjim from replacing the context's implementation coherently.
|
||||
|
||||
### Existing UUIDs move with their metadata
|
||||
|
||||
The four existing UUIDs move into an API-only `CurrencyTypeIds` constants class. It contains no metadata, mappings, or value instances and is therefore not a currency registry. The hardcoded implementation owns current names, symbols, and external mappings—including the Evelyn IOU name and mint—while production consumers resolve API UUIDs or available external identities through their injected service. No consumer imports `impl.hc`, and no static `CurrencyType` or `TradingPair` objects remain.
|
||||
|
||||
### Raydium uses response mint order
|
||||
|
||||
`RaydiumImpl` receives `CurrencyIdentityService` beside `SolanaBlockChain`. `fetchPoolPrice` extracts both response mint addresses and optional symbol metadata, creates references in a Solana-mint namespace, resolves each through the service, and constructs `TradingPair(mintA, mintB)`. Missing external symbol fields do not prevent lookup. Other Raydium calculations and State pool accounting likewise resolve actual pool mints and preserve A/B order rather than assuming SOL/SyrupUSDC. Constructor injection is the temporary integration seam until Nenjim provides dynamic dependencies.
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Existing constructors and imports break during migration] → Update all production call sites and compile every affected Gradle module before completion.
|
||||
- [Raydium response shape differs between endpoints] → Reuse the existing pool-node extraction path and validate address/symbol fields explicitly with clear IO errors.
|
||||
- [A second registry survives unnoticed] → Search the complete production tree for old types, static pairs, and legacy imports during final review.
|
||||
- [No new automated regression coverage] → Respect the explicit issue scope and rely on compilation, strict OpenSpec validation, and focused diff/static review.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. Introduce the AssetAZ API and hardcoded implementation with the preserved catalogue and required Solana mint mappings.
|
||||
2. Create one implementation instance in NenjimHub's autorun composition root and pass it through every identity-dependent construction chain.
|
||||
3. Move `CurrencyType`, migrate production imports, and replace static trading-pair use with resolutions from the injected service.
|
||||
4. Inject the service into Raydium and resolve response mint identities.
|
||||
5. Delete the legacy registries only after all production references are gone.
|
||||
6. Compile affected modules without running tests, validate OpenSpec strictly, and inspect the complete diff.
|
||||
|
||||
Rollback consists of reverting the change as one unit because the package move, registry deletion, and constructor change are intentionally atomic.
|
||||
@@ -0,0 +1,29 @@
|
||||
## Why
|
||||
|
||||
Currency identities are currently duplicated in static registries and coupled to callers such as Raydium. AssetAZ needs one service-owned UUID identity model that can resolve external identifiers without making symbols or integrations the canonical identity.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add a public AssetAZ Currency Identity Service API and immutable external-reference value type.
|
||||
- Publish stable AssetAZ currency UUID constants in an API-only identifier class so consumers never depend on the hardcoded implementation package.
|
||||
- Add a hardcoded reference implementation containing the current currency definitions and Solana mint mappings.
|
||||
- **BREAKING** Move `CurrencyType` from the shared basic value-types package to `com.r35157.assetaz.valuetypes` and define equality by UUID alone.
|
||||
- **BREAKING** Remove `WellKnownCurrencyTypes` and `WellKnownTradingPairs`; construct trading pairs from identities resolved by the service.
|
||||
- Inject the Currency Identity Service into `RaydiumImpl` and resolve pool mint identities when producing prices and ranges.
|
||||
- Create the hardcoded service exactly once in NenjimHub's autorun composition root and pass that shared service instance to every component that requires currency identities.
|
||||
- Preserve canonical currency metadata as non-null while allowing external references to omit symbol metadata and allowing currencies to have no external references.
|
||||
- Do not add or rewrite unit tests or Nenjim Test Tool code as part of this change.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `assetaz-currency-identity-service`: Defines UUID-based currency identity, external-identifier resolution, the immutable hardcoded catalogue, and its use by Raydium.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
None.
|
||||
|
||||
## Impact
|
||||
|
||||
The change affects the AssetAZ value-type and service packages, public UUID identifiers, all production imports of `CurrencyType`, NenjimHub dependency wiring, hardcoded ticker data, Raydium construction and pricing, State pool accounting, and callers that construct identity-dependent components. It removes the two legacy static currency/trading-pair registries. No external dependency or ValueTag configuration change is required.
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
## Purpose
|
||||
|
||||
Provides one authoritative AssetAZ identity model for currencies and translates stable UUIDs and namespaced external identifiers without treating display symbols as identity.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Stable AssetAZ currency identity
|
||||
The system SHALL represent a currency as an immutable `CurrencyType` with a non-null UUID, name, and symbol. Its UUID is its complete stable identity. Equality and hash codes SHALL depend only on that UUID, regardless of name, symbol, instance identity, or metadata changes.
|
||||
|
||||
#### Scenario: Metadata changes for the same UUID
|
||||
- **WHEN** two currency values have the same UUID but different names or symbols
|
||||
- **THEN** they compare equal and have the same hash code
|
||||
|
||||
#### Scenario: Matching metadata for different UUIDs
|
||||
- **WHEN** two currency values have different UUIDs but identical names and symbols
|
||||
- **THEN** they do not compare equal
|
||||
|
||||
#### Scenario: Missing canonical metadata
|
||||
- **WHEN** construction omits a currency name or symbol
|
||||
- **THEN** construction fails without producing an incomplete currency value
|
||||
|
||||
### Requirement: Resolve canonical currencies
|
||||
The Currency Identity Service SHALL resolve a known AssetAZ UUID to a non-null current currency value and SHALL fail with a clear exception for an unknown UUID.
|
||||
|
||||
#### Scenario: Resolve known UUID
|
||||
- **WHEN** a client resolves a configured AssetAZ currency UUID
|
||||
- **THEN** the service returns the current currency metadata for that UUID
|
||||
|
||||
#### Scenario: Resolve unknown UUID
|
||||
- **WHEN** a client resolves an unconfigured UUID
|
||||
- **THEN** the service throws an exception that clearly identifies the unknown UUID
|
||||
|
||||
### Requirement: Resolve namespaced external identities
|
||||
The Currency Identity Service SHALL resolve external currencies by the pair `namespace + externalId`. External symbols MAY be absent and SHALL be retained as metadata when present, but SHALL NOT participate in lookup identity or equality. A namespace SHALL describe the external identification system rather than an observing price source.
|
||||
|
||||
#### Scenario: Resolve a Solana mint
|
||||
- **WHEN** a client supplies a configured Solana-mint namespace and mint address with symbol metadata
|
||||
- **THEN** the service returns the currency mapped to that namespace and mint address
|
||||
|
||||
#### Scenario: Symbol differs from configured metadata
|
||||
- **WHEN** the namespace and external identifier are configured but the supplied symbol differs
|
||||
- **THEN** the external references compare equal and the service resolves the same currency because the symbol is not part of external identity
|
||||
|
||||
#### Scenario: External symbol is absent
|
||||
- **WHEN** a client supplies a configured namespace and external identifier without symbol metadata
|
||||
- **THEN** the service resolves the currency and returns its non-null canonical symbol
|
||||
|
||||
#### Scenario: Unknown external identity
|
||||
- **WHEN** a client supplies an unconfigured namespace and external identifier
|
||||
- **THEN** the service throws an exception that clearly identifies the unknown external identity
|
||||
|
||||
### Requirement: Reverse external-reference lookup
|
||||
The Currency Identity Service SHALL return all configured external references for a known AssetAZ UUID as a non-null immutable set, including an empty set when none exist, and SHALL fail clearly for an unknown UUID.
|
||||
|
||||
#### Scenario: Currency has multiple references
|
||||
- **WHEN** a known UUID has references in multiple external systems
|
||||
- **THEN** reverse lookup returns every reference without exposing mutable registry state
|
||||
|
||||
#### Scenario: Known currency has no references
|
||||
- **WHEN** a known UUID has no configured external references
|
||||
- **THEN** reverse lookup returns an empty immutable set
|
||||
|
||||
#### Scenario: Reverse lookup Evelyn IOU
|
||||
- **WHEN** a client requests external references for the Evelyn IOU UUID
|
||||
- **THEN** the result contains its configured Solana mint reference
|
||||
|
||||
### Requirement: Immutable conflict-free hardcoded catalogue
|
||||
The hardcoded Currency Identity Service SHALL preserve the existing AssetAZ currency UUIDs, maintain one current currency value for each UUID, support multiple external references per UUID, reject conflicting UUID or external-identity mappings during initialization, expose no public mutation operation, and be safe for concurrent reads after construction. NenjimHub SHALL create exactly one hardcoded service instance for its autorun context and SHALL pass that same instance to every autorun component that requires currency identities.
|
||||
|
||||
#### Scenario: Conflicting external mapping
|
||||
- **WHEN** initialization maps the same namespace and external identifier to two different AssetAZ UUIDs
|
||||
- **THEN** initialization fails with a clear conflict exception
|
||||
|
||||
#### Scenario: Conflicting currency metadata
|
||||
- **WHEN** initialization provides conflicting current values for the same UUID
|
||||
- **THEN** initialization fails with a clear conflict exception
|
||||
|
||||
#### Scenario: Compose autorun components
|
||||
- **WHEN** NenjimHub constructs its autorun component graph
|
||||
- **THEN** it creates one hardcoded Currency Identity Service and injects that same instance into every component that requires it
|
||||
|
||||
### Requirement: Trading pairs use service-owned identities
|
||||
Production code SHALL construct trading pairs from currency values obtained from the current Currency Identity Service and SHALL NOT maintain a parallel static registry of canonical currency or trading-pair instances.
|
||||
|
||||
#### Scenario: Construct a configured pair
|
||||
- **WHEN** production code needs a trading pair for configured currencies
|
||||
- **THEN** it resolves both UUIDs or external identities through the current service before constructing the pair
|
||||
|
||||
### Requirement: Stable UUID identifiers are implementation-independent
|
||||
The API SHALL expose stable AssetAZ currency UUID constants without names, symbols, external mappings, or `CurrencyType` instances. Consumers that require a known AssetAZ UUID SHALL use these API identifiers and SHALL NOT import the hardcoded Currency Identity Service implementation.
|
||||
|
||||
#### Scenario: Consumer resolves a known UUID
|
||||
- **WHEN** a consumer needs a known AssetAZ currency by UUID
|
||||
- **THEN** it obtains the UUID from the API identifier class and resolves it through its injected Currency Identity Service
|
||||
|
||||
### Requirement: Pool amounts follow actual mint identities
|
||||
Pool accounting SHALL resolve mint A and mint B through the Currency Identity Service using their actual namespaced Solana mint addresses and SHALL preserve the pool's A/B order when assigning currency types to amounts.
|
||||
|
||||
#### Scenario: State loads a pool
|
||||
- **WHEN** State receives pool information with mint A and mint B
|
||||
- **THEN** amount A uses the currency resolved from mint A and amount B uses the currency resolved from mint B
|
||||
|
||||
### Requirement: Raydium resolves response currencies
|
||||
Raydium SHALL receive a Currency Identity Service dependency and SHALL build a fetched pool price's trading pair in Raydium response order by resolving `mintA` and `mintB` as namespaced Solana mint identities. It SHALL NOT resolve currencies by symbol alone.
|
||||
|
||||
#### Scenario: Fetch a configured Raydium pool price
|
||||
- **WHEN** Raydium returns a price plus configured mint A and mint B identifiers, with or without symbols
|
||||
- **THEN** the returned asset price uses a trading pair whose base is the service resolution of mint A and whose quote is the service resolution of mint B
|
||||
|
||||
#### Scenario: Raydium returns an unknown mint
|
||||
- **WHEN** either returned mint identity is not configured
|
||||
- **THEN** pool-price creation fails with the Currency Identity Service's clear unknown-identity exception
|
||||
@@ -0,0 +1,35 @@
|
||||
## 1. Currency Identity API and Catalogue
|
||||
|
||||
- [x] 1.1 Move `CurrencyType` into the AssetAZ value-types package and make equality and hashing UUID-only.
|
||||
- [x] 1.2 Add the annotated immutable `ExternalCurrencyReference` and read-only `CurrencyIdentityService` API.
|
||||
- [x] 1.3 Implement the immutable hardcoded catalogue with preserved UUIDs, reverse lookup, Solana mint mappings, and construction-time conflict detection.
|
||||
|
||||
## 2. Production Migration
|
||||
|
||||
- [x] 2.1 Migrate every production `CurrencyType` import and replace hardcoded ticker pair construction with identities from the current service.
|
||||
- [x] 2.2 Inject the Currency Identity Service into `RaydiumImpl` and resolve Raydium mint identities and response-ordered trading pairs.
|
||||
- [x] 2.3 Update production construction/configuration sites for the new dependencies and remove `WellKnownCurrencyTypes` and `WellKnownTradingPairs`.
|
||||
|
||||
## 3. Verification
|
||||
|
||||
- [x] 3.1 Compile every affected module without running unit tests.
|
||||
- [x] 3.2 Run strict OpenSpec validation and `git diff --check`.
|
||||
- [x] 3.3 Review the complete diff and production tree for incomplete migrations, old imports, parallel currency registries, and unintended test or Nenjim Test Tool changes.
|
||||
|
||||
## 4. Composition-Root Correction
|
||||
|
||||
- [x] 4.1 Create the hardcoded Currency Identity Service exactly once in `NenjimHubImpl.startAutoRunProcesses()` and pass it into every autorun construction chain that needs it.
|
||||
- [x] 4.2 Replace identity consumers' local hardcoded-service construction with required `CurrencyIdentityService` constructor dependencies.
|
||||
- [x] 4.3 Compile main and test source sets, strict-validate OpenSpec, run `git diff --check`, and confirm no hardcoded service construction remains outside the NenjimHub composition root.
|
||||
|
||||
## 5. Public API Documentation
|
||||
|
||||
- [x] 5.1 Document the public Currency Identity Service, external-reference, and currency value APIs, including identity semantics, nullability, and failure behavior.
|
||||
- [x] 5.2 Compile main and test source sets and rerun strict OpenSpec validation and `git diff --check`.
|
||||
|
||||
## 6. Review Corrections
|
||||
|
||||
- [x] 6.1 Require complete canonical currency metadata, add API-owned UUID identifiers, and preserve the Evelyn IOU name and Solana mint mapping.
|
||||
- [x] 6.2 Make external-reference equality use namespace plus external ID while retaining optional symbols and catalogue conflict detection.
|
||||
- [x] 6.3 Resolve State pool currencies from actual mint A/B identities and make Raydium symbol extraction optional.
|
||||
- [x] 6.4 Remove consumer dependencies on `impl.hc`, compile without tests, strict-validate OpenSpec, run `git diff --check`, and review the complete migration.
|
||||
Reference in New Issue
Block a user