What is the correct way to keep the chain of modifications on the same asset?

Hello everyone,

I am proceeding with my code thank you to this community I’ll never thank you enough :pray: :pray: :pray:
With your great help, I managed to write a code to: create an asset (with a key), update the asset, retrieve the asset with FetchByKey, then, make a proposal to sell the asset, and finally a contract to sell the asset. I have a question and a problem:

1- In one of the previous topics (Testing fetchByKey - #4 by WallaceKelly) Wallace very kindly suggested that there is no need to copy all instances in the asset, I can just search the asset code. However, I don’t understand if I have to repeat the key and the maintainer in the AssetProposal and in the AssetContract. What is the correct way to keep the chain of the asset, being created, updated, proposed for sale and sold? At the moment I copied the entire Asset.

2- My code doesn’t compile for an issue apparently related to the parties (buyerSolicitor = proposerOwnerSolicitor) and (buyer = proposerOwner). However, everything looks fine to me and I don’t understand where I am wrong.

I copy my code below, hoping that someone will be so kind as to, (again and again :smile: :smile: ) help me. I also copied the module Asset (which should be ok) for completeness.

In my defence, I try a lot and a lot before coming back to the community as I am very conscious that you are all busy and my issues are banal for all other people. :pray: :pray: :pray: :pray: :pray:

module SellAsset where

import Asset 
import DA.Time (time)

type AssetProposalId = ContractId AssetProposal
type AssetContractId = ContractId AssetContract

template AssetProposal
    with 
        
        --idCode : Text
        asset: Asset 
        proposerOwnerSolicitor:Party
        proposerOwner:Party
        notes: Text
        date: Time

    where 
        signatory asset.ownerSolicitor
        observer asset.owner, proposerOwner, asset.auctionHouse

-- What the seller can do (through the Owner Solicitor)

-- Propose to sell the asset
        choice MakeAssetContractOffer
            : AssetProposalId
            with
                assetproposal : Text 
            controller asset.ownerSolicitor
            do create this

--revise the offer 
        choice ReviseAsseContractOffer
            : AssetProposalId
            with 
                offerRevison :Text
            controller asset.ownerSolicitor
            do create this with
                notes = offerRevison

-- What the buyer can do (through the New Owner Solicitor)

--reject the offer 
        choice RejectAssetContractOffer
            :  AssetProposalId
            with
                feedback : Text
            controller proposerOwnerSolicitor 
            do create this with 
                notes = feedback  

---accept the offer

template AssetContract 
    with 
        --idCode: Text
        asset : Asset
        buyer : Party
        seller: Party
        buyerSolicitor : Party
        sellerSolicitor : Party
        contractNotes : Text
        contractDate : Time
        auctionHouseInContract :Party

    where 
        signatory buyerSolicitor, sellerSolicitor
        observer buyer, seller, auctionHouseInContract

        choice AcceptContractOffer
            : AssetContractId    
            with
            controller buyerSolicitor
            do create AssetContract with 
             
                asset
                buyer = proposerOwner
                seller = asset.owner
                sellerSolicitor = asset.ownerSolicitor
                buyerSolicitor  = proposerOwnerSolicitor
                contractNotes  
                contractDate 
                auctionHouseInContract = asset.auctionHouse

module Asset where

type AssetId = ContractId Asset

template Asset 
  with

    ownerSolicitor : Party
    owner : Party
    auctionHouse :Party --also makes sure that all parties are legit
    address :Text
    idCode: Text --To check how to create an asset ID. To be generated offline 
    a_description : Text 
    a_documents : [Text]
    a_docLink : Text --to be reviwed to create a link to the documents       
    v_description : Text 
    v_documents : [Text]
    v_docLink : Text --to be reviwed to create a link to the documents 
    date: Time

  where
    signatory ownerSolicitor
    observer owner,auctionHouse  

    key (ownerSolicitor, idCode) : (Party, Text)
    maintainer key._1
        
    choice UpdateAsset 
      : ContractId Asset 
      with 

            new_owner : Party
            new_address :Text
            new_a_description : Text 
            new_a_documents : [Text]
            new_a_docLink : Text       
            new_v_description : Text 
            new_v_documents : [Text]
            new_v_docLink : Text 
            new_date:Time

      controller ownerSolicitor 
        do 
            create this with
 
              owner = new_owner
              address = new_address
              a_description = new_a_description 
              a_documents = a_documents ++ new_a_documents
              a_docLink = new_a_docLink      
              v_description = new_v_description
              v_documents = v_documents ++ new_v_documents
              v_docLink = new_v_docLink
              date = new_date

template AssetHelper
    with
      caller : Party
  where 
    signatory caller
    
    choice GetAssetByIdCode : (AssetId, Asset)
          with 
            idCode : Text
          controller caller
          do
            fetchByKey @Asset (caller, idCode)

Yes, if your other contracts (e.g., AssetProposal and AssetContract) are dealing with an asset you have three options… you can either pass around (1) the maintainer/key to that asset, or (2) the contract id of the asset, or (3) all the data about the asset (the way you have it now).

  • With option 1, reference-by-key, there is only one copy of the information about the asset, which you can always reference by key, even if the information about the asset (for example, the description) is updated.

  • With option 2, reference by contract id, there is only one copy of the information about the asset, which you can try to reference by contract id. However, if the asset’s description is changed after the AssetProposal is created, any old reference ids will no longer be valid.

  • With option 3, include the entire data structure in the other contracts, you potentially end up with copies of the information about the asset. That is, you will have the original Asset contract on the ledger, and then you will additionally have an AssetProposal contract on the ledger that has within it a copy of the Asset. If you subsequently update the description in the original Asset contract, that will have no effect on the description that is within the asset information stored within the AssetProposal. Maybe that is a good thing in your application? Maybe not.

It all depends on how you want it to work. There’s no one right way.

Looking at your definition of the AssetContract, it does not include any definition of proposerOwner or proposerOwnerSolicitor. The code tries to use the values, but they are not set anywhere. That is, the values of proposerOwner and proposerOwnerSolicitor are not being passed in when the contract is created or when the choice is exercised. It would be like an “undefined variable” in other languages.

Hi Wallace,

I have no words to thank you for your support. It took me a good part of yesterday night after your answer (thank you again for replying very quickly :pray: :pray: :pray: : pray:) and today to fully understand and implement what I have to do, but finally today it works!!!
I can now refine the code for this part of my project and move to the next part, which I am going to start on Monday!

Thank you ever so much again!!! You are fantastic! Have a great great weekend :smiley: :smiley: :smiley: