Solana'da Teslimat ve Ödeme (DvP)

Teslimat ve Ödeme (DvP), menkul kıymet transferinin ödeme transferiyle eş zamanlı gerçekleşmesini sağlayan bir menkul kıymet uzlaşma yöntemidir. Bu yöntem, işlemin her iki ayağının da atomik olarak gerçekleşmesini — ya her ikisi tamamlanır ya da hiçbiri tamamlanmaz — garanti ederek karşı taraf riskini ortadan kaldırır.

Sorun

Tahvil (ticari senet gibi) satın aldığınızda, geleneksel olarak iki şeyin gerçekleşmesi gerekir:

  1. Para gönderirsiniz → Satıcı
  2. Satıcı tahvilleri gönderir → Siz

Bunlar ayrı ayrı gerçekleşirse risk oluşur — ya ödeme yaparsınız ama tahvilleri hiç almazsanız? Ya da tam tersi?

Çözüm

(DvP) "Teslimat ve Ödeme", her iki transferin de tam olarak aynı anda gerçekleşmesi ya da hiçbirinin gerçekleşmemesi anlamına gelir. Her iki tarafın eş zamanlı olarak değiş tokuş yaptığı bir takas gibidir.

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

Bu kılavuz, uyumlu tahvil ihracı için SPL Token 2022 uzantılarını ve uzlaşma için standart USDC'yi kullanarak Solana üzerinde özel Rust programları yazmadan eksiksiz bir DvP iş akışının nasıl uygulanacağını göstermektedir.

Eğitim Amaçlı Referans Uygulama

Bu uygulamanın kaynak kodunu kullanarak DvP'yi yerel ortamda deneyebilirsiniz.

Bu kılavuz yalnızca araştırma ve eğitim amaçlı bir referans uygulama sunmaktadır. Bu kodu üretim ortamında DOĞRUDAN kullanmayın; önce şunları yapın:

  • Kapsamlı güvenlik denetimleri
  • Uygun anahtar yönetim sistemleri
  • Düzenleyici uyumluluk incelemesi
  • Hukuki danışmanlık
  • Kapsamlı testler ve değişiklikler

DvP için Neden Solana?

Solana'nın mimarisi, geleneksel menkul kıymet uzlaşmasına kıyasla önemli avantajlar sağlar:

KriterGeleneksel (T+2)Solana
Uzlaşma MantığıTakas MerkezleriAtomik işlem paketleme
Uzlaşma Süresi2 gün<1 saniye
İşlem Maliyeti$50-500<$0,01
Karşı Taraf RiskiYüksek (aracılar)Sıfır (atomik çalıştırma)
KesinlikGün sonu~400ms

Solana'nın atomik işlem paketleme özelliği, aracıları ortadan kaldırırken anlık, ucuz ve güvenli uzlaşmalar sağlar.

Mimariye Genel Bakış

DvP sistemi şu temel bileşenlerden oluşur:

  1. Tahvil Token'ı (Ticari Senet): Token Extensions ile SPL Token 2022
  2. Uzlaşma Para Birimi: Standart USDC (mevcut SPL token'ı)
  3. Uzlaşma Aracısı: Yetki devri aracılığıyla atomik takasları yönetir
  4. Beyaz Liste Sistemi: Tahvil tutabilecek adresleri denetler

Temel Tasarım İlkeleri

  • Özel Program Yok: Yalnızca Token Extensions ve standart USDC kullanılır
  • Atomik Uzlaşma: Tek işlem, her iki transferin birlikte başarılı olmasını veya birlikte başarısız olmasını sağlar
  • Varsayılan Dondurulmuş Durum: Tahviller, düzenleyici uyumluluk için açık beyaz listeye alınmayı gerektirir
  • Yetki Devri: Uzlaşma aracısı, varlık gözetimi üstlenmeden koordinasyonu sağlar
  • Ağ Durumu İletişimi: Noktadan noktaya API bağlantısı gerekmez
┌─────────────────────────────────────────────────────┐
│ 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) │
│ │
└─────────────────────────────────────────────────────┘

İşlemi yöneten güvenilir bir taraftır. Her iki taraf da yetkiyi uzlaşma aracısına devreder; uzlaşma aracısı daha sonra atomik takası gerçekleştirir.

┌─────────┐ delegates ┌──────────────────┐ delegates ┌──────────┐
│ Issuer │ ─────────────────→ │ Settlement Agent │ ←──────────────── │ Investor │
└─────────┘ (bonds) │ (trusted) │ (USDC) └──────────┘
│ │
│ executes atomic │
│ transaction │
└──────────────────┘

Token Extensions ile Tahvil Token'ı

SPL Token 2022, özel programlar gerektirmeden uyumlu menkul kıymet ihracını mümkün kılan güçlü uzantılar sunar:

Tahviller İçin Temel Uzantılar

  1. Varsayılan Hesap Durumu Uzantısı: Tüm yeni token account'larını varsayılan olarak dondurulmuş şekilde ayarlayarak açık beyaz listeye alınmayı zorunlu kılar
  2. Metadata Uzantısı: Tahvil ayrıntılarını zincir üzerinde saklar (ISIN, vade tarihi, kupon oranı vb.)
  3. Kalıcı Temsilci (isteğe bağlı): Mevzuatın gerektirmesi halinde yetkili kurtarma veya geri alma işlemlerine olanak tanır

Yetki Yapılandırması

  • Basım Yetkisi: İhraçcı (arz oluşturmayı denetler)
  • Dondurma Yetkisi: Uzlaşma Aracısı (beyaz listeyi yönetir)
  • Güncelleme Yetkisi: Uzlaşma Aracısı (metadata'yı güncelleyebilir)

Varsayılan dondurulmuş durum, düzenleyici uyumluluk açısından kritik öneme sahiptir. Yalnızca açıkça beyaz listeye alınmış adreslerin menkul kıymetleri almasını ve tutmasını sağlayarak KYC/AML gerekliliklerini karşılar.

Eksiksiz DvP Uygulaması

DvP Motorunu Kurma

Önce tüm işlemleri yöneten temel DvP motor sınıfını oluşturun:

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`);
}
}

Eksiksiz Kullanım Örneği

DvP iş akışının tamamını gösteren eksiksiz bir örnek aşağıda verilmiştir:

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);

Ek Özellikler

Metadata Güncelleme

Uzlaşma aracısı (güncelleme yetkisiyle) metadata alanlarını güncelleyebilir:

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]);
}

Beyaz Listeden Çıkarma

Yerleşik removeFromWhitelist metodunu kullanarak hesaplarını dondurarak bir yatırımcının tahvil tutma yetkisini kaldırın:

await dvp.removeFromWhitelist(bondMint, investorBondAccount);

Dondurma ve Yakma Karşılaştırması

Bir hesabın dondurulması transferleri engeller ancak hesabı ve bakiyeyi korur. Tamamen kaldırmak için önce tahvilleri ihraçcıya geri transfer etmek, ardından hesabı dondurmak isteyebilirsiniz.

Çok Taraflı Uzlaşma

Birden fazla tarafı kapsayan daha karmaşık senaryolar için, birden fazla transferi tek bir atomik işlemde paketleyebilirsiniz:

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;
}

İşlem Boyutu Sınırları

Solana işlemlerinin bir boyut sınırı vardır (~1232 bayt). Her transfer talimatı ~200 bayt ekler. Çok büyük çok taraflı uzlaşmalar için hesap adreslerini sıkıştırmak ve işlem başına daha fazla transfer sığdırmak amacıyla Adres Arama Tabloları kullanmayı düşünebilirsiniz.

Üretim Ortamı Değerlendirmeleri

Üretime geçmeden önce şu konuları ele aldığınızdan emin olun:

  1. Güvenlik: Profesyonel anahtar yönetim altyapısı, çoklu imza denetimleri, kod tabanının kapsamlı olarak denetlenmesi
  2. Düzenleyici Uyumluluk: Menkul kıymet tescili, KYC/AML sistemleri, transfer kısıtlamaları ve yasal çerçeve
  3. Anahtar Yönetimi: Uygun yedekleme ve kurtarma prosedürleriyle profesyonel saklama çözümleri
  4. İşlem İşleme: Güvenilir uzlaşma gerçekleştirimi için öncelik ücretleri, yeniden deneme mantığı, onay yönetimi ve RPC yedekliliği
  5. Operasyonlar: Uzlaşma planlaması, başarısız işlem yönetimi, mutabakat ve müşteri desteği
  6. İzleme: Gerçek zamanlı takip, uyarı ve otomatik düzenleyici raporlama

SPL Token Kısıtlaması

SPL Token account'ları aynı anda yalnızca bir temsilciye sahip olabilir. Bu durum, çok taraflı senaryolarda birden fazla sıralı yetki devri veya farklı mimari desenler kullanarak bu kısıtlamayı göz önünde bulundurarak tasarım yapmanız gerekebileceği anlamına gelir.

Hesap Durumunu İnceleme

DvPEngine, token account durumunu incelemek için bir yardımcı içerir. Bu, beyaz liste durumunu doğrulamak, uzlaşma tamamlanmasını onaylamak, transfer sorunlarını hata ayıklamak ve hesap durumlarını denetlemek için kullanışlıdır.

// 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}`);

Sonraki Adımlar

Solana'da DvP'nin temellerini anladıktan sonra:

  1. Token Extensions'ı Keşfedin: Ek uyumluluk özellikleri için Transfer Hook'lar gibi diğer Token 2022 uzantıları hakkında bilgi edinin

  2. Token ACL Uygulayın: Daha gelişmiş uyumluluk ihtiyaçları için izin verilenler/engellenler listelerini izinsiz çözme yetenekleriyle uygulamak amacıyla Token ACL kullanmayı düşünün. Bu, kullanıcıların tam uyumluluk denetimini korurken beyaz liste doğrulamasını self-servis olarak gerçekleştirmesine olanak tanır.

  3. Düzenleyici Derinlemesine İnceleme: Bulunduğunuz yargı bölgesindeki menkul kıymet mevzuatı konusunda hukuk uzmanlarına danışın

  4. Üretim Mimarisi: Güçlü anahtar yönetimi, izleme ve felaket kurtarma sistemleri tasarlayın

Sonuç

Solana'nın atomik işlem modeli ve Token 2022 uzantıları, menkul kıymetler için uyumlu DvP uzlaşmalarının uygulanmasına yönelik güçlü bir temel sağlar. Şunların bir araya gelmesi:

  • Yerel atomik çalıştırma (akıllı sözleşme riski yok)
  • Saniyenin altında kesinlik
  • Sıfıra yakın işlem maliyetleri
  • Yerleşik uyumluluk özellikleri (dondurulmuş varsayılanlar, metadata)

Solana'yı menkul kıymet uzlaşma altyapısını modernize etmek için ideal bir platform haline getirir.

Ancak bu eğitim referansından üretime geçmek, güvenlik, uyumluluk, saklama ve operasyonlar konusunda önemli miktarda ek çalışma gerektirmektedir. Menkul kıymet tokenizasyonuyla ilgilenirken her zaman nitelikli hukuki, düzenleyici ve teknik uzmanlarla birlikte çalışın.

Is this page helpful?

© 2026 Solana Vakfı. Tüm hakları saklıdır.