refactor: replace REST token registry with DB-based assets-ext reads#730
refactor: replace REST token registry with DB-based assets-ext reads#730matiwinnetou wants to merge 31 commits into
Conversation
…eReaders Replace the HTTP-based token metadata fetching (tokens.cardano.org REST API) with direct database reads via yaci-store assets-ext CIP-26/CIP-68 StorageReaders. The yaci-indexer now syncs token metadata into local DB tables, and the API module reads from them directly — eliminating external REST dependency, caching layer, and improving reliability. Key changes: - Add yaci-store-assets-ext extension to both api and yaci-indexer modules - Create AssetsExtReadOnlyConfiguration for API (read-only, no processors/cron jobs) - Rewrite TokenRegistryServiceImpl to use Cip26/Cip68 StorageReaders - Delete HTTP gateway, domain models, Guava token cache and related tests - Include pre-release jars in libs/ as file-based Maven repo (temporary) - Keep TOKEN_REGISTRY_LOGO_FETCH toggle for logo enable/disable Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Remove yaci-store-assets-ext dependency from API module. Instead, create own JPA entities (TokenMetadataEntity, TokenLogoEntity, MetadataReferenceNftEntity) mapping to the same tables, following the existing project pattern. Introduce TokenQueryService with @transactional(readOnly=true) that abstracts CIP-26/CIP-68 query details and priority-based merge. TokenRegistryServiceImpl is now a thin delegate that only handles asset extraction from Rosetta domain objects and forwards metadata lookup to TokenQueryService. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Fork CIP-26 metadata and logo repository calls in parallel using StructuredTaskScope.ShutdownOnFailure (Java 24 preview), then join before the merge phase in queryMetadataBatch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
23 tests covering: - Single subject query: empty results, CIP-26 only, CIP-68 only, full override, partial override, null decimals default - CIP-68 prefix conversion: non-fungible prefix skipped, plain asset name skipped, short subject skipped, correct 0014df10->000643b0 conversion, bare prefix edge case - Logo handling: disabled flag, CIP-26 BASE64 logo, CIP-68 URL logo, CIP-68 overrides CIP-26 logo, disabled suppresses CIP-68 logo, null logo graceful handling - Batch queries: multiple subjects, missing subjects fallback, batch logo fetch, batch CIP-68 override, null logo filtering Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
TokenRegistryMapper (14 tests): - Full field mapping, null handling, all-null fields - Logo format mapping: BASE64, URL, null format, null value - End-to-end: CIP-26/CIP-68 logos through full mapping pipeline DataMapper (7 tests): - ADA amount creation with null symbol - Native token amount with metadata - Logo passthrough for both BASE64 and URL formats - Null metadata graceful handling - Version passthrough - Value negation for spent/unspent Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Drop the file-based libs/ repository approach in favor of resolving yaci-store-assets-ext from ~/.m2/repository (installed via ./gradlew publishToMavenLocal from the yaci-store build). Bumps the version to 2.1.0-pre4-adaf5b0-SNAPSHOT. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Drop the unused TokenQueryService.queryMetadata() method and its private applyCip26(builder, cip26, subject) helper. The method was never called from production code — all paths go through queryMetadataBatch, including single-subject use cases. Rewrites the 18 TokenQueryServiceTest call sites to exercise the batch path with single-element lists, preserving full coverage of CIP merge semantics, prefix conversion, and logo handling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
#4/#7 Pass AssetFingerprint through instead of re-parsing subject strings. TokenQueryService.queryMetadataBatch now accepts Collection<AssetFingerprint> directly and returns Map<AssetFingerprint, TokenRegistryCurrencyData>. The CIP-68 prefix check uses fingerprint.getSymbol() instead of substring gymnastics on the concatenated subject. TokenRegistryServiceImpl's delegation drops the dual subjects-list + subjectToPolicyId-map plumbing and no longer calls toSubject() twice per asset. #5 Detect CIP-68 logo format from the value instead of hardcoding URL. Known URL schemes (http://, https://, ipfs://, ar://) map to URL; everything else (raw base64, data: URIs) maps to BASE64. Adds 5 new tests for the detection logic covering each case. #6 Consistent decimals policy in TokenQueryService: never default null to 0 in the query layer — let the downstream mapper (AccountMapperUtil.getDecimalsWithFallback) provide the fallback. CIP-26 and CIP-68 paths now behave the same for null decimals. TokenRegistryServiceImplTest simplified: dropped the fallback-when-missing test since that behavior is owned by TokenQueryService and already covered by its tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Replace the N+1 per-subject CIP-68 query pattern in TokenQueryService with a single native SQL call using ROW_NUMBER() OVER (PARTITION BY policy_id, asset_name ORDER BY slot DESC) + row-value tuple IN. Before: 1 (or 2 with logos) CIP-26 queries + K individual CIP-68 queries, where K = number of CIP-68 fungible tokens in the batch. A wallet with 50 CIP-68 tokens triggered 51-52 round-trips. After: 2 or 3 queries total (CIP-26 metadata, CIP-26 logos when enabled, CIP-68 latest-by-slot) regardless of batch size. The CIP-68 query is skipped entirely when no fungible token candidates are present. Implementation uses Spring Data JPA's custom repository fragment pattern (MetadataReferenceNftRepositoryCustom + Impl suffix, auto-detected). Dynamic SQL builds the correct number of positional placeholders at call time; values are bound via Query.setParameter so there is no SQL injection surface. The native query is portable across H2 2.2.x and PostgreSQL 12+. The derived method findFirstByPolicyIdAndAssetNameAndLabelOrderBySlotDesc had only one production caller and is removed. Test stubs are updated to mock the new batch method; ArgumentCaptor verifies that the fungible-to-reference-NFT prefix conversion still produces the correct PolicyAssetPair input. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
The fork/join block in queryMetadataBatch is deliberate: parallelising the two CIP-26 queries (metadata + logos) saves a round-trip at the cost of losing the outer readOnly transaction context inside the forked virtual threads. Since CIP-26 rows are only written during the periodic offchain token-registry sync, the read-skew risk is negligible for our use case. Document the caveat, the reasoning, and the revert recipe so a future reader is not surprised when they notice that each fork opens its own transaction. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Picks up the upstream CIP-68 batch-query optimization (bloxbean/yaci-store commit d358232b8) which replaces the per-subject N+1 pattern in TokenQueryService.prefetchBatch with a single window-function query. Only affects the yaci-indexer classpath — the api module uses its own JPA entities and its own MetadataReferenceNftRepository batch query, so no behavioral change on the read path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Adds an optional host-m2 build stage to the api and yaci-indexer Dockerfiles. During the mvn step we bind-mount the stage and copy com/bloxbean/cardano artifacts into the cache, then build with -nsu so Maven does not try to re-resolve snapshots from remote repos. The host-m2 context is wired into the api, indexer, and integration-test-indexer compose files via additional_contexts, defaulting to $HOME/.m2/repository. Regular builds without the context are unaffected because the default stage is empty scratch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
…store Replace the custom repository fragment (MetadataReferenceNftRepositoryCustom + CustomImpl) with a single @query(nativeQuery=true) method on MetadataReferenceNftRepository using CONCAT(policy_id, asset_name) IN (:concatenatedKeys). Policy IDs are fixed 56-char hex so the concatenation is unambiguous. Mirrors the upstream approach in bloxbean/yaci-store's MetadataReferenceNftRepository.findLatestByConcatenatedKeys — the two codebases now share the same SQL shape and the same Spring Data idiom. Once #731 merges the api and yaci-indexer modules into rosetta-app, this downstream repository layer disappears and the upstream query becomes the single source of truth. Removes ~56 lines net: - Delete MetadataReferenceNftRepositoryCustom interface (PolicyAssetPair record + findLatestByPolicyAssetPairs method) - Delete MetadataReferenceNftRepositoryCustomImpl (dynamic tuple-IN EntityManager implementation) - TokenQueryService.queryMetadataBatch collects List<String> concatenated keys instead of List<PolicyAssetPair>, calls findLatestByConcatenatedKeys - Tests: 14 stubs switch from findLatestByPolicyAssetPairs(anyList(), ...) to findLatestByConcatenatedKeys(anyCollection(), ...); ArgumentCaptor test verifies the concatenated string instead of a PolicyAssetPair Performance trade-off: CONCAT on the WHERE side means the planner can't do composite-index seeks on (policy_id, asset_name, slot); it does a label-filtered scan + CONCAT comparison instead. Acceptable because metadata_reference_nft is a small table (one row per token metadata update, updates are rare) and the optional idx_metadata_reference_nft _policy_label index from optional-indexes.sql turns the scan into an index scan when needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Clients rely on a runtime switch to turn token-registry enrichment on and off; the assets-ext refactor dropped it. Reintroduce a single flag, TOKEN_REGISTRY_ENABLED (default false), and route it through TokenQueryServiceImpl so disabled requests short-circuit to a policyId-only fallback without hitting the DB. Also revert the decimals-non-null contract from e5efb3b: the disabled fallback now mirrors main (policyId only, subject/decimals null), so the mergeMetadata path no longer seeds decimals=0. Restored getDecimalsWithFallback in AccountMapperUtil and TransactionMapperUtils and flipped TokenRegistryCurrencyData.decimals back to @nullable. Stripped the legacy HTTP-era flags (TOKEN_REGISTRY_BASE_URL, TOKEN_REGISTRY_CACHE_TTL_HOURS, TOKEN_REGISTRY_REQUEST_TIMEOUT_SECONDS) from every env template, docker-compose, Helm chart, CI workflow, and doc that still referenced them. Enabled token registry + logo on preprod (.env.docker-compose-preprod, values-preprod.yaml). Rewrote docs/docs/advanced-configuration/token-metadata.md to describe the new DB-backed yaci-store assets-ext flow instead of the removed cf-token-metadata-registry HTTP proxy setup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
…decimals
Client feedback: on most Rosetta chains decimals is a native, mandatory
field on every asset — and on Cardano we need to enrich it via assets-ext
even when the rest of the token-registry metadata isn't exposed. So the
flag shouldn't gate DB access; it should gate only the extra enrichment
fields in currency.metadata.
New wire contract:
- currency.decimals — always populated (CIP-26/CIP-68 value or 0 fallback)
- currency.metadata.policyId — always populated
- currency.metadata.{subject,name,description,ticker,url,logo,version}
— only when TOKEN_REGISTRY_ENABLED=true
Code changes:
- TokenQueryServiceImpl drops the enabled short-circuit and always
queries the assets-ext tables; mergeMetadata seeds decimals=0 and
always populates policyId + subject.
- TokenRegistryCurrencyData.decimals back to @nonnull Integer.
- AccountMapperUtil / TransactionMapperUtils drop the
getDecimalsWithFallback helper and inline metadata.getDecimals().
- DataMapper injects TOKEN_REGISTRY_ENABLED; when false it emits a
policyId-only CurrencyMetadataResponse, when true it delegates to
TokenRegistryMapper for the full mapping. Decimals continues to flow
to CurrencyResponse.decimals unconditionally.
Tests:
- DataMapperTest gains a TokenRegistryEnabledFlagTests nested class
covering both flag states and null-metadata input.
- AccountMapperUtilTest and TransactionMapperUtilsTest flip the flag on
at construction since they assert on enrichment fields.
- TokenQueryServiceTest drops the RegistryEnabledFlagTests class and
updates the 'nothing found' assertions to match the new contract
(subject populated, decimals=0).
Env and docs:
- New .env.docker-compose-preview (NETWORK=preview, PROTOCOL_MAGIC=2,
enrichment + logos on). Allow-listed in .gitignore.
- token-metadata.md rewritten to separate 'decimals always' from
'enrichment gated'; per-network defaults table (mainnet off,
preprod/preview on).
- env-vars.md, helm-values.md, kubernetes/deployment.md updated to
reflect the new semantics.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Drops an /etc/apt/apt.conf.d/99-retries file into every ubuntu:24.04 stage before the first apt call: Acquire::Retries "5"; Acquire::http::Timeout "30"; Acquire::https::Timeout "30"; Acquire::http::No-Cache "true"; Motivation: docker compose builds on shared hosts have been hitting "File has unexpected size" errors from security.ubuntu.com when a mirror edge is mid-sync. Retries + No-Cache let apt transparently re-fetch from a fresh mirror instance instead of failing the whole build. Does not help when the mirror is serving a permanently-wrong file (nothing does), but cleans up the common transient case. Applied to: - api/Dockerfile (build-common) - yaci-indexer/Dockerfile (build-common) - docker/dockerfiles/mithril/Dockerfile (cardano-builder + mithril-runner) - docker/dockerfiles/node/Dockerfile (cardano-builder + node-runner) - docker/dockerfiles/postgres/Dockerfile Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
| build: | ||
| context: ./ | ||
| dockerfile: ./api/Dockerfile | ||
| additional_contexts: |
There was a problem hiding this comment.
to remove after yaci-store assets-ext module release.
| context: ./ | ||
| dockerfile: ./yaci-indexer/Dockerfile | ||
| additional_contexts: | ||
| host-m2: ${HOST_M2:-${HOME}/.m2/repository} |
There was a problem hiding this comment.
to remove after yaci-store assets-ext module release.
| # Seed the Maven cache with artifacts from the optional host-m2 context | ||
| # (e.g. locally-built yaci-store snapshots), then build with -nsu so Maven | ||
| # does not try to re-resolve those snapshots from remote repos. | ||
| RUN --mount=type=cache,target=/root/.m2 \ |
There was a problem hiding this comment.
to remove after yaci-store release
|
Blocked:
|
Aligns MetadataReferenceNftEntity, TokenLogoEntity and TokenMetadataEntity with the JPA entity convention used across the codebase: identity is defined by @id fields only, using Lombok's @EqualsAndHashCode(onlyExplicitlyIncluded = true) plus @EqualsAndHashCode.Include on each @id. This avoids proxy/lazy-loading pitfalls and matches the upstream yaci-store style. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: migrate to JDK 25 LTS and update dependencies Migrate the project from JDK 24 to JDK 25 LTS and update all stable dependencies across the multi-module build. JDK 25 migration required adapting the StructuredTaskScope preview API (ShutdownOnFailure replaced by Joiner-based open() API) in both LedgerBlockServiceImpl and AddressHistoryServiceHibernate. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: use explicit types instead of var for StructuredTaskScope Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Mateusz Czeladka <mateusz.czeladka@cardanofoundation.org> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
…_metadata / cip68_metadata) Yaci-store assets-ext renamed its tables and merged the logo column into cip26_metadata. Retarget rosetta entities, drop the now-redundant logo table + parallel-fetch plumbing, and remove the label filter that silently hid latest reference-NFT rows tagged with a co-minted prefix. - Entities: TokenMetadataEntity -> cip26_metadata (+ logo column); MetadataReferenceNftEntity -> cip68_metadata; TokenLogoEntity removed. - Repository: drop label filter from findLatestByConcatenatedKeys to match upstream "latest row regardless of label" semantics. - TokenQueryServiceImpl: drop StructuredTaskScope and TokenLogoRepository; single CIP-26 query reads logo on the same row. TOKEN_REGISTRY_LOGO_FETCH retained as a wire-gating flag (no longer saves a DB query). - Tests: rewrite TokenQueryServiceTest for the new shape (64 tests pass). - Docs: update token-metadata.md data-flow diagram and SQL examples. - Bump yaci-store snapshot to 2.1.0-pre4-ca14bd5-SNAPSHOT. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
The previous H2 fixture (testData/devkit.db.mv.db) still carried the old ft_offchain_metadata / ft_offchain_logo / metadata_reference_nft tables. Indexer migrations against the new yaci-store snapshot create cip26_metadata and cip68_metadata, so 15 controller tests were failing with "Table CIP26_METADATA not found" / 500 errors. Regenerated end-to-end via scripts/regen-devkit-db.sh: - yaci-cli boots a local devnet (no Docker required) - topup_addresses env var funds the two test addresses - rosetta yaci-indexer runs with the h2-testdata profile, writing the V2 schema into testData/devkit.db - TestDataGenerator submits the canonical transaction set - two SQL UPDATE statements apply the genesis-block workaround - script verifies cip26_metadata + cip68_metadata are present before exit Minor test adjustments to match the regenerated fixture: - SearchControllerTest: total_count 27 -> 45 (more transactions in the new run; account-filter count of 6 unchanged) - AccountBalanceApiTest.accountBalanceMintedTokenAndEmptyName_TestORG: locate MyAsset by symbol filter rather than positional index, since devkit mint order is not guaranteed across regens - AccountCoinsApiTest.accountCoinsMultipleSpecifiedCurrencies_Test: expect decimals=0 for MyAsset (no CIP-26 row exists for it; TokenRegistry decimals resolution is covered by TokenQueryServiceTest) - MetadataApiTest.combineWithMetadataTest: TTL 735 -> 155 (chain-tip slot is shorter on the freshly-regenerated devkit) All 995 api tests now pass (8 skipped). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Per-project skill that wraps the devkit fixture regeneration. Triggers on
phrases like 'regenerate testdata', 'rebuild devkit.db', or on CI failures
mentioning 'Table CIP26_METADATA not found' (which indicate the committed
testData/devkit.db.mv.db is stale relative to the current yaci-store schema).
The skill folder contains:
- SKILL.md - workflow, common failure modes, categorisation of the
fixture-drift test adjustments
- regen-devkit-db.sh - the actual orchestration script, moved out of
scripts/ so the skill is self-contained
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Renamed .claude/skills/regenerate-testdata-db/ to .claude/skills/cardano-rosetta-java-regenerate-testdata-db/ to avoid collisions with same-named skills the user may have in other projects. Updated the SKILL.md `name:` frontmatter field and the in-doc path reference to the bundled regen-devkit-db.sh. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
💥 Preprod Tests: DEPLOYMENT FAILEDTests run against preprod network with live blockchain data |
Summary
Adds direct database access to token metadata tables (CIP-26 / CIP-68) populated by the
yaci-store-assets-extextension. The API module reads token metadata — name, ticker, decimals, description, logo — from the shared database via its own JPA entities and a batched query path, so/account/balance,/block/transaction, and/search/transactionscan enrich native-token balances and operations with metadata without any out-of-process call.What's in this PR
yaci-indexer (write side)
yaci-store-assets-ext+yaci-store-assets-ext-spring-boot-starterdependenciesstore.assets.ext.enabled=true+store.assets.ext.cip26.enabled=trueinapplication.propertiesapi module (read side)
Follows the existing project convention: own JPA entities map to yaci-store tables, no direct dependency on yaci-store jars (see "Why JPA entities are duplicated" below).
Read model under
api/common/model/entity/:TokenMetadataEntity→ft_offchain_metadata(CIP-26)TokenLogoEntity→ft_offchain_logo(CIP-26)MetadataReferenceNftEntity+MetadataReferenceNftId→metadata_reference_nft(CIP-68)Repositories under
api/common/model/repository/:TokenMetadataRepository,TokenLogoRepositoryMetadataReferenceNftRepository+MetadataReferenceNftRepositoryCustom/…CustomImpl— custom fragment with a native SQL window-function query that returns the latest-slot row per(policy_id, asset_name)pair in a single round-trip, regardless of batch sizeTokenQueryService:@Transactional(readOnly = true), owns all CIP-26/CIP-68 merge logic and priority (CIP-68 > CIP-26)0014df10→000643b0)TokenRegistryCurrencyDataCollection<AssetFingerprint>directly (no subject/policyId string shuffling)StructuredTaskScope.ShutdownOnFailureto fork the CIP-26 metadata and logo batch queries in parallel — with a documented caveat about@Transactionalcontext not propagating through virtual threads (accepted because CIP-26 rows are written only during the periodic offchain sync; read-skew risk is negligible for token metadata)http(s)://,ipfs://,ar://→URL; everything else (including raw base64 anddata:URIs) →BASE64TOKEN_REGISTRY_LOGO_FETCHtoggleTokenRegistryServiceImpl— thin delegate:BlockTx,AddressBalance,Utxo,Operation, etc.)TokenQueryService.queryMetadataBatch()withSet<AssetFingerprint>directlyConfig:
TOKEN_REGISTRY_LOGO_FETCHtoggle (defaultfalse) — whenfalse, logo columns are skipped entirely from the query path so logo blobs never leave the DB.Why JPA entities are duplicated (temporary)
This PR introduces three new JPA entities + repositories in the
apimodule that map to the exact same tablesyaci-store-assets-extowns upstream. This looks wasteful — yaci-store already publishesCip26StorageReaderandCip68StorageReaderinterfaces that do the same lookups — and it is.The duplication is forced by the current repo layout:
apiandyaci-indexerare two separate Spring Boot modules, and theapimodule has never pulled inyaci-store-*jars. Every yaci-store-backed table used by a Rosetta endpoint (address_utxo,block,transaction,pool_registration, etc.) has a duplicate*Entity+*Repositorydownstream — this PR just adds three more to that pile for the CIP-26/CIP-68 case.The real fix is to merge
apiandyaci-indexerinto a singlerosetta-appSpring Boot module and run yaci-store in read-only mode on the API replicas, so the api side can consume yaci-store's storage reader interfaces directly without any entity/repository duplication. Tracked in #731.Until #731 ships, this PR takes the pragmatic route:
MetadataReferenceNftRepositoryCustom+Impl) for the CIP-68 batch window-function query, even though the same query exists upstream inyaci-store-assets-extWhen #731 lands, this entire downstream entity/repository/custom-fragment layer for CIP-26/CIP-68 can be deleted in favor of
cip26StorageReader.findBySubjects(...)andcip68StorageReader.findBySubjects(...)— the upstream APIs the rosetta-app will consume directly.Tests (~62)
TokenQueryServiceTokenRegistryServiceImplTokenRegistryMapperDataMapperAmountbuilding with metadata, logo passthrough, ADA defaults, value negationFull api unit-test run:
761 tests, 0 failures, 21 errors— the 21 errors are pre-existing@SpringBootTestcontext-load failures that fail identically onmain(JDK-version/devkit-DB issue, unrelated to this PR).Temporary: pre-release SNAPSHOT
yaci-store-assets-extis not yet released. The yaci-indexer pom references2.1.0-pre4-d358232-SNAPSHOT, which must be installed to the local Maven repository via./gradlew publishToMavenLocalfrom thefeature/asset-store-extbranch of bloxbean/yaci-store. Revert this version bump once a proper release is cut — at which point the downstreamMetadataReferenceNftRepositoryCustomfragment can also be removed in favor of upstream'sCip68StorageReader.findBySubjects(...), and ultimately the whole downstream entity layer disappears with #731.Test plan
store.assets.ext.enabled=true— verifyft_offchain_metadata,ft_offchain_logo,metadata_reference_nftpopulate/account/balancereturns token metadata (name,ticker,decimals, etc.) from DBTOKEN_REGISTRY_LOGO_FETCH=truevsfalse— confirm logos only appear when enabled/blockand/search/transactionsalso carry token metadatamvn compile -pl api,yaci-indexerpasses🤖 Generated with Claude Code