Menyelesaikan Trade

SettleDvp ditandatangani oleh otoritas penyelesaian yang tercantum dalam catatan trade. Dalam satu transaksi, instruksi ini memindahkan amount_a dari leg aset ke tujuan pihak leg kas dan amount_b dari leg kas ke tujuan pihak leg aset, mengembalikan kelebihan dana di escrow mana pun kepada pihak dari leg tersebut, lalu menutup catatan dan kedua escrow. Jika salah satu transfer tersebut tidak dapat diselesaikan, instruksi gagal dan tidak ada yang berpindah.

Halaman ini melanjutkan dari membuat trade dan mendanai leg; klien, penanda tangan, trade, dan token account milik para pihak tetap digunakan.

Validasi ulang sebelum menandatangani

Otoritas penyelesaian menandatangani transaksi yang memindahkan kedua leg, sehingga ia melakukan pembacaan yang sama seperti setiap pihak sebelum menandatangani: pemilik, ukuran, pihak, mint, jumlah, masa berlaku, dan kedua tujuan (lihat mendanai leg). Program itu sendiri memeriksa ulang saat penyelesaian bahwa setiap mint masih termasuk dalam token program yang dicatat saat pembuatan, tidak membawa ekstensi yang diblokir, dan memiliki mint authority yang sama seperti saat trade dibuat, sehingga mint yang dibuat ulang dengan ekstensi yang diblokir, token program yang berbeda, atau mint authority yang berbeda tidak dapat diselesaikan.

Membuat akun penerima

Settle menulis ke empat token account yang tidak dibuat oleh program:

AkunMenerimaPemilik
userADestinationAtaBLeg kas (amount_b)user_a_settlement_destination
userBDestinationAtaALeg aset (amount_a)user_b_settlement_destination
userAAtaAKelebihan dana pada leg asetuser_a
userBAtaBKelebihan dana pada leg kasuser_b

Akun kelebihan dana hanya digunakan ketika escrow menyimpan lebih dari jumlah yang disepakati, tetapi siapa pun yang memegang mint dapat menciptakan kelebihan dengan mengirim beberapa unit dasar ke escrow. Jika akun pengembalian dana tidak ada, seluruh Settle gagal, jadi buat keempatnya secara idempoten dalam transaksi yang sama.

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 memberi tahu program berapa banyak akun yang ditambahkan setelah daftar tetap yang termasuk dalam transfer hook leg aset; sisanya masuk ke leg kas. Untuk mint tanpa transfer hook, berikan nol dan jangan tambahkan apa pun. Program account memo diwajibkan oleh instruksi dan hanya digunakan untuk tujuan yang memerlukan memo.

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

IDL yang dihasilkan hanya mencantumkan akun tetap, sehingga builder yang dihasilkan tidak mengetahui akun hook. Resolusikan extra account meta dari setiap hook mint dengan cara yang sama seperti untuk transfer langsung token tersebut, lalu tambahkan ke instruksi: akun leg aset terlebih dahulu, kemudian leg kas, dengan legAExtrasCount diatur ke jumlah pada kelompok pertama. Di TypeScript, sebarkan (spread) meta yang telah diresolusi ke array accounts milik instruksi; di Rust, gunakan add_remaining_accounts pada builder. Batasnya adalah 32 akun per leg, termasuk program hook dan akun validasi; batas akun transaksi dapat tercapai lebih dulu ketika kedua leg membawa hook. Program menghapus flag signer dari setiap akun yang diteruskan, sehingga hook tidak dapat memperoleh tanda tangan otoritas penyelesaian melalui jalur ini.

Mencatat hasil

Anggap trade telah selesai ketika transaksi Settle mencapai finalized. Catatan dan kedua escrow tidak lagi ada setelah penyelesaian, sehingga sistem yang membutuhkan ketentuannya di kemudian hari menyimpannya dari pembacaan sebelum penyelesaian atau dari transaksi pembuatan. rent dari akun yang ditutup telah diberikan kepada otoritas penyelesaian.

Error Settle

LegNotFunded berarti escrow menyimpan kurang dari jumlah yang disepakati; DvpExpired dan SettlementTooEarly berarti jendela waktu terlewat; MintAuthorityChanged dan BlockedMintExtension berarti mint berubah setelah pembuatan; RecipientAtaMismatch berarti token account tujuan atau pengembalian dana tidak ada atau tidak lagi dimiliki oleh pemilik dan mint yang diharapkan, biasanya karena langkah pembuatan akun di atas dilewati. Dalam setiap kasus, tidak ada yang berpindah, dan para pihak dapat membatalkan, tergantung pada otoritas mint (lihat membatalkan trade).

Langkah berikutnya

  • Membatalkan trade: memulihkan leg yang sudah didanai ketika trade tidak diselesaikan

Is this page helpful?

Daftar Isi

Edit Halaman
© 2026 Yayasan Solana. Semua hak dilindungi.