# Yields

Token holders receive periodic USDC coupon payments based on bond terms. Yields are calculated pro-rata from holder snapshots taken on the ICP Master Ledger and distributed via batched on-chain USDC transfers to verified wallets on Plume, Base, and Canton.


# Yield Distribution Flow

sequenceDiagram
    participant ASSET as Underlying Asset
    participant SPV as Luxembourg SPV
    participant PA as Paying Agent
    participant DW as Distribution Wallet
    participant ML as ICP Master Ledger
    participant CALC as Off-Chain Calculation
    participant EVM as EVM (Plume / Base / Canton)

    ASSET->>SPV: Cash flow received
    SPV->>PA: Funds transferred
    PA->>DW: USDC conversion

    DW->>ML: get_holder_snapshot(token_id, timestamp)
    ML-->>CALC: Holder balances at snapshot time

    CALC->>CALC: Calculate per-holder amounts
    CALC->>EVM: Submit batched USDC transfer

    EVM-->>DW: Transfer confirmation
    DW->>ML: Record YieldPayment transaction

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

# Snapshot Mechanism

# Record Date

At the scheduled distribution date, the ICP Master Ledger captures all verified token holders and their balances at a specific point in time. The snapshot resolves race conditions from transfers near the distribution date.

flowchart LR
    SCHEDULE[Scheduled Distribution Date] --> SNAPSHOT[ICP Master Ledger Snapshot]
    SNAPSHOT --> CALC[Calculate Per-Holder Amounts]
    CALC --> PAY[Batched USDC Transfer]

# 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;
};

# Multi-Chain Positions

If an investor holds tokens on multiple chains, distributions are sent to the wallet on the chain where the tokens are currently held. The Master Ledger maintains chain-specific positions.

flowchart TB
    subgraph "Holder A"
        PLUME_A[Plume: 50 tokens]
        BASE_A[Base: 30 tokens]
    end

    PLUME_A --> YIELD_PLUME[USDC to Plume wallet]
    BASE_A --> YIELD_BASE[USDC to Base wallet]

# Settlement Currency

USDC throughout: subscription, coupon distributions, and principal redemption. This eliminates fiat off-ramp friction for crypto-native investors while maintaining the regulated character of the underlying instrument.

Chain Stablecoin
Plume USDC
Base USDC
Canton USDC

# Distribution Execution

# Batched On-Chain Transfer

A batched USDC transfer transaction is constructed containing one transfer call per eligible holder: from the distribution wallet to each verified holder address. All eligible holders receive USDC in a single block. The distribution transaction hash is recorded in the ICP Master Ledger as a YieldPayment transaction for audit purposes.

# Distribution Schedule

Distributions are contractually scheduled per bond documentation (quarterly, semi-annual, or annual). The schedule is fixed at issuance and disclosed in the Pricing Supplement. No issuer discretion over timing.

# 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

# Distribution Record

type Distribution = record {
    id : DistributionId;
    token_id : TokenId;
    distribution_type : DistributionType;

    // Timing
    record_date : Timestamp;
    payment_date : Timestamp;
    completed_at : opt Timestamp;

    // Amounts
    total_amount : nat;
    currency : Text;                // "USDC"

    // Status
    status : DistributionStatus;
    total_recipients : nat32;
    successful_payments : nat32;
    failed_payments : nat32;
};

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;
};

# 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]
Scenario Resolution
Invalid address Holder updates address, distribution retried
Insufficient gas Retry with higher gas
Chain unavailable Queue for retry when chain recovers

For the full yield distribution architecture, see ../architecture/yield-distribution.md.