Build success, but excercise error

daml

module Currency where

template Publisher
  with
    name: Party
    value: Decimal
  where
    signatory name
    key name: Party
    maintainer key

    nonconsuming choice Publish: ()
      with
        amount : Decimal
        owner : Party
      controller
        name
      do
        create Owner with
          name = owner
          cash = Currency with publisher = name, amount
        return ()

    nonconsuming choice Transfer: ()
      with
        transferAmount : Decimal
        giver: Owner
        receiver: Owner
      controller
        giver.name
      do
        let delta = giver.cash.amount - transferAmount
        assertMsg "not enough cash" (delta < 0.0)
        
        create giver with cash = giver.cash with amount = giver.cash.amount - transferAmount
        create receiver with cash = receiver.cash with amount = receiver.cash.amount + transferAmount
        return ()


template Owner
  with
    name: Party
    cash: Currency
  where
    signatory cash.publisher
    key name: Party
    maintainer key

template Currency
  with
    publisher : Party
    amount : Decimal
  where
    signatory publisher

tsx

  const publish = async (owner: Party, amount: Decimal): Promise<boolean> => {
    try {
      await ledger.exerciseByKey(Currency.Publisher.Publish, name, {owner, amount});
      return true;
    } catch (error) {
      alert(`Unknown error:\n${error}`);
      return false;
    }
  }

result:
io.grpc.StatusRuntimeException: INVALID_ARGUMENT: Command interpretation error in LF-DAMLe: Interpretation error: Error: node NodeId(1) (dcccd8fecddd546a7e56fd59c5e2943e1926b411da42e385be2dbadb4c0071ef:Currency:Owner) has maintainers TreeSet(user1) which are not a subset of the signatories TreeSet(Bank). Details: Last location: [DA.Internal.Prelude:381], partial transaction: root node NodeId(1): NodeCreate(ContractId(00b7e041f9ebbb2c9d088428417352c0302209e3c2a8b19984d3ba9445a5414f2a),ContractInst(dcccd8fecddd546a7e56fd59c5e2943e1926b411da42e385be2dbadb4c0071ef:Currency:Owner,ValueRecord(Some(dcccd8fecddd546a7e56fd59c5e2943e1926b411da42e385be2dbadb4c0071ef:Currency:Owner),ImmArray((Some(name),ValueParty(user1)),(Some(cash),ValueRecord(Some(dcccd8fecddd546a7e56fd59c5e2943e1926b411da42e385be2dbadb4c0071ef:Currency:Currency),ImmArray((Some(publisher),ValueParty(Bank)),(Some(amount),ValueNumeric(0E-10))))))),),Some(Location(7109c6bec5e868575d0732faf86ff6e6c3986fdf6e22ee51d59bd7b828f3df0d,DA.Internal.Prelude,$u002b$u002b,(380,25),(380,27))),TreeSet(Bank),TreeSet(Bank),Some(KeyWithMaintainers(ValueParty(user1),TreeSet(user1))))

How can I resolve this problem?

3 Likes

Hi @Xuyx, welcome to the DAML forums!

The key error message is slightly buried in the result:

You can see from the first segment in brackets that the error concerns a contract of type Owner. The first segment is the package hash, the second one the module Currency, and the third one the template, Owner.

It goes on to say that the set of maintainers user1 is not a subset of the signatories Bank. Looking at the Owner template that indeed appears to the issue. You have signatory cash.publisher, but maintainer key, where key == name. Maintainers must always be signatories as well.

Your Owner contract specifies an owner of an amount of currency. Using just name as a key will get you into trouble as DAML ensures a uniqueness constraint on keys. In that case contract keys should really be thought of in analogy with primary keys in RDBs. To have a good primary key on a position like your Owner contract, you have three options:

  1. You either ensure that a given user only ever has one contract of type Owner per publisher, in which case you can use use the pair (name, cash.publisher) as the key and key._2 as the maintainer or
  2. You give each position a reference that you use as a key (like an ID column in an RDB) or
  3. You don’t use contract keys on the Owner template.
1 Like

Thanks for your detailed answer to my question in such a short time.
I will try it immediately.

1 Like
type OwnerKey = (Party, Party)
template Owner
  with
    name: Party
    cash: Currency
  where
    signatory cash.publisher
    key (name, cash.publisher): OwnerKey
    maintainer key._1

After I update my code like this and build and run codegen, I find that a new dependency is required but none in node_modules.

var pkg40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7 = require('@daml.js/40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7');

In this case, what should I do?

Hi Xuyx,

This error message seems to suggest you may need to regenerate your JS bindings. In fact, you need to rerun the code generator every time you change your DAML code. The easiest way to achieve that depends on the version of the SDK you’re using (we’ve worked hard on improving that experience over the past couple months).

For SDK 1.5 and earlier, you should kill the yarn start and daml start processes and run (starting from the root of your project):

daml build
daml codegen js .daml/dist/*.dar -o daml.js
cd ui
yarn install --force --frozen-lockfile

then you can restart the daml start and yarn start processes.

If you are using SDK 1.6, you should kill the daml start and npm start processes, then run (starting from the root of the project):

daml build
daml codegen js .daml/dist/*.dar -o daml.js

and then restart the daml start and npm start processes.

Finally, for completeness: if you’re working with a recent 1.7 snapshot, or once you upgrade to 1.7 after it’s published, to process will be to select the terminal running the daml start command, and simply press the r key (r followed by Enter on Windows).

Hi, @Gary_Verhaegen .
I’m using SDK1.6.And I have run

daml codegen js .daml/dist/Currency-1.0.0.dar  -o UI/daml.js

And it upates the file automatically in

UI\daml.js\Currency-1.0.0\lib\Currency\module.js

, adding following code:

var pkg40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7 = require('@daml.js/40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7');
var pkgd14e08374fc7197d6a0de468c968ae8ba3aadbf9315476fd39071831f5923662 = require('@daml.js/d14e08374fc7197d6a0de468c968ae8ba3aadbf9315476fd39071831f5923662');

However, the path

UI\node_modules\@daml.js\

only has folder

d14e08374fc7197d6a0de468c968ae8ba3aadbf9315476fd39071831f5923662

no

40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7

I have tried to run:

npm i @daml.js/40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7

But it doesn’t work.

Maybe try removing the node_modules and run npm install again just to make sure that the installation of the packages is complete.

Hi, drsk:
Thank you for your kind help.

I tried npm i again just now, but it didn’t work.

The package I’m using is copied from the one created by dam new create-daml-app --template create-daml-app, in SDK 1.6.
All the dependencies is the same except “@daml.js/Currency”: “file:daml.js/Currency-1.0.0” and puppeteer wait-on @types/jest @types/node @types/puppeteer @types/wait-on.

The attachment is my project which I refer to dam new create-daml-app --template create-daml-app.

(Attachment Currency.zip is missing)

Hi, drsk:
Thank you for your kind help.

I tried npm i again just now, but it didn’t work. The result is the same.

The package I’m using is copied from the one created by dam new create-daml-app --template create-daml-app, in SDK 1.6.
All the dependencies is the same except “@daml.js/Currency”: “file:daml.js/Currency-1.0.0” and puppeteer wait-on @types/jest @types/node @types/puppeteer @types/wait-on.

I tried to attach my project by zip but I’m not authorized.

Hi @Xuyx, I believe you should be able to share your example via a a private message. Then we can take a look and see if there’s anything off

Hi @cocreature, I’m willing to upload my project but I only can upload files of these formats:
jpg, jpeg, png, gif, daml, yaml, mp4, mov, mp3, webp
no zip or other formats.

I think email may be a good choice, but I don’t know the address of you.

My email address is xuyx@bayconnect.com.cn.

1 Like

Hi @Xuyx,

The issue is caused by the outdated package-lock.json file. It looks like you generated that before you had a dependency on the Tuple2 (that’s what pulls in 40f452260bef3f29dede136108fc08a88d5a5250310281067087da6f0baddff7) and NPM doesn’t appear to update it automatically. If you remove package-lock.json and node_modules and rerun npm install, it should be generated correctly. This is definitely something we need to make clearer in our documentation.

ftr, this is @Xuyx’s projects which reproduces the issue.

1 Like

It works!

Thank you very much.

Thank you for your patience with this @Xuyx, I’ve opened #7928 to track a fix.

1 Like