Registry Utility - Retrieve Holdings API Example

This example shows how to retrieve holdings using the HTTP JSON API.

The example below retrieves all holdings of a user for a specific registrar, instrument, and minimum amount.

Prerequisites

  1. A running validator node connected to one of DevNet, TestNet, or MainNet

  2. The Utility DARs installed on your validator node

  3. A valid business user token (<user-token>) obtained from the IAM of the validator node

  4. A business user and associated party (<user-party>) created through the Validator API

  5. The JSON API endpoint (<http-json-api>) of the participant node

  6. curl and jq installed 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="eyJhbGciOiJIUzI1NiJ9.eyJzY29wZSI6ImRhbWxfbGVkZ2VyX2FwaSIsImlhdCI6MTc1OTk5MjE0NiwiYXVkIjoiaHR0cHM6Ly91dGlsaXR5LmNhbnRvbi5uZXR3b3JrIiwic3ViIjoiaG9sZGVyIn0.4zuioSDoiysXfNLmobyW0xqXmJEY1tnvX7QOnHv1ASU"
10USER_PARTY_ID="holder::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567"
11
12# filtering criteria
13ADMIN_PARTY_ID="registrar::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567"
14INSTRUMENT_ID="INST"
15MIN_AMOUNT="5.0"
16
17# endpoint for json-api
18HTTP_JSON_API="http://localhost:8001/api/json-api"
19
20# token standard holding interface, may change when new versions of splice exists
21HOLDING_INTERFACE="718a0f77e505a8de22f188bd4c87fe74101274e9d4cb1bfac7d09aec7158d35b:Splice.Api.Token.HoldingV1:Holding"
22
23# utility holding template, may change when a new version of the utility exists
24HOLDING_TEMPLATE="dd3a9f2d51cc4c52d9ec2e1d7ff235298dcfb3afd1d50ab44328b1aaa9a18587:Utility.Registry.Holding.V0.Holding:Holding"

The required information is:

Required Information

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
 5DATAFILE="source.sh"
 6source "$DATAFILE"
 7
 8OFFSET=$(curl -s GET \
 9    --url "${HTTP_JSON_API}/v2/state/ledger-end" \
10    --header "Accept: application/json" \
11    --header "Authorization: Bearer ${USER_TOKEN}")
12
13echo "$OFFSET" | jq
14
15OUTPUTFILE="response-obtain-ledger-offset.json"
16echo "$OFFSET" > "$OUTPUTFILE"

The result is the ledger end offset at this moment, stored in response-obtain-ledger-offset.json. For example:

1{
2  "offset": 4308
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
 9DATAFILE="source.sh"
10source "$DATAFILE"
11
12# Get offset from previous step
13if [[ -f "response-obtain-ledger-offset.json" ]]; then
14  JSONCONTENT=$(cat "response-obtain-ledger-offset.json")
15  OFFSET=$(echo "$JSONCONTENT" | jq -r ".offset")
16else
17  echo "Error: response-obtain-ledger-offset.json not found"
18  exit 1
19fi
20
21RESULT=$(curl -s \
22    --url "${HTTP_JSON_API}/v2/state/active-contracts" \
23    --header "Authorization: Bearer ${USER_TOKEN}" \
24    --header "Content-Type: application/json" \
25    --request POST \
26    --data @- <<EOF
27{
28    "verbose": false,
29    "activeAtOffset": "${OFFSET}",
30    "filter": {
31        "filtersByParty": {
32            "${USER_PARTY_ID}": {
33                "cumulative": [{
34                    "identifierFilter": {
35                        "TemplateFilter": {
36                            "value": {
37                                "templateId": "${HOLDING_TEMPLATE}",
38                                "includeCreatedEventBlob": false
39                            }
40                        }
41                    }
42                }]
43            }
44        }
45    }
46}
47EOF
48)
49
50# Filter holdings for a specific holder, instrument ID, admin, and minimum amount
51FILTERED=$(echo "$RESULT" | jq \
52  --arg USER_PARTY_ID "$USER_PARTY_ID" \
53  --arg INSTRUMENT_ID "$INSTRUMENT_ID" \
54  --arg ADMIN_PARTY_ID "$ADMIN_PARTY_ID" \
55  --arg MIN_AMOUNT "$MIN_AMOUNT" \
56  '[
57    .[]
58    | .contractEntry.JsActiveContract.createdEvent.createArgument
59    | select(
60        .registrar == $ADMIN_PARTY_ID and
61        .owner == $USER_PARTY_ID and
62        .instrument.id == $INSTRUMENT_ID and
63        .instrument.source == $ADMIN_PARTY_ID and
64        (.amount | tonumber) >= ($MIN_AMOUNT | tonumber)
65    )
66  ]'
67)
68
69echo "--- All utility holdings of ${USER_PARTY_ID} with amount>=${MIN_AMOUNT} as of offset ${OFFSET} ---"
70echo "$FILTERED" | jq
71
72OUTPUTFILE="response-retrieve-utility-holdings.json"
73echo "$FILTERED" > "$OUTPUTFILE"

The result is the Holding Cids, stored in response-retrieve-utility-holdings.json. For example:

 1[
 2  {
 3    "operator": "operator::1220b39df5ed0e3c584cd97e86e779def933d545bf9a4fab3c0fd3e4ad3f7a36b8fe",
 4    "provider": "provider::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567",
 5    "registrar": "registrar::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567",
 6    "owner": "holder::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567",
 7    "instrument": {
 8      "source": "registrar::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567",
 9      "id": "INST",
10      "scheme": "RegistrarInternalScheme"
11    },
12    "label": "",
13    "amount": "10.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
 9DATAFILE="source.sh"
10source "$DATAFILE"
11
12# Get offset from previous step
13if [[ -f "response-obtain-ledger-offset.json" ]]; then
14  JSONCONTENT=$(cat "response-obtain-ledger-offset.json")
15  OFFSET=$(echo "$JSONCONTENT" | jq -r ".offset")
16else
17  echo "Error: response-obtain-ledger-offset.json not found"
18  exit 1
19fi
20
21RESULT=$(curl -s \
22    --url "${HTTP_JSON_API}/v2/state/active-contracts" \
23    --header "Authorization: Bearer ${USER_TOKEN}" \
24    --header "Content-Type: application/json" \
25    --request POST \
26    --data @- <<EOF
27{
28    "verbose": false,
29    "activeAtOffset": "${OFFSET}",
30    "filter": {
31        "filtersByParty": {
32            "${USER_PARTY_ID}": {
33                "cumulative": [{
34                    "identifierFilter": {
35                        "InterfaceFilter": {
36                            "value": {
37                                "interfaceId":"$HOLDING_INTERFACE",
38                                "includeInterfaceView": true,
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.interfaceViews[]
60    | select(
61        .viewValue.owner == $USER_PARTY_ID and
62        .viewValue.instrumentId.id == $INSTRUMENT_ID and
63        .viewValue.instrumentId.admin == $ADMIN_PARTY_ID and
64        (.viewValue.amount | tonumber) > ($MIN_AMOUNT | tonumber)
65    )
66  ]'
67)
68
69echo "--- All interface holdings of ${USER_PARTY_ID} with amount>=${MIN_AMOUNT} as of offset ${OFFSET} ---"
70echo "$FILTERED" | jq
71
72OUTPUTFILE="response-retrieve-holdings.json"
73echo "$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::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567",
11      "instrumentId": {
12        "admin": "registrar::1220d301ababbed7bc8d6f6a80ce16f33933a7274a3013241b7fb373ca7e4f0d6567",
13        "id": "INST"
14      },
15      "amount": "10.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.