Поставка против платежа (DvP) — это метод расчётов по ценным бумагам, который гарантирует, что передача ценных бумаг происходит одновременно с передачей платежа. Это устраняет риск контрагента, обеспечивая атомарное исполнение обеих частей транзакции — либо обе выполняются, либо ни одна.
Проблема
Когда вы покупаете облигации (например, коммерческие бумаги), традиционно необходимо, чтобы произошли два события:
- Вы отправляете деньги → Продавцу
- Продавец отправляет облигации → Вам
Если эти события происходят раздельно, возникает риск — что если вы заплатили, но так и не получили облигации? Или наоборот?
Решение
(DvP) «Поставка против платежа» означает, что обе передачи происходят в один и тот же момент, либо не происходит ни одной. Это похоже на своп, где обе стороны обмениваются одновременно.
┌─────────────────────────────────────────────────────┐│ ONE ATOMIC TRANSACTION │├─────────────────────────────────────────────────────┤│ ││ Investor ──── $95,000 USDC ────→ Issuer ││ ││ Issuer ─────── 100 Bonds ──────→ Investor ││ ││ ✅ Both happen together, or neither happens ││ │└─────────────────────────────────────────────────────┘
Это руководство демонстрирует, как реализовать полный рабочий процесс DvP на Solana с использованием расширений SPL Token 2022 для выпуска соответствующих требованиям облигаций и стандартного USDC для расчётов — без написания кастомных программ на Rust.
Учебная эталонная реализация
Вы можете использовать исходный код этой реализации, чтобы попробовать DvP локально.
Это руководство предоставляет эталонную реализацию исключительно в ознакомительных и образовательных целях. НЕ используйте этот код напрямую в продакшене без:
- Комплексного аудита безопасности
- Надлежащих систем управления ключами
- Проверки соответствия нормативным требованиям
- Юридической консультации
- Всестороннего тестирования и доработки
Почему Solana для DvP?
Архитектура Solana предоставляет значительные преимущества по сравнению с традиционными системами расчётов по ценным бумагам:
| Аспект | Традиционный (T+2) | Solana |
|---|---|---|
| Логика расчётов | Клиринговые палаты | Атомарная упаковка транзакций |
| Время расчётов | 2 дня | <1 секунды |
| Стоимость транзакции | $50–500 | <$0.01 |
| Риск контрагента | Высокий (посредники) | Нулевой (атомарное исполнение) |
| Финальность | Конец дня | ~400 мс |
Атомарная упаковка транзакций Solana устраняет посредников, обеспечивая мгновенные, дешёвые и безопасные расчёты.
Обзор архитектуры
Система DvP состоит из следующих основных компонентов:
- Токен облигации (коммерческая бумага): SPL Token 2022 с Token Extensions
- Расчётная валюта: Стандартный USDC (существующий SPL-токен)
- Расчётный агент: Оркестрирует атомарные свопы через делегированные полномочия
- Система белого списка: Контролирует, какие адреса могут держать облигации
Ключевые принципы проектирования
- Без кастомных программ: Использует только Token Extensions Program и стандартный USDC
- Атомарные расчёты: Единая транзакция гарантирует, что обе передачи завершатся успешно или потерпят неудачу вместе
- Заморозка по умолчанию: Облигации требуют явного добавления в белый список для соответствия нормативным требованиям
- Делегированные полномочия: Расчётный агент координирует действия, не принимая активы в хранение
- Коммуникация через состояние сети: Прямое API-подключение точка-точка не требуется
┌─────────────────────────────────────────────────────┐│ DvP Settlement Flow │├─────────────────────────────────────────────────────┤│ ││ 1. Bond Creation (Token-2022 + Extensions) ││ └─> Default State: FROZEN ││ └─> Freeze Authority: Settlement Agent/Issuer ││ └─> Token metadata: Bond information ││ ││ 2. Whitelist Participants ││ └─> Whitelist issuer, mint bonds ││ └─> Whitelist investor for trading ││ ││ 3. Delegate Authority to settlement agent ││ ├─> Issuer delegates bonds ││ └─> Investor delegates USDC ││ ││ 4. Atomic Settlement ││ ├─> Transfer bonds: Issuer → Investor ││ └─> Transfer USDC: Investor → Issuer ││ (Both or neither - atomic) ││ │└─────────────────────────────────────────────────────┘
Доверенная сторона, оркестрирующая сделку. Обе стороны делегируют полномочия расчётному агенту, который затем исполняет атомарный своп.
┌─────────┐ delegates ┌──────────────────┐ delegates ┌──────────┐│ Issuer │ ─────────────────→ │ Settlement Agent │ ←──────────────── │ Investor │└─────────┘ (bonds) │ (trusted) │ (USDC) └──────────┘│ ││ executes atomic ││ transaction │└──────────────────┘
Токен облигации с Token Extensions
SPL Token 2022 предоставляет мощные расширения, позволяющие выпускать соответствующие требованиям ценные бумаги без кастомных программ:
Необходимые расширения для облигаций
- Расширение Default Account State: Устанавливает все новые token account в состояние «заморожен» по умолчанию, требуя явного добавления в белый список
- Расширение метаданных: Хранит детали облигации в блокчейне (ISIN, дата погашения, купонная ставка и т.д.)
- Постоянный делегат (опционально): Разрешает авторизованное восстановление или изъятие актива, если этого требует регулирование
Конфигурация полномочий
- Mint Authority: Эмитент (управляет созданием предложения)
- Freeze Authority: Расчётный агент (управляет белым списком)
- Update Authority: Расчётный агент (может обновлять метаданные)
Состояние заморозки по умолчанию критически важно для соответствия нормативным требованиям. Оно гарантирует, что только явно добавленные в белый список адреса могут получать и держать ценные бумаги, выполняя требования KYC/AML.
Полная реализация DvP
Настройка движка DvP
Сначала создайте основной класс движка DvP, который обрабатывает все операции:
import {Connection,Keypair,PublicKey,Transaction,SystemProgram,sendAndConfirmTransaction,LAMPORTS_PER_SOL} from "@solana/web3.js";import {approve,thawAccount,freezeAccount,getAccount,getAssociatedTokenAddress,getOrCreateAssociatedTokenAccount,createTransferCheckedInstruction,TOKEN_2022_PROGRAM_ID,TOKEN_PROGRAM_ID,ExtensionType,getMintLen,createInitializeMintInstruction,createInitializeDefaultAccountStateInstruction,createInitializeMetadataPointerInstruction,AccountState,LENGTH_SIZE,TYPE_SIZE} from "@solana/spl-token";import {pack,createInitializeInstruction,createUpdateFieldInstruction,type TokenMetadata} from "@solana/spl-token-metadata";interface BondTokenConfig {name: string;symbol: string;decimals: number;maturityDate: Date;couponRate: number;isin?: string;description?: string;}interface DvPParams {bondMint: PublicKey;usdcMint: PublicKey;bondAmount: number;usdcAmount: number;issuer: PublicKey;investor: PublicKey;}interface DvPResult {signature: string;bondAmount: number;usdcAmount: number;timestamp: Date;bondsSent: boolean;usdcReceived: boolean;}/*** DvP Engine - Reference Implementation** This implementation demonstrates Delivery vs Payment (DvP) on Solana using:* - SPL Token 2022 with Default Account State extension for bonds* - Standard USDC for settlement* - Atomic transactions for settlement* - Delegated authority pattern for settlement agent** ⚠️ IMPORTANT: This is a reference implementation for educational purposes.* Do NOT use in production without proper audits and security reviews.*/export class DvPEngine {private connection: Connection;private settlementAgent: Keypair;constructor(connection: Connection, settlementAgent: Keypair) {this.connection = connection;this.settlementAgent = settlementAgent;}/*** Creates a bond token using Token-2022 with Default Account State and Metadata extensions* Bonds are frozen by default and require whitelisting* Metadata is stored onchain using the TokenMetadata extension*/async createBondToken(issuer: Keypair,config: BondTokenConfig): Promise<PublicKey> {console.log("\n🏗️ Creating bond token with Token-2022 + Metadata...");console.log(` Name: ${config.name}`);console.log(` Symbol: ${config.symbol}`);console.log(` Coupon Rate: ${config.couponRate}%`);console.log(` Maturity: ${config.maturityDate.toISOString().split("T")[0]}`);// Generate new keypair for the mintconst mintKeypair = Keypair.generate();// Create the metadata object to get EXACT sizeconst metadata: TokenMetadata = {mint: mintKeypair.publicKey,name: config.name,symbol: config.symbol,uri: config.description || "",additionalMetadata: [["couponRate", config.couponRate.toString()],["maturityDate", config.maturityDate.toISOString()],["isin", config.isin || ""]]};// Size of metadata using pack() - this gives us the EXACT sizeconst metadataLen = pack(metadata).length;// Size of MetadataExtension: 2 bytes for type, 2 bytes for lengthconst metadataExtension = TYPE_SIZE + LENGTH_SIZE;// Calculate space for mint with extensions (without metadata)const extensions = [ExtensionType.DefaultAccountState,ExtensionType.MetadataPointer];const spaceWithoutMetadataExtension = getMintLen(extensions);// Calculate rent for FULL space (mint + metadata + TLV overhead)const lamports = await this.connection.getMinimumBalanceForRentExemption(spaceWithoutMetadataExtension + metadataLen + metadataExtension);// Build transaction following the official docs patternconst transaction = new Transaction().add(// 1. Create account with just base space, but rent for full spaceSystemProgram.createAccount({fromPubkey: issuer.publicKey,newAccountPubkey: mintKeypair.publicKey,space: spaceWithoutMetadataExtension, // Just base spacelamports, // But rent for full space (includes metadata + TLV)programId: TOKEN_2022_PROGRAM_ID}),// 2. Initialize metadata pointer (before mint!)createInitializeMetadataPointerInstruction(mintKeypair.publicKey,issuer.publicKey, // authoritymintKeypair.publicKey, // metadata address (self)TOKEN_2022_PROGRAM_ID),// 3. Initialize default account state (frozen)createInitializeDefaultAccountStateInstruction(mintKeypair.publicKey,AccountState.Frozen,TOKEN_2022_PROGRAM_ID),// 4. Initialize mintcreateInitializeMintInstruction(mintKeypair.publicKey,config.decimals,issuer.publicKey, // mint authoritythis.settlementAgent.publicKey, // freeze authorityTOKEN_2022_PROGRAM_ID),// 5. Initialize metadatacreateInitializeInstruction({programId: TOKEN_2022_PROGRAM_ID,mint: mintKeypair.publicKey,metadata: mintKeypair.publicKey,name: config.name,symbol: config.symbol,uri: config.description || "",mintAuthority: issuer.publicKey,updateAuthority: this.settlementAgent.publicKey}));// 6. Add custom metadata fieldsfor (const [field, value] of metadata.additionalMetadata) {if (value) {transaction.add(createUpdateFieldInstruction({programId: TOKEN_2022_PROGRAM_ID,metadata: mintKeypair.publicKey,updateAuthority: this.settlementAgent.publicKey,field: field,value: value}));}}// Send transactionawait sendAndConfirmTransaction(this.connection,transaction,[issuer, mintKeypair, this.settlementAgent],{ commitment: "confirmed" });console.log(`✅ Bond token created: ${mintKeypair.publicKey.toBase58()}`);console.log(` Mint Authority: ${issuer.publicKey.toBase58()}`);console.log(` Freeze Authority: ${this.settlementAgent.publicKey.toBase58()}`);console.log(` Update Authority: ${this.settlementAgent.publicKey.toBase58()}`);console.log(` Default State: FROZEN (requires whitelisting)`);console.log(` ✨ Metadata: ON-CHAIN`);return mintKeypair.publicKey;}/*** Whitelists a participant by creating their bond account and thawing it*/async whitelist(bondMint: PublicKey,participant: PublicKey,payer: Keypair): Promise<PublicKey> {console.log(`\n🔓 Whitelisting participant: ${participant.toBase58()}`);// Get or create token account (will be frozen by default if new)const bondAccount = await getOrCreateAssociatedTokenAccount(this.connection,payer,bondMint,participant,false,"confirmed",{ commitment: "confirmed" },TOKEN_2022_PROGRAM_ID);console.log(` Account: ${bondAccount.address.toBase58()}`);// Only thaw if the account is frozenif (bondAccount.isFrozen) {await thawAccount(this.connection,this.settlementAgent,bondAccount.address,bondMint,this.settlementAgent,[],{ commitment: "confirmed" },TOKEN_2022_PROGRAM_ID);console.log(`✅ Participant whitelisted and account thawed`);} else {console.log(`✅ Participant already whitelisted (account was not frozen)`);}return bondAccount.address;}/*** Removes an investor from whitelist by freezing their account*/async removeFromWhitelist(bondMint: PublicKey,investorBondAccount: PublicKey): Promise<void> {console.log(`\n🔒 Removing from whitelist: ${investorBondAccount.toBase58()}`);await freezeAccount(this.connection,this.settlementAgent,investorBondAccount,bondMint,this.settlementAgent,[],{ commitment: "confirmed" },TOKEN_2022_PROGRAM_ID);console.log(`✅ Account frozen and removed from whitelist`);}/*** Delegates authority to settlement agent for a token account*/async delegateAuthority(owner: Keypair,tokenAccount: PublicKey,amount: number,decimals: number,programId: PublicKey): Promise<void> {const amountWithDecimals = amount * Math.pow(10, decimals);console.log(`\n🤝 Delegating authority...`);console.log(` Account: ${tokenAccount.toBase58()}`);console.log(` Amount: ${amount}`);console.log(` Delegate: ${this.settlementAgent.publicKey.toBase58()}`);await approve(this.connection,owner,tokenAccount,this.settlementAgent.publicKey,owner.publicKey,amountWithDecimals,[],{ commitment: "confirmed" },programId);console.log(`✅ Authority delegated`);}/*** Executes atomic DvP settlement* Both bond and USDC transfers happen in a single transaction*/async executeDvP(params: DvPParams): Promise<DvPResult> {console.log(`\n⚡ Executing atomic DvP settlement...`);console.log(` Bonds: ${params.bondAmount}`);console.log(` USDC: ${params.usdcAmount}`);console.log(` Issuer: ${params.issuer.toBase58()}`);console.log(` Investor: ${params.investor.toBase58()}`);// Get all associated token account addresses (deterministically)const issuerBondAccount = await getAssociatedTokenAddress(params.bondMint,params.issuer,false, // allowOwnerOffCurveTOKEN_2022_PROGRAM_ID);const investorBondAccount = await getAssociatedTokenAddress(params.bondMint,params.investor,false,TOKEN_2022_PROGRAM_ID);const investorUSDCAccount = await getAssociatedTokenAddress(params.usdcMint,params.investor,false,TOKEN_PROGRAM_ID);const issuerUSDCAccount = await getAssociatedTokenAddress(params.usdcMint,params.issuer,false,TOKEN_PROGRAM_ID);// Build atomic transactionconst transaction = new Transaction();// Add bond transfer instruction (Issuer → Investor)transaction.add(this.createTransferCheckedIx(issuerBondAccount,params.bondMint,investorBondAccount,params.bondAmount,0, // bonds have 0 decimalsTOKEN_2022_PROGRAM_ID));// Add USDC transfer instruction (Investor → Issuer)transaction.add(this.createTransferCheckedIx(investorUSDCAccount,params.usdcMint,issuerUSDCAccount,params.usdcAmount * 1e6, // USDC has 6 decimals6,TOKEN_PROGRAM_ID));// Send atomic transactionconsole.log(`\n📡 Sending atomic transaction...`);const signature = await sendAndConfirmTransaction(this.connection,transaction,[this.settlementAgent],{ commitment: "confirmed" });console.log(`✅ DvP SETTLED ATOMICALLY`);console.log(` Signature: ${signature}`);console.log(` Bonds transferred: ${params.bondAmount}`);console.log(` USDC transferred: ${params.usdcAmount}`);return {signature,bondAmount: params.bondAmount,usdcAmount: params.usdcAmount,timestamp: new Date(),bondsSent: true,usdcReceived: true};}/*** Helper to create a transferChecked instruction using delegated authority*/private createTransferCheckedIx(source: PublicKey,mint: PublicKey,destination: PublicKey,amount: number,decimals: number,programId: PublicKey) {return createTransferCheckedInstruction(source,mint,destination,this.settlementAgent.publicKey, // Settlement agent acts via delegationamount,decimals,[],programId);}/*** Gets account information for inspection*/async getAccountInfo(tokenAccount: PublicKey, programId: PublicKey) {const account = await getAccount(this.connection,tokenAccount,"confirmed",programId);return {address: tokenAccount,mint: account.mint,owner: account.owner,amount: account.amount,isFrozen: account.isFrozen};}/*** Airdrops SOL for testing (devnet/testnet only)*/async airdropSol(publicKey: PublicKey, amount: number): Promise<void> {console.log(`\n💰 Airdropping ${amount} SOL to ${publicKey.toBase58()}`);const signature = await this.connection.requestAirdrop(publicKey,amount * LAMPORTS_PER_SOL);await this.connection.confirmTransaction(signature, "confirmed");console.log(`✅ Airdrop complete`);}}
Полный пример использования
Ниже приведён полный пример, демонстрирующий весь рабочий процесс DvP:
import { Connection, Keypair, clusterApiUrl, PublicKey } from "@solana/web3.js";import {getOrCreateAssociatedTokenAccount,mintTo,TOKEN_2022_PROGRAM_ID,TOKEN_PROGRAM_ID} from "@solana/spl-token";// Standard USDC mint address on mainnetconst USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");async function runDvPExample() {// 1. Initialize connection and keypairsconst connection = new Connection(clusterApiUrl("devnet"));const settlementAgent = Keypair.generate();const issuer = Keypair.generate();const investor = Keypair.generate();console.log("🚀 Starting DvP Workflow\n");// 2. Initialize DvP engineconst dvp = new DvPEngine(connection, settlementAgent);// 3. Airdrop SOL for transaction fees (devnet only)await dvp.airdropSol(settlementAgent.publicKey, 2);await dvp.airdropSol(issuer.publicKey, 2);await dvp.airdropSol(investor.publicKey, 2);// 4. Create commercial paper (bond) token with metadataconst bondMint = await dvp.createBondToken(issuer, {name: "ACME Commercial Paper Series A",symbol: "ACME-CP-A",decimals: 0, // Bonds are whole unitsmaturityDate: new Date("2026-12-31"),couponRate: 4.5, // 4.5% annual couponisin: "US0000000001",description: "https://acme.com/bonds/series-a"});// 5. Whitelist issuer and mint bondsconsole.log("\n🏦 Whitelisting issuer for bond holding...");const issuerBondAccount = await dvp.whitelist(bondMint,issuer.publicKey,settlementAgent);console.log("\n💰 Minting 100 bonds to issuer...");await mintTo(connection,issuer,bondMint,issuerBondAccount,issuer,100, // 100 bonds[],{ commitment: "confirmed" },TOKEN_2022_PROGRAM_ID);// 6. Whitelist investor (KYC/AML approved)await dvp.whitelist(bondMint, investor.publicKey, settlementAgent);// 7. Setup USDC for investorconsole.log("\n💵 Setting up USDC for investor...");const investorUSDCAccount = await getOrCreateAssociatedTokenAccount(connection,investor,USDC_MINT,investor.publicKey,false,"confirmed",{ commitment: "confirmed" },TOKEN_PROGRAM_ID);// In production, investor would acquire USDC from exchange/market// For this example, assume they have 95,000 USDC// 8. Delegate authority to settlement agentconsole.log("\n🔐 Delegating authority to settlement agent...");// Issuer delegates bondsawait dvp.delegateAuthority(issuer,issuerBondAccount,100, // 100 bonds0, // 0 decimalsTOKEN_2022_PROGRAM_ID);// Investor delegates USDCawait dvp.delegateAuthority(investor,investorUSDCAccount.address,95000, // $95,0006, // USDC decimalsTOKEN_PROGRAM_ID);// 9. Execute atomic DvP settlementconsole.log("\n⚡ Executing atomic DvP settlement...");console.log(" Terms: 100 bonds @ $950 each = $95,000\n");const result = await dvp.executeDvP({bondMint,usdcMint: USDC_MINT,bondAmount: 100,usdcAmount: 95000,issuer: issuer.publicKey,investor: investor.publicKey});console.log("\n✨ Settlement complete!");console.log(` Transaction: ${result.signature}`);console.log(` Timestamp: ${result.timestamp.toISOString()}`);console.log(` View on explorer: https://explorer.solana.com/tx/${result.signature}?cluster=devnet`);// 10. Verify balancesconsole.log("\n🔍 Verifying final balances...");const issuerBondInfo = await dvp.getAccountInfo(issuerBondAccount,TOKEN_2022_PROGRAM_ID);console.log(` Issuer bonds: ${issuerBondInfo.amount}`);const investorBondInfo = await dvp.getAccountInfo(await getAssociatedTokenAddress(bondMint,investor.publicKey,false,TOKEN_2022_PROGRAM_ID),TOKEN_2022_PROGRAM_ID);console.log(` Investor bonds: ${investorBondInfo.amount}`);console.log(` Investor frozen: ${investorBondInfo.isFrozen}`);}// Run the examplerunDvPExample().catch(console.error);
Дополнительные возможности
Обновление метаданных
Расчётный агент (с правами на обновление) может обновлять поля метаданных:
import { createUpdateFieldInstruction } from "@solana/spl-token-metadata";async function updateBondMetadata(connection: Connection,settlementAgent: Keypair,bondMint: PublicKey,field: string,value: string): Promise<void> {const transaction = new Transaction().add(createUpdateFieldInstruction({programId: TOKEN_2022_PROGRAM_ID,metadata: bondMint,updateAuthority: settlementAgent.publicKey,field: field,value: value}));await sendAndConfirmTransaction(connection, transaction, [settlementAgent]);}
Удаление из белого списка
Чтобы лишить инвестора возможности держать облигации, заморозьте его аккаунт с помощью
встроенного метода removeFromWhitelist:
await dvp.removeFromWhitelist(bondMint, investorBondAccount);
Заморозка vs Сжигание
Заморозка аккаунта предотвращает переводы, но сохраняет аккаунт и баланс. Для полного удаления вы можете сначала перевести облигации обратно эмитенту, а затем заморозить аккаунт.
Многосторонние расчёты
Для более сложных сценариев с участием нескольких сторон вы можете объединить несколько переводов в одну атомарную транзакцию:
import { sendAndConfirmTransaction } from "@solana/web3.js";import { createTransferCheckedInstruction } from "@solana/spl-token";interface TransferLeg {from: PublicKey;to: PublicKey;mint: PublicKey;amount: number;decimals: number;programId: PublicKey;}async function executeMultiPartyDvP(connection: Connection,settlementAgent: Keypair,legs: TransferLeg[]): Promise<string> {const transaction = new Transaction();// Add all transfer legs to single transactionfor (const leg of legs) {const fromAccount = await getAssociatedTokenAddress(leg.mint,leg.from,false,leg.programId);const toAccount = await getAssociatedTokenAddress(leg.mint,leg.to,false,leg.programId);// Add transfer instruction using delegated authoritytransaction.add(createTransferCheckedInstruction(fromAccount,leg.mint,toAccount,settlementAgent.publicKey, // Uses delegated authorityleg.amount * Math.pow(10, leg.decimals),leg.decimals,[],leg.programId));}// All legs settle atomically - either all succeed or all failconst signature = await sendAndConfirmTransaction(connection,transaction,[settlementAgent],{ commitment: "confirmed" });console.log(`✅ Multi-party DvP settled: ${legs.length} legs`);return signature;}
Ограничения размера транзакции
Транзакции Solana имеют ограничение по размеру (~1232 байта). Каждая инструкция перевода добавляет ~200 байт. Для очень крупных многосторонних расчётов рассмотрите использование Address Lookup Tables для сжатия адресов аккаунтов и размещения большего количества переводов в одной транзакции.
Требования для продакшена
Перед развёртыванием в продакшен убедитесь, что вы решили следующие вопросы:
- Безопасность: Профессиональная инфраструктура управления ключами, контроль с мульти-подписью, комплексный аудит кодовой базы
- Соответствие нормативным требованиям: Регистрация ценных бумаг, системы KYC/AML, ограничения на переводы и правовая база
- Управление ключами: Профессиональные решения для хранения с надлежащими процедурами резервного копирования и восстановления
- Обработка транзакций: Приоритетные комиссии, логика повторных попыток, обработка подтверждений и резервирование RPC для надёжного исполнения расчётов
- Операции: Планирование расчётов, обработка несостоявшихся сделок, сверка и поддержка клиентов
- Мониторинг: Отслеживание в реальном времени, оповещения и автоматизированная регуляторная отчётность
Ограничение SPL Token
SPL Token account может иметь только одного делегата одновременно. Это означает, что для многосторонних сценариев вам может потребоваться обойти это ограничение, используя несколько последовательных делегирований или иные архитектурные паттерны.
Проверка состояния аккаунта
DvPEngine включает вспомогательный метод для проверки состояния token account. Это полезно
для верификации статуса белого списка, подтверждения завершения расчётов, отладки
проблем с переводами и аудита состояний аккаунтов.
// Get detailed account informationconst accountInfo = await dvp.getAccountInfo(investorBondAccount,TOKEN_2022_PROGRAM_ID);console.log("Account Information:");console.log(` Address: ${accountInfo.address.toBase58()}`);console.log(` Mint: ${accountInfo.mint.toBase58()}`);console.log(` Owner: ${accountInfo.owner.toBase58()}`);console.log(` Balance: ${accountInfo.amount}`);console.log(` Frozen: ${accountInfo.isFrozen}`);
Следующие шаги
Освоив основы DvP на Solana:
-
Изучите Token Extensions: Узнайте о других расширениях Token 2022, таких как Transfer Hooks, для дополнительных функций соответствия требованиям
-
Реализуйте Token ACL: Для более сложных требований соответствия рассмотрите использование Token ACL для реализации списков разрешений и блокировок с возможностью самостоятельной разморозки. Это позволяет пользователям самостоятельно проходить верификацию белого списка при полном сохранении контроля соответствия.
-
Углублённое изучение регулирования: Проконсультируйтесь с юридическими экспертами по законодательству о ценных бумагах в вашей юрисдикции
-
Производственная архитектура: Разработайте надёжные системы управления ключами, мониторинга и аварийного восстановления
Заключение
Атомарная модель транзакций Solana и Token Extensions обеспечивают мощную основу для реализации соответствующих требованиям DvP-расчётов по ценным бумагам. Совокупность:
- Нативного атомарного исполнения (без риска смарт-контрактов)
- Финальности менее чем за секунду
- Почти нулевых транзакционных издержек
- Встроенных функций соответствия требованиям (заморозка по умолчанию, метаданные)
Делает Solana идеальной платформой для модернизации инфраструктуры расчётов по ценным бумагам.
Однако переход от этой учебной эталонной реализации к продакшену требует значительной дополнительной работы в области безопасности, соответствия требованиям, хранения активов и операционной деятельности. При работе с токенизацией ценных бумаг всегда привлекайте квалифицированных юридических, регуляторных и технических экспертов.
Is this page helpful?