Variable not in scope: submitMulti

To further clarify the points in my previous post.

  1. The creator is also a member of the Guild so 1 creator and 4 members make 5 guild members, i wasnt sure how to reflect that the creator is also a member

  2. You asked about constraints. I wanted to ensure that someone that joins a guild is not a member of another guild. I have NO clue about how to even begin that process. Ultimately, what I would like to setup is that one person can only join another guild if they’re either not a member of a guild currently, or they have to first leave the other guild then they can join the new guild.

1 Like

Hi @krmmalik,

These are interesting constraints. Daml cannot meaningfully have the kind of global, implicit state required to express “a person can only be a member of a single guild” without additional context, because Daml is designed for distributed systems in which nobody may know the entire state of the system.

This is the same in the real world: there is no way to ensure that someone is not a member of two groups without some kind of referee entity that knows about both groups.

The approach you would need to use here is the same kind of structure you would have to set up in the real world: the guild cannot exist by itself, it needs to exist as part of a context; some sort of registry that can see the membership of every guild and thus enforce the constraint. Note that this means “every guild that is part of the same registry”, not “every guild in the whole world”.

Another way to look at this problem is that Daml makes trust decisions explicit: users have to choose who they trust. And by “making explicit” here I mean that the nebulous concept of “the system” that you would have to trust in most other software design approaches does not exist in a Daml system. So ultimately you need to trust someone (person or group) to tell you whether or not a person is trying to be a member of more than one guild, and that someone can only know up to the guilds they can see.

Does that make sense? @bernhard is better than I am at explaining this part.

2 Likes

Yes @Gary_Verhaegen , that makes sense, thank you. This has given me enough input to know how to address the situation. I’ll keep this in mind going forward. Thank you.

1 Like

A post was split to a new topic: Understanding preconsuming, assert, and this

I just wanted to go through each line that is new conceptually to me and see if i’ve understood it correctly just so that it can help me move forward. I did reference each line and piece of code against documentation but have some doubts about whether I fully understand what is going on with each line. I’d be grateful for a confirmation on each line to say whether I have understood it correctly or not?

It’s really the choices aspect only. I have my head around contract templates now but choices are completely new to me and this was a lot to take in one go.

so

preconsuming choice Agree: ContractId ProposeGuild

Here we are setting up a choice agree and setting it up for the ProposeGuild contract, yes?
I wasn’t sure why it was a preconsuming choice however. I mean, I understand that the contract is archived beforehand hence the word preconsuming, but I didn’t understand why that is necessary here?

with member: Party

member doesn’t appear in the ProposeGuild or Guild` template, so why do we set it up new here? Why not requestedMember or agreedmember? is it because he/she is neither agreed nor requested at this stage?

assert $ member `elem` requestedMembers

I hardly understood this line at all. Here we are asserting that the member will be mapped into requestedMember?

create this with agreedMembers = member::agreedMembers

Why are we using this ? I’ve not seen that in the creation of a contract before. What does it do? What are we creating here?

That’s my first round of questions, and then I have more on this choice you have setup if you don’t mind. I really appreciate you writing this out for me but I haven’t been able to get my head around what the code is doing exactly.

1 Like

Hi @krmmalik,

I’ll address one point at a time.

preconsuming choice Agree: ContractId ProposeGuild

Here we are setting up a choice agree and setting it up for the ProposeGuild contract, yes?

You can think of choices as functions acting on templates. Here we declare a new choice called Agree that acts on contracts of type ProposeGuild and has a return value of type ContractId ProposeGuild. In other words, when you later on write something like:

ret <- submit party do exerciseCmd proposeCid Agree with ..

the type of ret will be ContractId ProposeGuild.

I wasn’t sure why it was a preconsuming choice however.

A choice can have one of four qualifiers:

  • preconsuming archives the contract before the choice code is executed; this means that the choice code cannot fetch the current contract, because it has already been archived when the code runs. Note that this does not prevent you from accessing the payload (attributes) of the current contract, as those are still in scope.
  • postconsuming archives the contract after the choice has finished running. This means the choice code can fetch the contract if it needs to, but it also means you cannot create a new contract with the same key (because the current one has not been archived yet).
  • nonconsuming means the Daml engine will not automatically archive the contract for you. Note that this does not always mean that the choice does not archive the contract, as the choice code can still call archive self explicitly. This can be very useful if you want to do something before and after archiving, or if you only want to archive if some conditions are met.
  • The default behaviour, when no qualifier is present before the choice keyword, is what is known as a consuming choice in the documentation. Consuming choices have additional properties with respect to privacy that I do not fully understand, and therefore I tend to avoid them. This is why I default to preconsuming unless I have a good reason to use one of the others. In this specific case I think all three options (postconsuming, preconsuming and consuming) that end up archiving the contract would work equally well.
with member: Party

member doesn’t appear in the ProposeGuild or Guild` template, so why do we set it up new here? Why not requestedMember or agreedmember? is it because he/she is neither agreed nor requested at this stage?

This with ... syntax is defining the parameters of the choice, which you can think of as the function arguments. When you exercise the choice, you need to supply them; in this case, in order to call the choice with exerciseCmd, you will need to supply a party. We do not want to reuse a name that already exists here specifically because we want to be able to compare this member party provided by the caller of the API (who would be able to pass in whatever they want) with the parties saved in the contract (agreedMembers and requestedMembers).

assert $ member `elem` requestedMembers

I hardly understood this line at all. Here we are asserting that the member will be mapped into requestedMember?

Not quite. assert is a special operation that takes one Boolean argument (True or False) and does nothing if it is True. In this case, the expression:

member `elem` requestedMember

is True if the member supplied by the person calling the API to exercise the Agree choice is present in the requestedMember list supplied by the person who created the ProposeGuild contract, and False if member is not an element of the requestedMembers list.

If the argument to assert is False, the Daml system interrupts the execution and cancels the current transaction, without having made any change to the ledger. So this line can be read as “proceed only if the person who is currently accepting is someone who has been asked and has not responded yet”.

create this with agreedMembers = member::agreedMembers

Why are we using this ?

The create function takes a payload for a contract and creates a corresponding entry on the ledger. The syntax for creating records (contract payloads are always records) in Daml is fairly varied. Assuming a record defined by:

data MyRecord = MyRecord with a: Int, b: Text

which, as you may recall, can be used directly in Daml, but is also what would be generated for a template:

template MyRecord
  with
    a: Int
    b: Text
  where
  ...

the most direct way to create a record of that type would be:

let mr = MyRecord with a = 1, b = "hello"

But if you already have one, there is a convenient notation to copy it then change only a few keys:

let mr2 = mr with a = 3 -- same as MyRecord with a = 3, b = "hello"

Getting back to our use-case, in the code of a choice you always have access to the special this variable that represents the payload of the contract the choice is being exercised on. So in this case the syntax:

this with agreedMembers = member::agreedMembers
                requestedMembers = DA.List.Delete member requestedMembers

is just a shorthand for:

ProposeGuild with guildName = guildName
                  creator = creator
                  agreedMembers = member::agreedMembers
                  requestedMembers = DA.List.Delete member 

Did I mention that the syntax to create records is very varied? Both of these would also have been equivalent in this context:

ProposeGuild with guildName -- if there is no "=", use the value with the
                  creator -- same name in the current scope
                  agreedMembers = member::agreedMembers
                  requestedMembers = DA.List.Delete member 
ProposeGuild with agreedMembers = member::agreedMembers
                  requestedMembers = DA.List.Delete member
                  .. -- .. means "use values from scope" for
                     -- all values that have the same name as a field

You may also have been confused by the expressions member::agreedMembers and DA.List.delete member requestedMembers. The first one,

member :: agreedMembers

is using the “cons” operator :: to construct a list. You can see this in operation at the repl:

$ daml repl
daml> let a = [1, 2]
daml> 3 :: a
[3,1,2]
daml> 

The function DA.List.delete elem list returns a new list that has the same elements as list except for the first occurrence of elem. Back to the repl:

daml> import DA.List
daml> DA.List.delete 1 [2, 3, 4]
[2,3,4]
daml> DA.List.delete 4 [2, 3, 4]
[2,3]
daml> DA.List.delete 4 [2, 3, 4, 5, 4]
[2,3,5,4]
daml> 

One important line you did not ask about is:

controller member

This tells Daml that only the party member is allowed to exercise this choice. In this case, the combination of these two lines:

        with member: Party
        controller member

means that the person (party) exercising the choice has to pass themselves as a parameter, as in:

  propId2 <- submit rita do
    exerciseCmd propId1 Agree with member = rita

In many cases the controller of a choice will be a single, fixed, known party identified directly on the contract (say, in this case, creator). But in some cases (like here) it is useful to make the controller of a choice an explicit parameter of that choice. Daml will ensure that only the party itself can submit that choice (i.e. Rita could not do exerciseCmd propId2 Agree with member = john), but we can then add more constraints on it if we want. In this case, it is useful to restrict further to only people who are invited.

Hope that helps clarify some of your questions; do not hesitate to ask more if needed.

2 Likes

Holy wowsers. Thank you so much for breaking this down for me. I’m going to take some time to study everything that you’ve said line by line and get back to you.

I was actually rather embarrassed to ask about some of the other stuff you mentioned that I didn’t so I’m really glad you covered it because it probably would have been my next set of questions.

Please allow me some time and I will get back to you.

1 Like

No need to be, none of us were born programmers.

1 Like

I appreciate you saying that. This means much more to me than you know. A lot of this journey – even though it’s just begun – has just been dealing with the sheer imposter syndrome of it all.

1 Like

Let me know when you get over it, I sure haven’t lol

1 Like

Aha! That’s ironically quite reassuring!

1 Like

Just circling back here @Gary_Verhaegen to let you know I finally managed to get back to working on this. Apologies for getting back to you after quite some time.

I went through each line, line by line and all of your explanations and I managed to understand exactly what is going on now, thanks to your explanations. So a big thank you!

1 Like

No worry at all and glad I could be of assistance!

2 Likes

So I have a next set of questions which is not around requiring further explanations on the previous as such but next on my journey forward. Admin might want to break this out into a new thread however, but it does require some repetition so i’ll repost some code to carry along the background context.

I have setup a proposal contract so a party can issue proposals and for that I need all members of the Guild to be a signatory on the issuing of the proposal.

Now rather than doing that in a drawn out explicit way, I was reading Use Case 2 in this blog post and wondering if I can use that same learning?

I know that I have set up Guild as a contract template here, but is there a way I could group the creator and members together so that I can have one entity as a signatory on my proposal contract?

I tried to follow the blog post example but while i understand it somewhat conceptually I got stuck trying to implement it in practice.

Here’s my code for the Proposal contract:

template Proposal with
    issuer: Party
    investor: Party
    projectdescription: Text
    unitsrequired: Int
    marketingcost: Int
    distributioncost: Int
    additionalcost: Int
    proposalId: Text -- Key
    item: Item

  where
    signatory issuer
    observer investor

This is where I wanted to add something like say

signatory issuer, guild

Where all the members of the Guild sign off on the proposal. Note that the issuer would have to be said member of the guild as well and there would be overlap between the issuer and members of the guild as the issuer is also a member of the guild as well anyway. Only a guild member can issue a proposal.

I know that right now I could do something like

guild: Guild

In the template

and then I could add something like

signatory issuer, guild.members

(not sure if my syntax is entirely correct here, but hopefully this demonstrates the point)

and then all the members of the guild would have to sign-off on this proposal. I don’t know if I would have to run an extra check before hand to see if that person is a member of said guild and if the guild needs to be specified beforehand but this is the general pattern I was going to follow logically speaking.

Would this be the right way to go about it? Or perhaps there is a more concise/elegant way of doing it?

This way sounds right to me, you’d just need to use the Propose and Accept pattern to make sure everyone signs the contract. If you want to make sure the issuer is a member of guild.members then you can add an ensure clause like:

ensure issuer `elem` guild.members -- can also write this as the following but it's less common: ensure elem issuer guild.members

Here the function elem is specified inline between the arguments issuer and guild.members and it returns a Bool, evaluating to True if issuer is an element of the guild.members list. Then ensure only succeeds if the boolean it receives is True if this check failed then the contract wouldn’t be allowed to be created.

Now because you’re using ensure to make sure the issuer is an element of the guild.members then you technically don’t need to specify the issuer twice so your signatory line can simply be:

signatory guild.members

One gotcha here is that any guild.member can attempt to make any member an issuer unless the issuer is careful to check that new obligations aren’t being made for them that they didn’t consent to so this will need to be handled in client-side code to check.

Here’s my full code for reference:

template Guild
  with
    members: [Party]
    owner: Party
  where
    signatory owner

template Proposal with
    issuer: Party
    investor: Party
    guild: Guild
    projectdescription: Text
    unitsrequired: Int
    marketingcost: Int
    distributioncost: Int
    additionalcost: Int
    proposalId: Text -- Key
    item: Item

  where
    signatory guild.members
    ensure issuer `elem` guild.members
    observer investor
1 Like

Thanks! I’ll try implementing this next week and report back.

1 Like

Hi @krmmalik,

This is veering a bit away from my expertise. While I know how the Daml language works “in the small”, I have not personally written any large Daml application and am thus not best placed to recommend “big” design decisions. I’ll comment as best I can, but I won’t be able to provide definite answers.

I think it’s important to clarify exactly what you want to express here. The delegation pattern in this blog post illustrates a way to give special authority to each member of a group. This is is not the same as saying every single member of the group has agreed to the decision.

In the specific example of the blog post, Alice is given authority to add people to the legal team, and then she can just go and do it. Note that:

  • She does not need to be a member of the legal team herself.
  • Other admins do not need to vet what she’s doing; there is no record of them ever agreeing to anything she does.
  • Members of the legal team do not know about each other.
  • Other team admins may not know about Alice being an admin until they observe her first admin action.
  • Other admins are not involved in nominating a new admin; this is a unilateral decision on the part of org.

Some of these can be easily changed (e.g. adding group as an observer on the GroupMember template would mean group members know about each other), but the fundamental process here is one of delegation: an authority figure (here the org party) gives a limited set of administrative powers individually to each person in a group. The group is there to facilitate the management of those administrative rights; individual members do not “act as a group”, so to speak.

The actions of Alice can only reasonably engage the responsibility of Alice herself and of org; other admins have no say in the matter.

Another point to note is that, because the blog post defines group membership as the existence of a (manager, group, member) contract on the ledger, with only manager and member as stakeholders, groups do not exist on the ledger as a separate thing and group members do not (necessarily) know about each other. This is fine for permission groups, but from what I understand of your use-case I’m not sure it’s a good fit. You probably want to be able to talk about properties of the guild as a separate thing itself.

If you wanted to say that every member of a guild can make proposals to investors on behalf of the entire guild without needing the explicit approval of other guild members, then you could use the pattern from the blog post. You would likely still need a propose/accept pattern between “the guild” and the investors, though.

2 Likes

I think it’s worth noting that there are really two “stages” of propose/accept in this process:

  1. A guild member wants to make a proposal to an investor and needs to collect the signature of other guild members.
  2. “The guild”, or a subset thereof, makes a proposal (signed by all, or “enough”, guild members) to an investor.

@anthony’s Proposal template is already the second stage of that process. The names are getting in the way a little bit here, but you’d likely want to have a ProposalProposal template made by a single member to the rest of the guild first (and that would get rid of the issuer problem mentioned by @anthony). You could work around the awkward names by using more creative (but longer) names for your templates, such as GuildMemberWantsToMakeProposal and ProposalFromGuildToInvestors. Or, well, you can probably come up with something better. The point is, because you have two levels of propose/accept, you’ll likely need at least 3 templates:

  1. The initial template created by a single guild member to collect all the signatures (we’ve discussed that one in the past).
  2. The template that represents a “signed by the guild” proposal ready to be shown to an investor, with the investor(s) as observers, used to collect investor signatures.
  3. A final template that represents the agreed upon contract, where all the guild members and all the participating investors are signatories.
2 Likes

Thanks for the great write-ups as always @Gary_Verhaegen . Experience “in the small” is very valuable to me here, although on a sidenote, it would be nice to pick the brain of someone that has worked on a large application for maybe a podcast interview or something. That would be super interesting.

Anyway, I appreciate you breaking down the differences between what I am intending and what the blog post is describing. I didn’t realise DAML allows you to be so granular about the way things are agreed and what authority is required in light of that.

I’m going to attempt the proposal-accept pattern the way you suggested over the next few days. To be honest, I did have a feeling it would have to be done in some way similar to this and it will now give me a chance to practise the proposal-accept pattern a little further.

Thanks again.

1 Like

A post was split to a new topic: Indentation error in record creation