Canton Console how to represent DA.Set & DA.Map

Hi team,

I am trying to follow tutorials under link to create the IOU contract in canton console.

However, I have difficulty on presenting DA.Set and DA.Map as shown in below modified Iou template. Can you please share me an example on how to construct the createIouCmd ?


template Iou
  with
    payer: Party
    owner: Party
    amount: Amount
    observers: Set Party
    referenceId:  Map.Map Party Text
  where

    ensure (amount.value >= 0.0)

    signatory payer
    observer observers

many thanks in advanced!

Cheers,
Dorrit

1 Like

Hi @Dorrit_Du,

Can you share a bit more information on what you’re trying to accomplish and what error message you’re getting, or what behaviour you’re seeing that is unexpected?

Your code, unchanged, seems to compile fine for me. Here is the full code I have:

module Main where

import DA.Set
import DA.Map as Map

data Amount = Amount { value: Decimal }
  deriving (Eq, Show)

template Iou
  with
    payer: Party
    owner: Party
    amount: Amount
    observers: Set Party
    referenceId:  Map.Map Party Text
  where

    ensure (amount.value >= 0.0)

    signatory payer
    observer observers

Hi Gary,

Apologies for unclear description. I am able to deployethe dar file consisting the above IOU template on my canton setup. Now I am trying to create an IOU contract under canton console but I am not sure how to construct observers and referenceId fields(i.e Set and Map)

Here is the error I got when creating the contract.

@ active_participant2.ledger_api.commands.submit(Seq(party), Seq(createIouCmd))
ERROR c.d.c.c.EnterpriseConsoleEnvironment - Request failed for participant_2a.
  GrpcClientError: INVALID_ARGUMENT/INVALID_ARGUMENT(8,8414cf93):

thanks,
Dorrit

Ah, I have no experience with the Canton console at all. I’ll reach out to the Canton team and make sure they see this thread.

1 Like

In the meantime it may be worth giving a little bit more context on that Console error: could you share the entire Console session? I’m especially interested in how you constructed party and createIouCmd.

Hey @Dorrit_Du,
If you’re still having this issue, could you please share the whole error message as well as the whole console session as Gary suggested?

Hi, I have shared the error message to Gary via slack.
Can anyone show the examples how to construct DA.Set and DA.Map? this will solve my problem, thanks!

I am having another test for Map type only

template PartyInfo2
  with
    operator : Party -- party onboarding --
    referenceId : Map.Map Text Text
  where
    signatory operator

here is the command I put in canton console:
step 1
val createIouCmd2 = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Map("testKey" -> "testValue")))

step2

@ participant1.ledger_api.commands.submit(Seq(bank), Seq(createIouCmd2 ))
ERROR c.d.c.c.EnterpriseConsoleEnvironment - Request failed for participant1.
  GrpcClientError: INVALID_ARGUMENT/COMMAND_PREPROCESSING_FAILED(8,062dbf94): mismatching type: GenMap Text Text and value: ValueRecord(None,ImmArray((Some(testKey),ValueText(testValue))))
  Request: SubmitAndWaitTransactionTree(actAs = Bank::122085663808..., commandId = '', workflowId = '', submissionId = '', deduplicationPeriod = None(), ledgerId = 'participant1', commands = ...)
  CorrelationId: 062dbf94-69cd-4f50-93b7-76040b991100
  Context: HashMap(participant -> 'participant1', err -> TypeMismatch(TApp(TApp(TBuiltin(BTGenMap),TBuiltin(BTText)),TBuiltin(BTText)),ValueRecord(None,ImmArray((Some(testKey),ValueText(testValue)))),mismatching type: GenMap Text Text and value: ValueRecord(None,ImmArray((Some(testKey),ValueText(testValue))))), definite_answer -> false, commands -> {readAs: [], deduplicationPeriod: {duration: 'PT168H'}, submittedAt: '2022-05-06T04:54:08.235587Z', ledgerId: 'participant1', applicationId: 'CantonConsole', actAs: ['Bank::122085663808764779236ac9539e7295c5534020dfb860023200d389dd0ca828ef02'], commandId: '19b84dcb-80a5-4ce3-8cb1-a3680611b92a', workflowId: })
  Command BaseLedgerApiAdministration$ledger_api$commands$.submit invoked from cmd25.sc:1
com.digitalasset.canton.console.CommandFailure: Command execution failed.

A Scala map maps to a Daml-LF record. There doesn’t seem to be any convenience helpers for building a Daml-LF map so you have to build it somewhat verbosely:

val createCmd = ledger_api_utils.create(
  pkgId,
  "PartyInfo",
  "PartyInfo2",
  Map(
    "operator" -> bank,
      "referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))
1 Like

Thanks, @cocreature . It will be great if you can share us the DA.SET example as well.

From the above solution that you gave, now I am getting below error. Do I miss any import?

val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))
cmd10.sc:1: not found: value Value
val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))
                                                                                                                          ^
cmd10.sc:1: not found: value GenMap
val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))
                                                                                                                                           ^
cmd10.sc:1: not found: value GenMap
val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))
                                                                                                                                                      ^
cmd10.sc:1: not found: value Value
val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))
                                                                                                                                                                        ^
cmd10.sc:1: not found: value Value
val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))
                                                                                                                                                                              ^
cmd10.sc:1: not found: value Value
val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo2",Map("operator" -> bank,"referenceId" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Text("testKey"))), Some(Value(Value.Sum.Text("testValue")))))))))

Ah right, I forgot to paste the imports:

import com.daml.ledger.api.v1.value.{GenMap, Value}

should to the trick.

Set k is not a primitive Daml-LF value, it’s defined as a wrapper around Map k v, see daml/Types.daml at 5d8ebd7a08761ac4a8bc848eb0ff8e6871492b4a · digital-asset/daml · GitHub

So if you build a map as described above with unit values and then wrap it in Map("map" -> genmapexpression) you should get a valid set.

1 Like

Finally, it works for the Map!

However, trying the Set one

template PartyInfo1
  with
    operator : Party -- party onboarding --
    legalEntityId: Text
    observers : Set Party
  where
    signatory operator

here is the way I did:

var mapvalue = Map("map" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Party("Bank::1220db907e2de9c35f5a665eb42c418235fa39ee231758ed14b05a75803d24c81107"))), Some(Value(Value.Sum.Party(null)))))))

val createCmd = ledger_api_utils.create(pkgIou.packageId,"PartyInfo","PartyInfo1",Map("operator" -> bank,"legalEntityId" -> "hello","observers" -> mapvalue))

createCmd: com.daml.ledger.api.v1.commands.Command = Command(
  command = Create(
    value = CreateCommand(
      templateId = Some(
        value = Identifier(
          packageId = "df14a3a49cfbf399df880613d84eea51cdbc67c403e49246212dda0b7a4c6df6",
          moduleName = "PartyInfo",
          entityName = "PartyInfo1"
        )
      ),
      createArguments = Some(
        value = Record(
          recordId = None,
          fields = List(
            RecordField(
              label = "operator",
              value = Some(value = Value(sum = Party(value = "Bank::1220db907e2de9c35f5a665eb42c418235fa39ee231758ed14b05a75803d24c81107")))
            ),
            RecordField(label = "legalEntityId", value = Some(value = Value(sum = Text(value = "hello")))),
            RecordField(
              label = "observers",
              value = Some(
                value = Value(
                  sum = Record(
                    value = Record(
                      recordId = None,
                      fields = List(
                        RecordField(
                          label = "map",
                          value = Some(
                            value = Value(
                              sum = GenMap(
                                value = GenMap(
                                  entries = List(
                                    Entry(
                                      key = Some(
                                        value = Value(
                                          sum = Party(value = "Bank::1220db907e2de9c35f5a665eb42c418235fa39ee231758ed14b05a75803d24c81107")
                                        )
                                      ),
                                      value = Some(value = Value(sum = Party(value = null)))
                                    )
                                  )
                                )
                              )
                            )
                          )
                        )
                      )
                    )
                  )
                )
              )
            )
          )
        )
      )
    )
  )
)

@ participant1.ledger_api.commands.submit(Seq(bank), Seq(createCmd))
ERROR c.d.c.c.EnterpriseConsoleEnvironment - Request failed for participant1.
  GrpcClientGaveUp: CANCELLED/Failed to stream message
  Request: SubmitAndWaitTransactionTree(actAs = Bank::1220db907e2d..., commandId = '', workflowId = '', submissionId = '', deduplicationPeriod = None(), ledgerId = 'participant1', commands = ...)
  Causes: null
  Command BaseLedgerApiAdministration$ledger_api$commands$.submit invoked from cmd21.sc:1
com.digitalasset.canton.console.CommandFailure: Command execution failed.

what wrong with above? thanks so much!

Can you try replacing null with ()?

Both in the mapvalue definition:

var mapvalue = Map("map" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Party("Bank::1220db907e2de9c35f5a665eb42c418235fa39ee231758ed14b05a75803d24c81107"))), Some(Value(Value.Sum.Party(())))))))

and in the nested observers field:

value = Some(value = Value(sum = Party(value = ())))

There is no magic conversion from null or () to Daml-LF unit here, you have to specify it verbosely:

val createCmd = ledger_api_utils.create(pkgId,"PartyInfo","PartyInfo1",Map("operator" -> bank,"legalEntityId" -> "foobar", "observers" -> Map("map" -> Value.Sum.GenMap(GenMap(Seq(GenMap.Entry(Some(Value(Value.Sum.Party(bank.toProtoPrimitive))), Some(Value(Value.Sum.Unit(Empty()))))))))))

This requires an import: import com.google.protobuf.empty.Empty

thanks @cocreature ! it works!