E2E Property Rentals Written in Daml
Renting a property is still quite a manual and cumbersome process because different actors have different views of it and can’t fully trust each other, so paperwork is put in place to mitigate risks.
If we were able to solve these paperwork issues, we could apply the same approach to not only rentals but also many other multi-party processes.
Defining the shared rental process
Suppose we’ve been hired by rental market players to improve their business.
The first thing we’d do is to sit together and to define a shared process and, after several iterations, we might agree on the following one:
Authority: registers properties to their landlords and grants licenses to rental agencies.
Landlord: owns a property and can delegate its rental to an agency.
Agency: governs the whole process on behalf of the landlord.
Tenant: the current tenant of a property, runs property visits.
Renter(s): prospective tenants that can be invited to visits by the agency and can apply.
A successful process runs as follows, with stages represented as Daml contracts:
- The authority registers a
Propertyto a landlord and offers an
AgencyLicenseOfferto a rental agency.
- The agency accepts the
- The landlord turns the
Propertyinto a Rental and delegates the rental to an agency through
RentalDelegateOffer. From now on, the agency manages the property’s rental.
- The agency accepts and updates the
Rental, inviting one or more prospective tenants for a visit through
- A prospective tenant creates a
- The current tenant schedules and runs the visit(s), whose completion is audited by a
- The prospective renter(s) may create a
- The agency may accept at most one application and emits a
RentalContractOfferwhile locking the
Rentalby transforming it into a
RentalPendingContract, preventing other applications from being accepted.
- The selected applicant may accept it and
Of course any stage of the process is allowed to fail: the agency license can be withdrawn and any offer can be rejected; the actors, though, should still be free to engage in new agreements.
Renting in Daml
Translating a process into Daml is fairly straightforward, as Daml is built around the concepts of multi-party agreements, but it also means defining it more precisely and dealing with inconsistencies immediately. For this reason, it might be actually a good idea to use Daml as a design aid from the start.
In the following sections we’re going to analyze Rental.daml which can be obtained by cloning this. Alternatively you can check out a short video demo:
Some patterns are commonly used in Daml processes:
- The state of the active processes are stored as contracts and the blueprints for contracts are templates. Templates can have parameters, signatories and observers (i.e. parties that resp. endorse or see contracts), as well as lookup keys.
- Templates also define the process transitions as choices and restrict the parties that can perform them. Since choices can define many actions that can also be choices, exercising a choice can trigger a rather big set of actions.
- Choices execute atomically, i.e. either all actions will be applied in the order specified or none of them will.
Let’s have a look at the
AgencyLicenseOffer template that represents the initial state of a rental process for an agency:
This template employs Daml offer-accept pattern for rights delegation:
- A party submits a
create AgencyLicenseOffertransaction, with herself as the
authorityis a signatory, i.e. it signs the contract, and also automatically an observer (but not vice-versa).
agencyis declared as a controller for two choices, i.e. it can exercise either
AgencyLicenseOffer_Refusewith the endorsement of
authoritythat created the contract.
AgencyLicenseOffercontract is archived (this is the default behavior) and a new
AgencyLicensereplaces it. Alternatively, exercising
AgencyLicenseOffer_Refusewill only archive the offer.
A short tour of Rental.daml
Rental.daml follows the previously described process closely, so I’ll concentrate on portions that introduce new concepts.
Initially, when the authority offers a license to an agency, we maintain role separation and, with the following assertion, ensure that they are not the same party:
Similarly, when the authority registers a property to a landlord, specific clauses are in place to avoid conflicts of interest:
Also note that the authority can always revoke a license through an empty consuming choice on the license contract:
All offer-accept steps provide similar empty choices to refuse an offer:
Also note that the property registry ID is a key for the
This key is used to refer to
Rental independently from its contract ID that changes because the
Rental gets transformed into a
RentalPendingContract when a rental application is accepted:
This mechanism effectively locks the
Rental so that there is at most one contract offer. If it is refused, the
RentalPendingContract becomes a
Finally, non-consuming choices are used for non-exclusive steps like offering a visit, exercising these choices won’t archive the
Daml scenarios are scripted submissions similar to commands issued by a Daml application and are used for testing and documentation.
The repository includes a scenario that tests authorization and the happy path.
Triggers simplify off-ledger automation, i.e. automatic submissions in reaction to ledger updates. They are effective for cleanup and bookkeeping tasks as they can be written in Daml (they are currently considered experimental).
In our Daml Rental model, we allow many visits and applications for a single property; this means that, when the property is rented, the pending visits and applications must be rejected.
It is possible to let our model track pending activities and archive them when a rental lease is signed but it is easier to write a cleanup trigger that will react to ledger events and perform the cleanup.
User Interface in Daml
Daml offers a sandbox with an UI that allows utilitarian interaction with the model during development.
A dedicated user interface is expected for a production-ready application though. For this we offer a React-Typescript scaffolding based on
create-react-app that provides a starting point to modern, single-page web applications that interact with Daml. You can check it out here.
Since I already had my own React-TypeScript scaffold, I decided to reuse that one:
It currently includes all the tables but only two actions: creating and renting a property.
Invoking the Daml JSON API
Daml Rental invokes the Daml JSON API through Axios, for example here’s the implementation of
loadContracts, which gets all contracts belonging to a specific template:
Authentication and Authorization
The Daml platform is agnostic w.r.t. Identity and Access Management (IAM) architectures.
The Ledger API Server offers a gRPC API and supports out-of-the-box requests that carry a JWT token signed by a well-known issuer; the token includes the capabilities of the submitter, i.e. on behalf of which parties it can read and write.
The Daml platform also includes a JSON API that translates between REST and gRPC requests/responses, forwarding the JWT token.
Daml Rental accesses the JSON API through Axios and authenticates by attaching the user token to every request:
This example covers the bulk of a real-world rental process and was written in one week by reusing an empty React-Redux-Typescript scaffold; a similar or better productivity gain can be achieved by using create-daml-app.
The most thought-intensive part was designing the rental process which is where Daml really shined. Daml allowed me to focus exclusively on the business logic and customer interactions in my Daml application. I didn’t have to worry about the JSON API, data persistence, or access management which greatly decreased my mental load.
On the frontend side writing a dedicated UI was mostly busywork and the API integration was extremely smooth.
If you want start building and learning, Daml has also a new learn section where you can begin to code online: