Assigning parties within and then assigning within data constructor

Hey DAMLer’s!

I am working on converting some scenarios to scripts so that I can use them to initialize my ledger. I have written/adjusted scripts before to initialize versions of the ex-bond-issuance and ex-bond-trading model, and am now working with our version of ex-cdm-swaps.

The scenarios in the Event.daml file here reference various helper scenarios in various files and subdirectories in the Test folder.

From the docs steps 1-5 are fairly straightforward. I am having trouble with step 6 when it comes to initializing the parties.

Currently, the scenario imports the parties from the Counterparty.daml file which are the results of their own scenarios.

My initial thought was to convert the scenarios in the Counterparty.daml file to scripts and import the results in the Event.daml. This is the code I tried and the error I received at the **starred line** of code :

module Test.ExampleData.Counterparty where
import Daml.Script
import Prelude hiding (getParty)

getParty : Text -> Script Party
getParty name = allocatePartyWithHint name (PartyIdHint name)

data Counterparty = Counterparty
  with
    damlParty : Party
    partyId : Text
    account : Text
    name : Text

p01_1 : Counterparty -> Script ()
p01_1 = do
  **damlParty <- getParty "CSD-P01"**
  return Counterparty with
          damlParty
          partyId = "5264151754007"
          account = "P01547927812"
          name = "CSD-P01"

The error:

> C:\Users\James Jaworski\OneDrive\BloqbookV2\sandbox-srm\src\daml\DA\srm\Test\ExampleData\Counterparty.daml:20:3: error:
>     • Couldn't match expected type ‘Counterparty -> Script ()’
>                   with actual type ‘Script Counterparty’
>     • In a stmt of a 'do' block: damlParty <- getParty "CSD-P01"
>       In the expression:
>         do damlParty <- getParty "CSD-P01"
>            return
>              Counterparty
>                {damlParty, partyId = "5264151754007", account = "P01547927812",
>                 name = "CSD-P01"}
>       In an equation for ‘p01_1’:
>           p01_1
>             = do damlParty <- getParty "CSD-P01"
>                  return
>                    Counterparty
>                      {damlParty, partyId = "5264151754007", account = "P01547927812",
>                       name = "CSD-P01"}

I have tried a few different ways, but each step keeps leading to a different type error and then I’m back to square one.

Does this approach make sense? And if so does anyone have any suggestions as to how I can assign the parties and then assign them to the Counterparty data constructor?

Or should I be considering initializing my parties in the test Event.daml which will ultimately be used to initialize the ledger?

1 Like

The issue in your example is the type of p01_1. If you look at the definition, you can see that it takes no arguments, operates in the Script action and produces a Counterparty at the end. So the correct type here is Script Counterparty and indeed that compiles:

p01_1 : Script Counterparty
p01_1 = do
  damlParty <- getParty "CSD-P01"
  return Counterparty with
          damlParty
          partyId = "5264151754007"
          account = "P01547927812"
          name = "CSD-P01"

As for how you should handle party allocation in DAML Scripts, I generally recommend to separate your scripts in a few different definitions, I’ll use ex-bond-issuance as an example that handles this similarly:

  1. A datatype that defines all parties that you will use in your script.
  2. The actual script logic which accepts a value of the datatype defined in 1. This function does not allocate any parties itself. It gets all parties from the argument. When running against a real ledger, you will can then handle party allocation outside of the daml script which can be convenient if you need the parties outside of daml script as well and just pass in the value via --input-file.
  3. For running it in Daml Studio, a function that allocates the parties and then calls the script from 2. If you have more than one script, you might want to factor out just the party allocation so you can reuse it. In ex-bond-issuance it’s simply inlined.
2 Likes

Thanks for the advice and breaking down those elements found in ex-bond-issuance.

So here, instead of type Party I could use type Counterparty.

data cdmParties =
  srmParties with
    d03_5 : Counterparty
    p01_1 : Counterparty
    d02_2 : Counterparty
    centralBank : Party
    operator : Party

And then for 2.

Something like this:

setupMarket : Script ()
setupMarket = do
  debug "Ledger is being initialized..."
  let do3_5 = Counterparty with
                      damlParty = getParty "CSD-P01"
                      partyId = "5264151754007"
                      account = "P01547927812"
                      name = "CSD-P01" 
   (with the rest of the parties here)
  setupMarketWithParties $ cdmParties with ..
1 Like

One minor correction, getParty is of type Text -> Script Party. You have to bind it in the do block instead of directly assigning it to damlParty. So something like:

setupMarket : Script ()
setupMarket = do
  debug "Ledger is being initialized..."
  p <- getParty "CSD-P01"
  let do3_5 = Counterparty with
                      damlParty = p
                      partyId = "5264151754007"
                      account = "P01547927812"
                      name = "CSD-P01" 
   (with the rest of the parties here)
  setupMarketWithParties $ cdmParties with ..
2 Likes

Hmmm… There must be some other piece I am missing. I will keep investigating.

getParty : Text -> Script Party
getParty name = allocatePartyWithHint name (PartyIdHint name)

setupMarket : Script ()
setupMarket = do
  debug "Ledger is being initialized..."
  p <- getParty "CSD-P01"
  let do3_5 = Counterparty with
                      damlParty = p
                      partyId = "5264151754007"
                      account = "P01547927812"
                      name = "DEALER-D03" 
  b <- getParty "CSD-P01"
  let d02_2 = Counterparty with
                      damlParty = b
                      partyId = "9377538274179"
                      account = "D03225622378"
                      name = "DEALER-D02"
  r <- getParty "CSD-P01"
  let p01_1 = Counterparty with
                      damlParty = r
                      partyId = "9377538274179"
                      account = "D03225622378"
                      name = "CSD-P01"
  centralBank <- getParty "CentralBank"
  operator <- getParty "Operator"
  setupMarketWithParties $ CdmParties with ..

data CdmParties =
  CdmParties with
    d03_5 : Counterparty
    p01_1 : Counterparty
    d02_2 : Counterparty
    centralBank : Party
    operator : Party

Here are the errors:

    `C:\Users\James Jaworski\OneDrive\BloqbookV2\sandbox-srm\src\daml\DA\srm\Test\Event.daml:27:17: error:
        • Couldn't match type ‘DA.Internal.Desugar.Party’
                         with ‘Party’
          NB: ‘Party’ is defined at
                C:\Users\James Jaworski\OneDrive\BloqbookV2\sandbox-srm\src\daml\DA\srm\Org\Issa\Srm\Classes.daml:(8192,1)-(8208,28)
              ‘DA.Internal.Desugar.Party’
                is defined in ‘DA.Internal.LF’ in package ‘daml-stdlib-1.8.0’
          Expected type: Script Party
            Actual type: Script DA.Internal.Desugar.Party
        • In the expression: allocatePartyWithHint name (PartyIdHint name)
          In an equation for ‘getParty’:
              getParty name = allocatePartyWithHint name (PartyIdHint name)`

I get this error at p, b, and r:

 C:\Users\James Jaworski\OneDrive\BloqbookV2\sandbox-srm\src\daml\DA\srm\Test\Event.daml:34:35: error:
    • Couldn't match expected type ‘DA.Internal.Desugar.Party’
                  with actual type ‘Party’
      NB: ‘Party’ is defined at
            C:\Users\James Jaworski\OneDrive\BloqbookV2\sandbox-srm\src\daml\DA\srm\Org\Issa\Srm\Classes.daml:(8192,1)-(8208,28)
          ‘DA.Internal.Desugar.Party’
            is defined in ‘DA.Internal.LF’ in package ‘daml-stdlib-1.8.0’
    • In the ‘damlParty’ field of a record
      In the expression:
        Counterparty
          {damlParty = p, partyId = "5264151754007",
           account = "P01547927812", name = "DEALER-D03"}
      In an equation for ‘do3_5’:
          do3_5
            = Counterparty
                {damlParty = p, partyId = "5264151754007",
                 account = "P01547927812", name = "DEALER-D03"}
1 Like

The error comes from the fact that you’ve defined your own type called Party in addition to the builtin one. If you look closely at the error, it tells you the location of the two definitions:

 NB: ‘Party’ is defined at
            C:\Users\James Jaworski\OneDrive\BloqbookV2\sandbox-srm\src\daml\DA\srm\Org\Issa\Srm\Classes.daml:(8192,1)-(8208,28)
          ‘DA.Internal.Desugar.Party’
            is defined in ‘DA.Internal.LF’ in package ‘daml-stdlib-1.8.0’

DA.Internal.Desugar is the builtin one. The other one is the one you defined. You have to resolve the ambiguity in some way and tell the compiler which one you mean. There are a few different options:

  1. Rename the one you defined. In this case, this is probably what I’d recommend just because Party is so common that having something else with the same name is going to confuse whoever reads that code.
  2. Don’t import the one you defined. There are a few different options for that, either don’t import the module Org.Issa.Srm.Classes at all, import only the definitions you need (assuming party is not one of them) via import Org.Issa.Srm.Classes (names, of, the, definitions, you, reference) or import everything except for Party via import Org.Issa.Srm.Classes hiding Party.
  3. import qualified Org.Issa.Srm.Classes as SomeModuleName. That will allow you to reference the definitions from Org.Issa.Srm.Classes as SomeModuleName.SomeDefinition so SomeModuleName.Party will give you the Party type you defined while Party refers to the builtin one.
  4. Reference the builtin one via Prelude.Party. Prelude refers to the module that is implicitly imported everywhere so this way you can make sure to reference the builtin party type.
2 Likes

Thanks for the explanation. That was really helpful. I had not realized that Prelude was referencing the universal module. If I see errors that start with “DA.internal…” then it is referring to some error/ambiguity/etc. from the Prelude module?

I was also a bit confused because some errors from the compiler specifically say “ambiguous reference”. Once broken down it was easier for me to recognize that it was an ambiguous reference, it wasn’t obvious to me from the start.

1 Like

DAML allows one module to reexport definitions from another module. So in this case Prelude is reexporting the definition from DA.Internal.*. While it is not enforced, you can usually assume that something referencing DA.Internal.* is reexported from Prelude and you imported it that way.

2 Likes