CapitalStack
Inherits: StateAware, Patchable, BoardControlled, ICapitalStack
Author: Daniel Yamagata & Naveen Ailawadi
A smart contract that lays out the logic for the capital stack of a company. The capital stack is the foundation for the mergers, acquistions, recapitalization, and liquidation of companies in the Mezzanine protocol A capital stack is made up of:
Seniority Levels
Assets
Each seniority level and asset is associated with an 'asset class'. An asset of a given class can be inserted into only one seniority level of the same class. There are three types of asset classes, defined by the following enum:
0: Null
1: Common Equity
2: Preferred Equity
3: Debt
A seniority level or asset with asset class 'Null' is considered invalid and cannot be added to the stack. Seniority levels must be added, such that a new seniority level's asset class cannot be below the previous's asset class and cannot exceed the next's asset class. For example, a seniority level of 'Common Equity' cannot be inserted above 'Debt' Here is a visual example:
Seniority levels are represented by a circular, doubly linked list. Their indexes are not assumed to be sequential
State Variables
CapitalStackStorageLocation
Functions
_getCapitalStackStorage
constructor
init
Initializes state, inserts a common equity seniority level, adds the common shares to the capital, and creates a document for the common shares in the document registry. Can only be called once
Called atomically by the MezzDeployer during the deployment of a Mezz Instance
Parameters
__CapitalStack_init
addSeniorityLevel
Adds a seniority level to the capital stack. Only callable by the company's board of directors, who are the signers of the treasury contract. Seniority levels in a capital stack follow specific rules in how they can be inserted: Each seniority level has an associated 'AssetClass' defined by the following enum:
0: Null
1: Common Equity
2: Preferred Equity
3: Debt
A seniority level cannot be inserted if the previous seniority level, associated with 'previousSeniorityLevelIndex', has a higher 'AssetClass' than the proposed seniority level. For example, a seniority level of Common Equity cannot be inserted above a seniority level of Preferred Equity. Once inserted, only assets of that given class can be added to the given seniority level. A Mezzanine company can insert seniority levels above or below seniority levels of the same asset class. For example, a seniority level of Preferred Equity can be inserted above or below another seniority level of Preferred Equity. A company may do this since these different levels may be treated differently during liquidation, recapitalization, etc. Seniority levels with new types of asset classes can be added easily via upgrades
Parameters
Returns
_addSeniorityLevel
Adding a seniority level has four cases:
(A) The list is empty. Should only be true during initialization
(B) An insertion at the front of the list
'previousSeniorityLevelIndex' is zero
(C) An insertion at the back of the list
The 'next' of 'previousSeniorityLevelIndex' is zero
(D) An insertion in the middle of the list
'previousSeniorityLevelIndex' is greater than zero but its 'next' is not equal to zero
The sentinel acts both as a header and a tail. The 'next' of the sentinel indicates the 'front' of the list while the 'previous' of the sentinel indicates the 'back' of the list Cases (A) and (D) are handled the same. Cases are handled differently to optimize for SSTOREs
_addToFrontOfSeniorityLevelList
Case (B): An insertion at the front of the list
_addToBackOfSeniorityLevelList
Case (C): An insertion at the back of the list
_addToMiddleOfSeniorityLevelList
Cases (A) and (D): An insertion in an empty list or in the middle of the list, respectively
removeSeniorityLevel
Removes a seniority level with 'seniorityLevelIndexToRemove' from the capital stack. Only callable by the company's board of directors, who are the signers of the Treasury. The seniority level must be empty, meaning it contains no assets.
Parameters
addAssetToSeniorityLevel
Adds an asset to a seniority level. Only callable by the company's board of directors, who are the signers of the Treasury The asset must have the same 'AssetClass' as the seniority level it is being added to. This function adds a document to the document registry that is associated with the asset. It can be updated at any time. An asset can only be part of one seniority level and cannot be moved retroactively to a different seniority level.
A treasury cannot call this function with its multi-sig functionality but instead must call the 'addAssetToCapitalStack' function
Parameters
Returns
_addAssetToSeniorityLevel
Adds an asset to the seniority level at 'seniorityLevelIndex' and creates a document for the asset
Returns
removeAsset
Removes an asset from the capital stack. Only callable by the company's board of directors, who are the signers of the Treasury. A company cannot remove their initial common shares from the capital stack. All Mezz assets must implement a 'removable()' function that returns a bool indicating the asset's removability upon certain conditions. For example, Mezz shares are not removable if their total supply is greater than zero. If the 'removable()' of 'assetToRemove' returns false, this function will revert
A treasury cannot call this function with its multi-sig functionality but instead must call the 'removeAssetFromCapitalStack' function
Parameters
updateAssetDocument
Updates an asset's document in the document registry
Returns
getSeniorityLevelInfo
Returns information regarding a seniority level as a 'DataTypes.SeniorityLevelInfo' struct
Returns an empty struct if the seniority level does not exist
getSeniorityLevels
Returns the seniority levels of the capital stack in ascending order as an array of 'DataTypes.SenioritylevelInfo' structs. For instance, the ith index of the return values would be considered below the ith + 1 index of the return values in the capital stack.
Seniority level indexes are non-sequential
getAssetsInSeniorityLevel
Returns the assets in the seniority level with 'seniorityLevelIndex' as an array of addresses
Returns an empty array of addresses if 'seniorityLevelIndex' does not exist
getSeniorityLevelIndexByAsset
Returns zero if the asset is not in the stack. Otherwise, returns the seniority level index for 'asset'
getNumberOfAssetsInSeniorityLevel
Returns the number of assets in the seniority level with 'seniorityLevelIndex'
Will also returns zero if the seniority level does not exist
isAssetInCapitalStack
Returns true if 'asset' is in the capital stack, false otherwise
totalSeniorityLevels
Returns the total number of seniority levels
getDocumentIndexByAsset
Returns the document index for 'asset'
Reverts if 'asset' is not in the stack
_validateAssetIsInStack
Reverts if 'asset' has not been added to the capital stack
_addDocumentForAsset
Creates a new document in the document registry, sets the '_documentIndexByAsset' mapping, and returns the document index
_incrementCurrentSeniorityLevelIndex
This function is kept as virtual in case overflow protection is desired in the future
_incrementSeniorityLevelsRemoved
This function is kept as virtual in case overflow protection is desired in the future
coreId
Returns the coreId of the implementation as a bytes32
The core ID is the keccak256 hash of the contract name followed by a version under the following syntax: "mezzanine.coreId.ContractName.vX" For example, the core ID of the 2nd version of the Treasury would be the following: keccak256(abi.encodePacked("mezzanine.coreId.Treasury.v2"))
version
Returns the version of the implementation as a uint256
supportsInterface
ERC165 support
upgradeToNewerVersion
Upgrades 'this' to a newer version via the Mezz Migrator. Only callable by the Treasury, whose signers are the board of directors
Will revert if the protocol state is 'Paused' or 'Frozen'
Parameters
_authorizePatch
Access control for 'resetToPatchedLatestVersion()'
Structs
CapitalStackStorage
Last updated