In the lifecycle of publicly traded companies, e.g., stocks in ACME Inc., there are what is known as corporate actions (CAs). Examples of these include dividend payments, stock splits, and ballot for the annual general meeting (AGM).
Assuming ACME has been digitized as an asset through that pallet, Polymesh can manage some types of CAs as well for you.
This is handled through three pallets:
- Corporate Actions, which is the base layer handling setups, CA initiation, documents linking, and removal.
- Ballots, through which corporate ballots for AGMs can be conducted.
- Capital Distributions, through which benefits, e.g., dividends, can be distributed to investors.
Now let's dig into the details!
Initiating a corporate action
All CAs start with
initiate_corporate_action, a dispatchable function that creates a CA.
When creating the CA, the associated asset's ticker, free-form text, and the CA kind, e.g., a notice or a benefit need to be provided.
A declaration date should also be provided when initiating a corporate action. This is the date that the corporate action was declared, and should be earlier than both the record date, and the time when the corporate action is initiated on-chain.
Additionally, a record date, withholding taxes, and the targets of the CA can be specified.
For more on those, read on.
Corporate Action Agent (CAA)
The function must be called by the asset's corporate action agent (CAA). By default, the CAA is the asset's owner. Using the authorization system, this can be changed, assigning someone else as CAA.
When the owner is not CAA, they can no longer initiate CAs, tweak the setup, ballots, distributions, or related functionality. Who the CAA is can be reset, however, using the dispatchable
Record Dates & Checkpoints
Supposing that ACME is traded frequently, it would be difficult to know the entitlement of each investor in a distribution, or how much voting power each holder can use in an ballot. To provide these services with stable reference points, the CA pallet uses checkpoints to determine an investor's balance and the total supply. For CAs, the checkpoint used is known as the record date, and is specified when creating the CA.
A record date can be specified in one of three ways:
- By providing an existing checkpoint, created in the past.
- Specifying a scheduled time at which a checkpoint should be created.
- Providing an existing irremovable schedule.
Once a CA has been initiated, assuming the services attached to the CA, such as a ballot or a distribution, permit, the record date can still be changed using the dispatchable
Some CAs have taxable components. Chief among them are dividends, where the investor receives income by holding the asset. In some jurisdictions, it is the responsibility of the issuer, or the CAA to deduct tax from any dividends and send it to the relevant government. For example, if ACME is based in Sweden, 20% tax would apply.
Polymesh can handle this withholding tax natively, allowing you to specify how many % that should be withheld. This % can either be specified generally for all investors (the default withholding tax), or customized to specific individual investors (DID-specific withholding tax).
When the same taxes are used over and over again for many CAs, the process can be simplified by specifying asset level defaults. This is achieved using
set_did_withholding_tax, where the former is general and the latter is DID-specific.
By default, a CA for some asset will apply to, or target, every investor holding any asset balance. Sometimes however, for whatever reason, some identities must be excluded from the target set. When creating a CA, the target set can either be specified inclusively, or alternatively, a set of identities can be excluded explicitly. As with taxes, an asset level default can also be set, using
Where the free-form text is insufficient, or existing documentation relevant for the CA already exists, asset documentation can instead be linked to the CA. Supposing that both a CA and asset documents already exist, they can be related using
link_ca_doc, linking the CA to a list of documents.
Polymesh can do more than merely record CAs on-chain. A capital distribution, such as paying a dividend to investors, can also be handled natively. Once CA of the predictable or unpredictable benefit kind has been created, the dispatchable
distribute, in the capital distributions pallet, is used to attach a distribution to the CA.
distribute, the CA, an amount of a currency to distribute from a portfolio of the CAA, and the start / expiry dates of the distribution, are specified.
Once a distribution exists, and the start time is due, investors can use
claim before any expiry date to pull their benefit to their default portfolio. However, the CAA, or the owner, can also use
push_benefit to push benefits to investors. Once the distribution has expired, the distribution creator can
reclaim any remaining balance.
Before a distribution has started, it can also be cancelled, using
Polymesh can also handle ballots on-chain. For example, a corporation's annual general meeting can be conducted using ballots.
A ballot has a start and end date, during which investors can vote on motions included in the ballot. These motions in turn are associated with descriptions and links to more information.
More importantly, however, motions contain choices, e.g., a) "aye", b) "aye with X amendment", and c) "nay", to which weights can be assigned. These weights or votes are based on how many tokens each investor holds. For example, an investor with 200 tokens will have 200 votes and one with 100 tokens has 100. Those 200 votes could be assigned like so: a) 50, b) 150, c) 0.
Motions are independent of each other. For example, consider a vote on who should be in the board of directors, and a motion to discharge the old board from liability. These would be independent, and therefore, all 200 tokens can be reused on each motion.
Optionally, a ballot can be configured with ranked-choice voting (RCV). This allows voters to specify that the weight, assigned to a choice not making it, should fall back to a different choice. For example, consider 3 choices paired with weights:
- a) 49 votes, no fallback
- b) 100 votes, fallback to a)
- c) 120 votes, no fallback.
In this case, c) initially has most weight assigned to it. However, once a) has been discarded, the 49 votes it would move over to b), which now has 149 votes in total. Therefore, b) becomes the adopted choice.
Now let's go over how a ballot can be made, tweaked, and voted on. Once a CA of the notice kind has been created, the a ballot can be attached using
attach_ballot. This function will take the aforementioned details such as the motion data.
After the ballot has been created, but before voting has started, the ballot's configuration may be amended, in 3 ways:
change_endto change when no more votes will be accepted,
change_metato change the title and the motions,
change_rcvto change whether RCV is supported or not.
Moreover, before the start, the ballot can be removed using
Once the start date is due, any token holder can use
vote to assign votes to all choices. Investors can vote as many times as they want, regretting their choices, until the end is due.