Skip to main content

Fungible Assets

Overview

Fungible assets on Polymesh can represent any type of digitalised asset, and are originated and managed through the asset base layer logic in Polymesh.

This ensures that all assets are created in a standardised manner, allowing related functionality such as corporate actions, settlement and compliance, to function seamlessly across all assets.

Once an asset has been created, its ownership is represented via balances of that assets tokens held by different investors.

Ownership of an asset on Polymesh can be determined via its:

  • total supply: the total number of tokens that represent ownership in the asset

  • investor balances: the individual balance of each investing identity in the asset

The asset pallet documentation can be found at: https://docs.polymesh.live/pallet_asset/index.html

Polymesh allows you to manage the full lifecycle of any asset directly on the Polymesh blockchain, including the issuance, initial distribution or fund-raise of the asset and any subsequent corporate actions such as dividend payments, capital distributions or corporate ballots.

Asset tokens can be either divisible or indivisible.

Ticker Registration

Every asset on Polymesh has a unique ticker - a 12 character identifier for the asset.

Users can register a ticker, and then when they are ready create an asset associated with that registered ticker.

Ticker registrations can be transferred between identities and have an expiry date, currently set to 60 days from their initial registration.

Registering a ticker ensures no other user can issue an asset with that ticker whilst the registration is valid (i.e. has not expired), and has a protocol fee associated with it (currently 1000 POLYX).

Asset Creation

Having registered a ticker, users can then create their asset, specifying the type of the asset (e.g. Equity, Bond, Fund).

The asset is initially created with a zero total supply. For the initial issuance of the asset, see the Issuance section.

As well as being identified via a unique ticker, assets can be associated with additional external identifiers, such as ISINs, CUSIPs, CINs, LEIs and DTIs, with Polymesh validating that these identifiers are consistent (i.e. that their checksums match).

If a ticker is not currently reserved, the ticker registration is done automatically when a user creates an asset.

Documentation

Polymesh allows the issuer of an asset to associate documents with that asset.

The actual document is not stored on-chain, and instead the asset is associated with a document reference on-chain, where the reference includes a name, the URL at which the document can be found (this may be a permissioned URL requiring an investor in the asset to have some credentials to access the document), as well as an optional document type, filing date, and hash of the document contents.

Documentation can only be updated or modified by the identity that issued the corresponding asset (the asset issuer).

Ownership

All asset ownership in Polymesh is at the identity level. Whilst an investor can organise their assets into different portfolios under their identity, compliance is enforced at the identity level, so in order to send or receive a particular assets token, the relevant identity must have claims that match the compliance rules specified by the asset issuer for the asset.

Asset Issuers

The asset issuer is the identity which registered the ticker and created the asset. The asset issuer can transfer ownership of an asset to another identity by issuing a TransferAsset authorisation which must be accepted by the target identity.

The asset issuer also has some additional controls which are solely accessible to them. These include:

  • updating documentation and identifiers for their asset

  • freeze and unfreeze any transfers of their asset

  • add and remove compliance rules for their asset

  • permission venues to settle their asset

In addition an asset issuer can execute a controller transfer of their token. This allows them to force transfer ownership of their asset tokens from any investor back to the primary issuance agent of the asset. The primary issuance agent is an identity which an asset issuer specifies for their asset, and is responsible for treasury management and token distribution.

Issuance

The issuance process for assets in Polymesh allows the originator of an asset (the asset issuer) to issue and distribute their asset to investors.

Roles

Every asset, identified by its unique ticker, is associated with one or more identities:

  • the asset issuers identity: this is the identity that created the asset

  • external agents identities: these are the (optional) identities responsible for managing the asset on behalf of the issuer

External Agents

External agents are other Polymesh identities that have been granted permissions related to a particular ticker. Their role is to manage the asset on behalf of the asset issuer.

External agents can be added to an asset by the asset issuer (or an existing agent of the asset with appropriate permissions) by issuing a BecomeAgent authorisation. The external agent identity then needs to accept this authorisation.

Each external agent can be placed into a new or existing permission group, with permissions then derived from this group for all agents within it.

There are some pre-defined agent permission groups which are:

pub enum AgentGroup {
/// Has all permissions.
Full,
/// Custom defined agent group drawn from 2).
/// The other groups have hard-coded mappings to `Permissions` in code.
Custom(AGId),
/// Manages identities of agents themselves.
ExceptMeta,
/// Agent group corresponding to a Corporate Action Agent (CAA) on Polymesh Mainnet v1.
PolymeshV1CAA,
/// Agent group corresponding to a Primary Issuance Agent (PIA) on Polymesh Mainnet v1.
PolymeshV1PIA,
}

Alternatively an asset issuer can create a new agent permission group using the Custom enum variant, with whatever permissions are appropriate to their use-case, and then add external agents related to their asset to this group.

Process

Once an asset issuer has created and configured their asset, they can then issue tokens representing ownership in the asset to themselves or a distribution external agent of the asset.

The agent can then distribute those asset tokens to investors directly or via an security token offering, in both cases using the settlement engine.

This approach allows a clean separation between the issuance process, which bypasses both the compliance and settlement engine and is restricted to only issuance to the configured agents, and the distribution process which uses both the compliance and settlement engines.

Checkpoints

An asset checkpoint is a collection of records representing the balances of that asset at a given time. The balances recorded are the total asset balance and all the balances held by identities.

This is useful for capital distributions and corporate ballots where we need a consistent set of balances as of some specific time (or block).

Creating a checkpoint

There are two ways to create a checkpoint.

  1. Call the dispatchable create_checkpoint(ticker) in the checkpoint pallet. This creates a checkpoint for the asset of ticker. The total balance is recorded instantly, and each balance held by an identity is recorded just before the next transaction to or from that identity. Since the balances of identities are not recorded instantly, we call this process lazy checkpointing. A consequence of this method is that no records are made if there are no transactions.

  2. Create a checkpoint schedule using the dispatchable create_schedule(ticker, schedule) in the same pallet. A schedule consists of a set of Moment values. Scheduled checkpoints are created automatically at times defined by the schedule but are otherwise identical in nature to manual checkpoints. Scheduling of the next checkpoint happens lazily as well, on an asset transaction or minting. If there are no such transactions by the time a checkpoint is due, it does not get rescheduled, which is fine with the scheduler since it takes into account any missed checkpoints.

Accessing an existing checkpoint

The checkpoints of an asset form a sequence that is indexed starting from 1. The total balance and balances of identities are stored at these indices.

To read the total supply of ticker at checkpoint index i one calls the getter total_supply_at(ticker, i) in the asset pallet. The getter returns the value directly from runtime storage.

To read the checkpoint balance of identity one calls the function get_balance_at(ticker, identity, i) in the same pallet. This function returns the checkpoint balance at i by searching for the least checkpoint index greater or equal to i or, if no such record exists due to the absence of transactions, the current asset balance of identity.

The time at which a checkpoint was made is stored in a map indexed by checkpoint sequence numbers and can be read knowing the required sequence number.