Unable to fetch contracts using JSON-api

Hi All,

i am using simple-topology and uploaded the dar files per my requirement and created an instrument (have used in memory as storage).When i am trying to fetch it or query using JSON-api its showing nothing

module Instrument where
 
template Instrument
  with
    issuer: Party
    name: Text
    faceValue: Decimal
    availableUnits: Int
  where
    signatory issuer
   key (issuer, name) : (Party, Text)
    maintainer key._1
 
    choice Buy : ContractId Investment
      with
        investor: Party
        units: Int
      controller investor
      do
        assertMsg "Not enough units available" (units <= availableUnits)
        archive self
        create Investment with
          investor
          issuer
          instrument = name
          units
          faceValue
 
template Investment
  with
    investor: Party
    issuer: Party
    instrument: Text
    units: Int
    faceValue: Decimal
  where
    signatory issuer
    observer investor
 
    key (investor, instrument) : (Party, Text)
    maintainer key._1

canton {
participants {
participant1 {
storage.type = memory
admin-api.port = 5212
ledger-api.port = 5211
}
participant2 {
storage.type = memory
admin-api.port = 5222
ledger-api.port = 5221
}
}
domains {
mydomain {
init.domain-parameters.protocol-version = 5
storage.type = memory
public-api.port = 5218
admin-api.port = 5219
}
}
// enable ledger_api commands for our getting started guide
features.enable-testing-commands = yes
}

JWT token is based on this data
{ "https://daml.com/ledger-api": { "ledgerId": "participant1", "applicationId": "app", "actAs": ["Admin"] } }

participant1.health.status 
res34: com.digitalasset.canton.health.admin.data.NodeStatus[com.digitalasset.canton.health.admin.data.ParticipantStatus] = Participant id: PAR::participant1::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1
Uptime: 25m 15.120995s
Ports: 
        ledger: 5211
        admin: 5212
Connected domains: 
        mydomain::12207609020e...
Unhealthy domains: None
Active: true
Components: 
        memory_storage : Ok()
        crypto : Ok()
        sync-domain : Ok()
        sync-domain-ephemeral : Ok()
        sequencer-client : Ok()
        acs-commitment-processor : Ok()
val instrumentContract = participant1.ledger_api.acs.find_generic(admin, _.templateId.isModuleEntity("Instrument", "Instrument"))   
instrumentContract: com.digitalasset.canton.admin.api.client.commands.LedgerApiTypeWrappers.WrappedCreatedEvent = WrappedCreatedEvent(
  event = CreatedEvent(
    eventId = "#12205e0aaa6d1166fa6ad68f0a312a60a1a8327760de6aff5cbec700c445480866a3:0",
    contractId = "00a86d864c6465cf63e1f04099c06015f9dc7cccdda1a479c70fa20e1d18da4ff2ca021220b7f96eab4970c4a0d84c856cacd74829b0ed7e02e626462ad4d14f1af1739a4d",
    templateId = Some(
      value = Identifier(
        packageId = "aab0d269460c5609143208182f83a1b3e387fde21e7164aeac3b8314f676808a",
        moduleName = "Instrument",
        entityName = "Instrument"
      )
    ),
    packageName = None,
    contractKey = Some(
      value = Value(
        sum = Record(
          value = Record(
            recordId = Some(
              value = Identifier(
                packageId = "40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7",
                moduleName = "DA.Types",
                entityName = "Tuple2"
              )
            ),
            fields = Vector(
              RecordField(
                label = "_1",
                value = Some(
                  value = Value(sum = Party(value = "Admin::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1"))
                )
              ),
              RecordField(label = "_2", value = Some(value = Value(sum = Text(value = "Government Bond 2030"))))
            )
          )
        )
      )
    ),
    createArguments = Some(
      value = Record(
        recordId = Some(
          value = Identifier(
            packageId = "aab0d269460c5609143208182f83a1b3e387fde21e7164aeac3b8314f676808a",
            moduleName = "Instrument",
            entityName = "Instrument"
          )
        ),
        fields = Vector(
          RecordField(
            label = "issuer",
            value = Some(value = Value(sum = Party(value = "Admin::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1")))
          ),
          RecordField(label = "name", value = Some(value = Value(sum = Text(value = "Government Bond 2030")))),
          RecordField(label = "faceValue", value = Some(value = Value(sum = Numeric(value = "1000.0000000000")))),
          RecordField(label = "availableUnits", value = Some(value = Value(sum = Int64(value = 1000L))))
        )
      )
    ),
    createdEventBlob = <ByteString@5e45b0 size=0 contents="">,
    interfaceViews = Vector(),
    witnessParties = Vector("Admin::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1"),
    signatories = Vector("Admin::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1"),
    observers = Vector(),
    agreementText = Some(value = ""),
    createdAt = Some(value = Timestamp(seconds = 1745072933L, nanos = 620619000, unknownFields = UnknownFieldSet(fields = Map())))
  )
)

CURL command response i am getting
if QUERY curl -X POST http://localhost:8089/v1/query \ -H "Content-Type: application/json" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2RhbWwuY29tL2xlZGdlci1hcGkiOnsibGVkZ2VySWQiOiJwYXJ0aWNpcGFudDEiLCJhcHBsaWNhdGlvbklkIjoiYXBwIiwiYWN0QXMiOlsiQWRtaW4iXX19.mFiLvCV8yis2we2coIJVG76qPqna8whLNCIYk_WOEpk" \ -d '{ "templateIds": [ "aab0d269460c5609143208182f83a1b3e387fde21e7164aeac3b8314f676808a:Instrument:Instrument" ], "query": {} }' {"result":[],"status":200}

if FETCH

curl -X POST http://localhost:8089/v1/fetch \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2RhbWwuY29tL2xlZGdlci1hcGkiOnsibGVkZ2VySWQiOiJwYXJ0aWNpcGFudDEiLCJhcHBsaWNhdGlvbklkIjoiYXBwIiwiYWN0QXMiOlsiQWRtaW4iXX19.mFiLvCV8yis2we2coIJVG76qPqna8whLNCIYk_WOEpk" \
  -d '{
    "templateId": "aab0d269460c5609143208182f83a1b3e387fde21e7164aeac3b8314f676808a:Instrument:Instrument",
    "key": null
  }'
{"errors":["JsonError: spray.json.DeserializationException: Can't read null as Record(IndexedSeq((_1,TypePrim(PrimTypeParty,IndexedSeq())), (_2,TypePrim(PrimTypeText,IndexedSeq()))))"],"status":400}

please help how to fetch contracts more efficiently especially when using in-memory

Thanks !!

The following field from your JWT…

{
  "https://daml.com/ledger-api": {
    "ledgerId": "participant1",
    "applicationId": "app",
    "actAs": [
      "Admin"
    ]
  }
}

… instructs Canton that the submitted commands should be able to act as a Daml party named “Admin.” For example, this JWT would give the curl call permission to query for contracts visible to a Daml party named “Admin.”

In contrast, notice that the contract which actually exists on ledger…

RecordField(
  label = "issuer",
  value = Some(value = Value(sum = Party(value = "Admin::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1")))
),
RecordField(label = "name", value = Some(value = Value(sum = Text(value = "Government Bond 2030")))),
RecordField(label = "faceValue", value = Some(value = Value(sum = Numeric(value = "1000.0000000000")))),
RecordField(label = "availableUnits", value = Some(value = Value(sum = Int64(value = 1000L))))

…mentions not a Daml party named “Admin”, but a Daml party named Admin::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1.

That would cause your curl command to return the empty list of all contracts visible to a (non-existent) party named Admin.

What happens if your token contains the Daml party Admin::1220d3193c258400218299684a9dd0adac9ba709c40b66187ccc27b1877e80e97bb1 ?


By the way, you are currently using a deprecated form of JWT named Custom Daml Claims Access Tokens. That JWT form uses the Daml party id (e.g., Admin::120d...). You may want to consider switching to the preferred Audience-based Token, which uses the Canton User (instead of the Daml party) to specify authorizations. You can then create a Canton User named “Admin” and give that user the right to act as the Daml party Admin::120d....

2 Likes

Got it Kelly

Thanks much !