Alım Satımı Takas Etme

SettleDvp, alım satım kaydında belirtilen takas yetkilisi tarafından imzalanır. Tek bir işlemde varlık bacağının amount_a tutarını nakit bacağı tarafının hedef hesabına, nakit bacağının amount_b tutarını ise varlık bacağı tarafının hedef hesabına taşır; her iki escrow hesabındaki fazlalığı ilgili bacağın tarafına iade eder, ardından kaydı ve her iki escrow hesabını kapatır. Bu transferlerden herhangi biri tamamlanamazsa talimat başarısız olur ve hiçbir şey hareket etmez.

Bu sayfa, alım satım oluşturma ve bacakları fonlama sayfalarının devamıdır; istemci, imzalayanlar, trade ve tarafların token account'ları aynen devralınır.

İmzalamadan önce yeniden doğrulama

Takas yetkilisi her iki bacağı da taşıyan işlemi imzalar; bu nedenle imzalamadan önce her tarafın yaptığı okumanın aynısını yapar: sahip, boyut, taraflar, mint'ler, tutarlar, son kullanma zamanı ve her iki hedef hesap (bkz. bacakları fonlama). Programın kendisi de takas sırasında her mint'in hâlâ oluşturma anında kaydedilen token program'a ait olduğunu, engellenmiş bir uzantı taşımadığını ve alım satım oluşturulduğundaki mint yetkilisiyle aynı yetkiliye sahip olduğunu yeniden kontrol eder. Dolayısıyla engellenmiş bir uzantıyla, farklı bir token program ile veya farklı bir mint yetkilisiyle yeniden oluşturulmuş bir mint takas edilemez.

Alıcı hesaplarını oluşturma

Settle, programın oluşturmadığı dört token account'a yazar:

HesapAldığıSahip
userADestinationAtaBNakit bacağı (amount_b)user_a_settlement_destination
userBDestinationAtaAVarlık bacağı (amount_a)user_b_settlement_destination
userAAtaAVarlık bacağındaki fazlalıkuser_a
userBAtaBNakit bacağındaki fazlalıkuser_b

Fazlalık hesapları yalnızca bir escrow hesabı kararlaştırılan tutardan fazlasını tuttuğunda kullanılır; ancak mint'e sahip herhangi biri escrow hesabına birkaç temel birim göndererek fazlalık oluşturabilir. İade hesabı mevcut değilse Settle işleminin tamamı başarısız olur; bu nedenle dördünü de aynı işlemde idempotent olarak oluşturun.

import {
findAssociatedTokenPda,
getCreateAssociatedTokenIdempotentInstruction,
} from "@solana-program/token-2022";
const destinationA = t.userASettlementDestination; // defaults to userA
const destinationB = t.userBSettlementDestination; // defaults to userB
const [userADestinationAtaB] = await findAssociatedTokenPda({
mint: mintB,
owner: destinationA,
tokenProgram: tokenProgramB,
});
const [userBDestinationAtaA] = await findAssociatedTokenPda({
mint: mintA,
owner: destinationB,
tokenProgram: tokenProgramA,
});
// userAAtaA and userBAtaB are from fund the legs.
const createRecipientAccounts = [
{ ata: userADestinationAtaB, owner: destinationA, mint: mintB, tokenProgram: tokenProgramB },
{ ata: userBDestinationAtaA, owner: destinationB, mint: mintA, tokenProgram: tokenProgramA },
{ ata: userAAtaA, owner: userA, mint: mintA, tokenProgram: tokenProgramA },
{ ata: userBAtaB, owner: userB, mint: mintB, tokenProgram: tokenProgramB },
].map(({ ata, owner, mint, tokenProgram }) =>
getCreateAssociatedTokenIdempotentInstruction({
payer: authoritySigner,
ata,
owner,
mint,
tokenProgram,
}),
);

Settle

legAExtrasCount, sabit listeden sonra eklenen hesaplardan kaçının varlık bacağının transfer hook'una ait olduğunu programa bildirir; geri kalanı nakit bacağına aittir. Transfer hook'u olmayan mint'ler için sıfır geçin ve hiçbir şey eklemeyin. Memo program account'ı talimat için zorunludur ve yalnızca memo gerektiren hedefler için kullanılır.

import { MEMO_PROGRAM_ADDRESS } from "@solana-program/memo";
import { getSettleDvpInstruction } from "./dvp";
const settleInstruction = getSettleDvpInstruction({
settlementAuthority: authoritySigner,
swapDvp,
mintA,
mintB,
dvpAtaA: escrowA,
dvpAtaB: escrowB,
userADestinationAtaB,
userBDestinationAtaA,
userAAtaA,
userBAtaB,
tokenProgramA,
tokenProgramB,
memoProgram: MEMO_PROGRAM_ADDRESS,
legAExtrasCount: 0,
});
const { context: settleContext } = await client.sendTransaction([
...createRecipientAccounts,
settleInstruction,
]);
const settleSignature = settleContext.signature;
console.log("Submitted:", settleSignature);
// sendTransaction returns at the client's commitment (confirmed by default).
// Wait for finalized before recording the trade as settled.
let finalized = false;
for (let attempt = 0; attempt < 30 && !finalized; attempt++) {
const {
value: [status],
} = await client.rpc.getSignatureStatuses([settleSignature]).send();
if (status?.err) {
throw new Error("Settle transaction failed");
}
finalized = status?.confirmationStatus === "finalized";
if (!finalized) {
await new Promise((resolve) => setTimeout(resolve, 2_000));
}
}
if (!finalized) {
// A closed record means it settled; an open one is safe to settle again.
throw new Error("Settle not finalized after 60s; read the trade record");
}
console.log("Settled:", settleSignature);

Transfer hook'ları

Oluşturulan IDL yalnızca sabit hesapları listeler; bu nedenle oluşturulan builder'lar hook hesaplarından haberdar değildir. Her hook mint'inin ek account meta'larını, o token'ın doğrudan transferi için yapacağınız şekilde çözümleyin, ardından bunları talimata ekleyin: önce varlık bacağının hesapları, sonra nakit bacağının hesapları; legAExtrasCount ilk gruptaki sayıya ayarlanmalıdır. TypeScript'te çözümlenen meta'ları talimatın accounts dizisine yayın (spread); Rust'ta builder üzerinde add_remaining_accounts kullanın. Üst sınır, hook programı ve doğrulama hesabı dahil bacak başına 32 hesaptır; her iki bacak da hook taşıyorsa işlem hesap sınırı önce devreye girebilir. Program, iletilen her hesaptan imzalayan (signer) bayrağını kaldırır; bu nedenle bir hook bu yol üzerinden takas yetkilisinin imzasını elde edemez.

Sonucu kaydetme

Settle işlemi finalized durumuna ulaştığında alım satımı takas edilmiş sayın. Takastan sonra kayıt ve her iki escrow hesabı artık mevcut değildir; bu nedenle koşullara sonradan ihtiyaç duyan bir sistem, bunları takas öncesi okumasından veya oluşturma işleminden saklamalıdır. Kapatılan hesapların rent'i takas yetkilisine gitmiştir.

Settle hataları

LegNotFunded, bir escrow hesabının kararlaştırılan tutardan azını tuttuğu anlamına gelir; DvpExpired ve SettlementTooEarly zaman aralığının kaçırıldığını belirtir; MintAuthorityChanged ve BlockedMintExtension bir mint'in oluşturulduktan sonra değiştiği anlamına gelir; RecipientAtaMismatch ise bir hedef veya iade token account'ının eksik olduğunu ya da artık beklenen sahip ve mint'e ait olmadığını belirtir; bu genellikle yukarıdaki hesap oluşturma adımının atlanmasından kaynaklanır. Her durumda hiçbir şey hareket etmemiştir ve taraflar, mint yetkililerinin izin verdiği ölçüde işlemi geri alabilir (bkz. alım satımı geri alma).

Sonraki adımlar

Is this page helpful?

İçindekiler

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