How to Use the Equity Extension Package

To follow the script used in this tutorial, you can clone the Daml Finance repository. In particular, the Equity test folder src/test/daml/Daml/Finance/Instrument/Equity/Test/ is the starting point of this tutorial.

How to Use the Equity Extension in Your Application

As explained in the Getting Started section and on the Architecture page, your app should only depend on the interface layer of Daml Finance. For equities this means that you should only include the equity interface package.

Your initialization scripts are an exception, since they are only run once when your app is initialized. This creates the necessary factories. Your app can then create equity instruments through these factory interfaces.

The Equity Interface

The equity extension supports different lifecycle related events, for example dividends, stock splits and mergers. These are modeled using the choices on the Equity interface, namely DeclareDividend, DeclareReplacement and DeclareStockSplit. We will now demonstrate each one with a concrete lifecycle event.

Dividend

The most common lifecycle event of an equity is probably dividends. This normally means that the holder of a stock receives a given amount of cash for each stock held. This is modeled using the DeclareDividend choice. It creates a Distribution Event, which allows you to specify distribution per share. In the case of a cash dividend, this would be a cash instrument. However, the company can also choose to distribute additional stock or even stock options. Since the Distribution Event supports an arbitrary perUnitDistribution instrument, it can be used to model those use cases as well.

In order to process a lifecycle event, you have to create two versions of the instrument: one before the event and one after the event. In the case of a dividend event, this means one instrument cum dividend (which includes the dividend) and one ex dividend (which does no longer include the dividend):

  cumEquityInstrument <- originateEquity issuer issuer "EQUITY-INST-1" "0" "ABC" pp now
  exEquityInstrument <- originateEquity issuer issuer "EQUITY-INST-1" "1" "ABC" [] now

After the instrument has been created, you can book a holding on it. This is not limited to integer holdings, but fractional holdings are supported as well:

  -- Distribute holdings: fractional holdings are also supported.
  investorEquityCid <- Account.credit [publicParty] cumEquityInstrument 1000.25 investorAccount

We create a distribution rule for the cash dividend. It defines the business logic for the dividend and it has the issuer as signatory:

  -- Create cash dividend rule
  distributionRuleCid <- toInterfaceContractId @Lifecycle.I <$> submit issuer do
    createCmd Distribution.Rule with
      providers = singleton issuer
      lifecycler = issuer
      observers = singleton publicParty
      id = Id "LifecycleRule"
      description = "Rule to lifecycle an instrument following a distribution event"

We also need a distribution event, which defines the terms of the dividend. In this case, it is USD 2 cash per share (this also works for a fractional amount of shares):

  -- Create cash dividend event: USD 2 per share (this also works with fractional shares)
  distributionEventCid <-
    Instrument.submitExerciseInterfaceByKeyCmd @Equity.I [issuer] [] cumEquityInstrument
      Equity.DeclareDividend with
        id = Id $ "ABC - " <> show now
        description = "Cash Dividend"
        effectiveTime = now
        newInstrument = exEquityInstrument
        perUnitDistribution = [qty 2.0 cashInstrument]

This allows the issuer to lifecycle the instrument by exercising the Evolve choice:

  -- Lifecycle cash dividend
  (_, [effectCid]) <- submit issuer do
    exerciseCmd distributionRuleCid Lifecycle.Evolve with
      observableCids = []
      eventCid = distributionEventCid
      instrument = cumEquityInstrument

This results in a lifecycle effect, which can be settled. The settlement of effects is covered in the Lifecycling tutorial.

Bonus issue

Instead of a cash dividend, a company may also decide to offer free shares (or warrants) instead of cash to current shareholders. This is called bonus issue and it is modeled in a similar way to the dividend above. The main difference is in the distribution event, which now distributes a different instrument (equity instead of cash):

  -- Create bonus issue event: receive 2 additional shares for each share currently held
  -- (this also works with fractional shares)
  distributionEventCid <-
    Instrument.submitExerciseInterfaceByKeyCmd @Equity.I [issuer] [] cumEquityInstrument
      Equity.DeclareDividend with
        id = Id $ "ABC - " <> show now
        description = "Bonus issue"
        effectiveTime = now
        newInstrument = exEquityInstrument
        perUnitDistribution = [qty 2.0 exEquityInstrument]

Similarly, if there is a bonus issue that awards warrants instead of equity, that can be modeled in the same way. Just replace the equity instrument by a warrant instrument on the perUnitDistribution line above.

Dividend option

A company may give shareholders the option of choosing what kind of dividend they want to receive. For example, a shareholder could choose between a dividend in cash or in stock. The DeclareDividend choice can be used for this as well. The issuer creates one event for each dividend option that shareholders can choose from:

  -- Create dividend option event.
  -- For each share currently held, the shareholder can choose to either receive cash (USD 10.5) or
  -- stock (1.5 additional shares).
  -- perUnitDistribution is an arbitrary list, so this can be extended with additional options, e.g.
  -- warrants or cash in a different currency.
  distributionEventCashCid <-
    Instrument.submitExerciseInterfaceByKeyCmd @Equity.I [issuer] [] cumEquityInstrument
      Equity.DeclareDividend with
        id = Id $ "ABC - " <> show now
        description = "Dividend option: cash"
        effectiveTime = now
        newInstrument = exEquityInstrument
        perUnitDistribution = [qty 10.5 cashInstrument]

  distributionEventStockCid <-
    Instrument.submitExerciseInterfaceByKeyCmd @Equity.I [issuer] [] cumEquityInstrument
      Equity.DeclareDividend with
        id = Id $ "ABC - " <> show now
        description = "Dividend option: stock"
        effectiveTime = now
        newInstrument = exEquityInstrument
        perUnitDistribution = [qty 1.5 exEquityInstrument]

The issuer then lifecycles each event individually, to generate two alternative lifecycling effects:

  -- Lifecycle dividend option
  (_, [effectCashCid]) <- submit issuer do
    exerciseCmd distributionRuleCid Lifecycle.Evolve with
      observableCids = []
      eventCid = distributionEventCashCid
      instrument = cumEquityInstrument

  (_, [effectStockCid]) <- submit issuer do
    exerciseCmd distributionRuleCid Lifecycle.Evolve with
      observableCids = []
      eventCid = distributionEventStockCid
      instrument = cumEquityInstrument

The investor can then claim one or the other:

  -- The investor chooses the stock dividend
  result <- submitMulti [investor] [publicParty] do
    exerciseCmd claimRuleCid Claim.ClaimEffect with
      claimer = investor
      holdingCids = [investorEquityCid]
      effectCid = effectStockCid
      batchId = Id "DividendOptionSettlement"

When this is settled, the investor’s holding is consumed, which prevents the investor from receiving more than one of the dividend options.

Rights Issue

In order to raise money, a company may decide to give current shareholders the right (but not the obligation) to purchase additional shares at a discounted price. This can be modeled using two components:

  • An option instrument, which describes the economic term of the rights a shareholder receives. For example, this could be a European option with a strike price below the current spot price, and a maturity three weeks in the future. The Generic Tutorial describes how to create a European option.
  • The DeclareDividend choice to distribute the above option instrument in the correct proportion (e.g. 3 option contracts for each 10 shares held). This can be done in the same way as the Bonus Issue example described earlier, just change the perUnitDistribution line to distribute the option instrument you created above.

When current shareholders receive the option instrument they can typically choose between:

  1. Exercising the option. The Generic Tutorial describes how to elect to exercise the option.
  2. Choosing not to exercise the option. The option will expire worthless.
  3. Selling the option. This is not always possible, it depends on the terms of the rights issue. Getting Started: Settlement describes how this could be done.

Stock split

A stock split is when a company increases its number of shares. For example, a 2-for-1 stock split means that a shareholder will have two shares after the split for every share held before the split. This is modeled using the DeclareStockSplit choice, which has an adjustmentFactor argument.

The DeclareStockSplit choice creates a Replacement Event, which allows you to replace units of an instrument with another instrument (or a basket of other instruments). Consequently, this interface can also be used for other types of corporate actions (for example, see the merger scenario below).

The workflow for a stock split is quite similar to that of a dividend above. We start by defining the instrument before and after the lifecycle event:

  preEquityInstrument <- originateEquity issuer issuer "INST-1" "0" "AAPL" pp now
  postEquityInstrument <- originateEquity issuer issuer "INST-1" "1" "AAPL" [] now

We create a replacement rule for the stock split:

  -- Create lifecycle rule
  replacementRuleCid <- toInterfaceContractId @Lifecycle.I <$> submit issuer do
    createCmd Replacement.Rule with
      providers = singleton issuer
      lifecycler = issuer
      observers = singleton publicParty
      id = Id "LifecycleRule"
      description = "Rule to lifecycle an instrument following a replacement event"

We also need a replacement event. For a 2-for-1 stock split, the adjustmentFactor is 1/2 = 0.5:

  -- Create stock split event
  replacementEventCid <-
    Instrument.submitExerciseInterfaceByKeyCmd @Equity.I [issuer] [] preEquityInstrument
      Equity.DeclareStockSplit with
        id = Id $ "APPL - " <> show now
        description = "Stocksplit"
        effectiveTime = now
        newInstrument = postEquityInstrument
        adjustmentFactor = 0.5

This allows the issuer to lifecycle the instrument:

  -- Lifecycle stock split
  (_, [effectCid]) <- submit issuer do
    exerciseCmd replacementRuleCid Lifecycle.Evolve with
      observableCids = []
      eventCid = replacementEventCid
      instrument = preEquityInstrument

This results in a lifecycle effect, which can be settled (similar to the dividend scenario above).

Reverse Stock Split

The stock split described above increases the number of shares available. Alternatively, a company may also decide to decrease the number of shares. This is referred to as reverse stock split or stock consolidation.

The DeclareStockSplit choice supports this as well. For example, for a 1-for-10 reverse split, modify the adjustmentFactor to 10/1 = 10.0 in the example above.

Merger

The merger scenario models the case when one company acquires another company and pays for it using its own shares. This is modeled using the DeclareReplacement choice, which also uses the Replacement Event (like the stock split scenario above). This is a mandatory exchange offer: no election is required (or possible) by the shareholder.

We start by defining the instrument before and after the merger. Shares of company ABC are being replaced by shares of company XYZ:

  mergingInstrument <- originateEquity merging merging "INST-1" "0" "ABC" pp now
  mergedInstrument <- originateEquity merged merged "INST-2" "0" "XYZ" pp now

We create a replacement rule for the merger:

  -- Create lifecycle rules
  replacementRuleCid <- toInterfaceContractId @Lifecycle.I <$> submit merging do
    createCmd Replacement.Rule with
      providers = singleton merging
      lifecycler = merging
      observers = singleton publicParty
      id = Id "LifecycleRule"
      description = "Rule to lifecycle an instrument following a replacement event"

We also need a replacement event. Two shares of ABC are replaced by one share of XYZ, so the factor used in perUnitReplacement is 0.5:

  -- Create replacement event
  -- perUnitReplacement is an arbitrary list of instruments, so the investor can also receive a
  -- combination of shares and cash.
  replacementEventCid <-
    Instrument.submitExerciseInterfaceByKeyCmd @Equity.I [merging] [] mergingInstrument
      Equity.DeclareReplacement with
        id = Id $ "ABC merge - " <> show now
        description = "Merge"
        effectiveTime = now
        perUnitReplacement = [qty 0.5 mergedInstrument]

This allows the issuer to lifecycle the instrument:

  -- Lifecycle replacement event
  (_, [effectCid]) <- submit merging do
    exerciseCmd replacementRuleCid Lifecycle.Evolve with
      eventCid = replacementEventCid
      observableCids = []
      instrument = mergingInstrument

This results in a lifecycle effect, which can be settled as usual.

Frequently Asked Questions

How do I transfer or trade an Equity?

When you have created a holding on an Equity instrument this can be transfered to another party. This is described in the Getting Started: Transfer tutorial.

In order to trade an Equity (transfer it in exchange for cash) you can also initiate a delivery versus payment with atomic settlement. This is described in the Getting Started: Settlement tutorial.

How do I process dividend payments for an Equity?

On the dividend payment date, the issuer will need to lifecycle the Equity. This will result in a lifecycle effect for the dividend, which can be cash settled. This is described in detail in the Lifecycling and the Intermediated Lifecycling tutorials (depending on what kind of settlement you need).