#
Minting
Token minting creates the on-chain representation of a bond on the Internet Computer master ledger.
#
Minting Flow
sequenceDiagram
participant ISSUER as Issuer
participant II as Issuer Interface
participant ML as Master Ledger
participant STORE as Metadata Store
ISSUER->>II: Create Token Request
II->>II: Validate Issuer Auth
II->>ML: create_token(params)
ML->>ML: Validate Parameters
ML->>ML: Generate Token ID
ML->>STORE: Store Metadata
ML->>ML: Mint Initial Supply
ML->>ML: Assign to Issuer Treasury
ML-->>II: Token Created
II-->>ISSUER: Token ID + Details
#
Token Creation
#
Create Token Request
type CreateTokenArgs = record {
// Bond identification
isin : Text;
name : Text;
symbol : Text;
// Token parameters
total_supply : nat;
decimals : nat8;
// Bond metadata
bond_metadata : BondMetadata;
// Compliance
transfer_restrictions : TransferRestrictions;
};
type BondMetadata = record {
issuer_name : Text;
issuer_id : Text;
maturity_date : Timestamp;
coupon_rate_bps : nat16; // Basis points
coupon_frequency : CouponFrequency;
collateral_type : Text;
collateral_location : Text;
prospectus_hash : Text; // IPFS hash
legal_docs_hash : Text; // IPFS hash
};
type TransferRestrictions = record {
kyc_required : bool;
lock_period : opt Duration;
max_holders : opt nat32;
geographic_restrictions : vec Text;
};
#
Token ID Generation
Token IDs are deterministically generated from the ISIN:
Token ID = SHA256(ISIN || Canister ID || Timestamp)
= "trtg_ch1234567890_a1b2c3..."
#
Token Data Model
#
On-Chain Token Record
type Token = record {
// Identity
id : TokenId;
isin : Text;
name : Text;
symbol : Text;
// Supply
total_supply : nat;
circulating_supply : nat;
decimals : nat8;
// Metadata
bond_metadata : BondMetadata;
// State
status : TokenStatus;
created_at : Timestamp;
created_by : Principal;
// Compliance
transfer_restrictions : TransferRestrictions;
// Treasury
treasury_balance : nat;
};
type TokenStatus = variant {
Pending; // Created but not yet active
Active; // Trading enabled
Suspended; // Trading halted
Matured; // Past maturity date
Redeemed; // Fully redeemed
};
#
Initial State
After minting, the token is in this state:
#
Metadata Storage
#
On-Chain vs Off-Chain
flowchart TB
subgraph On-Chain (Master Ledger)
ID[Token ID]
ISIN[ISIN]
SUPPLY[Supply Info]
STATUS[Status]
HASHES[Document Hashes]
end
subgraph Off-Chain (IPFS)
PROSPECTUS[Prospectus PDF]
LEGAL[Legal Documents]
IMAGES[Property Images]
REPORTS[Valuation Reports]
end
HASHES --> PROSPECTUS
HASHES --> LEGAL
HASHES --> IMAGES
HASHES --> REPORTS
#
IPFS Document Structure
{
"version": "1.0",
"isin": "CH1234567890",
"documents": {
"prospectus": {
"hash": "QmProspectusHash...",
"name": "Prospectus_TRTG-DR1.pdf",
"size": 2048576
},
"term_sheet": {
"hash": "QmTermSheetHash...",
"name": "TermSheet_TRTG-DR1.pdf",
"size": 524288
},
"valuation": {
"hash": "QmValuationHash...",
"name": "Valuation_Report.pdf",
"size": 1048576
}
},
"collateral": {
"type": "commercial_real_estate",
"location": "Dominican Republic",
"description": "Land development project",
"images": [
"QmImage1...",
"QmImage2..."
]
}
}
#
Validation Rules
#
Pre-Mint Validation
flowchart TB
REQ[Create Token Request] --> V1{Valid ISIN?}
V1 -->|No| E1[Error: Invalid ISIN]
V1 -->|Yes| V2{ISIN Unique?}
V2 -->|No| E2[Error: ISIN Exists]
V2 -->|Yes| V3{Valid Symbol?}
V3 -->|No| E3[Error: Invalid Symbol]
V3 -->|Yes| V4{Valid Supply?}
V4 -->|No| E4[Error: Invalid Supply]
V4 -->|Yes| V5{Valid Metadata?}
V5 -->|No| E5[Error: Invalid Metadata]
V5 -->|Yes| MINT[Proceed with Minting]
#
Validation Checks
#
Issuer Treasury
After minting, all tokens are held in the issuer's treasury:
flowchart LR
MINT[Mint 10,000 Tokens] --> TREASURY[Issuer Treasury]
TREASURY --> DIST1[Distribution to Investor A]
TREASURY --> DIST2[Distribution to Investor B]
TREASURY --> DIST3[Distribution to Investor C]
#
Treasury Operations
candid
service : {
// Get treasury balance
treasury_balance : (TokenId) -> (nat) query;
// Distribute from treasury (issuer only)
distribute : (DistributeArgs) -> (Result<TransactionId, Error>);
// Return to treasury (issuer only, for buybacks)
return_to_treasury : (ReturnArgs) -> (Result<TransactionId, Error>);
}
type DistributeArgs = record {
token_id : TokenId;
recipient : Principal;
amount : nat;
memo : opt Text;
};
#
Token Activation
After minting, the token must be activated before trading:
sequenceDiagram
participant ISSUER as Issuer
participant ML as Master Ledger
participant GOV as Governance
Note over ISSUER,GOV: Token in Pending state
ISSUER->>ML: activate_token(token_id)
ML->>ML: Verify all metadata present
ML->>ML: Verify collateral docs
ML->>GOV: Log activation
ML->>ML: Set status = Active
ML-->>ISSUER: Token Activated
Note over ISSUER,GOV: Trading now enabled
#
Activation Checklist
Before activation:
- All metadata fields populated
- Document hashes verified
- Collateral documentation complete
- Issuer treasury funded
- Compliance review passed
#
Canister Interface
#
Token Creation
candid
service : {
// Create new token (issuer only)
create_token : (CreateTokenArgs) -> (Result<TokenId, Error>);
// Activate token for trading (issuer only)
activate_token : (TokenId) -> (Result<(), Error>);
// Get token details
get_token : (TokenId) -> (opt Token) query;
// List all tokens
list_tokens : (opt TokenStatus) -> (vec Token) query;
// Update metadata (issuer only, limited fields)
update_metadata : (TokenId, MetadataUpdate) -> (Result<(), Error>);
}
#
Error Types
type MintError = variant {
NotAuthorized;
InvalidIsin : Text;
IsinAlreadyExists;
InvalidSymbol : Text;
InvalidSupply;
InvalidMetadata : Text;
InvalidDocumentHash : Text;
MaturityInPast;
InternalError : Text;
};
#
Events
Token creation emits events for indexing and auditing:
type TokenEvent = variant {
Created : record {
token_id : TokenId;
isin : Text;
symbol : Text;
total_supply : nat;
created_by : Principal;
timestamp : Timestamp;
};
Activated : record {
token_id : TokenId;
activated_by : Principal;
timestamp : Timestamp;
};
MetadataUpdated : record {
token_id : TokenId;
updated_by : Principal;
fields : vec Text;
timestamp : Timestamp;
};
};