I have a rookie question about modeling assets and accounts in Daml. I’m looking to create a primitive generic model that represents an asset with issuer and owner as signatories, and I’m looking to implement workflows with this asset, which require delegation of issuer’s authority to the owner and vice versa. An example of such workflow is an airdrop, where an issuer mints the asset to the owner without requiring explicit owner’s consent for each airdrop transaction.
I understand that delegation of authority in Daml is achieved by creating a role template with the party delegating the authority as a signatory and the party receiving delegated authority as a controller on the choices, which carry out the actions that require delegated authority. E.g. I can implement a role template named AssetHoldingAccount with issuer and owner as signatories, and with issuer as a controller on the choice named Airdrop, which creates the asset with issuer and owner. With this construct, once the AssetHoldingAccount contract has been created following propose/accept pattern, the issuer party can unilaterally exercise the Airdrop choice and create Asset contract with AssetHoldingAccount’s owner as a signatory. Owner’s consent is implied by way of the owner being a signatory on the AssetHoldingAccount contract.
Now I need to link the Asset and the AssetHoldingAccount templates. One way to do this is to have a common key for the two templates. Another way I can think of is to have the data from one contract to be part of the other. E.g. instead of using the type Party for the owner field in the Asset template, use the AssetHoldingAccount. This construct can have an intuitive interpretation as “the asset can only be created and held in an account, it cannot exist outside of an account”. It also allows to access the fields within AssetHoldingAccount contract from the Asset template to ensure for example that both have the same party owner.
I was advised against using this construct by @Leonid_Rozenberg on the grounds that with this construct it’s possible that the Asset contract may contain the data from the AssetHoldingAccount contract that does not exist on the ledger. I’m afraid I’m not quite following why this is necessarily a problem, and hence why this design is not recommended. I think the answer to this question may be of interest to more than me, hence I’m posting it on the forum in hope that someone can explain to me what is fundamentally wrong with the code snippet below.
template AssetHoldingAccount
with
issuer : Party
symbol : Text
owner : Party
where
signatory issuer, owner
key (issuer, symbol, owner) : (Party, Text, Party)
maintainer key._1
nonconsuming choice Airdrop
: ContractId Asset
with
quantity : Decimal
controller issuer
do
create Asset with
issuer
owner
symbol
quantity
template Asset
with
issuer : Party
symbol : Text
owner : AssetHoldingAccount
quantity : Decimal
where
signatory issuer, owner.owner
ensure quantity > 0.0
choice Transfer
: ContractId AssetTransfer
with
newOwner : AssetHoldingAccount
controller owner.owner
do
create AssetTransfer with
asset = this
newOwner
template AssetTransfer
with
asset : Asset
newOwner : AssetHoldingAccount
where
signatory (signatory asset)
observer (observer asset), newOwner.owner
let
targetAsset = asset with
owner = newOwner
ensure (ensure asset) && (ensure targetAsset)
choice Transfer_Accept
: ContractId Asset
controller asset.issuer, newOwner.owner
do
create targetAsset
choice Transfer_Cancel
: ContractId Asset
controller asset.owner.owner
do
create asset
choice Transfer_Reject
: ContractId Asset
controller newOwner.owner
do
create asset