How to create access control model using DAML contract?

Hello,

I am new learner to daml. I am having a use case in which I want to implement access control model, As you guys are familiar with the existing daml wallet, There’s a feature, you can send few coins to another party & that party need to accept the transaction. However, I want to give that control to some middle party who can also accept or reject the incoming requests.

please let me know, how can we achieve it in same scenario ?

Hi @Virendra_Solanke
Welcome to the Daml community.
Here’s one way you can model this delegation.

module AssetWithTransferAcceptDelegation where

import Daml.Script

template Asset 
  with
    issuer : Party
    owner : Party
    amount : Decimal
  where
    signatory issuer, owner

    choice Propose_Transfer : ContractId AssetTransfer
      with
        recipient : Party
      controller owner
      do
        create AssetTransfer with
          asset = this
          recipient
          transfer_accept_delegate = None

template AssetTransfer
  with
    asset : Asset
    recipient : Party
    transfer_accept_delegate : Optional Party
  where
    signatory (signatory asset)
    observer recipient, transfer_accept_delegate

    choice AssetTransfer_Accept : ContractId Asset
      controller recipient
      do
        create asset with
          owner = recipient

    -- This choice provides visibility of the AssetTransfer contract to the delegate
    choice AssetTransfer_Add_Delegate : ContractId AssetTransfer
      with 
        delegate : Party
      controller recipient
      do
        create this with
          transfer_accept_delegate = Some delegate

-- This template is a role contract providing asset transfer recipient's authority,
-- which is required to create Asset contract in recipient's name
template AssetTransferDelegate
  with
    delegator : Party
    delegate : Party
  where
    signatory delegator
    observer delegate

    -- This choice could be consuming or nonconsuming
    -- depending on whether the delegation to accept transfer
    -- should be valid for only one transfer 
    -- or whether it should be persistent
    choice AssetTransfer_Accept_By_Delegate : ContractId Asset
      with
        transferCid : ContractId AssetTransfer
      controller delegate
      do
        exercise transferCid AssetTransfer_Accept

test = script do
  issuer <- allocateParty "Issuer"
  alice <- allocateParty "Alice"
  bob <- allocateParty "Bob"
  charlie <- allocateParty "Charlie"

  -- Issuer creates asset
  a <- submit issuer do
    createCmd Asset with
      issuer
      owner = issuer
      amount = 10.0

  -- Issuer proposes asset transfer to Alice
  atp <- submit issuer do
    exerciseCmd a Propose_Transfer with recipient = alice

  -- Alice accepts the transfer. Now Alice owns the asset.
  a <- submit alice do
    exerciseCmd atp AssetTransfer_Accept

  -- Alice proposes asset transfer to Bob
  atp <- submit alice do
    exerciseCmd a Propose_Transfer with recipient = bob

  -- Bob gives visibility of AssetTransfer contract to Charlie 
  atp <- submit bob do
    exerciseCmd atp AssetTransfer_Add_Delegate with delegate = charlie

  -- Bob creates delegation contract, which provides Bob's authority 
  -- required to create Asset with owner = bob
  atd <- submit bob do
    createCmd AssetTransferDelegate with
      delegator = bob
      delegate = charlie

  -- Charlie accepts asset transfer proposal on Bob's behalf
  a <- submit charlie do
    exerciseCmd atd AssetTransfer_Accept_By_Delegate with transferCid = atp

  return ()
1 Like

Hi,@a_putkov
Thanks for the solution. I will try to integrate this with front end soon.

Hi, @a_putkov . I have tried given solution. Also I have tried to build the given code . but its giving an error .
so I have question regarding the problem statement I am trying to solve & as follows :-
Can we achieve this by only mentioning extra party as signatory in Asset Template of existing daml sample wallet & then from front end we pass the third party id within payload ?

I don’t see how adding another signatory on the Asset template would be helpful here. The effect of adding another signatory to the Asset template would be the requirement to have that party’s authorization for every creation and archival of an Asset contract. In other words it would complicate the creation and archival of Asset contracts, and it won’t do anything to help with delegation.
Delegation of authority in Daml is achieved through choices and their controllers. By specifying a controller on a choice the signatories on the template delegate their authority to the choice controller. The controller is the party that can exercise the choice, while all actions in the body of the choice carry the authority of the contract’s signatories.
In the Wallet Sample App the acceptance of a transfer proposal results in the creation of an Asset contract, which requires the authority of the owner of the Asset contract being created (i.e. of the recipient of the transfer proposal). To delegate this authority to another party we need a template, where the recipient of the transfer is a signatory and the delegate is the controller on a choice. Neither Asset nor AssetTransfer template satisfies this criteria, which is why the example I provided introduces another template named AssetTransferDelegate.
I assume the errors you experienced came about when you replaced the Asset module in the Wallet Sample App with AssetWithTransferAcceptDelegation module I provided, right? If this is indeed what happened, the compile errors should be expected, since AssetWithTransferAcceptDelegation module modifies the original Asset and AssetTransfer templates, and these modifications need to be reflected in other modules that utilize these templates.

Hi @a_putkov ,
Thanks for the brief on signatory & delegation . I will let u know once I succeed.

Hi @a_putkov ,
Please let me know if this will work . I want some 3rd party might accept or reject incoming request.

module Asset where

data AssetType = AssetType with

    issuer: Party

    symbol: Text

    reference : Optional Text     
  deriving (Eq, Show)
  

template Asset with
    assetType : AssetType

    owner : Party
    amount : Decimal
    observers : Set Party
  where
    signatory assetType.issuer, owner
    observer observers
    ensure (if assetType.fungible then amount>0.0 else (amount==1.0))

    choice Propose_Transfer : ContractId AssetTransfer
      with
        recipient : Party
      controller owner
      do
        create AssetTransfer with
          asset = this
          recipient
          transfer_accept_delegate = None
   

template AssetTransfer
  with
    asset : Asset
    recipient : Party
    transfer_accept_delegate : Optional Party
  where
    signatory (signatory asset)
    observer recipient
    ensure (if asset.assetType.fungible then asset.amount>0.0 else (asset.amount==1.0))

    choice AssetTransfer_Add_Delegate : ContractId AssetTransfer
      with 
        delegate : Party
      controller recipient
      do
        create this with
          transfer_accept_delegate = Some delegate

    choice Cancel_Transfer : ContractId Asset
      controller asset.owner, transfer_accept_delegate
      do
        create asset

    choice Reject_Transfer : ContractId Asset
      controller recipient, transfer_accept_delegate
      do
        create asset

    choice Accept_Transfer : ContractId Asset
      controller recipient, asset.assetType.issuer, transfer_accept_delegate
      do
        create asset with
          owner = recipient
          observers = Set.empty

template AssetTransferDelegate
  with
    delegator : Party
    delegate : Party
  where
    signatory delegator
    observer delegate

    choice AssetTransfer_Accept_By_Delegate : ContractId Asset
      with
        transferCid : ContractId AssetTransfer
      controller delegate
      
      do
        exercise transferCid Accept_Transfer

Nope. This won’t work, I’m afraid. When you list multiple parties as controllers of a choice, the authority of all of these parties will be required to exercise the choice. E.g. the exercise of your Accept_Transfer choice on the AssetTransfer template will need to be jointly authorized by the asset issuer, the recipient of the transfer and the delegate. The AssetTransfer_Accept_By_Delegate choice on AssetTransferDelegate template provides the authority of the delegator. If the delegator is the recipient of the transfer and AssetTransfer_Accept_By_Delegate choice is exercised by the delegate, then the exercise of Accept_Transfer choice on AssetTransfer contract that is called from AssetTransfer_Accept_By_Delegate choice will be authorized by the recipient and the delegate. However, the Accept_Transfer choice requires authorization from 3 controllers including the asset issuer. Hence the exercise will fail because of missing authorization from the asset issuer.

so even if we remove transfer_accept_delegate as controller , it will not work in this template ?
could you please suggest what will be the possible solution for this template from wallet reference application ? I am just playing around & looking for possibilities I can try.
Simple use case I want to built in existing wallet reference app is to just show that incoming request in third parties account, so that he can also accept or reject on behalf of some party.

@Virendra_Solanke
If you remove transfer_accept_delegate from the list of controllers of Accept_Transfer choice, then the party provided in transfer_accept_delegate field (supposedly the delegate) will not be able to exercise the choice, which certainly doesn’t help your use case.
I’m not sure I understand the request for an example, as I did provide one (including a test script to demonstrate that it works) earlier on this thread. Does the example I provided not work for you for some reason?

Hi @a_putkov ,
I have tried your example, It works fine, But I am asking for the wallet app which is I am referring currently.
we know whenever some party sends some asset tokens to some other party, the request comes under inbound or outbound, what I am trying to do is, the same request must go to some other party other than who is doing transactions. so that we can allow that third party to accept or reject it.
I hope this time, I am able to explain you the problem I am trying to solve.

@Virendra_Solanke
It’s perfectly possible to implement the workflow you’re interested in in the Wallet Sample App. But it’s not trivial. The example I provided is one step towards the complete implementation, but it’s far from the full solution. It modifies the original implementation in the Wallet Sample App of Asset & AssetTransfer templates and introduces a new AssetTransferDelegate template. These changes have a knock-on effect on other parts of the app, namely on the templates in the Account module, the triggers and the UI code. All these pieces will need to be modified to reflect the changes in the Asset module. And then an additional workflow will need to be created in the UI to allow the recipient of the transfer to select a delegate.
Does this make sense?

Yes @a_putkov it make sense now.
Thank you for the brief again.