Ownable

Ownable is single-owner authorization for Daml. It is the Daml analogue of OpenZeppelin's Ownable2Step: one owner party at a time, a two-step ownership transfer, and a renounce path.

The package has no dependency on other OpenZeppelin packages.

Experimental. Version 0.x, unaudited, and subject to a redesign before release. Source: experiments/access/ownable-v1 in OpenZeppelin/canton-contracts.

import OpenZeppelin.OwnableV1

Why Transfer Has Two Steps

In Solidity, transferOwnership(newOwner) is one call. Daml cannot do this. The owner is a signatory of the Ownership contract, and Daml requires the authority of every signatory to create a contract. The current owner alone cannot make another party a signatory.

Transfer is therefore an offer and an acceptance. The owner creates an OwnershipOffer, and the new owner accepts it. As a result, no party becomes owner without its agreement.

While an offer is pending, no Ownership contract exists. The offer archives the Ownership contract. Acceptance creates a new one for the new owner. A decline or a withdrawal creates a new one for the current owner. Applications that require an active Ownership contract must handle this period.

Ownership is not bound to a specific resource. The application must define which Ownership contract controls each protected resource.

Templates

Ownership

Ownership of a resource by one party.

FieldTypeDescription
ownerPartyThe current owner.

Signatory owner, no observers. Other parties read the contract through explicit disclosure. owner controls both choices, and both are consuming.

  • Ownership_OfferOwnership (takes newOwner : Party, returns ContractId OwnershipOffer): start a transfer to newOwner. Fails if newOwner is the current owner.
  • Ownership_RenounceOwnership (returns ()): give up ownership permanently (the renounceOwnership analogue). No Ownership contract remains.

OwnershipOffer

A pending transfer.

FieldTypeDescription
ownerPartyThe owner that made the offer.
newOwnerPartyThe party that can accept.

Signatory owner, observer newOwner. All choices are consuming and take no arguments.

ChoiceControllerResultDescription
OwnershipOffer_AcceptnewOwnerContractId OwnershipCreates Ownership for newOwner, with newOwner as signatory.
OwnershipOffer_DeclinenewOwnerContractId OwnershipReturns ownership to owner.
OwnershipOffer_WithdrawownerContractId OwnershipReturns ownership to owner.

A signatory can archive Ownership or OwnershipOffer directly. This leaves no Ownership contract, so the resource has no owner.

Transferring Ownership

Each step is a separate submission by a different party. In Daml Script:

-- alice, the current owner, makes the offer
offerCid <- submit alice do
  exerciseCmd ownershipCid Ownership_OfferOwnership with newOwner = bob

-- bob accepts and becomes the owner
newOwnershipCid <- submit bob do
  exerciseCmd offerCid OwnershipOffer_Accept

Errors

MessageCause
Ownable: new owner is the current ownerThe offer names the current owner.
  • Access Control when more than one party or action needs separate authorization.
  • Pausable for an emergency stop.