Error: No instance for (Show IAsset)

I have an interface defined as below:

data VAsset = VAsset with 
  issuer : Party 
  owner : Party 
  obs: [Party]
  
  quantity: Decimal 
  assetType: Text 
    
interface IAsset where 
  viewtype VAsset 
  setOwner: Party -> IAsset 
  setObs: [Party] -> IAsset
  setQuantity : Decimal -> IAsset

I am trying to use it in a template as given below:


template TransferProposal  --this gives error
  with 
    newOwner: Party 
    asset: IAsset 

  where 
    signatory (signatory asset) 

    choice AcceptProposal: ContractId IAsset 
      controller newOwner 
      do 
        
        create (fromInterface @VAsset asset) with 
          owner = newOwner

Two questions:

  1. I get an error:
No instance for (Show IAsset)
        arising from the second field of ‘TransferProposal’ (type ‘IAsset’)
      Possible fix:
        use a standalone 'deriving instance' declaration,
          so you can specify the instance context yourself
    • When deriving the instance for (Show TransferProposal)typecheck

I tried making VAsset deriving (Eq, Show) but that doesn’t help.

  1. Is the create… statement written above the right way to create an asset without knowing which asset type it is? Only owner is changed.

Thanks!!

An interface can only be used to abstract over the representation of whole contracts on the ledger, providing (one way!) access to each one’s view, and of course abstract choice signatures. It cannot be used to abstract over arbitrary data structures, which is what the asset variable as used here must be.

This is because there is no way to make an interface serializable according to the specific definition linked here. The (Eq, Show) test is usually just a quick sanity check as a shortcut to this, but even if you try to hack around the system, you won’t be allowed to do it:

error type checking template Main.TransferProposal :
  expected serializable type:
  * reason: template argument
  * found: Main:TransferProposal
  * problem:
      unserializable data type Main:TransferProposal [Daml-LF typechecker]

You cannot create a contract without knowing what template type it has. Once it has been created, you can interact with its choices, its view, and optionally convert to a template (note that @VAsset cannot possibly be a fromInterface argument because it is not a template), but it must be created concretely.

To abstract over create template, that selection should be abstracted behind an interface choice; if you have a ContractId of that interface, you can then invoke all sorts of choices whose actual concrete resulting templates depend on the implementer of the interface.

Thanks @Stephen

The error goes away if I change the asset type to ContractId IAsset

template TransferProposal  
  with 
    newOwner: Party 
    asset: ContractId IAsset
...