Couldn't match expected type ‘Address’ with actual type ‘User -> Address’ • Probable cause: ‘med_det’ is applied to too few arguments(error in ContractId DataTransfer )

aliceUser <- do
  mbAliceUser <- queryContractId alice newAliceCid
  case mbAliceUser of
    None -> fail "Alice doesn't have a User contract"
    Some aliceUser -> return aliceUser
return ()
1 Like
diff --git a/daml/Main.daml b/daml/Main.daml
index c50e0a9..5dd7a8e 100644
--- a/daml/Main.daml
+++ b/daml/Main.daml
@@ -44,7 +44,7 @@ template DataRequest
       do
 
 
-        create $ DataTransfer with req = requester, acc = acceptor, meddetails =  med_det
+        create $ DataTransfer with req = requester, acc = acceptor, meddetails =  medet
     nonconsuming choice CancelacceptorRequest: ()
       controller requester
       do

With a little bit more text:

Hi @nikhilreddy,

The Daml compiler is getting confused a bit here. On line 47, you’ve written med_det, which is not in scope as a local variable. Thus, the compiler looks for it in the global scope, and finds a function med_det : User -> Address. It then complains that you’re trying to assing a function of type User -> Address in a field that expects an Address, and suggests applying the function to an argument (of type User) in order to get an Address.

Where does that med_det function come from? A template declaration like

template User with
    username: Party
    med_det: Address
    age:  Int
  where
  ...

implicitly generates a data declaration along the lines of:

data User = User with username : Party, med_det : Address, age: Int

which, in turn, automatically generates functions to extract each field of the record, which you can’t really write in Daml but would look like:

username : User -> Party
username (User p _ _) = p

med_det : User -> Address
med_det (User _ a _) = a

age : User -> Int
age (User _ _ a) = a

You can define your own aliases if you want; something like this would compile fine:

user_age : User -> Int
user_age (User _ _ a) = a
1 Like

Hi Gary, here I am looking to get the med details directly from USER… to DATA TRANSFER with out Involving DATA REQUEST… I am using DATA REQUEST just for authentication process… when the acceptor accept’s the data request then the reciever get the details

aliceUser <- do
  mbAliceUser <- queryContractId alice newAliceCid
  case mbAliceUser of
    None -> fail "Alice doesn't have a User contract"
    Some aliceUser -> return aliceUser
return ()

Your DataTransfer has a meddetails field. That means you need to supply a value for that field; there is no way around that. You’ve written when creating DataTransfer

meddetails =  med_det

The problem is, what do you intend to say by referring to med_det here?

If you don’t want to include it directly in the DataRequest, you could do something else. You’ve assigned username as a key for User; you could fetchByKey @User requester to fetch the appropriate User contract, grab the med_det out of it, and include it in the DataTransfer that way. Since requester is a signatory to DataRequest, they effectively agree to having their own contract fetched on invocation of the Accept choice.

You could also include a contract ID at which the med_det can be found in the DataRequest contract, but I think the previous idea is easier to think about.

1 Like

Yeah, I thought of it but I don’t know how to Implement it
i tried but unable to doit

In order to implement @Stephen’s suggestion, all you need to do is replace lines 46 and 47 with:

        (_, user) <- fetchByKey @User acceptor
        create $ DataTransfer with req = requester, acc = acceptor, meddetails =  med_det user
2 Likes

thank you, It works

can you please help me understand that part

Not anymore, no: it looks like your code has disappeared. Would you mind sharing it again?

Hi I deployed my code in dabl and I am unable to seee med details after creating the contract and I am facing the error like this when I accept the data request

CommandService Error, io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Command interpretation error in LF-DAMLe: dependency error: couldn't find key: GlobalKey(b35991929eb994b8d2f7e956fd4c65203a4914056cecbce7bcbd2cd1f8a7ba59:Main:User, ValueParty(ledger-party-299ee654-4325-4188-9903-9aaf9c426dec)). Details: Last location: [DA.Internal.Template.Functions:216], partial transaction: <empty transaction>.

Here is my code

module User where

import Daml.Script


template User with
    username: Party
    med_det: Address
    age:  Int
  where
    signatory username

    key username: Party  
    maintainer key

    nonconsuming choice NewDataRequest: ContractId DataRequest with
        acceptor: Party
      controller username
      do
        create $ DataRequest with requester = username, ..

    nonconsuming choice AcceptDataRequest: ContractId DataTransfer with
        dataRequest: (Party, Party)
      controller username
      do
        exerciseByKey @DataRequest dataRequest Accept


template DataRequest
  with
    requester: Party
    acceptor: Party

  where
    signatory requester
    observer acceptor

    key (requester, acceptor): (Party, Party)
    maintainer key._1

    nonconsuming choice Accept: ContractId DataTransfer

      controller acceptor
      do
        (_, user) <- fetchByKey @User acceptor
        create $ DataTransfer with req = requester, acc = acceptor, meddetails =  med_det user 
    nonconsuming choice CancelacceptorRequest: ()
      controller requester
      do
        archive self




template DataTransfer
  with
    req: Party
    acc: Party
    meddetails: Address
  where
    signatory req, acc
    key (req, acc): (Party, Party)
    maintainer [key._1, key._2]



    nonconsuming choice CancelDataTransfer1: ()
      controller req
      do
        archive self

    nonconsuming choice CancelDataTransfer2: ()
      controller acc
      do
        archive self


data Address = Address {
  history: Text,
  cured: Text,
  medication: Text
} deriving (Eq, Show)





test = script do
  nikhil <- allocateParty "nikhil"
  -- jeevan <- allocateParty "jeevan"
  chandan <- allocateParty "chandan"

  
  usercid <- submit chandan $ createCmd $ User  {username= chandan, med_det = Address {history = "Fever", cured = "NO", medication = "paracetmol"}, age = 21}
  usercid <- submit nikhil $ createCmd $ User  {username=nikhil, med_det = Address {history = "Throat Infection", cured = "yes", medication = "Azitromycin"}, age = 21}

  -- submit jeevan $ createCmd $ User with username=jeevan
  submit nikhil $ exerciseByKeyCmd @User nikhil $ NewDataRequest with acceptor=chandan
  -- submit chandan $ exerciseByKeyCmd @DataRequest (nikhil,chandan) Accept


Thanks for posting your code again. Let me try to explain in a bit more depth.

The lines:

      do
        (_, user) <- fetchByKey @User acceptor
        create $ DataTransfer with req = requester, acc = acceptor, ```

rely on the fact that your User template defines its username field as a key. Defining a key for a template is not mandatory; when a key is defined, it has two effects:

  • The maintainer is responsible for ensuring that there cannot be two contracts of the same template and with the same key at the same time.
  • It is possible to fetch the “current contract with this key” without knowing the contract ID in advance. (The contract ID for a given key can change over time if the contract bearing the key is archived and another one with the same key is subsequently created.)

So the effect of those two lines is to attempt to fetch a User contract with key acceptor (assuming that’w what your intent was: they accept to share their personal medical details with the requester), using the authority of the acceptor as they are the one executing the choice, and then create a DataTransfer containing a copy of the med_det field of the User contract we just fetched. (Note that this is a one-time copy, so the requester doe not get future updates.)

fetchByKey (reference doc, explanations on keys) is an operation that may fail, for example if there is no contract for the given key at the time of execution. The notation (_, user) <- fetchByKey ... means "execute the fetchByKey operation over there on the ledger, and then, if you do find a matching contract, discard the contract ID and bind the payload to the local variable user".

It is part of the semantics of fetchByKey that it will fail the current transaction if no matching contract is found. You can work around that by using visibleByKey and/or lookupByKey, but be aware that they are a bit more restrictive in the permissions they require.

The error message you’re seeing is specifically telling you that: you were not able to find a User contract for the given Party. In general, this may be because the contract does not exist, or because the current request does not have sufficient permissions to fetch it. In your case, I strongly suspect the former. In particular, deploying to Daml Hub does not automatically run your test script, so you may not have the contracts you expect.

I am not sufficiently familiar with Daml Hub myself to give you specific guidance on how to properly initialize your ledger and create the required contracts, but I’m sure someone will chime in with more information on that front.

Also note that unfortunately Daml Hub doesn’t support allocateParty yet. In your script, you will need to refer to parties that you have already created through the console.

See https://hub.daml.com/docs/quickstart/#run-the-script-against-your-ledger for more information.

1 Like

thank you somuch

1 Like

Hi gary can you help me to automatically add the medical contracts of a patient from any database to the ledger

1 Like

It will depend on these other databases. If you want to have a running process that monitors any change to a live database and propagates those changes to a Daml ledger, the technologies involved will heavily depend on what that other database is and what facilities it offers for detecting changes.

Generally speaking, in that situation, you’ll need to write a program yoourself in whatever general-purpose (i.e. not Daml) language you’re most comfortable with, and that program will interact on the one hand wth your database using its APIs, and on the other hand with the Daml ledger using either the gRPC API or the JSON API.

To facilitate such approaches, we provide Java language bindings and codegen for the gRPC API, as well as JavaScript (actually TypeScript) language bindings and codegen for the JSON API. What the codegen does in both case is automatically translate your Daml types into sensible language-specific data definitions, so you don’t have to do that rather repetitive task yourself.

While we provide tools to make those two languages easier to work with, you should be able to use any language that has gRPC bindings with the gRPC API, and any language that has HTTP support (i.e. “all of them”?) for the JSON API.

If instead you are thinking of a one-time manual import, you can use Daml Script with an input. You would need to use whatever tools your database has to extract your data in the form of a JSON file, and then you would be able to use the --input-file of the daml script command to read that file in as Daml data and run a Daml script with that.

1 Like

Is there any manual to implement the contracts from MONGO DB

1 Like

Not at this time, no. Your best bet would be some sort of cron job that extracts the data from MongoDB to a JSON file and then runs daml script with that file as input, I think.

I’d advise some careful design here, though, as replicating data between databases often results in synchronization issues. You’ll have to be very clear on which side is the “master” in such cases.

2 Likes