- Overview
- Setup
- Tutorials
- How Tos
- Reference
Registry Utility - Retrieve Holdings API Example¶
This example shows how to retrieve holdings on CNU 0.12.x and later using the HTTP JSON API.
The example below retrieves all holdings of a user for a specific registrar, instrument, and minimum amount.
Prerequisites¶
A running validator node connected to one of DevNet, TestNet, or MainNet
The Utility DARs installed on your validator node
A valid business user token (
<user-token>) obtained from the IAM of the validator nodeA business user and associated party (
<user-party>) created through the Validator APIThe JSON API endpoint (
<http-json-api>) of the participant nodecurlandjqinstalled on your system
Preparation¶
Add all the required information to the source.sh file:
1#!/usr/bin/env bash
2
3## =================================================================================================
4## Purpose: Configurations for this example, amend variables as needed.
5## Script: source.sh
6## =================================================================================================
7
8# Users's details
9USER_TOKEN="<PASTE_USER_JWT_HERE>"
10USER_PARTY_ID="holder::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b"
11
12# Filtering criteria
13ADMIN_PARTY_ID="registrar::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b"
14INSTRUMENT_ID="INST"
15MIN_AMOUNT="1.0"
16
17# JSON API endpoint (pick one)
18# - Remote (TestNet/MainNet/other): HTTP_JSON_API="https://<your-host>/api/json-api"
19# - DevNet (example): HTTP_JSON_API="https://utility.utility.cnu.devnet.da-int.net/api/json-api"
20# - Local (example): HTTP_JSON_API="http://localhost:8001/api/json-api"
21HTTP_JSON_API="http://localhost:8001/api/json-api"
22
23# Token standard holding interface, may change when new versions of splice exists
24HOLDING_INTERFACE="#splice-api-token-holding-v1:Splice.Api.Token.HoldingV1:Holding"
25
26# Utility holding template, may change when a new version of the utility exists
27HOLDING_TEMPLATE="#utility-registry-holding-v0:Utility.Registry.Holding.V0.Holding:Holding"
The required information is:
Details of |
Description |
|---|---|
User |
JWT, user ID, and party ID of the user |
Registrar |
Party ID of the registrar you want to query holdings for. |
Instrument |
The identifier of the specific instrument you want to query holdings for. |
Minimum amount |
The minimum amount for the holdings you want to query. |
Retrieve Holdings¶
1. Obtain the Ledger End Offset¶
Run the following script to obtain the ledger end offset:
1#!/usr/bin/env bash
2
3# obtain-ledger-offset.sh - Obtains the ledger end offset
4
5SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6DATAFILE="${SCRIPT_DIR}/source.sh"
7source "$DATAFILE"
8
9OFFSET=$(curl -sS --fail-with-body --request GET \
10 --url "${HTTP_JSON_API}/v2/state/ledger-end" \
11 --header "Accept: application/json" \
12 --header "Authorization: Bearer ${USER_TOKEN}")
13
14echo "$OFFSET" | jq
15
16OUTPUTFILE="${SCRIPT_DIR}/response-obtain-ledger-offset.json"
17echo "$OFFSET" > "$OUTPUTFILE"
The result is the ledger end offset at this moment, stored in response-obtain-ledger-offset.json.
For example:
1{
2 "offset": 400
3}
2. Retrieve Utility Holdings¶
Run the following script to retrieve the Utility Holdings of the user, filtered by the specified instrument ID and minimum amount:
1#!/usr/bin/env bash
2
3## =================================================================================================
4## Purpose: Retrieves holdings of the user for a specific instrument and minimum amount
5## Authorized by: User
6## Script: retrieve-utility-holdings.sh
7## =================================================================================================
8
9SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10DATAFILE="${SCRIPT_DIR}/source.sh"
11source "$DATAFILE"
12
13# Get offset from previous step
14if [[ -f "${SCRIPT_DIR}/response-obtain-ledger-offset.json" ]]; then
15 JSONCONTENT=$(cat "${SCRIPT_DIR}/response-obtain-ledger-offset.json")
16 OFFSET=$(echo "$JSONCONTENT" | jq -r ".offset")
17else
18 echo "Error: response-obtain-ledger-offset.json not found"
19 exit 1
20fi
21
22RESULT=$(curl -sS --fail-with-body \
23 --url "${HTTP_JSON_API}/v2/state/active-contracts" \
24 --header "Authorization: Bearer ${USER_TOKEN}" \
25 --header "Content-Type: application/json" \
26 --request POST \
27 --data @- <<EOF
28{
29 "verbose": false,
30 "activeAtOffset": "${OFFSET}",
31 "filter": {
32 "filtersByParty": {
33 "${USER_PARTY_ID}": {
34 "cumulative": [{
35 "identifierFilter": {
36 "TemplateFilter": {
37 "value": {
38 "templateId": "${HOLDING_TEMPLATE}",
39 "includeCreatedEventBlob": false
40 }
41 }
42 }
43 }]
44 }
45 }
46 }
47}
48EOF
49)
50
51# Filter holdings for a specific holder, instrument ID, admin, and minimum amount
52FILTERED=$(echo "$RESULT" | jq \
53 --arg USER_PARTY_ID "$USER_PARTY_ID" \
54 --arg INSTRUMENT_ID "$INSTRUMENT_ID" \
55 --arg ADMIN_PARTY_ID "$ADMIN_PARTY_ID" \
56 --arg MIN_AMOUNT "$MIN_AMOUNT" \
57 '[
58 .[]
59 | .contractEntry.JsActiveContract.createdEvent.createArgument
60 | select(
61 .registrar == $ADMIN_PARTY_ID and
62 .owner == $USER_PARTY_ID and
63 .instrument.id == $INSTRUMENT_ID and
64 .instrument.source == $ADMIN_PARTY_ID and
65 (.amount | tonumber) >= ($MIN_AMOUNT | tonumber)
66 )
67 ]'
68)
69
70echo "--- All utility holdings of ${USER_PARTY_ID} with amount>=${MIN_AMOUNT} as of offset ${OFFSET} ---"
71echo "$FILTERED" | jq
72
73OUTPUTFILE="${SCRIPT_DIR}/response-retrieve-utility-holdings.json"
74echo "$FILTERED" > "$OUTPUTFILE"
The result is the Holding Cids, stored in response-retrieve-utility-holdings.json. For example:
1[
2 {
3 "operator": "operator::1220a6f417751797b91ab08423236f8c0d3c53f1ec62ed1afd4602816390b68be8f0",
4 "provider": "provider::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b",
5 "registrar": "registrar::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b",
6 "owner": "holder::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b",
7 "instrument": {
8 "source": "registrar::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b",
9 "id": "INST",
10 "scheme": "RegistrarInternalScheme"
11 },
12 "label": "",
13 "amount": "1.0000000000"
14 }
15]
3. Retrieve Canton Network Token Standard Holdings¶
Run the following script to retrieve the Canton Network Token Standard Holdings of the user, filtered by the specified instrument ID and minimum amount:
1#!/usr/bin/env bash
2
3## =================================================================================================
4## Purpose: Retrieves holdings of the user for a specific instrument and minimum amount
5## Authorized by: User
6## Script: retrieve-holdings.sh
7## =================================================================================================
8
9SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10DATAFILE="${SCRIPT_DIR}/source.sh"
11source "$DATAFILE"
12
13# Get offset from previous step
14if [[ -f "${SCRIPT_DIR}/response-obtain-ledger-offset.json" ]]; then
15 JSONCONTENT=$(cat "${SCRIPT_DIR}/response-obtain-ledger-offset.json")
16 OFFSET=$(echo "$JSONCONTENT" | jq -r ".offset")
17else
18 echo "Error: response-obtain-ledger-offset.json not found"
19 exit 1
20fi
21
22RESULT=$(curl -sS --fail-with-body \
23 --url "${HTTP_JSON_API}/v2/state/active-contracts" \
24 --header "Authorization: Bearer ${USER_TOKEN}" \
25 --header "Content-Type: application/json" \
26 --request POST \
27 --data @- <<EOF
28{
29 "verbose": false,
30 "activeAtOffset": "${OFFSET}",
31 "filter": {
32 "filtersByParty": {
33 "${USER_PARTY_ID}": {
34 "cumulative": [{
35 "identifierFilter": {
36 "InterfaceFilter": {
37 "value": {
38 "interfaceId":"$HOLDING_INTERFACE",
39 "includeInterfaceView": true,
40 "includeCreatedEventBlob": false
41 }
42 }
43 }
44 }]
45 }
46 }
47 }
48}
49EOF
50)
51
52# Filter holdings for a specific holder, instrument ID, admin, and minimum amount
53FILTERED=$(echo "$RESULT" | jq \
54 --arg USER_PARTY_ID "$USER_PARTY_ID" \
55 --arg INSTRUMENT_ID "$INSTRUMENT_ID" \
56 --arg ADMIN_PARTY_ID "$ADMIN_PARTY_ID" \
57 --arg MIN_AMOUNT "$MIN_AMOUNT" \
58 '[
59 .[]
60 | .contractEntry.JsActiveContract.createdEvent.interfaceViews[]
61 | select(
62 .viewValue.owner == $USER_PARTY_ID and
63 .viewValue.instrumentId.id == $INSTRUMENT_ID and
64 .viewValue.instrumentId.admin == $ADMIN_PARTY_ID and
65 (.viewValue.amount | tonumber) >= ($MIN_AMOUNT | tonumber)
66 )
67 ]'
68)
69
70echo "--- All interface holdings of ${USER_PARTY_ID} with amount>=${MIN_AMOUNT} as of offset ${OFFSET} ---"
71echo "$FILTERED" | jq
72
73OUTPUTFILE="${SCRIPT_DIR}/response-retrieve-holdings.json"
74echo "$FILTERED" > "$OUTPUTFILE"
The result is the Holding Cids, stored in response-retrieve-holdings.json. For example:
1[
2 {
3 "interfaceId": "718a0f77e505a8de22f188bd4c87fe74101274e9d4cb1bfac7d09aec7158d35b:Splice.Api.Token.HoldingV1:Holding",
4 "viewStatus": {
5 "code": 0,
6 "message": "",
7 "details": []
8 },
9 "viewValue": {
10 "owner": "holder::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b",
11 "instrumentId": {
12 "admin": "registrar::1220163a2070cd9cf831721c6a84e19b7727b9825636ea9b09f24229f45a341f7c4b",
13 "id": "INST"
14 },
15 "amount": "1.0000000000",
16 "lock": null,
17 "meta": {
18 "values": {
19 "utility.digitalasset.com/holding-label": ""
20 }
21 }
22 }
23 }
24]
Note
In Canton 3, the JSON API no longer supports direct querying as in Canton 2. As a result, any
filtering of holdings must be performed client-side after retrieving the data. For advanced
querying and filtering, it is recommended to use the PQS.