التسليم مقابل الدفع (DvP) على سولانا

التسليم مقابل الدفع (DvP) هو أسلوب تسوية للأوراق المالية يضمن أن يتم نقل الأوراق المالية في آنٍ واحد مع تحويل الدفعة. يُلغي هذا الأسلوب مخاطر الطرف المقابل من خلال ضمان تنفيذ كلا طرفَي الصفقة بشكل ذري - إما أن يكتملا معاً أو لا يكتمل أيٌّ منهما.

المشكلة

عندما تشتري سندات (مثل الأوراق التجارية)، يحتاج الأمر تقليدياً إلى حدوث شيئين:

  1. أنت ترسل الأموال ← البائع
  2. البائع يرسل السندات ← أنت

إذا حدث كلٌّ منهما بشكل منفصل، ثمة مخاطرة — ماذا لو دفعت ولم تحصل على السندات قط؟ أو العكس؟

الحل

(DvP) "التسليم مقابل الدفع" يعني أن كلا التحويلين يحدثان في اللحظة ذاتها تماماً، أو لا يحدث أيٌّ منهما. يشبه الأمر مقايضة يتبادل فيها الطرفان في آنٍ واحد.

┌─────────────────────────────────────────────────────┐
│ ONE ATOMIC TRANSACTION │
├─────────────────────────────────────────────────────┤
│ │
│ Investor ──── $95,000 USDC ────→ Issuer │
│ │
│ Issuer ─────── 100 Bonds ──────→ Investor │
│ │
│ ✅ Both happen together, or neither happens │
│ │
└─────────────────────────────────────────────────────┘

يوضّح هذا الدليل كيفية تنفيذ سير عمل DvP كامل على سولانا باستخدام امتدادات SPL Token 2022 لإصدار السندات المتوافقة مع المعايير وعملة USDC القياسية للتسوية، وكل ذلك دون كتابة برامج Rust مخصصة.

تطبيق مرجعي تعليمي

يمكنك استخدام الكود المصدري لهذا التطبيق لتجربة تنفيذ DvP محلياً.

يوفر هذا الدليل تطبيقاً مرجعياً للاستكشاف والأغراض التعليمية فحسب. لا تستخدم هذا الكود مباشرةً في بيئة الإنتاج دون:

  • إجراء تدقيقات أمنية شاملة
  • أنظمة إدارة مفاتيح مناسبة
  • مراجعة الامتثال التنظيمي
  • استشارة قانونية
  • اختبار مكثف وتعديلات

لماذا سولانا لـ DvP؟

توفر بنية سولانا التحتية مزايا جوهرية مقارنةً بتسوية الأوراق المالية التقليدية:

الجانبالتقليدي (T+2)سولانا
منطق التسويةغرف المقاصةتجميع المعاملات الذري
وقت التسويةيومانأقل من ثانية واحدة
تكلفة المعاملة50-500$أقل من 0.01$
مخاطر الطرف المقابلمرتفعة (وسطاء)معدومة (تنفيذ ذري)
النهائيةنهاية اليوم~400 مللي ثانية

يُلغي تجميع المعاملات الذري في سولانا الوسطاء مع توفير تسويات فورية وزهيدة التكلفة وآمنة.

نظرة عامة على البنية

يتكوّن نظام DvP من المكونات الأساسية التالية:

  1. رمز السند (الأوراق التجارية): SPL Token 2022 مع Token Extensions
  2. عملة التسوية: USDC القياسية (رمز SPL موجود)
  3. وكيل التسوية: ينسّق عمليات المبادلة الذرية عبر السلطة المفوّضة
  4. نظام القائمة البيضاء: يتحكم في العناوين المسموح لها بحيازة السندات

مبادئ التصميم الرئيسية

  • لا برامج مخصصة: يستخدم Token Extensions في SPL Token 2022 وعملة 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 2022 Extensions

يوفر SPL Token 2022 امتدادات قوية تتيح إصدار الأوراق المالية المتوافقة مع المعايير دون برامج مخصصة:

الامتدادات الأساسية للسندات

  1. امتداد حالة الحساب الافتراضية: يضبط جميع token account الجديدة على الحالة المجمّدة افتراضياً، مما يستلزم الإدراج الصريح في القائمة البيضاء
  2. امتداد البيانات الوصفية: يخزّن تفاصيل السند على السلسلة (ISIN، تاريخ الاستحقاق، سعر الكوبون، وغيرها)
  3. المفوَّض الدائم (اختياري): يسمح بالاسترداد أو الاسترجاع المصرّح به إذا اقتضت ذلك اللوائح

إعداد الصلاحيات

  • صلاحية الإصدار: المُصدِر (يتحكم في إنشاء العرض)
  • صلاحية التجميد: وكيل التسوية (يدير القائمة البيضاء)
  • صلاحية التحديث: وكيل التسوية (يمكنه تحديث البيانات الوصفية)

حالة التجميد الافتراضية بالغة الأهمية للامتثال التنظيمي. فهي تضمن أن العناوين المدرجة في القائمة البيضاء صراحةً وحدها يمكنها استقبال الأوراق المالية وحيازتها، مما يستوفي متطلبات 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 mint
const mintKeypair = Keypair.generate();
// Create the metadata object to get EXACT size
const 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 size
const metadataLen = pack(metadata).length;
// Size of MetadataExtension: 2 bytes for type, 2 bytes for length
const 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 pattern
const transaction = new Transaction().add(
// 1. Create account with just base space, but rent for full space
SystemProgram.createAccount({
fromPubkey: issuer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: spaceWithoutMetadataExtension, // Just base space
lamports, // But rent for full space (includes metadata + TLV)
programId: TOKEN_2022_PROGRAM_ID
}),
// 2. Initialize metadata pointer (before mint!)
createInitializeMetadataPointerInstruction(
mintKeypair.publicKey,
issuer.publicKey, // authority
mintKeypair.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 mint
createInitializeMintInstruction(
mintKeypair.publicKey,
config.decimals,
issuer.publicKey, // mint authority
this.settlementAgent.publicKey, // freeze authority
TOKEN_2022_PROGRAM_ID
),
// 5. Initialize metadata
createInitializeInstruction({
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 fields
for (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 transaction
await 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 frozen
if (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, // allowOwnerOffCurve
TOKEN_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 transaction
const transaction = new Transaction();
// Add bond transfer instruction (Issuer → Investor)
transaction.add(
this.createTransferCheckedIx(
issuerBondAccount,
params.bondMint,
investorBondAccount,
params.bondAmount,
0, // bonds have 0 decimals
TOKEN_2022_PROGRAM_ID
)
);
// Add USDC transfer instruction (Investor → Issuer)
transaction.add(
this.createTransferCheckedIx(
investorUSDCAccount,
params.usdcMint,
issuerUSDCAccount,
params.usdcAmount * 1e6, // USDC has 6 decimals
6,
TOKEN_PROGRAM_ID
)
);
// Send atomic transaction
console.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 delegation
amount,
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 mainnet
const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
async function runDvPExample() {
// 1. Initialize connection and keypairs
const 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 engine
const 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 metadata
const bondMint = await dvp.createBondToken(issuer, {
name: "ACME Commercial Paper Series A",
symbol: "ACME-CP-A",
decimals: 0, // Bonds are whole units
maturityDate: new Date("2026-12-31"),
couponRate: 4.5, // 4.5% annual coupon
isin: "US0000000001",
description: "https://acme.com/bonds/series-a"
});
// 5. Whitelist issuer and mint bonds
console.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 investor
console.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 agent
console.log("\n🔐 Delegating authority to settlement agent...");
// Issuer delegates bonds
await dvp.delegateAuthority(
issuer,
issuerBondAccount,
100, // 100 bonds
0, // 0 decimals
TOKEN_2022_PROGRAM_ID
);
// Investor delegates USDC
await dvp.delegateAuthority(
investor,
investorUSDCAccount.address,
95000, // $95,000
6, // USDC decimals
TOKEN_PROGRAM_ID
);
// 9. Execute atomic DvP settlement
console.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 balances
console.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 example
runDvPExample().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);

التجميد مقابل الحرق

تجميد الحساب يمنع التحويلات لكنه يحافظ على الحساب والرصيد. للإزالة الكاملة، قد ترغب أولاً في تحويل السندات إلى المُصدِر، ثم تجميد الحساب.

التسوية متعددة الأطراف

في السيناريوهات الأكثر تعقيداً التي تشمل أطرافاً متعددة، يمكنك تجميع عدة تحويلات في معاملة ذرية واحدة:

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 transaction
for (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 authority
transaction.add(
createTransferCheckedInstruction(
fromAccount,
leg.mint,
toAccount,
settlementAgent.publicKey, // Uses delegated authority
leg.amount * Math.pow(10, leg.decimals),
leg.decimals,
[],
leg.programId
)
);
}
// All legs settle atomically - either all succeed or all fail
const signature = await sendAndConfirmTransaction(
connection,
transaction,
[settlementAgent],
{ commitment: "confirmed" }
);
console.log(`✅ Multi-party DvP settled: ${legs.length} legs`);
return signature;
}

حدود حجم المعاملة

لمعاملات سولانا حدٌّ للحجم (~1232 بايت). كل تعليمة تحويل تُضيف ~200 بايت. للتسويات الكبيرة متعددة الأطراف، فكّر في استخدام جداول بحث العناوين لضغط عناوين الحسابات وتكثيف عدد التحويلات في كل معاملة.

اعتبارات الإنتاج

قبل النشر في بيئة الإنتاج، تأكد من معالجة ما يلي:

  1. الأمان: بنية تحتية احترافية لإدارة المفاتيح، وضوابط متعددة التوقيع، وعمليات تدقيق شاملة لقاعدة الكود
  2. الامتثال التنظيمي: تسجيل الأوراق المالية، وأنظمة KYC/AML، وقيود التحويل، والإطار القانوني
  3. إدارة المفاتيح: حلول حضانة احترافية مع إجراءات نسخ احتياطي واسترداد مناسبة
  4. معالجة المعاملات: رسوم الأولوية، ومنطق إعادة المحاولة، ومعالجة التأكيد، وتكرار RPC لتنفيذ تسوية موثوق
  5. العمليات: جدولة التسويات، ومعالجة الصفقات الفاشلة، والتسوية الحسابية، ودعم العملاء
  6. المراقبة: التتبع الفوري، والتنبيهات، والتقارير التنظيمية الآلية

قيود SPL Token

يمكن لـ token account في SPL Token أن يمتلك مفوَّضاً واحداً فقط في كل مرة. هذا يعني أنه في السيناريوهات متعددة الأطراف، قد تحتاج إلى تصميم حل يتجاوز هذا القيد باستخدام تفويضات متسلسلة متعددة أو أنماط معمارية مختلفة.

فحص حالة الحساب

تتضمن DvPEngine أداةً مساعدة لفحص حالة token account. وهذا مفيد للتحقق من حالة القائمة البيضاء، وتأكيد اكتمال التسوية، وتصحيح مشكلات التحويل، ومراجعة حالات الحسابات.

// Get detailed account information
const 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 على سولانا:

  1. استكشاف Token Extensions: تعرّف على امتدادات Token 2022 الأخرى مثل Transfer Hooks للحصول على ميزات امتثال إضافية

  2. تطبيق Token ACL: لاحتياجات الامتثال الأكثر تطوراً، فكّر في استخدام Token ACL لتطبيق قوائم السماح/الحظر مع قدرات إلغاء التجميد بدون إذن. يتيح هذا للمستخدمين إجراء التحقق من القائمة البيضاء ذاتياً مع الحفاظ على التحكم الكامل في الامتثال.

  3. التعمق التنظيمي: استشر خبراء قانونيين في لوائح الأوراق المالية في نطاق اختصاصك القضائي

  4. بنية الإنتاج: صمّم أنظمة قوية لإدارة المفاتيح والمراقبة والتعافي من الكوارث

الخلاصة

يوفر نموذج المعاملات الذري في سولانا وامتدادات Token 2022 أساساً متيناً لتنفيذ تسويات DvP المتوافقة مع المعايير للأوراق المالية. ويجمع هذا النموذج بين:

  • التنفيذ الذري الأصلي (بدون مخاطر العقود الذكية)
  • النهائية دون الثانية الواحدة
  • تكاليف معاملات شبه معدومة
  • ميزات امتثال مدمجة (التجميد الافتراضي، البيانات الوصفية)

مما يجعل سولانا المنصة المثالية لتحديث البنية التحتية لتسوية الأوراق المالية.

غير أن الانتقال من هذا المرجع التعليمي إلى بيئة الإنتاج يستلزم عملاً إضافياً جوهرياً في مجالات الأمان والامتثال والحضانة والعمليات. احرص دائماً على العمل مع خبراء قانونيين وتنظيميين وتقنيين مؤهلين عند التعامل مع ترميز الأوراق المالية.

Is this page helpful?