Exercises

This chapter collects somewhat more advanced exercises for CSL. Most of them require the use of the CSL standard library and/or some functionality that is documented in the contract language reference or value expression reference and not presented in detail in the introductory chapters.

Writing and running contracts

Exercise: Age-restricted purchase

Write a contract for operating a shop where some items are age-restricted. This means that the buyer will have to provide a valid identification in order to purchase these items.

Allow for multiple items to be sold. The valid id only has to be presented once for the entire purchase.

Test the contract with both restricted and unrestricted items (solution).

Exercise: Shopping basket

Write a contract which allows you to add multiple items from the shop to your basket and paying for all of them together.

Try adding an event for removing an item from the basket. Remember to check that the item was indeed first added to it.

Try running the contract to see if Checkout behaves as you expect. Test that if you added an item once, you can remove it also only once (solution).

Exercise: Two-buyer protocol

Write a protocol in which two buyers interact with one seller. Buyers first negotiate which item to purchase. They then make enquiries about its price. Seller informs both of them about the price of the item they agreed on. Each of the buyers declares how much of the price they are willing to pay. The buyer who suggested the item to be purchased declares his share first. Otherwise, if the sum of the two offers is at least as high as the price, the seller delivers the item to the buyers.

Try writing this contract using subcontracts for the different stages: item negotiations, price enquiry, two buyers declaring shares etc.

Run the contract and verify that at each stage, correct events are expected (solution).

Expressions and reports

Exercise: Bank account balance

AccountOperations is a very simplistic way of managing a single bank account.

type Deposit : Event { amount : Int }

type Withdraw : Event { amount : Int }

template rec AccountOperations() =
  (<*> d : Deposit where
     d.amount > 0
  or
  <*> w : Withdraw where
    w.amount > 0)
  then AccountOperations()

Write a reporting function which calculates the balance of a bank account. Your function should be of type ContractId -> Int.

Next, change the contract in such a way, that it prevents the balance to drop below 0 (solution).

Exercise: Reimbursement for business travel

The following declaration specifies a protocol allowing an employee to inform their employer about a planned business travel. The employer can either accept or reject the planned trip.

type Transportation
  | Bike
  | Bus
  | Car
  | Plane
  | Other Int

val calculateTransportationPrice =
  \ Bike -> 0
  | Bus -> 10
  | Car -> 50
  | Plane -> 500
  | Other price -> price

type TravelNotice : Event {
  employee : Agent,
  transport : Transportation,
  startDate : DateTime,
  endDate : DateTime
}

type TravelAcknowledgement : Event {
  employee : Agent,
  startDate: DateTime,
  endDate: DateTime
}

type TravelCancellation : Event {
  employee : Agent,
  startDate: DateTime,
  endDate: DateTime
}

template BusinessTravelAgreement (employer, employee) =
  <employee> tn : TravelNotice where
    tn.employee = employee
  then
  (<employer> ta : TravelAcknowledgement where
    tn.employee = ta.employee &&
    tn.startDate = ta.startDate &&
    tn.endDate = ta.endDate
  or
  <employer> tc : TravelCancellation where
    tn.employee = tc.employee &&
    tn.startDate = tc.startDate &&
    tn.endDate = tc.endDate)

Write a reporting function which calculates how much money should the employee be reimbursed for, based on the mode of transportation and the duration of travel. Assume that for trips shorter than 24 hours there is no per diem, but for trips of 1 day or longer, the employee gets 50 Euros for each full day.

Next, write a report which calculates how much should each employee be reimbursed. The function that calculates this report should have the following type: List ContractId -> List Agent -> List (Tuple Agent Int). Remember that employees might take multiple business trips, and that only approved trips are reimbursed (solution).

Hint

When using the provided GUI to solve this exercise, make sure that the source code is the same for all of the contracts to be included in the report. This ensures that contracts can see each other, allowing you to run generateTravelReport with all the contract identifiers of different contracts you run.

For instance, if you have 3 instances of BusinessTravelAgreement and 2 employees, you can run:

\c1 -> \c2 -> \c3 -> \a1 -> \a2 -> generateTravelReport [c1,c2,c3] [a1,a2]

in the Reports tab, and select appropriate arguments.