#
Distribution
Tokens are distributed from the issuer treasury to KYC-verified investors on their preferred live chain (Plume, Base, or Canton). Only wallets registered in the ERC-3643 Identity Registry — verified via SumSub and synchronized from the ICP KYC Registry — can receive tokens.
#
Distribution Flow
sequenceDiagram
participant INV as Investor
participant KYC as ICP KYC Registry
participant II as Issuer Interface
participant ML as Master Ledger
participant CF as Chain Fusion
participant EVM as EVM Chain (Plume / Base / Canton)
INV->>KYC: Complete KYC via SumSub
KYC-->>INV: Verified
INV->>II: Purchase Request (USDC)
II->>KYC: Verify Status
KYC-->>II: Verified
INV->>II: Select Target Chain
II->>ML: distribute(investor, amount, chain)
ML->>ML: Reserve from Treasury
ML->>CF: request_mint(investor, amount, chain)
CF->>EVM: Mint ERC-3643 Tokens
EVM-->>CF: Confirmed
CF->>ML: confirm_distribution
ML-->>INV: Tokens on selected chain
#
Investor Onboarding
#
KYC Verification
Before receiving tokens, investors must complete KYC/AML verification through SumSub:
flowchart TB
START[Start Onboarding] --> SUMSUB[SumSub Verification]
subgraph SumSub
DOC[Document Upload]
FACE[Liveness Check]
SOF[Source of Funds]
AML[Sanctions Screening]
end
SUMSUB --> DOC --> FACE --> SOF --> AML
AML --> RESULT{Approved?}
RESULT -->|Yes| BACKEND[Issuer Backend]
RESULT -->|No| REJECT[Rejected]
BACKEND --> KYC[ICP KYC Registry]
KYC --> CF[Chain Fusion]
CF --> ERC[ERC-3643 Identity Registry on EVM]
#
Investor Requirements
#
Chain Selection
Investors choose their preferred live chain for receiving tokens:
flowchart TB
INV[Investor] --> SELECT{Select Chain}
SELECT --> PLUME[Plume]
SELECT --> BASE[Base]
SELECT --> CANTON[Canton]
#
Chain Requirements
All chains use EVM-compatible addresses. The wallet must be registered in the ERC-3643 Identity Registry on the target chain before tokens can be received.
#
Distribution Process
Distribution involves Chain Fusion for cross-chain minting from the ICP Master Ledger:
sequenceDiagram
participant II as Issuer Interface
participant ML as Master Ledger
participant CF as Chain Fusion
participant EVM as EVM Chain
II->>ML: distribute(token, investor, amount, chain)
ML->>ML: Reserve tokens from treasury
ML->>CF: request_mint(...)
CF->>CF: Build ERC-3643 mint transaction
CF->>CF: Request threshold signature
CF->>EVM: Submit signed mint TX
EVM-->>CF: TX Hash
CF->>CF: Wait for finality
EVM-->>CF: Confirmed
CF->>ML: confirm_mint(request_id, tx_hash)
ML->>ML: Complete distribution
ML-->>II: Success
#
Distribution Types
#
Primary Distribution
Initial distribution to investors during the offering period. Subscription in USDC; ERC-3643 tokens delivered to verified wallet.
type PrimaryDistribution = record {
token_id : TokenId;
investor : Principal;
amount : nat;
target_chain : Chain;
target_address : Text;
purchase_price : nat; // In USDC
subscription_date : Timestamp;
};
#
Secondary Distribution
Issuer distributing from treasury after initial offering:
type SecondaryDistribution = record {
token_id : TokenId;
recipient : Principal;
amount : nat;
target_chain : Chain;
target_address : Text;
reason : DistributionReason;
};
type DistributionReason = variant {
AdditionalPurchase;
Replacement; // Lost wallet recovery
Transfer; // Internal transfer
};
#
Batch Distribution
For efficiency, multiple distributions can be batched per chain:
flowchart LR
BATCH[Batch Request] --> VALIDATE[Validate All]
VALIDATE --> GROUP[Group by Chain]
GROUP --> PLUME_BATCH[Plume Batch]
GROUP --> BASE_BATCH[Base Batch]
GROUP --> CANTON_BATCH[Canton Batch]
PLUME_BATCH --> EXEC1[Execute]
BASE_BATCH --> EXEC2[Execute]
CANTON_BATCH --> EXEC3[Execute]
#
Batch Request
type BatchDistributeArgs = record {
token_id : TokenId;
distributions : vec DistributionEntry;
};
type DistributionEntry = record {
recipient : Principal;
amount : nat;
target_chain : Chain;
target_address : Text;
};
#
Address Verification
Before distribution, addresses are verified against the ERC-3643 Identity Registry:
flowchart TB
ADDR[Recipient Address] --> CHECK1{Valid Format?}
CHECK1 -->|No| E1[Error: Invalid Format]
CHECK1 -->|Yes| CHECK2{Registered in Identity Registry?}
CHECK2 -->|No| E2[Error: Not Whitelisted]
CHECK2 -->|Yes| CHECK3{Matches KYC Principal?}
CHECK3 -->|No| E3[Error: Address Mismatch]
CHECK3 -->|Yes| OK[Proceed with Distribution]
#
Error Handling
#
Distribution Errors
type DistributionError = variant {
NotAuthorized;
TokenNotFound;
TokenNotActive;
InsufficientTreasury;
RecipientNotKyc;
InvalidAddress : Text;
ChainNotSupported;
AddressNotWhitelisted;
AmountTooLow;
AmountTooHigh;
ChainFusionError : Text;
InternalError : Text;
};
#
Retry Logic
flowchart TB
DIST[Distribution] --> SUBMIT[Submit to Chain]
SUBMIT --> RESULT{Success?}
RESULT -->|Yes| DONE[Complete]
RESULT -->|No| CHECK{Retryable?}
CHECK -->|Yes| RETRY[Retry with Backoff]
RETRY --> SUBMIT
CHECK -->|No| FAIL[Mark Failed]
FAIL --> REFUND[Refund Treasury]Failed distributions automatically refund the treasury reserve.