cardano-foundation / cardano-foundation/cardano-rosetta-java
Asset data addition via /call endpoint
- Dominant language
- Java
- Stars
- 26
- Forks
- 15
- Avg merge
- 5d 3h
- Merged PRs (30d)
- 2
Description
## Why
Integrators migrating from `cardano-graphql` need standalone asset lookups. Today, asset metadata in Rosetta is only ever returned *attached to an `Amount`* — inside `/block`, `/block/transaction`, `/account/balance`, `/account/coins` or `/search/transactions` responses. There is no way to ask "what is asset X?" without first finding a transaction or address that happens to contain it.
Concretely, these `cardano-graphql` queries have no clean Rosetta equivalent:
```graphql
query assets($assetId: Hex) {
assets(where: { assetId: { _eq: $assetId } }) {
assetId assetName name decimals fingerprint policyId
}
}
query assets($fingerprint: String) {
assets(where: { fingerprint: { _eq: $fingerprint } }) { ... }
}
query assets($assetId: Hex) {
assets(where: { assetId: { _eq: $assetId } }) {
tokenMints_aggregate { aggregate { sum { quantity } } }
}
}
```
Gaps today:
| Field | Status |
|---|---|
| `policyId`, `assetName` (hex), `decimals`, `name`, `ticker`, `description`, `url`, `logo` | available, but only bundled into `Amount.currency` |
| `assetId` / subject | available as `currency.metadata.subject` |
| `fingerprint` (CIP-14 `asset1…`) | **not exposed anywhere** |
| token supply (`tokenMints_aggregate`) | **not available — mints are not indexed** |
| lookup by assetId / by fingerprint | **not possible** |
## What
Add a read-only asset lookup method to the existing `/call` endpoint, in the same style as the already-implemented `get_parse_error_blocks` / `mark_parse_error_block_checked` (`CallServiceImpl`). This keeps us inside the Mesh spec (`/call` is the sanctioned escape hatch for network-specific procedures) without inventing non-standard endpoints.
New method:
- **`get_asset_data`** — look up a single asset by `asset_id` **or** by `fingerprint`, returning identifiers, Token Registry metadata, and current supply.
It must be advertised in `NetworkOptionsResponse.allow.call_methods` (already wired via `CallService.getSupportedMethods()`), and documented in the `CallRequest` / `CallResponse` descriptions in `api.yaml`.
*(Sample values below are illustrative — the shape is what matters, not the exact hex/fingerprints.)*
### 1. `get_asset_data` — by asset id
`asset_id` = base16 `policyId` + base16 `assetName` (same value as today's `currency.metadata.subject`).
**Request**
```json
{
"network_identifier": { "blockchain": "cardano", "network": "mainnet" },
"method": "get_asset_data",
"parameters": {
"asset_id": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209484f534b59"
}
}
```
**Response**
```json
{
"result": {
"asset": {
"asset_id": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209484f534b59",
"policy_id": "1e349c9bdea19fd6c147626a5260bc44b71635f398b67c59881df209",
"asset_name": "484f534b59",
"fingerprint": "asset17q7r59zlc3dgw0venc80pdv566q6yguw03f0d9",
"decimals": 0,
"name": "Hosky Token",
"ticker": "HOSKY",
"description": "Hosky Token",
"url": "https://hosky.io",
"logo": { "format": "BASE64", "value": "iVBORw0KGgo..." },
"version": 1,
"supply": {
"quantity": "1000000000000000",
"total_minted": "1000000000000000",
"total_burned": "0",
"as_of_block": 12345678
}
}
},
"idempotent": false
}
```
Notes on the response shape:
- `policy_id`, `asset_name`, `asset_id` and `fingerprint` are derived on-chain/locally — always present. `asset_name` stays base16; decoding it to a display string is left to the caller, since on-chain asset names are arbitrary bytes and not guaranteed to be valid UTF-8 (e.g. CIP-68 label prefixes).
- `decimals`, `name`, `ticker`, `description`, `url`, `logo`, `version` come from the Cardano Token Registry (reuse `TokenRegistryService`) — omitted when the asset isn't registered. Fallback for `decimals` stays `0`, consistent with current behaviour.
- `supply.quantity` is the net of mints minus burns, i.e. the direct equivalent of `tokenMints_aggregate { aggregate { sum { quantity } } }`. `total_minted` / `total_burned` are broken out because they're free once mint events are indexed and save callers a second query. `as_of_block` pins the figure to a block height so callers can reason about staleness.
- `idempotent: false` — both Token Registry entries and supply change over time.
### 2. `get_asset_data` — by fingerprint
Requires implementing CIP-14 fingerprint derivation, which we don't have today. Note the existing `AssetFingerprint` class is a misnomer — it holds `policyId` + hex `assetName`, not a CIP-14 bech32 fingerprint.
**Request**
```json
{
"network_identifier": { "blockchain": "cardano", "network": "mainnet" },
"method": "get_asset_data",
"parameters": {
"fingerprint": "asset17q7r59zlc3dgw0venc80pdv566q6yguw03f0d9"
}
}
```
**Response** — same shape as above.
Exactly one of `asset_id` / `fingerprint` must be supplied; supplying both or neither is a parameter error.
### 3. Unknown / unregistered assets
An asset that exists on chain but has no Token Registry entry still returns the derived fields and `supply`, with the registry fields omitted — matching the existing fallback behaviour in `TokenRegistryServiceImpl.createFallbackMetadata`:
```json
{
"result": {
"asset": {
"asset_id": "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e",
"policy_id": "29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6",
"asset_name": "4d494e",
"fingerprint": "asset1jsa0nakldvzq0aqf0mkstd0j4rt3nc5f0uf75t",
"decimals": 0,
"supply": {
"quantity": "5000000000",
"total_minted": "5000000000",
"total_burned": "0",
"as_of_block": 12345678
}
}
},
"idempotent": false
}
```
An asset that has never been minted on this network is a not-found error rather than an empty object.
### Errors
Reuse the existing `/call` error factories:
- unknown method → `callMethodNotSupported`
- missing / malformed / mutually exclusive parameters → `callParameterMissing`
- `asset_id` not valid hex, or shorter than a 56-char policy id → parameter error
- offline mode → `notSupportedInOfflineMode` (already handled in `CallApiImplementation`)
### Prerequisite: indexing mint/burn events
Supply is the one part of this that isn't just a re-shaping of data we already hold. Today there is **no mint data in the database at all**:
- `OperationType` has no mint or burn type, so mints never become operations.
- There is no mint or asset table in the schema — the jOOQ tables are `Address`, `AddressUtxo`, `Block`, `Transaction`, `TxInput`, `Withdrawal`, staking/governance and friends.
- Supply cannot be back-computed from UTXOs either, since `store.utxo.pruning-enabled` defaults to `true` and spent UTXOs are pruned.
So this needs indexer work first. The enabled yaci-store starters in `yaci-indexer/pom.xml` are currently blocks, transaction, utxo, staking, governance, epoch and admin — no assets/mint store. Worth checking whether an upstream yaci-store assets module can be enabled to capture mint/burn events before we consider writing our own aggregation, and what the storage cost of that looks like.
Suggested split if that turns out to be sizeable:
1. identifiers + Token Registry metadata + CIP-14 fingerprint (self-contained, deliverable now)
2. `supply` block (depends on mint indexing)
### Reference
- Mesh specifications — `/call`, `CallRequest`, `CallResponse`, `Allow.call_methods`: https://github.com/coinbase/mesh-specifications
- Existing implementation to mirror: `api/src/main/java/org/cardanofoundation/rosetta/api/call/service/CallServiceImpl.java`
- Registry lookup to reuse: `api/src/main/java/org/cardanofoundation/rosetta/api/common/service/TokenRegistryServiceImpl.java`
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with api/src/main/java/org/cardanofoundation/rosetta/api/call/service/CallServiceImpl.java and TokenRegistryServiceImpl.java, then inspect yaci-indexer/pom.xml for an upstream assets module that can capture mint and burn events. The first deliverable is asset identifiers, metadata, and CIP-14 fingerprint support; supply fields require mint indexing and should be assessed separately.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend, blockchain, database
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100