Skip to main content

States

Params​

Module parameters stored as a singleton. Contains the platform administrator address.

message Params {
string platform_admin = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}
  • platform_admin: The address authorised to register new depositories

DepositoryCounter​

A global sequence counter that auto-increments when new depositories are registered. Used to generate unique depository IDs.

Depositories​

A mapping from depository ID to the Depository object:

message Depository {
string id = 1;
string owner = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string pauser = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string region = 4;
bool paused = 5;
}
  • id: Unique identifier (auto-generated from counter)
  • owner: Address that can manage the depository (authorise issuers, update params)
  • pauser: Address that can pause/unpause the depository
  • region: Geographic region identifier
  • paused: Whether the depository is currently paused

AuthorizedIssuers​

A mapping from (depository_id, issuer) pair to boolean, tracking which issuers are authorised for each depository.

Key: (depository_id, issuer) → Value: bool (true = authorised)

GlobalNotes​

An indexed map storing Global Note data. Primary key is (isin, issuer):

// Internal storage format
message InternalGlobalNote {
string depository_id = 1;
string global_note_hash = 2;
string pt_denom = 3;
}

The full GlobalNote is assembled from InternalGlobalNote combined with data from PTDenom:

message GlobalNote {
Payload payload = 1;
VersionMetadata metadata = 2;
}

message Payload {
string isin = 1;
string depository_id = 2;
string issuer = 3;
string global_note_hash = 4;
string total_supply = 5 [(cosmos_proto.scalar) = "cosmos.Int"];
uint64 asset_type_id = 6;
string notarised_asset_id = 7;
}

Indexes:

  • Issuer: Reverse index allowing lookup of all Global Notes by issuer address

PTDenom​

A mapping from PT denom string to PTDenom metadata:

type PTDenom struct {
ISIN string
TotalSupply math.Int
}

The PT denom is compiled from asset information: pt/{asset_type_id}/{notarised_asset_id}

PTTransferability​

A mapping from PT denom to transferability settings. Keyed under prefix 6 (KeyPTTransferability):

message PtTransferability {
bool paused = 1;
reserved 2;
reserved "restrict_send";
}
  • paused: If true, all transfers of this PT denom are blocked (hard freeze)

Field 2 (formerly restrict_send) has been removed and is now reserved. Per-address permissions no longer live on this record; they are held in the separate PtSendRestriction records below.

PtSendRestriction​

Per-address transfer permissions for a single PT denom, keyed by (pt_denom, address) under prefix 11 (KeyPTSendRestrictions):

message PtSendRestriction {
string address = 1;
bool can_send = 2;
bool can_receive = 3;
}
  • address: The account these permissions apply to
  • can_send: Whether the address may send this PT denom
  • can_receive: Whether the address may receive this PT denom

These records follow a blocklist model: an address with no record may both send and receive. When a record is present, its can_send / can_receive flags are enforced. These are managed by the PT's issuer (see MsgSetPTTransferability / MsgSendAndSetTransferability).

Addresses are canonicalized to their lowercase Bech32 rendering before every read and write, so equivalent case encodings (Bech32 also accepts all-uppercase) always map to the same record.

DepositoryBlockList​

Per-depository block entries that apply across all PT denoms of a depository, keyed by (depository_id, address) under prefix 12 (KeyDepositoryBlockList):

message DepositoryBlockEntry {
string address = 1;
bool block_send = 2;
bool block_receive = 3;
}
  • address: The account being blocked
  • block_send: If true, the address cannot send any PT of the depository
  • block_receive: If true, the address cannot receive any PT of the depository

Managed by the depository owner (see MsgSetDepositoryBlockList). As with PtSendRestriction records, addresses are canonicalized to their lowercase Bech32 rendering before every read and write.

Transfer Enforcement​

Transfers are gated by the bank BlockBeforeSend hook (x/depository/keeper/before_send.go). For each coin in a send, the hook applies these layers in a deliberate order — when several layers would reject, the error cites the broadest one:

  1. Depository-module-account exemption: sends where either side is the depository module account are always allowed, so issuance distribution, redemption and surrender can never deadlock on pause/blocks/restrictions. (User MsgSend into the depository module account is separately rejected for every denom by the bank's blocked_module_accounts_override list in app.yaml.)
  2. Module-account quarantine: a PT send into any other module account is rejected. The recipient is classified by asking x/auth (GetAccount + ModuleAccountI assertion), so future modules are covered automatically. This layer is denom-aware on purpose — module accounts that accept the native denom (fee collectors, a future x/servicefee) keep doing so; only PTs are quarantined.
  3. Depository block list: owner-controlled, spanning all PTs of the depository. Resolving the depository needs the Global Note; only a genuine not-found means the denom is not a live PT and this layer does not apply. Any other lookup failure (dangling index, decode error) rejects the send — state corruption fails closed, never open.
  4. Paused flag: issuer-controlled hard freeze on the PT denom.
  5. Per-address restrictions: issuer-controlled blocklist; a missing record means unrestricted.

The native (bond) denom is skipped entirely. The Global Note is the single source of truth for "this is a PT": a denom with no backing note is not a depository concern and passes through untouched — unless it squats on the reserved PT namespace (PT-…/aPT-…), in which case it is an unbacked/spoofed PT and the send is rejected (fail closed).

EVM / ERC20 coverage​

Every PT also has an ERC20 face: a dynamic precompile at the denom-derived address (keccak256(baseDenom)[12:]), registered at issuance. ERC20 transfer/transferFrom calls on it move the same bank coins through SendCoins, so the BlockBeforeSend hook — and therefore every layer above — applies identically to EVM transfers. Addresses are one account in two encodings (eth_secp256k1 keys): a block list or restriction entry stored for dchain1… binds the same 20-byte account acting as 0x… through MetaMask. Note the layers match the bank sender/recipient of each hop: PT held inside a contract is sent by the contract's own address, so screening investors happens at distribution time, before tokens could reach a contract.

Vesting prohibition​

PT denoms can never be placed in vesting accounts: the ante handler (x/depository/ante) rejects MsgCreateVestingAccount, MsgCreatePermanentLockedAccount and MsgCreatePeriodicVestingAccount (including nested in authz.MsgExec) whose amount touches the reserved PT namespace. Vesting-locked coins are unspendable, and SurrenderGlobalNote must be able to pull every holder's full balance at any time — a single vesting-locked PT would make the surrender of the entire note fail.

LatestPtHolders​

Returned when a Global Note is surrendered, recording the final state of PT ownership:

message LatestPtHolders {
string isin = 1;
repeated PtHolder holders = 2;
}

message PtHolder {
string holder = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string amount = 2 [(cosmos_proto.scalar) = "cosmos.Int"];
}

This data is returned in the MsgSurrenderGlobalNoteResponse and can be used for off-chain settlement processes.

State Relationships​

Params
│
└── platform_admin ─────────────────────────────────────────┐
│
DepositoryCounter │
│ │
└── generates ──► Depository ◄── registered by ─────────────┘
│
├── owner ──► can authorise issuers
│
└── pauser ──► can pause/unpause
│
▼
AuthorisedIssuers
│
└── (depository_id, issuer) → bool
│
▼
GlobalNotes
│
├── InternalGlobalNote
│ └── pt_denom ──► PTDenom
│ │
│ └── ISIN ──► PTTransferability
│
└── indexed by Issuer

Storage Keys​

PrefixNameDescription
1KeyParamsModule parameters
2KeyDepositoriesDepository records
3KeyGlobalNotesGlobal Note records
4KeyAuthorisedIssuersIssuer authorisation mapping
5KeyDepositoryCounterAuto-increment counter
6KeyPTTransferabilityPT transfer controls
7KeyPtDenomPT denomination metadata
8KeyGlobalNotesByIssuerIndex: Global Notes by issuer
11KeyPTSendRestrictionsPer-address PT restrictions
12KeyDepositoryBlockListPer-depository block entries