Skip to content

Latest commit

 

History

History

ex-20200802-safe-events

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Learning Exercise: SAFE Event Definitions

LegalRuleML would call these “Constitutive Rules” – an X counts as a Y for purposes of P under conditions C.

Source Text

From the “Cap and Discount” SAFE

reformatted slightly for org

Equity Financing

“Equity Financing” means a bona fide transaction or series of transactions with the principal purpose of raising capital, pursuant to which the Company issues and sells Preferred Stock at a fixed valuation, including but not limited to, a pre-money or post-money valuation.

Quibbles

Let’s go on a hunt for ambiguity! Imagine a scenario in which each transaction in the series issues and sells Preferred stock at a known valuation that is different to the valuation for every other transaction. Would you consider the “fixed valuation” criterion to be met?

If the subject of the sentence is “a series of transactions” then one could argue that within the series, the valuation is anything but fixed: it wibble-wobbles up and down with each transaction.

If the subject of the sentence is “a [bona fide] transaction”, then the valuation is fixed for that valuation.

In practice, this problem would not arise, because in a financing round, stock is always issued at the same price within that round. For certain values of “always”…

Dissolution Event

“Dissolution Event” means

  1. a voluntary termination of operations,
  2. a general assignment for the benefit of the Company’s creditors or
  3. any other liquidation, dissolution or winding up of the Company (excluding a Liquidity Event), whether voluntary or involuntary.

Liquidity Event

“Liquidity Event” means a Change of Control, a Direct Listing or an Initial Public Offering.

Change of Control

“Change of Control” means

  1. a transaction or series of related transactions in which any “person” or “group” (within the meaning of Section 13(d) and 14(d) of the Securities Exchange Act of 1934, as amended), becomes the “beneficial owner” (as defined in Rule 13d-3 under the Securities Exchange Act of 1934, as amended), directly or indirectly, of more than 50% of the outstanding voting securities of the Company having the right to vote for the election of members of the Company’s board of directors,
  2. any reorganization, merger or consolidation of the Company, other than a transaction or series of related transactions in which the holders of the voting securities of the Company outstanding immediately prior to such transaction or series of related transactions retain, immediately after such transaction or series of related transactions, at least a majority of the total voting power represented by the outstanding voting securities of the Company or such other surviving or resulting entity or
  3. a sale, lease or other disposition of all or substantially all of the assets of the Company.

Direct Listing

“Direct Listing” means the Company’s initial listing of its Common Stock (other than shares of Common Stock not eligible for resale under Rule 144 under the Securities Act) on a national securities exchange by means of an effective registration statement on Form S-1 filed by the Company with the SEC that registers shares of existing capital stock of the Company for resale, as approved by the Company’s board of directors. For the avoidance of doubt, a Direct Listing shall not be deemed to be an underwritten offering and shall not involve any underwriting services.

Initial Public Offering

“Initial Public Offering” means the closing of the Company’s first firm commitment underwritten initial public offering of Common Stock pursuant to a registration statement filed under the Securities Act.

Other Events?

The SAFE is notable for its absence of a repayment term.

From other SAFEs

do the other three SAFEs define the above events differently?

DMN representations

as MD

Fbonafidearityprincipal purposepursuant : predisEquityFinancing
1TRUEsingle, seriesraising capitalef_p(Company)TRUE
2----FALSE
Fissuessellssecurityvaluationval_p_p_oef_p_conditions
ordinarypre_money
preferredpost_money
debtother
safe
warrant
1truetruepreferredfixed-TRUE

as XML

Could someone please create and upload some XML .dmn files generated by a third-party modeling tool e.g. Camunda?

Interpretation

A plain reading suggests that the domain of discourse includes the following Things:

  • transactions
  • purposes, which attach to transactions
  • actions which are taken pursuant to transactions
  • valuations can be fixed or not fixed
  • fixed valuations can be pre- or post-money, or other

Adding some world knowledge, which should be generally agreed by anyone with some experience in corporate lawyering:

  • a transaction is embodied in the form of an agreement
  • agreements specify actions
  • actions include issuing and selling stock
  • preferred stock is one possible kind of stock
  • an agreement has two or more parties
  • in a preferred stock issue all the terms are substantially the same, especially the price per share

as Prolog

We start off by mapping each column of the decision table to its own Prolog predicate. This is a “dumb” process of syntax-level symbol manipulation.

isEquityFinancing(TxnGroup) :-
    bonafide_OK(TxnGroup, true),
    arity_OK(TxnGroup, [single, series]),
    pp_OK(TxnGroup, "raising capital"),
    pursuant_OK(TxnGroup).

The “smarter” layer of semantics come next. Some of these semantics are generalizable and could end up in a shared library.

%% predicates testing the transaction group as a whole

bonafide_OK(TG, X) :- TG.bonafide = X.
arity_OK(TG, [single|Xs]) :- (length(TG.txns,L), L = 1) ; arity_OK(TG, Xs).
arity_OK(TG, [series|Xs]) :- (length(TG.txns,L), L > 1) ; arity_OK(TG, Xs).
pp_OK(TG, X) :- attrMatch(TG, principalPurpose, X).

We use SWI-Prolog’s dict system to represent records; others may think of these are primitive objects.

%% utils

attrMatch(Object, Attr, Val) :- Object.Attr = Val.

The “pursuant” column links out to the agreements. It operates over an aggregate of agreements.

In this interpretation, all the agreements have to meet the requirements, for the aggregate to pass.

One could imagine another interpretation: if any agreeement meets the requirements, the aggregate will pass.

The following stanza repeats the pattern from above: first we do a syntactic mapping of column value to predicate, then we match the predicate against the specific agreement.

%% the "pursuant" thing means we have to test agreements in the aggregate
pursuant_OK(TG) :- maplist([Ag]>>agreement_OK(Ag), TG.txns).

agreement_OK(Ag) :- issues_OK(Ag,    true),
                    sells_OK(Ag,     true),
                    security_OK(Ag,  preferred),
                    valuation_OK(Ag, fixed).

%% the following predicates test individual agreements

issues_OK(   Agreement, X) :- attrMatch(Agreement, issues,   X).
sells_OK(    Agreement, X) :- attrMatch(Agreement, sells,    X).
security_OK( Agreement, X) :- attrMatch(Agreement, security, X).
valuation_OK(Agreement, X) :- attrMatch(Agreement, valuation, X).

Now we have the vocabulary to set up a few tests:

setup1(txngroup{bonafide:true,
                principalPurpose:"raising capital",
                txns: [ agreement{ parties:  [acme, rich],
                                   issues:    true,
                                   sells:     true,
                                   security:  preferred,
                                   valuation: fixed,
                                   val_ppo:   pre_money } ] }).

setup1b(TG1b) :- setup1(TG1), TG1b = TG1.put([principalPurpose:"evading taxes"]).

setup0(txngroup{bonafide:true,
                principalPurpose:"raising capital",
                txns: [ ] }).

And run them:

?- setup1(My), isEquityFinancing(My).
My = txngroup{bonafide:true, principalPurpose:"raising capital", txns:[agreement{issues:true, parties:[acme, rich], security:preferred, sells:true, val_ppo:pre_money, valuation:fixed}]} .

?- setup1b(My), isEquityFinancing(My).
false.

?- setup0(My), isEquityFinancing(My).
false.

How to interpret the results: the first is true, the others are false.

it would be nice to add explainability

In Haskell

To make this easier to think about, let’s set up a couple of concrete parties, Acme the company and Richard the investor.

acme = Party "Acme Inc." $ fromList (
  ["address" .= MyString "1 Monopoly Way"
  ,"state"   .= MyString "DE"
  ,"country" .= MyString "US"
  ,"bank"    .= MyString "WellsCitiChartered"
  ,"acct"    .= MyString "123-45-6789"])

rich = Party "Richard Moneybags III" $ fromList (
  ["address" .= MyString "1 Capitalist Way"
  ,"state"   .= MyString "NV"
  ,"country" .= MyString "US"
  ,"bank"    .= MyString "StandardFargoBank"
  ,"acct"    .= MyString "888-444-666"])
x .= y = (x,y)

A typical investment agreement will specify that the investor transfers funds to a certain bank account, and the company issues some kind of security.

transferFunds :: MyYMD -> Party -> Int -> String -> Clause
transferFunds closingDate investor amount dest =
  MkCl { name       = "transfer funds"
       , conditions = []
       , upon       = (Just closingDate, EvName "closing")
       , parties    = [investor]
       , deontic    = Must
       , actions    = [MkAct "transfer funds"
         (fromList [("currency",    MyString "USD")
                   ,("amount",      MyInt    amount)
                   ,("destination", MyString dest)])]
       , temporal   = T_Rel 3 (T_Event (EvName "closing"))
  }

There are many types of securities. Here we know the company will issue Preferred Stock:

issuePreferred :: Party -> Party -> Int -> Clause
issuePreferred company investor numShares =
  MkCl { name       = "issue shares"
       , conditions = [] -- always
       , upon       = (Nothing, GreenLight)
       , parties    = [company]
       , deontic    = Must
       , actions    = [MkAct "issue shares"
                      (fromList [("issues",          MyBool True)
                                ,("sells",           MyBool True)
                                ,("security",        MyString "preferred")
                                ,("valuation_fixed", MyBool True)
                                ,("val_p_p_o",       MyString "pre_money")
                                ,("numShares",       MyInt numShares)
                                ])]
       , temporal   = T_Rel 5 (T_Event (EvName "closing"))
       }

Note that we needed to wrap those actions in the appropriate deontic temporal modals, so we used the Clause type above.

Now we have enough to set up an entire set of transactions, each one embodied in a specific agreement between two parties:

mktxns :: Party -> [(Party,Int)] -> MyYMD -> Float -> [Transaction]
mktxns company investorAmounts closingDate pricepershare = do
  (investor,amount) <- investorAmounts
  let investorSendsMoney  = transferFunds closingDate investor amount (unwords $ mystr <$> [attrsc company ! k | k <- [ "bank", "acct" ] ])
      companyIssuesShares = issuePreferred company investor (floor (fromIntegral amount / pricepershare))
  return $
    -- a transaction is an agreement between the parties: company and investor
    MkTxn [company,investor]
    -- the state graph of the contract. you may consider this a finite state machine.
    (investorSendsMoney
      `hence` (companyIssuesShares
                `hence` fulfilled
                `lest`  breach)
      `lest`  breach)
-- the "hence" and "lest" bits basically mean "then" and "else"
-- see section 2.3 of Hvitved https://drive.google.com/file/d/1sLmVMZqHhQDzj8dikKt-8CNemF-nGCn1/view?usp=sharing
-- together, "hence" and "lest" construct a tree of clauses:
--       Node investorSendsMoney [ Node Breach [],
--                                 Node companyIssuesShare [ Node Breach [], Node Fulfilled [] ] ]
-- in which the first element is "what if the clause fails" and the second element is "what if the clause succeeds, then control passes to ..."

-- this agreement is an example of a declarative specification, and contains enough information for a PGF component to generate English:

--     "When in the course of human events on the date of closing the
--     aforesaid Investor pays the Correct Sum, being 100,000 Dollars,
--     then immediately and without delaye the Company shall issue
--     five hundred Shares of Preferred Stock and if it should fail to
--     do so within five days the Company shall be in BREACHE!."

We set up a transaction between the company Acme and the investor Richie Moneybags:

mytxns = mktxns acme [(rich,100000)] (2020,1,2) 10.0

The definition of an Equity Financing is phrased as a constitutive rule, in which transactions appear to be imbued with purpose and other attributes. No problem: https://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering says “We can solve any problem by introducing an extra level of indirection.” So let’s imbue some underlying thing with attributes:

data Imbued a = Imbued { underlying :: a
                       , attrs      :: Map String MyParamVal }

We characterize the series of transactions accordingly.

myFinancing1 = Imbued mytxns $ fromList
  [ ("bona fide",          MyBool True)
  , ("arity",              MyInt (length mytxns))
  , ("principal purpose",  MyString "raising capital")
  ]

All our ducks are now in a row; we can express the constitutive rule as a predicate upon the imbued object, where the constituent agreements must meet a certain set of criteria.

-- a thing is an Equity Financing if ...
isEF :: Imbued [Transaction] -> Bool
isEF im = and [ attrs im ! "bona fide"                        == MyBool True
              , myint (attrs im ! "arity")                    >= 1
              , attrs im ! "principal purpose"                == MyString "raising capital"
              , allActionVal "issue shares" "issues"          (== MyBool True)
              , allActionVal "issue shares" "sells"           (== MyBool True)
              , allActionVal "issue shares" "security"        (== MyString "preferred")
              , allActionVal "issue shares" "valuation_fixed" (== MyBool True)
              , allActionVal "issue shares" "val_p_p_o"       (`elem` [MyString x | x <- ["pre_money", "post_money", "other"]])
              ]
  where allActionVal n k p = -- the list comprehension below unwraps a seven-layer burrito. well, maybe five.
          all p $ [ params a ! k | txn                        <- underlying im
                                 , MkCl { actions = actions } <- flatten (getAgreement txn)
                                 , a                          <- actions
                                 , a.name == n -- we filter for the desired action name
                                 ]

-- todo: consider hxt's arrowlist approach to tree traversal and matching with >>>

To test “issues”, we match against the agreement graph, looking for some clause which specifies the issuance of shares.

We do the same with “sells”, but in a more sophisticated version of this code, we might test for consideration being exchanged on both sides. So we could match against the agreement graph, looking for some clause which specifies the transfer of Funds, and an immediate parent or child which specifies the transfer of some other valuable object.

And now we are in position to run a test!

describe "equity financing" $ do
  it "should consider the transactions to be an equity financing" $
    isEF myFinancing1 `shouldBe` True

If you’re curious about how the types fit together:

data EventBody = EvName String
               | GreenLight -- once the light turns green i.e. the clause is "entered"
               | NoticeReceived String (Maybe Party)
               deriving (Show, Eq)

-- every node has two children.
-- tail is the happy path, to which "execution" proceeds if the node is performed satisfactorily
-- head is the unhappy path.
type Agreement = Tree Clause

-- TODO: devise a monadic notation to make this even more readable as an EDSL
-- this syntax allows us to say x `hence` y `lest` z
infixr 7 `hence`
infixr 7 `lest`
x `hence` yz = Node x yz
y `lest`  z  = [ z, y ]

data Party = Party { name :: String
  , attrsc :: (Map String MyParamVal)
  } deriving (Show, Eq)
data Transaction = MkTxn [Party] Agreement
getAgreement (MkTxn ps a) = a

type MyYMD = (Integer, Int, Int)
type Event = (Maybe MyYMD, EventBody)
data Deontic = Must | May | Shant deriving (Show, Eq)

data State = World { date :: MyYMD
                   , history :: [Event]
                   } deriving (Show, Eq)
type ActionParams = Map String MyParamVal
data MyParamVal = MyString String
                | MyBool   Bool
                | MyInt    Int
                | MyChar   Char
                | MyList   [MyParamVal]
                deriving (Show, Eq)
mystr  (MyString x) = x
mybool (MyBool   x) = x
myint  (MyInt    x) = x
mychar (MyChar   x) = x
mylist (MyList   x) = x
data Action = MkAct { name   :: String
                    , params :: ActionParams }
            deriving (Show, Eq)

-- todo: expand this to the fuller set of DMN temporal predicates
data Temporal = T_Before MyYMD
              | T_After  MyYMD
              | T_Event  EventBody -- how to scope a relative event reference?
              | T_Rel    Days Temporal
              deriving (Show, Eq)
type Days = Int

data Clause = MkCl { name       ::  String
                   , conditions :: [State]
                   , upon       ::  Event
                   , parties    :: [Party]
                   , deontic    ::  Deontic
                   , actions    :: [Action]
                   , temporal   ::  Temporal
                   }
            | Fulfilled
            | Breach
  deriving (Show, Eq)
fulfilled = Node Fulfilled []
breach    = Node Breach []
getName MkCl { name = n } = n
getName Fulfilled         = "Fulfilled"
getName Breach            = "Breach"

A handful of utility functions…

  • visualize the contract as a graph of clauses
asDAG :: Transaction -> String
asDAG (MkTxn parties agreement) = unlines [ unwords ( "Parties:" : ( ( name :: Party->String ) <$> parties ) )
                                          , drawVerticalTree ( getName <$> agreement ) ]

Let’s use our main executable app to just print the tree

main = mapM_ putStrLn $ asDAG <$> underlying myFinancing1

Success! The left child is the non-performance path, and the right child is the performance path.

mengwong@venice4 events % stack exec events-exe
Parties: Acme Inc. Richard Moneybags III
      transfer funds
            |
   -------------
  /             \
Breach     issue shares
                |
           ---------
          /         \
        Breach  Fulfilled

NLG representations

See also https://github.com/smucclaw/nlg

let eng = lang gr
let action = translateAction gr $ issueSharesEasy 10
describe "natural language generation" $ do
  it "should turn a GF structure into English" $
    linearize gr eng (gf action) `shouldBe` "issues and sells preferred stock at a pre-money fixed valuation"

NLG assistance

Where do we locate the clues that help GF say the right thing?

Infrastructure

The following blobs of code help with the tangle/noweb auto-generation of Haskell code from this README.

-- DO NOT EDIT THIS FILE!
-- direct edits will be clobbered.
--
-- this file is autogenerated by tangling ex-20200802-safe-events/README.org
-- open the README.org in emacs and hit C-c C-v t to regenerate this file.

Test Driven Development!

{-# LANGUAGE OverloadedStrings, DuplicateRecordFields, QuasiQuotes #-}
{-# OPTIONS_GHC -F -pgmF=record-dot-preprocessor #-}

<<tangleWarning>>

module Main where

import Test.Hspec
import Data.Maybe
import Data.Map
import Control.Monad
import SAFE.Events
import PGF
import SAFE.NLG
import Grammars.SAFE
import Data.Tree
import Data.Tree.Pretty
import Control.Arrow
import Debug.Trace

main :: IO ()
main = do
  gr <- readPGF "src/grammars/SAFE.pgf"
  forM_ [spec1, spec2 gr] $ hspec
  return ()

<<test-setup>>

spec1 :: Spec
spec1 = do
  <<test-1>>

spec2 :: PGF -> Spec
spec2 gr = do
  <<test-2>>

Executable

{-# LANGUAGE OverloadedStrings, DuplicateRecordFields, QuasiQuotes #-}
{-# OPTIONS_GHC -F -pgmF=record-dot-preprocessor #-}

<<tangleWarning>>

module Main where

import SAFE.Events
import Data.Map
import Data.Tree

<<test-setup>>
<<exe>>

The library

{-# LANGUAGE OverloadedStrings, DuplicateRecordFields, QuasiQuotes, LambdaCase #-}
{-# OPTIONS_GHC -F -pgmF=record-dot-preprocessor #-}

<<tangleWarning>>

module SAFE.Events where
import Data.Map
import Data.Maybe
import Data.Tree
import Data.Tree.Pretty

<<basictypes>>
<<basicimplementation>>
:- use_module(library(clpq)).
:- use_module(library(yall)).
<<prolog>>