telegram-private-transfer Solana program (97FzQdWi26mFNR21AbQNg4KqofiCLqQydQfAvRQMcXhV) combined with MagicBlock Private Ephemeral Rollups (PER) — an ephemeral runtime that runs inside a Trusted Execution Environment (Intel TDX) for privacy-preserving execution.
The flow spans two execution domains:
- Base Solana — initialize deposits, fund the vault, create permissions, verify Telegram identity.
- MagicBlock PER — execute private balance updates (transfers, claims) with sub-second latency inside TEE.
- Commit back to base — undelegate to finalize PER state on the base chain.
Lifecycle Diagram
Source of Truth
| Component | Location |
|---|---|
| Private transfer program | programs/telegram-private-transfer/src/lib.rs |
| Telegram session verification | programs/telegram-verification/src/lib.rs |
| SDK client | sdk/private-transactions/src/LoyalPrivateTransactionsClient.ts |
| Shield/unshield test | sdk/private-transactions/tests/private-transactions-shield.test.ts |
On-Chain Data Structures
Deposit
Per-user, per-token account storing a balance number. Seeds:["deposit_v2", user_pubkey, token_mint].
amount). This separation is what enables private execution: delegated deposits can be updated inside PER by simply incrementing/decrementing amount, without moving actual tokens on-chain.
UsernameDeposit
Same concept, but keyed by Telegram username instead of wallet address. Seeds:["username_deposit_v2", username_bytes, token_mint].
Deposit via a transfer instruction. The recipient proves ownership of the username through on-chain Telegram session verification, then claims to their own Deposit.
Vault
Per-token custody account that holds actual SPL tokens. Seeds:["vault", token_mint].
modify_balance(increase=true), tokens transfer from the user’s token account to the vault’s associated token account. On withdrawal, tokens move back. The vault’s total balance always equals the sum of all deposit amounts for that token mint.
Program Instructions
| Instruction | Layer | Purpose |
|---|---|---|
initialize_deposit | Base | Create a deposit account (no-op if exists) |
initialize_username_deposit | Base | Create a username deposit account with validation |
modify_balance | Base | Deposit (increase=true) or withdraw (increase=false) real tokens to/from vault |
create_permission | Base | Create PER access control for a deposit |
create_username_permission | Base | Create PER access control for a username deposit (requires verified session) |
delegate | Base | Delegate deposit ownership to MagicBlock for PER execution |
delegate_username_deposit | Base | Delegate username deposit to PER |
transfer_deposit | PER | Transfer balance between two user deposits (accounting only) |
transfer_to_username_deposit | PER | Transfer from user deposit to username deposit (accounting only) |
claim_username_deposit_to_deposit | PER | Claim from username deposit to user deposit (requires verified Telegram session) |
undelegate | PER | Commit and return deposit ownership to the program |
undelegate_username_deposit | PER | Commit and return username deposit to the program |
Shield / Unshield Flow
The SDK and tests use “shield” and “unshield” terminology for moving tokens in and out of the private layer.Shield (wallet → private deposit)
initializeDeposit— create the deposit account if it doesn’t exist- Wrap SOL → wSOL if using native SOL
modifyBalance(increase=true)— transfer tokens from user’s ATA to vault, increment deposit amountcreatePermission— set up PER access control (idempotent)delegateDeposit— delegate to the TEE validator, moving the account into PER
Unshield (private deposit → wallet)
undelegateDeposit— commit PER state and return ownership to the program on base layermodifyBalance(increase=false)— transfer tokens from vault back to user’s ATA- Unwrap wSOL → SOL if native
- Re-delegate remaining balance if any (keeps non-withdrawn funds private)
Private transfers (while shielded)
All transfer operations happen on delegated accounts inside PER:- By address:
transferDeposit— moves balance between two user deposits - By username:
transferToUsernameDeposit— moves balance to a username deposit - Claim:
claimUsernameDepositToDeposit— recipient proves Telegram identity and claims to their deposit
amount fields — no actual token movement occurs until unshield.
MagicBlock PER Integration
Why PER?
Standard Solana accounts are fully public — anyone can read balances and trace transfers. PER runs a Solana-compatible validator inside Intel TDX (Trusted Execution Environment), providing:- Privacy: only users with granted permissions can read account state
- Speed: sub-second latency for balance updates
- Composability: same Solana program instructions, no bridges or new tokens
- Auditability: committed state lands back on base Solana
Delegation
When delegated, the deposit account’s owner changes from the program to the MagicBlock delegation program. The SDK enforces this invariant:- Base-only operations (
modifyBalance,createPermission) require the account to be not delegated - PER operations (
transferDeposit,transferToUsernameDeposit,claimUsernameDepositToDeposit) require the account to be delegated
Permissions
PER uses access control to determine who can see and interact with delegated accounts. The program creates permission PDAs via CPI to the ephemeral rollups access control program:create_permission— grants the deposit owner exclusive read/write accesscreate_username_permission— grants access to the username deposit for a verified Telegram session holder
AUTHORITY, TX_LOGS, TX_BALANCES, TX_MESSAGE, ACCOUNT_SIGNATURES.
Telegram Verification
Username claims require cryptographic proof of Telegram identity. This is handled by the separatetelegram-verification program (9yiphKYd4b69tR1ZPP8rNwtMeUwWgjYXaXdEzyNziNhz):
- Store — user submits Telegram MiniApp validation bytes to a
tg_session_v2PDA - Verify — program checks Ed25519 signature against Telegram’s public key, marks session as
verified
claim_username_deposit_to_deposit instruction then validates:
- The session is verified (
verified == true) - The session’s
user_walletmatches the claiming wallet - The session’s
usernamematches the username deposit
Why This Model
- Privacy-preserving execution — transfer logic runs inside TEE while delegated, invisible to external observers
- Auditable settlement — committed state lands back on base Solana accounts, verifiable by anyone
- Identity-gated claims — Telegram session verification controls username claim rights
- No token mixing — vault accounting ensures each user gets exactly their tokens back
- Composable — standard Anchor program, same instructions work on base and PER layers

