#
Distribution
Tokens are distributed from the issuer treasury to KYC-verified investors on their preferred blockchain.
#
Distribution Flow
sequenceDiagram
participant INV as Investor
participant KYC as KYC Registry
participant II as Issuer Interface
participant ML as Master Ledger
participant CF as Chain Fusion
participant EXT as External Chain
INV->>KYC: Complete KYC
KYC-->>INV: Verified
INV->>II: Purchase Request
II->>KYC: Verify Status
KYC-->>II: Verified
INV->>II: Select Target Chain
II->>ML: distribute(investor, amount, chain)
alt ICP Chain
ML->>ML: Transfer from Treasury
ML-->>INV: Tokens on ICP
else External Chain
ML->>ML: Reserve from Treasury
ML->>CF: request_mint(investor, amount, chain)
CF->>EXT: Mint Tokens
EXT-->>CF: Confirmed
CF->>ML: confirm_distribution
ML-->>INV: Tokens on External Chain
end
#
Investor Onboarding
#
KYC Verification
Before receiving tokens, investors must complete KYC:
flowchart TB
START[Start Onboarding] --> SUMSUB[Sumsub Verification]
subgraph Sumsub
DOC[Document Upload]
FACE[Facial Recognition]
AML[AML Screening]
end
SUMSUB --> DOC --> FACE --> AML
AML --> RESULT{Approved?}
RESULT -->|Yes| BIND[Bind to Principal]
RESULT -->|No| REJECT[Rejected]
BIND --> ELIGIBLE[Eligible for Distribution]
#
KYC Levels
#
Chain Selection
Investors choose their preferred chain for receiving tokens:
flowchart TB
INV[Investor] --> SELECT{Select Chain}
SELECT --> ICP[Internet Computer]
SELECT --> EVM[EVM Chain]
SELECT --> SOL[Solana]
SELECT --> COSM[Cosmos]
EVM --> ETH[Ethereum]
EVM --> BASE[Base]
EVM --> ARB[Arbitrum]
COSM --> OSMO[Osmosis]
#
Chain Requirements
#
Distribution Process
#
On ICP
Direct transfer from issuer treasury:
sequenceDiagram
participant II as Issuer Interface
participant ML as Master Ledger
participant INV as Investor
II->>ML: distribute(token, investor, amount)
ML->>ML: Check treasury balance
ML->>ML: Verify investor KYC
ML->>ML: Debit treasury
ML->>ML: Credit investor
ML->>ML: Record transaction
ML-->>II: Transaction ID
Note over INV: Balance updated
#
On External Chains
Involves Chain Fusion for cross-chain minting:
sequenceDiagram
participant II as Issuer Interface
participant ML as Master Ledger
participant CF as Chain Fusion
participant EXT as External Chain
II->>ML: distribute(token, investor, amount, chain)
ML->>ML: Reserve tokens
ML->>CF: request_mint(...)
CF->>CF: Build transaction
CF->>CF: Threshold signature
CF->>EXT: Submit mint TX
EXT-->>CF: TX Hash
CF->>CF: Wait for finality
EXT-->>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 offering period:
type PrimaryDistribution = record {
token_id : TokenId;
investor : Principal;
amount : nat;
target_chain : Chain;
target_address : Text;
purchase_price : nat; // In settlement currency
purchase_currency : Text; // e.g., "USD", "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
Promotional; // Marketing allocation
};
#
Batch Distribution
For efficiency, multiple distributions can be batched:
flowchart LR
BATCH[Batch Request] --> VALIDATE[Validate All]
VALIDATE --> GROUP[Group by Chain]
GROUP --> ICP_BATCH[ICP Batch]
GROUP --> EVM_BATCH[EVM Batch]
GROUP --> SOL_BATCH[Solana Batch]
ICP_BATCH --> EXEC1[Execute]
EVM_BATCH --> EXEC2[Execute]
SOL_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;
};
#
Batch Limits
#
Address Verification
Before distribution, addresses are verified:
flowchart TB
ADDR[Recipient Address] --> CHECK1{Valid Format?}
CHECK1 -->|No| E1[Error: Invalid Format]
CHECK1 -->|Yes| CHECK2{Not Blacklisted?}
CHECK2 -->|No| E2[Error: Blocked Address]
CHECK2 -->|Yes| CHECK3{Matches KYC Principal?}
CHECK3 -->|No| E3[Error: Address Mismatch]
CHECK3 -->|Yes| OK[Proceed]
#
Address Binding
Investors can register addresses for each chain:
candid
service : {
// Register address for a chain
register_address : (Chain, Text) -> (Result<(), Error>);
// Get registered addresses
get_addresses : () -> (vec AddressBinding) query;
// Verify address ownership (for EVM, sign message)
verify_address : (Chain, Text, blob) -> (Result<(), Error>);
}
type AddressBinding = record {
chain : Chain;
address : Text;
verified : bool;
registered_at : Timestamp;
};
#
Distribution Tracking
#
Transaction Record
type DistributionRecord = record {
id : TransactionId;
token_id : TokenId;
from : Principal; // Treasury
to : Principal; // Investor
amount : nat;
target_chain : Chain;
target_address : Text;
status : DistributionStatus;
created_at : Timestamp;
completed_at : opt Timestamp;
external_tx_hash : opt Text;
};
type DistributionStatus = variant {
Pending;
Processing;
Confirmed;
Failed : Text;
};
#
Query Interface
candid
service : {
// Get distribution by ID
get_distribution : (TransactionId) -> (opt DistributionRecord) query;
// List distributions for a token
list_distributions : (TokenId, Pagination) -> (vec DistributionRecord) query;
// List distributions for an investor
get_my_distributions : (Pagination) -> (vec DistributionRecord) query;
}
#
Error Handling
#
Distribution Errors
type DistributionError = variant {
NotAuthorized;
TokenNotFound;
TokenNotActive;
InsufficientTreasury;
RecipientNotKyc;
InvalidAddress : Text;
ChainNotSupported;
AddressBlocked;
AddressNotVerified;
AmountTooLow;
AmountTooHigh;
RateLimitExceeded;
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.
#
Events
type DistributionEvent = variant {
Initiated : record {
distribution_id : TransactionId;
token_id : TokenId;
recipient : Principal;
amount : nat;
target_chain : Chain;
timestamp : Timestamp;
};
Completed : record {
distribution_id : TransactionId;
external_tx_hash : opt Text;
timestamp : Timestamp;
};
Failed : record {
distribution_id : TransactionId;
reason : Text;
timestamp : Timestamp;
};
};