Demo — one transaction in, a typed business story out
cardano-ledger-rdf turns a Conway transaction into an RDF graph you can
read, pipe, and query. This page walks three pipelines on real mainnet
data — first one transaction, then the whole May 2026 Amaru treasury
history — and shows the difference an operator overlay makes: raw
addresses become named scopes, an opaque asset becomes USDM, and a pile of
independent transactions becomes one queryable lattice.
Every command runs against the published build. Nothing is hand-edited, and every number on this page is reproduced by a query you can see and re-run. Any token below — transaction id, address, asset — links to CardanoScan so you can verify on a neutral third party that the chain really says what we say it does.
Setup
You need two executables — cq-rdf (the RDF runtime: overlay, body,
blueprint, shacl) and tx-view (RDF → human views) — plus arq (the
SPARQL CLI from Apache Jena) for the query section. Pick the install
path that fits you; they all produce identical graphs.
Most operators and auditors don't want to compile Haskell. Grab a release artifact — no toolchain, no build:
# Linux x86_64 — AppImage (also .deb / .rpm / musl tarball on the releases page)
v=0.4.0.0
base=https://github.com/lambdasistemi/cardano-ledger-rdf/releases/download/v$v
curl -L "$base/cq-rdf-$v-x86_64-linux.AppImage" -o cq-rdf && chmod +x cq-rdf
curl -L "$base/tx-view-$v-x86_64-linux.AppImage" -o tx-view && chmod +x tx-view
# macOS arm64 — tarball: cq-rdf-$v-aarch64-darwin.tar.gz (and tx-view-…)
Release assets are versioned, so set v to the version you want.
Browse the latest release
for the current version string and the asset names for your
architecture. The same release still ships a deprecated tx-graph
compatibility symlink for one cycle so existing scripts keep working;
new work should target cq-rdf directly.
arq comes from Apache Jena (nix run nixpkgs#apache-jena -- ..., or your
distro's jena package).
Where the transaction comes from
cq-rdf body reads one Conway transaction either from a local CBOR
file or from a chain indexer — the graph and every answer below are
identical whichever you pick:
# A. fetch by txid from a public indexer (no local node)
cq-rdf body --provider koios <txid> # free, rate-limited
cq-rdf body --provider blockfrost --token "$BLOCKFROST_PROJECT_ID" <txid>
# B. read a CBOR you already have on disk
cq-rdf body path/to/signed-tx.cbor
Provider, token, or local file — the emitter is pure, so swapping the
source can't change the result. The examples use a $BLOCKFROST_PROJECT_ID
already exported in the environment.
Pipeline 1 — bare: the explorer baseline
The lead transaction is deliberately a SundaeSwap swap, not a plain payment: a swap engages a contract, so it carries redeemers and an inline order datum. That is exactly the material the overlay has to work on, and exactly what a block explorer leaves as opaque bytes.
Our swap is
10a5c1da…
— one rung of the treasury's ADA → USDM swap chain. Bare:
cq-rdf body --provider blockfrost --token "$BLOCKFROST_PROJECT_ID" \
10a5c1dafe7dd8d4ab680e35dc53b8b550da90bea55f2c758f36474064f2e598 \
| tx-view --graph - --view cli-tree
inputs:
- txOutRef: dfd355530e2d3baef6fc4cb22369c8b64aa117b0a84ff2cdaadc24cdc3fbc7bc#2
- txOutRef: dfd355530e2d3baef6fc4cb22369c8b64aa117b0a84ff2cdaadc24cdc3fbc7bc#3
referenceInputs:
- txOutRef: 11ace24a7b0caad4a68a38ef2fff18185dc9ea604e84425dab487cae94e4cf54#0
- txOutRef: 25ba96f5deb14bb5c56e7542d6a9ba8450f52cc698ebd74574e1a0525d861095#2
- txOutRef: 810bfcbde85ae72f27d7e8cd154c03c802de15d3fa0dd83a32a4b0fdba330b3c#0
- txOutRef: e7b395a93d49a17994d66df0e4778a01dee05e7711e6612f28d97b63e4e6311c#2
outputs:
- address: addr1x8ax5k9mutg07p2ngscu3chsauktmstq92z9de938j8nqaejyqwur6p8pqmycmzz55lcnan4x99mnt2a5fe54ggt4gxst7gy3n
coin: 42.891805 ADA
datum:
hash: 7c413435da13eabb7117a425f3a495f84ddfc2f8eb9caf8f00d512995bfaf299
rawBytes: d8799fd8799f581c64f35d26b237ad58e099041bc14c687ea7fdc58969d7d5b66e2540efffd87a9f9fd8799f581c7095faf3d48d582fbae8b3f2e726670d7a35e2400c783d992bbdeffbffd8799f581cf3ab64b0f97dcf0f91232754603283df5d75a1201337432c04d23e2effd8799f581c8bd03209d227956aaf9670751e0aa2057b51c1537a43f155b24fb1c1ffd8799f581c97e0f6d6c86dbebf15cc8fdf0981f939b2f2b70928a46511edd49df2ffffff1a00138800d8799fd8799fd87a9f581c32201dc1e82708364c6c42a53f89f675314bb9ad5da2734aa10baa0dffd8799fd8799fd87a9f581c32201dc1e82708364c6c42a53f89f675314bb9ad5da2734aa10baa0dffffffffd87980ffd87a9f9f40401a025c6d9dff9f581cc48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad480014df105553444d1a00989681ffffd87980ff
- address: addr1x8ax5k9mutg07p2ngscu3chsauktmstq92z9de938j8nqaejyqwur6p8pqmycmzz55lcnan4x99mnt2a5fe54ggt4gxst7gy3n
coin: 42.891804 ADA
datum:
hash: 0ef54f5a163374af92cd46099e7a092857ed5d16ff48f1a0db91b476feae827d
rawBytes: d8799fd8799f581c64f35d26b237ad58e099041bc14c687ea7fdc58969d7d5b66e2540efffd87a9f9fd8799f581c7095faf3d48d582fbae8b3f2e726670d7a35e2400c783d992bbdeffbffd8799f581cf3ab64b0f97dcf0f91232754603283df5d75a1201337432c04d23e2effd8799f581c8bd03209d227956aaf9670751e0aa2057b51c1537a43f155b24fb1c1ffd8799f581c97e0f6d6c86dbebf15cc8fdf0981f939b2f2b70928a46511edd49df2ffffff1a00138800d8799fd8799fd87a9f581c32201dc1e82708364c6c42a53f89f675314bb9ad5da2734aa10baa0dffd8799fd8799fd87a9f581c32201dc1e82708364c6c42a53f89f675314bb9ad5da2734aa10baa0dffffffffd87980ffd87a9f9f40401a025c6d9cff9f581cc48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad480014df105553444d1a00989680ffffd87980ff
- address: addr1xyezq8wpaqnssdjvd3p220uf7e6nzjae44w6yu625y965rfjyqwur6p8pqmycmzz55lcnan4x99mnt2a5fe54ggt4gxs8thzgk
coin: 1449833.102132 ADA
- address: addr1qx9aqvsf6gne2640jec828s25gzhk5wp2day8u24kf8mrs2v0zyuvk80fay35dx008p45ts0u6cdrv9g2maetq8jm8psznjcrz
coin: 99.092459 ADA
withdrawals:
- account: <urn:cardano:id:StakeScript:a64d1b9e1aeffe54056034d84977061b45a92691efc282fbee3fc094>
amount: 0.000000 ADA
collateral:
- txOutRef: dfd355530e2d3baef6fc4cb22369c8b64aa117b0a84ff2cdaadc24cdc3fbc7bc#3
fee: 0.454317 ADA
Raw bech32 addresses, two outputs locked at a script with an inline datum that is just a wall of CBOR. This is what every explorer shows. It is faithful, but it tells you nothing about what the transaction means to the treasury: which scope is spending, what contract those datums belong to, what's being bought.
Pipeline 2 — typed: the same tx, with the operator overlay
The overlay is a small, operator-authored
overlay.yaml: a flat
declaration of the treasury's scopes, the asset it trades, the vendors it
pays, and the on-chain contracts it engages. cq-rdf overlay emits it
as Turtle that concatenates with the body graphs. The file we end at is
the one the Amaru operator actually uses; rather than drop it on you
whole, we add it one feature at a time and watch each line earn its
keep.
Rung 1 — name the scopes
entities:
- name: amaru-treasury.network_compliance
from-address: addr1xyezq8wpaqnssdjvd3p220uf7e6nzjae44w6yu625y965rfjyqwur6p8pqmycmzz55lcnan4x99mnt2a5fe54ggt4gxs8thzgk
- name: amaru.network-wallet
from-address: addr1qx9aqvsf6gne2640jec828s25gzhk5wp2day8u24kf8mrs2v0zyuvk80fay35dx008p45ts0u6cdrv9g2maetq8jm8psznjcrz
- name: amaru.swap.v2 # the SundaeSwap order script, by hash
script: fa6a58bbe2d0ff05534431c8e2f0ef2cbdc1602a8456e4b13c8f3077
Concatenate the overlay (cq-rdf overlay --in overlay.yaml) onto the
body, and the addresses in the same transaction resolve to the
operator's own names:
outputs:
- address: amaru.swap.v2
coin: 42.891805 ADA
datum:
hash: 7c413435da13eabb7117a425f3a495f84ddfc2f8eb9caf8f00d512995bfaf299
rawBytes: d8799fd8799f581c64f35d26b237ad58e099041bc14c687ea7fdc58969d7d5b66e2540ef…
- address: amaru.swap.v2
coin: 42.891804 ADA
datum:
hash: 0ef54f5a163374af92cd46099e7a092857ed5d16ff48f1a0db91b476feae827d
rawBytes: d8799fd8799f581c64f35d26b237ad58e099041bc14c687ea7fdc58969d7d5b66e2540ef…
- address: amaru-treasury.network_compliance
coin: 1449833.102132 ADA
- address: amaru.network-wallet
coin: 99.092459 ADA
The two opaque script outputs are now plainly the treasury placing two
swap orders at amaru.swap.v2; the 1.45M ADA is change back to its own
operating scope; the 99 ADA is the network wallet. One transaction, now
legible. (Entities can be matched by full address, like the scopes, or by
script hash, like amaru.swap.v2 — which is why all of the protocol's
order UTxOs collapse to that one name.)
Rung 2 — resolve the asset
The swap is buying USDM, but USDM on-chain is just a policy id plus a hex-encoded name. Declare it once:
Now a query can ask for usdm and report human units instead of matching
c48cbb…0014df10·USDM
and dividing raw quantities by a million by hand. We lean on this in every
money query below — it is what turns 18750000000 into 18,750 USDM.
Rung 3 — map the vendor bridge and its paperwork
Vendor payments leave the treasury through one bridge address,
amaru.cag-payee. Name it, declare who is paid through it, and attach the
off-chain attestations (IPFS-pinned invoices and contracts) that back each
one:
- name: amaru.cag-payee
from-address: addr1q8qrds2nnx7clx3kcpp2l0eu45twmdcahsfu9m0xcwy59j6xz3vs0hnfaz9nhje8z34kfnds4jyk7hs6dnrag6e2lfgqtyf4rl
- name: amaru.antithesis
label: Antithesis Operations LLC
role: fuzz-testing vendor
paid-via: amaru.cag-payee
- name: amaru.castellum
label: Castellum Labs
role: engineering vendor
paid-via: amaru.cag-payee
attestations:
- ipfs: ipfs://bafkreicnoadlgnc6cqxggxboho7yt532lkonxcusj3ndsxdnv5szyswyam
label: Invoice INV-635
of: amaru.antithesis
# … contract, invoice, cycle-review for amaru.castellum
This is what makes the on-chain payment ↔ off-chain accountability join (below) answerable: the bridge, the vendors behind it, and the documents behind them are now all in the graph.
Rung 4 — register the contract blueprint
Finally, register the contract's CIP-57 blueprint. The script at
fa6a58bb… is SundaeSwap V3's order validator, so we register its real
upstream blueprint:
This puts the contract's schema in the graph: the raw script hash is now
known to be the named SundaeSwap V3 order contract, and its on-chain data
is carried losslessly as cardano:hasRawBytes for anyone to inspect or
decode. Where a registered schema matches a datum, the
cq-rdf blueprint typed-decode pass emits the
fields as typed triples (e.g. :SwapOrder_recipient …) — exercised on a
matching shape by the blueprint fixtures.
Honest limit on the live order datum
SundaeSwap's own blueprint types the order datum as opaque Data, and
its surrounding CIP-57 definitions are recursive — which the current
decoder does not resolve. So the live six-field V3 order above is
named and carried verbatim as raw CBOR, not decoded into fields.
This is a known gap, tracked alongside the case study (see its
limitations, gap #5),
not a claim this page makes. Typed decode lands today on contracts
whose schema is concrete; the recursive V3 datum is future work.
The complete file — every rung stacked together — is what we use for the batch:
# Operator overlay for the May 2026 Amaru Treasury case study.
#
# Phase 3 of epic #66 (separate runtime from apps): non-cardano
# vocabularies are opt-in through this `imports:` block. The treasury
# vocab owns the `paid-via`, `role`, `attests`, and `ipfs` keys.
#
# Typed-decode of on-chain datums/redeemers is delivered by the
# separate `cq-rdf blueprint --blueprints blueprints/` pass shipped
# in this directory; it is not declared here.
imports:
- treasury
entities:
- name: amaru-treasury.contingency
from-address: addr1x8ndhlcfy30t38z0tql64fpg8ply93r37xrgvdagfpsz5nhxm0lsjfz7hzwy7kpl42jzswr7gtz8ruvxscm6sjrq9f8qruq0ae
- name: amaru-treasury.network_compliance
from-address: addr1xyezq8wpaqnssdjvd3p220uf7e6nzjae44w6yu625y965rfjyqwur6p8pqmycmzz55lcnan4x99mnt2a5fe54ggt4gxs8thzgk
- name: amaru.swap-order
from-address: addr1x8ax5k9mutg07p2ngscu3chsauktmstq92z9de938j8nqaejyqwur6p8pqmycmzz55lcnan4x99mnt2a5fe54ggt4gxst7gy3n
- name: sundae.swap.v3.order
script: fa6a58bbe2d0ff05534431c8e2f0ef2cbdc1602a8456e4b13c8f3077
- name: amaru.network-wallet
from-address: addr1qx9aqvsf6gne2640jec828s25gzhk5wp2day8u24kf8mrs2v0zyuvk80fay35dx008p45ts0u6cdrv9g2maetq8jm8psznjcrz
- name: amaru.cag-payee
from-address: addr1q8qrds2nnx7clx3kcpp2l0eu45twmdcahsfu9m0xcwy59j6xz3vs0hnfaz9nhje8z34kfnds4jyk7hs6dnrag6e2lfgqtyf4rl
- name: usdm
asset:
policy: c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad
name: USDM
- name: amaru.antithesis
label: Antithesis Operations LLC
role: fuzz-testing vendor
paid-via: amaru.cag-payee
- name: amaru.castellum
label: Castellum Labs
role: engineering vendor
paid-via: amaru.cag-payee
attestations:
- ipfs: ipfs://bafkreicnoadlgnc6cqxggxboho7yt532lkonxcusj3ndsxdnv5szyswyam
label: Invoice INV-635
of: amaru.antithesis
- ipfs: ipfs://bafybeib3jef34ndw6oe24mkmifdvxe5jrv7ulh63rdllovyth27mqfj2da
label: Contract
of: amaru.castellum
- ipfs: ipfs://bafybeigy37ui2ikn7bim2vw6cojcbxkcndpjwh7cj5fv3vzs4cszezipxu
label: "Invoice #3508"
of: amaru.castellum
- ipfs: ipfs://bafybeihdmnitrbu2oir3r2fefnpqy3bk7zdz42olzmltmxyt5xag4i2t5a
label: May2026 cycle review
of: amaru.castellum
Why --graph -
tx-view reads the canonical Turtle graph from --graph FILE, or from
stdin with --graph - — that - is what lets cq-rdf body … | tx-view
work as a pipe. Diagnostics (e.g. "parent tx not in lattice", expected
when you emit one tx without its parents) ride stderr, so the Turtle
on stdout stays clean for the next stage.
Pipeline 3 — compose transactions into one lattice
What's behind a TX-in?
Look back at the bare swap. Its first input is
dfd355530e2d…#2. That reference is the whole story of composition:
behind every TX-in there is a transaction that created it as a TX-out.
So ask the obvious question — what produced dfd355530e2d…#2? — and emit
that transaction too:
cq-rdf body --provider blockfrost --token "$BLOCKFROST_PROJECT_ID" \
dfd355530e2d3baef6fc4cb22369c8b64aa117b0a84ff2cdaadc24cdc3fbc7bc > parent.ttl
cq-rdf body --provider blockfrost --token "$BLOCKFROST_PROJECT_ID" \
10a5c1dafe7dd8d4ab680e35dc53b8b550da90bea55f2c758f36474064f2e598 > child.ttl
cat parent.ttl child.ttl > pair.ttl
Concatenating the two Turtle files is the merge. The parent's output
and the child's input both refer to the same UTxO, and they were emitted
as the same content-addressed urn:cardano:utxo: IRI
(#56,
#57), so the
two graphs join on contact — no database, no foreign keys. Two
transactions are now one graph, linked by the UTxO one spent from the
other.
From a pair to a history — by address
You found that parent by following a txid. But an auditor rarely has the
txid; they have the wallet: show me everything this treasury did. A
public indexer answers that directly — "which transactions touched this
address?" — so instead of chasing txids one hop at a time, enumerate every
transaction in or out of each treasury scope and emit them all. That set,
de-duplicated, is docs/demo/selections.txt
— 88 transactions:
| operating scope enumerated | transactions |
|---|---|
amaru-treasury.network_compliance |
85 |
amaru-treasury.contingency |
2 |
amaru.swap-order |
76 |
amaru.network-wallet |
35 |
| union, de-duplicated | 88 |
(The vendor bridge amaru.cag-payee is a long-lived address shared across
many months, so it is not enumerated on its own — that would pull in
other cycles. Its two May payments spend network_compliance, so they are
already in the set. This by-address selection is the demo's own dataset;
the case study uses a
seed-plus-closure selection for a different purpose.)
# overlay once (entities, asset, vendors, attestations)
cq-rdf overlay --in docs/case-studies/2026-05-amaru-treasury/overlay.yaml > /tmp/may.ttl
# then one transaction body per line of the by-address selection
xargs -P8 -n1 cq-rdf body --provider blockfrost --token "$BLOCKFROST_PROJECT_ID" \
< docs/demo/selections.txt >> /tmp/may.ttl
Hold the signed CBORs locally instead? Drop the provider and pass paths — same graph:
The hand-expanded pair from a moment ago is just two nodes of the lattice this builds. Now every query ranges over the treasury's whole month at once.
Queries — visible SPARQL, auditable numbers
A number you can't see the query for is a number you have to trust. So each
query below is shown exactly as it runs (the real .rq, not a
paraphrase) next to its result. They go simple → complex, and every one is
a question an operator would actually ask. Run any of them with:
How big is the month?
# How big is this month? — the on-ramp question.
#
# Before any money question, an auditor asks "how much am I even looking
# at?" This counts the transactions in the merged lattice: the full set
# of treasury-address activity for the May 2026 cycle. One triple pattern,
# one aggregate — the simplest possible SPARQL over the graph.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
SELECT (COUNT(DISTINCT ?tx) AS ?transactions)
WHERE { ?tx a cardano:Transaction . }
The whole audit surface: 88 transactions. Everything below ranges over exactly this set.
Value transferred out of each operator scope
The headline number for an auditor: what left each operator scope this month, by asset. For every transaction T spending one of scope S's outputs we compute
per_tx_outflow(S, T) = inputs_from_S_in_T - outputs_back_to_S_in_T
clamped at zero, then sum across the month. Change UTxOs returning to the
same scope subtract cleanly — so the 3,852,000 ADA that came back to
contingency in 18d57a4f…
doesn't inflate its outflow; only the 205,000 that actually left does —
and a co-funder's contribution to a tx only moves the co-funder's own
row, never the other scope's. The scope filter is the amaru* prefix:
the two treasuries, the working wallet, and the swap-order intermediate.
# Value transferred OUT of each operator scope — net per scope per asset.
#
# For every operator-named scope S (anything under the amaru.* / amaru-
# treasury.* prefixes — the treasuries, the working wallet, the swap-order
# intermediate, the vendor bridge, the vendors themselves) and every
# transaction T spending one of S's outputs, we compute
#
# per_tx_out(S, T) = inputs_from_S_in_T - outputs_back_to_S_in_T
#
# clamped at 0, then summed across the month. Change UTxOs returning to
# the same scope subtract cleanly, so the 3,852,000 ADA that came back to
# contingency in 18d57a4f… does NOT inflate its outflow (only the 205,000
# that actually left does); and a co-funder's contribution to a tx only
# moves the co-funder's own per_tx_out, never the other scope's.
#
# Destination is deliberately NOT aggregated here: the working wallet
# co-funds the fee on essentially every transaction, so a single
# source-to-destination attribution from the UTxO graph alone would have
# to guess on every multi-input tx. The drill-down queries below cover
# destination one row at a time, where the chain itself disambiguates.
#
# Result, May 2026:
#
# amaru-treasury.contingency | ADA | 205,000.00 | 1 tx
# amaru-treasury.network_compliance | ADA | 1,707,820.24 | 31 tx
# amaru-treasury.network_compliance | USDM | 418,750.00 | 7 tx
# amaru.network-wallet | ADA | 20.82 | 33 tx
# amaru.swap-order | ADA | 1,707,817.86 | 52 tx
#
# Reading the table:
# - 205,000 ADA — the contingency → operating top-up (one event)
# — see contingency-inflow.rq
# - 1,707,820 ADA out of NC ≈ 1,707,817.86 out of swap-order: the same
# ADA traced through the swap intermediate, sold to SundaeSwap for
# USDM as the chain stepped down (gap of 2.38 ADA = the min-UTxO
# companion to the two cag-payee USDM payments)
# — see spends-graph.rq for the leg-by-leg view
# - 418,750 USDM — the two vendor payments through the cag-payee bridge
# — see vendor-bridge-disbursements.rq
# - 20.82 ADA out of the working wallet across 33 txs: this is the
# entire fee budget for the month — zero principal. Cross-check:
# SUM(cardano:hasFee) over those 33 txs is exactly 20.816875 ADA.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?scope ?asset
(SUM(?per_tx_out) AS ?outflow)
(COUNT(DISTINCT ?tx) AS ?txs)
WHERE {
?entity a cardano:Entity ; rdfs:label ?scope ; cardano:bech32 ?addr .
FILTER (STRSTARTS(?scope, "amaru"))
{
# ADA, per tx: gross spent from scope minus gross returned to scope.
{
SELECT ?addr ?tx (SUM(?lov)/1000000.0 AS ?in_sum) WHERE {
?tx a cardano:Transaction ;
cardano:hasInput/cardano:fromTxOutRef ?ref .
?ref cardano:hasTxId/cardano:bytesHex ?ptx ;
cardano:hasIndex ?pix .
?ptxn cardano:hasTxId/cardano:bytesHex ?ptx ;
cardano:hasOutput ?po .
?po cardano:hasIndex ?pix ;
cardano:atAddress/cardano:bech32 ?addr ;
cardano:lovelace ?lov .
} GROUP BY ?addr ?tx
}
OPTIONAL {
SELECT ?addr ?tx (SUM(?lov)/1000000.0 AS ?out_sum) WHERE {
?tx a cardano:Transaction ; cardano:hasOutput ?o .
?o cardano:atAddress/cardano:bech32 ?addr ;
cardano:lovelace ?lov .
} GROUP BY ?addr ?tx
}
BIND ("ADA" AS ?asset)
BIND (COALESCE(?out_sum, 0.0) AS ?out_)
BIND (IF (?in_sum > ?out_, ?in_sum - ?out_, 0.0) AS ?per_tx_out)
} UNION {
# USDM, per tx: same shape, restricted to the USDM asset id.
{
SELECT ?addr ?tx (SUM(?q)/1000000.0 AS ?in_sum) WHERE {
?tx a cardano:Transaction ;
cardano:hasInput/cardano:fromTxOutRef ?ref .
?ref cardano:hasTxId/cardano:bytesHex ?ptx ;
cardano:hasIndex ?pix .
?ptxn cardano:hasTxId/cardano:bytesHex ?ptx ;
cardano:hasOutput ?po .
?po cardano:hasIndex ?pix ;
cardano:atAddress/cardano:bech32 ?addr ;
cardano:hasAssetValue/rdf:rest*/rdf:first ?av .
?av cardano:hasIdentifier/cardano:bytesHex
"c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad0014df105553444d" ;
cardano:quantity ?q .
} GROUP BY ?addr ?tx
}
OPTIONAL {
SELECT ?addr ?tx (SUM(?q)/1000000.0 AS ?out_sum) WHERE {
?tx a cardano:Transaction ; cardano:hasOutput ?o .
?o cardano:atAddress/cardano:bech32 ?addr ;
cardano:hasAssetValue/rdf:rest*/rdf:first ?av .
?av cardano:hasIdentifier/cardano:bytesHex
"c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad0014df105553444d" ;
cardano:quantity ?q .
} GROUP BY ?addr ?tx
}
BIND ("USDM" AS ?asset)
BIND (COALESCE(?out_sum, 0.0) AS ?out_)
BIND (IF (?in_sum > ?out_, ?in_sum - ?out_, 0.0) AS ?per_tx_out)
}
}
GROUP BY ?scope ?asset
HAVING (SUM(?per_tx_out) > 0)
ORDER BY ?scope DESC(?outflow)
-----------------------------------------------------------------------
| scope | asset | outflow | txs |
=======================================================================
| "amaru-treasury.contingency" | "ADA" | 205000.0 | 1 |
| "amaru-treasury.network_compliance" | "ADA" | 1707820.240061 | 31 |
| "amaru-treasury.network_compliance" | "USDM" | 418750.0 | 7 |
| "amaru.network-wallet" | "ADA" | 20.816875 | 33 |
| "amaru.swap-order" | "ADA" | 1707817.860941 | 52 |
-----------------------------------------------------------------------
Five rows — and read together they tell the whole flow:
- 205,000 ADA out of
contingency— the mid-cycle reserve top-up to the operating scope (one transaction; see How much ADA came in from contingency?). - 1,707,820 ADA out of
network_compliance≈ 1,707,817.86 ADA out ofswap-order— the same ADA traced through the swap intermediate. NC places the orders, swap-order forwards them to SundaeSwap pools as the chain converts ADA to USDM. The 2.38 ADA gap is exactly the min-UTxO that accompanied the twocag-payeeUSDM payments. The leg-by-leg view is Which transaction spent which? — the swap chain. - 418,750 USDM out of
network_compliance— the two vendor payments through thecag-payeebridge (see What did we pay out, and to whom?). - 20.82 ADA out of
network-walletacross 33 txs — the working wallet's entire spend for the month is the fee budget. Zero principal:SUM(cardano:hasFee)over the same 33 txs is exactly 20.816875 ADA. This is why source-to-destination attribution from the graph alone is structurally ambiguous — the working wallet is on every transaction as a fee/collateral co-funder, so a row-by-row "who paid whom" attribution would have to guess every multi-input tx. The per-scope outflow above is honest precisely because it doesn't try.
Destination isn't aggregated in the headline for the same reason. The drill-downs each pick a transaction shape where the chain itself makes the recipient unambiguous.
Where did the USDM end up?
The complementary lens — destination-side, USDM only. Resolve each USDM output to a named scope through the overlay entities — so SundaeSwap pools, batchers and external addresses (which carry no entity) drop out entirely — and count only what was not spent again inside the batch, which nets out the change that cycled through the swaps:
# Where did the treasury's USDM end up? — net standing per scope.
#
# The honest "where did the money go" question. For every USDM-bearing
# output, we resolve the recipient to an operator scope BY JOINING TO THE
# OVERLAY ENTITIES (cardano:bech32) — so only addresses the operator has
# named (the treasury scopes and the vendor bridge) are counted at all.
# SundaeSwap pool, batcher and external addresses carry no entity, so they
# drop out automatically: no "other" bucket, no pool liquidity, no
# double-counted swap-chain change.
#
# An output is counted only if it is NOT spent again inside the lattice
# (EXISTS over the producer/consumer join). That nets out cycling change:
# the ~1.5M USDM that bounced through network_compliance as the swaps
# consolidated cancels to the standing balance. What survives is where the
# USDM actually came to rest:
#
# amaru.cag-payee 418750.0 (paid out to vendors)
# amaru-treasury.network_compliance 6381.62 (remainder still held)
#
# Sum = 425,131.62 USDM ever acquired = 418,750 paid + 6,381.62 retained.
# USDM carries 6 decimals.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?scope (SUM(?standing) AS ?usdm)
WHERE {
?entity a cardano:Entity ; rdfs:label ?scope ; cardano:bech32 ?addr .
?tx a cardano:Transaction ; cardano:hasTxId/cardano:bytesHex ?ptxid ; cardano:hasOutput ?out .
?out cardano:atAddress/cardano:bech32 ?addr ;
cardano:hasIndex ?ix ;
cardano:hasAssetValue/rdf:rest*/rdf:first ?asset .
?asset cardano:hasIdentifier/cardano:bytesHex
"c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad0014df105553444d" ;
cardano:quantity ?raw .
BIND (?raw / 1000000.0 AS ?received)
BIND (EXISTS {
?c cardano:hasInput/cardano:fromTxOutRef ?ref .
?ref cardano:hasTxId/cardano:bytesHex ?ptxid ; cardano:hasIndex ?ix .
} AS ?spentAgain)
BIND (IF(?spentAgain, 0.0, ?received) AS ?standing)
}
GROUP BY ?scope
HAVING (SUM(?standing) > 0)
ORDER BY DESC(?usdm)
-----------------------------------------------------
| scope | usdm |
=====================================================
| "amaru.cag-payee" | 418750.0 |
| "amaru-treasury.network_compliance" | 6381.618692 |
-----------------------------------------------------
Two rows, and they reconcile the entire stablecoin position: 418,750 USDM went out the vendor bridge, 6,381.62 USDM remains in the operating scope. Their sum, 425,131.62 USDM, is everything the treasury ever acquired. No millions, no pools — those were never a destination, only plumbing the swaps passed through.
What did we pay out, and to whom?
The 418,750 splits into exactly two on-chain payments:
# What did the treasury pay out through the vendor bridge?
#
# Every USDM output that landed on the cag-payee bridge (resolved through
# the overlay entity, not a hard-coded address), with the transaction it
# rode on. Two payments make up the whole May cycle:
#
# 400000.0 in tx affe90d1… (the Antithesis settlement)
# 18750.0 in tx c150d5c5… (the Castellum settlement)
#
# Total 418,750 USDM. Note the chain shows two payments to ONE bridge
# address — it cannot, by itself, say which vendor each belongs to. That
# attribution lives in the operator overlay (paid-via + attestations) and
# in the off-chain invoices; see vendor-attestations.rq.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?tx_id ?usdm
WHERE {
?bridge a cardano:Entity ; rdfs:label "amaru.cag-payee" ; cardano:bech32 ?addr .
?tx a cardano:Transaction ; cardano:hasTxId/cardano:bytesHex ?txid ; cardano:hasOutput ?o .
?o cardano:atAddress/cardano:bech32 ?addr ;
cardano:hasAssetValue/rdf:rest*/rdf:first ?asset .
?asset cardano:hasIdentifier/cardano:bytesHex
"c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad0014df105553444d" ;
cardano:quantity ?raw .
BIND (?raw / 1000000.0 AS ?usdm)
BIND (SUBSTR(?txid, 1, 12) AS ?tx_id)
}
ORDER BY DESC(?usdm)
-----------------------------
| tx_id | usdm |
=============================
| "affe90d1fa9a" | 400000.0 |
| "c150d5c5c676" | 18750.0 |
-----------------------------
affe90d1…
is the 400,000 USDM payment to Antithesis;
c150d5c5…
is the 18,750 USDM payment to Castellum. Both land on the same
bridge address, so the split by vendor is the operator's knowledge, not
the chain's — and it is exactly what the overlay's vendor declarations and
their backing paperwork make auditable:
# On-chain payment ↔ off-chain accountability, joined in one query.
#
# The overlay declares vendors that are paid through the cag-payee bridge
# (treasury:paidVia) and attaches off-chain attestations to them — an IPFS
# pointer to the invoice / contract / cycle-review (treasury:attests +
# treasury:ipfs, written by the emitter as `[] a treasury:Attestation ; …`,
# the W3C blank-node-property-list form). This query walks the bridge to
# the vendors and lists every attestation backing each one: the operator's
# audit trail, queryable alongside the chain.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
PREFIX treasury: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/treasury#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?vendor ?role ?invoice ?ipfs
WHERE {
?v treasury:paidVia ?bridge ;
rdfs:label ?vendor ;
treasury:role ?role .
?bridge rdfs:label "amaru.cag-payee" .
?att treasury:attests ?v ;
rdfs:label ?invoice ;
treasury:ipfs ?ipfs .
}
ORDER BY ?vendor ?invoice
| vendor | role | invoice | ipfs |
==========================================================================================================
| "amaru.antithesis" | "fuzz-testing vendor" | "Invoice INV-635" | <ipfs://bafkreicnoadl…> |
| "amaru.castellum" | "engineering vendor" | "Contract" | <ipfs://bafybeib3jef3…> |
| "amaru.castellum" | "engineering vendor" | "Invoice #3508" | <ipfs://bafybeigy37ui…> |
| "amaru.castellum" | "engineering vendor" | "May2026 cycle review" | <ipfs://bafybeihdmnit…> |
Each vendor's payment is backed by an IPFS-pinned invoice or contract, queryable right alongside the chain.
How much ADA came in from contingency?
Mid-cycle the swaps ran short of ADA. The reserve scope topped them up — a real business event, worth its own question:
# How much ADA came in from the contingency scope?
#
# Mid-cycle the swaps ran short of ADA, so the operator topped them up
# from the contingency scope. This finds every transaction that spends a
# contingency output and pays the network_compliance operating scope, and
# reports the ADA delivered. Both scopes are resolved through the overlay
# entities, so the query reads in the operator's own vocabulary.
#
# Result: 205,000 ADA, in tx 18d57a4f… — the contingency UTxO of
# 4,057,000 ADA was spent, 3,852,000 returned to contingency as change and
# 205,000 forwarded to network_compliance. Contingency is touched by only
# two transactions in its entire history, so this is the complete picture.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?from_tx (?lov / 1000000.0 AS ?ada_in)
WHERE {
?cont a cardano:Entity ; rdfs:label "amaru-treasury.contingency" ; cardano:bech32 ?cAddr .
?dest a cardano:Entity ; rdfs:label "amaru-treasury.network_compliance" ; cardano:bech32 ?dAddr .
?tx a cardano:Transaction ; cardano:hasTxId/cardano:bytesHex ?txid ;
cardano:hasInput/cardano:fromTxOutRef ?ref ;
cardano:hasOutput ?o .
?ref cardano:hasTxId/cardano:bytesHex ?ptx ; cardano:hasIndex ?pix .
?ptxn a cardano:Transaction ; cardano:hasTxId/cardano:bytesHex ?ptx ; cardano:hasOutput ?po .
?po cardano:hasIndex ?pix ; cardano:atAddress/cardano:bech32 ?cAddr .
?o cardano:atAddress/cardano:bech32 ?dAddr ; cardano:lovelace ?lov .
BIND (SUBSTR(?txid, 1, 12) AS ?from_tx)
}
-----------------------------
| from_tx | ada_in |
=============================
| "18d57a4f104d" | 205000.0 |
-----------------------------
205,000 ADA moved from amaru-treasury.contingency into
network_compliance in
18d57a4f…:
a 4,057,000 ADA reserve UTxO was spent, 3,852,000 returned as change, and
205,000 forwarded to keep the swaps going. Contingency is touched by only
two transactions ever, so this is the complete inflow.
Which transaction spent which? — the swap chain
The composability proof, and the shape of the whole operation. Each row is
a realised spend edge A#ix → B where both ends are in the lattice,
joined only through the shared UTxO IRI:
# Which transaction spent which? — the cross-tx join, and the swap chain.
#
# Each row is one realised spend edge: consumer transaction B spent output
# #ix of producer transaction A, where BOTH are in the lattice. The edge
# exists only because cat-merging the per-tx Turtle put A's output and B's
# input on the same content-addressed urn:cardano:utxo: IRI (#56/#57), so
# SPARQL joins them with no synthetic fixtures. The producer's recipient
# scope is resolved through the overlay entities.
#
# Sorted by ADA, the result lays the sequential swap chain bare: each swap
# spends the previous swap's change output (#2 at network_compliance) and
# the ADA steps down as it is converted to USDM —
# 64f27254 → dfd35553 → 10a5c1da → b5716ae9 → 26ef34aa → …
# This is exactly the auditor's "show me everything this wallet did, in
# order" — reconstructed from independent per-transaction graphs.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?producer ?ix ?consumer ?scope (?lov / 1000000.0 AS ?ada)
WHERE {
?ptxn a cardano:Transaction ; cardano:hasTxId/cardano:bytesHex ?ptx ; cardano:hasOutput ?o .
?o cardano:hasIndex ?ix ; cardano:lovelace ?lov ; cardano:atAddress/cardano:bech32 ?addr .
?entity a cardano:Entity ; rdfs:label ?scope ; cardano:bech32 ?addr .
?ctxn a cardano:Transaction ; cardano:hasTxId/cardano:bytesHex ?ctx ;
cardano:hasInput/cardano:fromTxOutRef ?ref .
?ref cardano:hasTxId/cardano:bytesHex ?ptx ; cardano:hasIndex ?ix .
FILTER (?ptx != ?ctx)
BIND (SUBSTR(?ptx, 1, 12) AS ?producer)
BIND (SUBSTR(?ctx, 1, 12) AS ?consumer)
}
ORDER BY DESC(?ada)
LIMIT 12
-----------------------------------------------------------------------------------------------
| producer | ix | consumer | scope | ada |
===============================================================================================
| "46c11538f39b" | 0 | "18d57a4f104d" | "amaru-treasury.contingency" | 4057000.0 |
| "64f27254f3c0" | 0 | "dfd355530e2d" | "amaru-treasury.network_compliance" | 1450000.0 |
| "dfd355530e2d" | 2 | "10a5c1dafe7d" | "amaru-treasury.network_compliance" | 1449918.885741 |
| "10a5c1dafe7d" | 2 | "b5716ae98bb4" | "amaru-treasury.network_compliance" | 1449833.102132 |
| "b5716ae98bb4" | 2 | "26ef34aa02ae" | "amaru-treasury.network_compliance" | 1410976.503281 |
| "26ef34aa02ae" | 2 | "f2791967f99a" | "amaru-treasury.network_compliance" | 1372563.060767 |
| "f2791967f99a" | 2 | "2695f20941ac" | "amaru-treasury.network_compliance" | 1293332.892131 |
| "2695f20941ac" | 2 | "b63aa2dd78c2" | "amaru-treasury.network_compliance" | 1215626.254430 |
| "b63aa2dd78c2" | 2 | "5fc04113da63" | "amaru-treasury.network_compliance" | 1137012.611931 |
| "5fc04113da63" | 2 | "5262be893119" | "amaru-treasury.network_compliance" | 1058398.969432 |
| "5262be893119" | 2 | "a38cb99bab8e" | "amaru-treasury.network_compliance" | 979785.326933 |
| "a38cb99bab8e" | 2 | "107e439f247f" | "amaru-treasury.network_compliance" | 901171.684434 |
-----------------------------------------------------------------------------------------------
Read it top to bottom and the sequential swap chain falls out: each row
consumes the previous swap's change (output #2 at network_compliance)
and the ADA steps down — dfd35553 → 10a5c1da (our hero swap) →
b5716ae9 → 26ef34aa → … — as each step is converted to USDM. The
contingency top-up (18d57a4f, first row) seeds the same pattern on a
second leg. This is the auditor's "show me everything this wallet did, in
order," reconstructed from transactions that were each emitted in complete
isolation.
What rate did we actually get?
Each SundaeSwap settlement is a price tick: a transaction that spends
the swap-order UTxO (the ADA the operator committed) and pays USDM back
to network_compliance. Read straight off the chain — no oracle, no
off-chain price — ada_in is the swap-order input and usdm_out is the
USDM landing on NC in the same tx:
# Actual settled ADA→USDM rate, per swap settlement.
#
# Each row is one SundaeSwap settlement: a transaction that spends a
# swap-order UTxO (the order NC placed) and pays USDM back to NC. We
# read the rate straight off the chain:
#
# ada_in = sum(ADA on swap-order inputs of the settlement tx)
# usdm_out = sum(USDM on NC outputs of the same tx)
# rate = usdm_out / ada_in (USDM per ADA)
#
# Both legs are joined on the same tx, so the rate is what the operator
# actually realised on chain — no oracle, no off-chain price, just
# (USDM received) / (ADA spent) per event.
#
# 52 settlements observed across the May 2026 lattice. Aggregated they
# reconcile the whole stablecoin position:
#
# sum(ada_in) = 1,654,998.00 ADA
# sum(usdm_out) = 425,131.62 USDM (= the 425,131.62 NC ever acquired)
# avg rate = 0.256877 USDM / ADA (3.8929 ADA / USDM)
#
# Per-leg the rate spreads ~0.243 → 0.264 USDM/ADA (~3.79 → 4.11 ADA/USDM)
# as the pool moved across the month.
PREFIX cardano: <https://lambdasistemi.github.io/cardano-ledger-rdf/vocab/cardano#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?tx_id ?ada_in ?usdm_out
(?usdm_out / ?ada_in AS ?usdm_per_ada)
(?ada_in / ?usdm_out AS ?ada_per_usdm)
WHERE {
?so a cardano:Entity ; rdfs:label "amaru.swap-order" ; cardano:bech32 ?soAddr .
?nc a cardano:Entity ; rdfs:label "amaru-treasury.network_compliance" ; cardano:bech32 ?ncAddr .
{
SELECT ?tx ?txid ?soAddr (SUM(?lov)/1000000.0 AS ?ada_in) WHERE {
?tx a cardano:Transaction ;
cardano:hasTxId/cardano:bytesHex ?txid ;
cardano:hasInput/cardano:fromTxOutRef ?ref .
?ref cardano:hasTxId/cardano:bytesHex ?ptx ;
cardano:hasIndex ?pix .
?ptxn cardano:hasTxId/cardano:bytesHex ?ptx ;
cardano:hasOutput ?po .
?po cardano:hasIndex ?pix ;
cardano:atAddress/cardano:bech32 ?soAddr ;
cardano:lovelace ?lov .
} GROUP BY ?tx ?txid ?soAddr
}
{
SELECT ?tx ?ncAddr (SUM(?q)/1000000.0 AS ?usdm_out) WHERE {
?tx cardano:hasOutput ?o .
?o cardano:atAddress/cardano:bech32 ?ncAddr ;
cardano:hasAssetValue/rdf:rest*/rdf:first ?av .
?av cardano:hasIdentifier/cardano:bytesHex
"c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad0014df105553444d" ;
cardano:quantity ?q .
} GROUP BY ?tx ?ncAddr
}
BIND (SUBSTR(?txid, 1, 12) AS ?tx_id)
}
ORDER BY ?tx_id
----------------------------------------------------------------------------------------------------------
| tx_id | ada_in | usdm_out | usdm_per_ada | ada_per_usdm |
==========================================================================================================
| "02fce56796d2" | 39306.82125 | 10057.846145 | 0.255880425461776561237447 | 3.90807541528564513550729 |
| "04bb08742e4a" | 20411.443265 | 5057.330292 | 0.247769362819724154376205 | 4.036011509330939305001992 |
| "0f9818a51aad" | 38120.299249 | 10016.057124 | 0.262748648917354672889074 | 3.805918714027493998944968 |
| … | … | … | … | … |
| "ee9d02118fce" | 38120.299249 | 10014.718939 | 0.262713544654629476568304 | 3.806427267823696634648011 |
----------------------------------------------------------------------------------------------------------
52 settlements across the month. Aggregated they reconcile the entire position: 1,654,998 ADA spent, 425,131.62 USDM received, average 0.256877 USDM/ADA (or 3.8929 ADA/USDM). Per-leg the rate spreads ~0.243 → 0.264 USDM/ADA as the pool moved through the month. The 425,131.62 USDM in the right column ties out exactly to Where did the USDM end up? above — the same coins, seen at the moment they were created.
Reproduce it yourself
Every command on this page runs against the published binaries. The
canonical end-to-end pipe lives in each case study's README.md — for
the May 2026 walk-through above:
cq-rdf overlay --in overlay.yaml > overlay.ttl
xargs -P8 -n1 cq-rdf body --provider blockfrost --token "$BLOCKFROST_PROJECT_ID" \
< selections.txt > bodies.ttl
cat overlay.ttl bodies.ttl \
| cq-rdf blueprint --blueprints blueprints/ \
> package.ttl
cq-rdf shacl --shapes shapes/ < package.ttl # author gate: exits non-zero on violations
package.ttl is the typed lattice; cq-rdf shacl reads it as a
separate gate (an empty report and exit 0 means the invariants held).
Then arq --data package.ttl --query <some-query>.rq for any SPARQL on
this page. The full case-study package, including overlay.yaml,
selections.txt, blueprints/, and shapes/, is in
docs/case-studies/2026-05-amaru-treasury/.
Watch it run
A capture of the workflow above, run against the published binaries on
the May 2026 Amaru treasury case study. The operator surveys the
declarative package (overlay, selections, blueprints, shapes), confirms
that $BLOCKFROST_PROJECT_ID is set without ever printing it, then
walks the four-stage pipe: cq-rdf overlay compiles the YAML into
Turtle, xargs -P8 cq-rdf body fetches all 101 transaction bodies in
parallel from Blockfrost, cq-rdf blueprint types the Sundae order
datums, and cq-rdf shacl validates the operator-declared invariants
(empty report, exit 0 — invariants held). The closing scenes run a real
SPARQL question against package.ttl — how much ADA came in from
contingency? lands the 205,000 ADA number this page already
quoted — and a typed-datum probe confirms 57 OrderDatum_destination
triples are first-class in the lattice.
Closing — write your own query
The queries above are examples, not the ceiling. The lattice is plain RDF, so the fastest way to ask your own question is to hand an LLM the vocabularies and describe what you want in English.
Two ontology files cover the lattice end-to-end — paste both alongside your question:
vocab/cardano/transactions.ttldefines the ledger-level vocabulary: every term the body emitter uses (cardano:hasOutput,cardano:atAddress,cardano:hasAssetValue,cardano:fromTxOutRef, …).vocab/treasury/overlay.ttldefines the treasury-overlay vocabulary used bycq-rdf overlaywhen the case study imports it:treasury:OffChainEntity,treasury:Attestation,treasury:paidVia,treasury:attests,treasury:role,treasury:ipfs.
Together they cover everything in /tmp/may.ttl — the body triples
plus the operator's overlay. A prompt that works:
Here are two RDF vocabularies for a Cardano on-chain lattice with a treasury overlay (paste
transactions.ttlandoverlay.ttl). Over a Turtle graph of merged transactions using these vocabularies, write a SPARQL query that answers: \. Operator scopes are cardano:Entitynodes carryingrdfs:labelandcardano:bech32; join outputs to them by bech32 to work in named scopes. Off-chain vendors paid via a bridge address aretreasury:OffChainEntitynodes carryingtreasury:paidViaandtreasury:attests.
Three questions to start from — each a real treasury question, each a few lines of SPARQL:
- "Every payment to a named vendor, with the backing invoice or contract from its attestations."
- "Which transactions spent the treasury's own change — the internal swap chain — and how did the ADA balance step down?"
- "Total ADA that entered the operating scope from the contingency reserve."
If the generated query references a term that isn't in the vocabulary, that's your signal it guessed — paste the error back and it will correct against the real schema.