Trade'in Takasını Gerçekleştirme

SettleDvp, trade kaydında adı geçen takas yetkilisi tarafından imzalanır. Tek bir işlemde, varlık bacağının amount_a miktarını nakit bacağı tarafının hedefine, nakit bacağının amount_b miktarını ise varlık bacağı tarafının hedefine aktarır; her iki escrow'daki fazla tutarı ilgili bacağın tarafına iade eder ve kaydı ile her iki escrow'u kapatır. Bu transferlerden herhangi biri tamamlanamazsa talimat başarısız olur ve hiçbir şey hareket etmez.

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

İmzalamadan önce yeniden doğrulayın

Takas yetkilisi her iki bacağı hareket ettiren işlemi imzaladığı için, imzalamadan önce her bir tarafla aynı okumayı yapar: sahip, boyut, taraflar, mint'ler, miktarlar, son kullanma zamanı ve her iki hedef (bkz. bacakları fonlama). Program ayrıca takas sırasında her mint'in hâlâ oluşturma anında kaydedilen token program'a ait olduğunu, engellenmiş bir extension taşımadığını ve trade oluşturulduğundaki mint authority'ye sahip olduğunu yeniden kontrol eder; dolayısıyla engellenmiş bir extension ile, farklı bir token program ile veya farklı bir mint authority ile yeniden oluşturulan bir mint takas edilemez.

Alıcı token account'larını oluşturun

Settle, program tarafından oluşturulmayan 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 fazla tutaruser_a
userBAtaBNakit bacağındaki fazla tutaruser_b

Fazla tutar hesapları yalnızca bir escrow kabul edilen miktardan fazlasını tuttuğunda kullanılır; ancak mint'e sahip olan herkes escrow'a birkaç temel birim göndererek fazla tutar oluşturabilir. İade hesabı yoksa Settle işleminin tamamı başarısız olur, bu yüzden dördünü de aynı işlemde idempotent biçimde 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 listenin ardından eklenen hesaplardan kaçının varlık bacağının transfer hook'una ait olduğunu programa bildirir; geri kalanlar nakit bacağınındır. 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ınkiler; legAExtrasCount ilk gruptaki sayıya ayarlanmalıdır. TypeScript'te çözümlenen meta'ları talimatın accounts dizisine spread edin; Rust'ta builder üzerinde add_remaining_accounts kullanın. Üst sınır, hook programı ve doğrulama hesabı dahil olmak üzere bacak başına 32 hesaptır; her iki bacak da hook taşıdığında işlem hesap sınırı önce devreye girebilir. Program, iletilen her hesaptan signer bayrağını kaldırır; dolayısıyla bir hook bu yol üzerinden takas yetkilisinin imzasını elde edemez.

Sonucu kaydedin

Settle işlemi finalized durumuna ulaştığında trade'i takas edilmiş sayın. Takastan sonra kayıt ve her iki escrow artık mevcut olmadığından, koşullara sonradan ihtiyaç duyan bir sistem bunları takas öncesi okumadan veya oluşturan işlemden saklar. Kapatılan hesapların rent'i takas yetkilisine geçmiştir.

Settle hataları

LegNotFunded, bir escrow'un kabul edilen miktardan azını tuttuğu anlamına gelir; DvpExpired ve SettlementTooEarly zaman aralığının kaçırıldığını gösterir; 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'in yetkililerine bağlı olarak işlemi geri alabilir (bkz. trade'i geri alma).

Sonraki adımlar

  • Trade'i geri alma: bir trade takas edilmediğinde fonlanmış bacakları geri kazanma

Is this page helpful?

İçindekiler

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