# 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

Parameter Value
Bond Principal $10,000,000
Token Supply 10,000 tokens
Annual Coupon Rate 7.5%
Coupon Frequency Semi-annual
Holder Balance 100 tokens
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 receipt

Pros: 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 Yield

Pros: 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:

Chain Stablecoin Contract
ICP ckUSDC mxzaz-hqaaa-...
Ethereum USDC 0xA0b86991c...
Base USDC 0x833589fCD...
Solana USDC EPjFWdd5Au...

# 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)

Coupon Record Date Payment Date Status
1 2024-08-15 2024-08-22 Paid
2 2025-02-15 2025-02-22 Paid
3 2025-08-15 2025-08-22 Scheduled
4 2026-02-15 2026-02-22 Scheduled
5 2026-08-15 2026-08-22 Scheduled
6 2027-02-15 2027-02-22 Scheduled

# 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]

# Unclaimed Yields

Scenario Resolution
Invalid address Holder updates address, claims manually
Insufficient gas Retry with higher gas
Chain down Queue for retry
Holder never claims Escrow for N months, then return to issuer