#
Yields
Token holders receive periodic coupon payments based on bond terms. Yields are calculated pro-rata and distributed to all verified holders.
#
Yield Distribution Flow
sequenceDiagram
participant ISSUER as Issuer
participant YD as Yield Distributor
participant ML as Master Ledger
participant CF as Chain Fusion
participant HOLDERS as Token Holders
ISSUER->>YD: Trigger Distribution
YD->>ML: Get Holder Snapshot
ML-->>YD: Holder Balances
YD->>YD: Calculate Amounts
YD->>YD: Fund Distribution
loop For Each Holder
alt On ICP
YD->>ML: Transfer Yield
else On External Chain
YD->>CF: Request Transfer
CF->>CF: Execute Cross-chain
end
end
YD->>ML: Record Distribution
YD-->>ISSUER: Distribution Complete
#
Coupon Calculation
#
Formula
Holder Yield = (Holder Balance / Total Supply) × Total Coupon Amount
#
Example
Total Annual Coupon = $10,000,000 × 7.5% = $750,000
Semi-Annual Coupon = $750,000 / 2 = $375,000
Holder's Share = (100 / 10,000) × $375,000 = $3,750
#
Snapshot Mechanism
#
Record Date
Holder balances are captured at a specific point in time:
flowchart LR
ANNOUNCE[Announce Record Date] --> RECORD[Record Date]
RECORD --> SNAPSHOT[Capture Snapshot]
SNAPSHOT --> CALC[Calculate Yields]
CALC --> PAY[Payment Date]
#
Snapshot Data
type HolderSnapshot = record {
token_id : TokenId;
snapshot_time : Timestamp;
total_supply : nat;
holders : vec HolderBalance;
};
type HolderBalance = record {
principal : Principal;
balance : nat;
chain : Chain;
address : Text;
};
#
Cross-Chain Aggregation
Balances are aggregated across all chains:
flowchart TB
subgraph Holder A
ICP_A[ICP: 50 tokens]
BASE_A[Base: 30 tokens]
SOL_A[Solana: 20 tokens]
end
ICP_A & BASE_A & SOL_A --> TOTAL_A[Total: 100 tokens]
TOTAL_A --> YIELD_A[Yield Calculation]
#
Distribution Process
#
Step 1: Create Distribution
type CreateDistributionArgs = record {
token_id : TokenId;
record_date : Timestamp;
payment_date : Timestamp;
total_amount : nat;
currency : Text; // "USDC", "USDT", etc.
distribution_chain : Chain; // Where yields are paid
};
#
Step 2: Take Snapshot
sequenceDiagram
participant YD as Yield Distributor
participant ML as Master Ledger
YD->>ML: get_holder_snapshot(token_id, record_date)
ML->>ML: Query all balances at timestamp
ML->>ML: Aggregate cross-chain holdings
ML-->>YD: HolderSnapshot
#
Step 3: Calculate Amounts
type YieldCalculation = record {
holder : Principal;
balance : nat;
share_pct : float64; // e.g., 0.01 = 1%
yield_amount : nat;
destination_chain : Chain;
destination_address : Text;
};
#
Step 4: Execute Payments
flowchart TB
DIST[Distribution] --> FUND{Funded?}
FUND -->|No| WAIT[Wait for Funding]
FUND -->|Yes| BATCH[Batch by Chain]
BATCH --> ICP_PAY[ICP Payments]
BATCH --> EVM_PAY[EVM Payments]
BATCH --> SOL_PAY[Solana Payments]
ICP_PAY & EVM_PAY & SOL_PAY --> CONFIRM[Confirm All]
CONFIRM --> COMPLETE[Mark Complete]
#
Payment Methods
#
Push Model
Yields automatically sent to holders:
sequenceDiagram
participant YD as Yield Distributor
participant HOLDER as Holder Wallet
YD->>HOLDER: Transfer Yield
Note over HOLDER: Automatic receiptPros: No action required from holders Cons: Higher gas costs, address must be valid
#
Pull Model
Holders claim their yields:
sequenceDiagram
participant HOLDER as Holder
participant YD as Yield Distributor
HOLDER->>YD: claim(distribution_id)
YD->>YD: Verify eligibility
YD->>HOLDER: Transfer YieldPros: Lower gas costs, holder controls timing Cons: Requires holder action, unclaimed yields
#
Hybrid Model
Push for ICP, pull for external chains:
flowchart TB
YIELD[Yield Payment] --> CHAIN{Chain?}
CHAIN -->|ICP| PUSH[Auto Push]
CHAIN -->|External| PULL[Holder Claims]
#
Yield Currency
#
Stablecoin Payments
Yields are typically paid in stablecoins:
#
Currency Conversion
If bond yields are in fiat, conversion happens before distribution:
flowchart LR
FIAT[USD from Issuer] --> CONVERT[Convert to USDC]
CONVERT --> FUND[Fund Distribution]
FUND --> PAY[Pay Holders]
#
Distribution Record
type Distribution = record {
id : DistributionId;
token_id : TokenId;
distribution_type : DistributionType;
// Timing
record_date : Timestamp;
payment_date : Timestamp;
created_at : Timestamp;
completed_at : opt Timestamp;
// Amounts
total_amount : nat;
currency : Text;
amount_per_token : nat; // For reference
// Status
status : DistributionStatus;
total_recipients : nat32;
successful_payments : nat32;
failed_payments : nat32;
// Snapshot
snapshot_hash : Text; // IPFS hash of full snapshot
};
type DistributionType = variant {
Coupon : nat32; // Coupon number (1, 2, 3...)
Special; // One-time distribution
Final; // At maturity
};
type DistributionStatus = variant {
Scheduled;
SnapshotTaken;
Funded;
Processing;
Completed;
PartiallyCompleted;
Failed : Text;
};
#
Canister Interface
candid
service : {
// Create distribution (issuer only)
create_distribution : (CreateDistributionArgs) -> (Result<DistributionId, Error>);
// Take holder snapshot
take_snapshot : (DistributionId) -> (Result<HolderSnapshot, Error>);
// Fund distribution
fund_distribution : (DistributionId) -> (Result<(), Error>);
// Execute distribution
execute_distribution : (DistributionId) -> (Result<(), Error>);
// Query distributions
get_distribution : (DistributionId) -> (opt Distribution) query;
list_distributions : (TokenId) -> (vec Distribution) query;
// For pull model
get_claimable : (Principal) -> (vec ClaimableYield) query;
claim : (DistributionId) -> (Result<nat, Error>);
// Get yield history for holder
get_yield_history : (Principal, TokenId) -> (vec YieldPayment) query;
}
type ClaimableYield = record {
distribution_id : DistributionId;
token_id : TokenId;
amount : nat;
currency : Text;
expires_at : opt Timestamp;
};
type YieldPayment = record {
distribution_id : DistributionId;
amount : nat;
currency : Text;
paid_at : Timestamp;
tx_hash : opt Text;
};
#
Scheduling
#
Automatic Scheduling
Coupons are scheduled at token creation:
type CouponSchedule = record {
token_id : TokenId;
frequency : CouponFrequency;
first_coupon_date : Timestamp;
coupons : vec ScheduledCoupon;
};
type ScheduledCoupon = record {
coupon_number : nat32;
record_date : Timestamp;
payment_date : Timestamp;
status : CouponStatus;
};
type CouponStatus = variant {
Scheduled;
Triggered;
Paid;
Skipped;
};
#
Example Schedule (3-Year Bond, Semi-Annual)
#
Error Handling
#
Failed Payments
flowchart TB
PAY[Payment Attempt] --> RESULT{Success?}
RESULT -->|Yes| RECORD[Record Success]
RESULT -->|No| RETRY{Retries Left?}
RETRY -->|Yes| BACKOFF[Wait & Retry]
BACKOFF --> PAY
RETRY -->|No| FAIL[Mark Failed]
FAIL --> ESCROW[Hold in Escrow]
ESCROW --> MANUAL[Manual Resolution]