Open-Cap-Table-Coalition / Open-Cap-Format-OCF

Open Cap Format (OCF) - The Open Source Company Capitalization Data Standard. OCF can be used to structure and track the complex data structures necessary to build and maintain accurate capitalization (cap) tables.
https://opencaptablecoalition.com
Other
143 stars 28 forks source link

[Enhancement]: Updating the vesting terms object to allow programmatic generation of vesting schedules with cliffs #514

Open arthur-clara opened 4 weeks ago

arthur-clara commented 4 weeks ago

Description of Enhancement :

Update the schema of the vesting_conditions object to include a variable called cliff_condition which references another vesting_condition and add an additional value to the trigger.type variable called CLIFF_CONDITION

Why is this Needed?

The current implementation of vesting_conditions is based on a linear branched flow through the next_condition_ids array. In the example below you would resolve the vesting start date condition then move to the cliff condition and then to the recurring vesting period condition. The problem emerges when we try to generate an actual vesting schedule from this process and determine the quantity of shares for each vesting period.

Using our classic example of 18 shares over four months, what is the number of shares that would be given at a 2 month cliff? Is it 9 shares or is it 8 shares or is it 10 shares? All three are possible depending on the allocation type. If allocation_type is CUMULATIVE_ROUNDING or CUMULATIVE_ROUNDDOWN the cliff quantity would be 9 shares. If allocation_type is BACK_LOADED or BACK_LOADED_TO_SINGLE_TRANCHE, it would be 8 shares. If allocation_type is FRONT_LOADED or FRONT_LOADED_TO_SINGLE_TRANCHE, it would be 10 shares.

With the current implementation, you need to skip over the cliff_condition and calculate the monthly_vesting_condition first and then know to go back to the cliff_condition and apply it. There is no way I can see that a system would be able to do this because there is nothing specifically signposting the cliff_condition as the cliff of the monthly_vesting_condition

The new proposed implementation is an attempt to solve it.

CURRENT IMPLEMENTATION OF VESTING CONDITIONS

{
    "id": "f58fa866-be71-4d79-b52a-ea5379a71551",
    "object_type": "VESTING_TERMS",
    "name": "Four Month / Two Month Cliff",
    "description": "50% of the total number of shares shall vest on the two-month anniversary of this Agreement, and an additional 1/4th of the total number of Shares shall then vest on the corresponding day of each month thereafter, until all of the Shares have been released on the fourth anniversary of this Agreement.",
    "allocation_type": "CUMULATIVE_ROUNDING",
    "vesting_conditions": [
        {
            "id": "start_condition",
            "quantity": "0",
            "trigger": {
                "type": "VESTING_START_DATE"
            },
            "next_condition_ids": ["cliff_condition"]
        },
        {
            "id": "cliff_condition",
            "description": "50% payout at 2 month",
            "portion": {
                "numerator": "2",
                "denominator": "4"
            },
            "trigger": {
                "type": "VESTING_SCHEDULE_RELATIVE",
                "period": {
                    "length": 2,
                    "type": "MONTHS",
                    "occurrences": 1,
                    "day_of_month": "VESTING_START_DAY_OR_LAST_DAY_OF_MONTH"
                },
                "relative_to_condition_id": "start_condition"
            },
            "next_condition_ids": ["monthly_vesting_condition"]
        },
        {
            "id": "monthly_vesting_condition",
            "description": "1/4 payout each month thereafter",
            "portion": {
                "numerator": "1",
                "denominator": "4"
            },
            "trigger": {
                "type": "VESTING_SCHEDULE_RELATIVE",
                "period": {
                    "length": 1,
                    "type": "MONTHS",
                    "occurrences": 2,
                    "day_of_month": "VESTING_START_DAY_OR_LAST_DAY_OF_MONTH"
                },
                "relative_to_condition_id": "cliff_condition"
            },
            "next_condition_ids": []
        }
    ]
}

PROPOSED IMPLEMENTATION

Essentially, we want to be able to signpost conditions as cliffs related to specific relative vesting conditions. The following implementation would provide systems the ability to track and calculate cliffs. Here is the above example vesting terms in the proposed implementation.

{
        "id": "four_month_monthly_two_month_cliff_cumulative_round_down",
        "object_type": "VESTING_TERMS",
        "name": "Four Month / Two Month Cliff - Cumulative Round Down",
         "description": "50% of the total number of shares shall vest on the two-month anniversary of this Agreement, and an additional 1/4th of the total number of Shares shall then vest on the corresponding day of each month thereafter, until all of the Shares have been released on the fourth anniversary of this Agreement.",
        "allocation_type": "CUMULATIVE_ROUND_DOWN",
        "vesting_conditions": [
            {
                "id": "start_condition",
                "portion": {
                "numerator": "0",
                "denominator": "4"
            },              "trigger": {
                    "type": "VESTING_START_DATE"
                },
                "next_condition_ids": ["monthly_vesting_condition"]
            },
            {
                "id": "monthly_vesting_condition",
                "description": "1/4 payout each month",
                "portion": {
                    "numerator": "1",
                    "denominator": "4"
                },
                "trigger": {
                    "type": "VESTING_SCHEDULE_RELATIVE",
                    "period": {
                        "length": 1,
                        "type": "MONTHS",
                        "occurrences": 4,
                        "day_of_month": "VESTING_START_DAY_OR_LAST_DAY_OF_MONTH"
                    },
                    "relative_to_condition_id": "start_condition"
                },
                "cliff_condition": "cliff_condition",
                "next_condition_ids": []
            },
            {
                "id": "cliff_condition",
                "description": "Cliff payout at 2nd month",
                "trigger": {
                    "type": "CLIFF_CONDITION",
                    "period": {
                        "type": "MONTHS",
                        "length": 2
                    },                        
                    "relative_to_condition_id": "monthly_vesting_condition"
                }
            }
        ]
    }

In this implementation, we point from the start_condition directly to the monthly_vesting_condition which is used to calculate the vesting period without a cliff as an intermediate step. The monthly_vesting_condition has a new optional cliff_condition variable which points the system to a cliff condition if required. The cliff_condition object has a description of the cliff with its unique type of trigger and the duration of the cliff. The cliff condition would be used to roll up the appropriate vesting periods into a single vesting period with the correct quantity based on the allocation_type.

JSv4 commented 4 weeks ago

@arthur-clara, @sachin-shrestha and @JSv4 to discuss.

MattCantor commented 3 weeks ago

I think the description of the vesting schedule in this example should be "50% of the total number of shares shall vest on the two-month anniversary of this Agreement the vesting start date, and an additional 1/4th of the total number of Shares shall then vest on the corresponding day of each month thereafter, until all of the Shares have been released on the fourth four-month anniversary of this Agreement the vesting start date"