Membuat Trade

CreateDvp mencatat ketentuan sebuah trade dan membuat dua akun escrow yang akan didanai oleh para pihak. Instruksi ini tidak memindahkan token. Siapa pun dapat mengirimkannya, sehingga catatan bisa berasal dari counterparty, operator otoritas penyelesaian, atau pihak ketiga, dan setiap peserta lain memverifikasi ketentuan yang tersimpan sebelum bertindak berdasarkan ketentuan tersebut (lihat mendanai kedua leg).

Cuplikan kode menggunakan klien yang dihasilkan secara langsung, dengan alamat placeholder, sehingga akun dan penanda tangan yang terlibat terlihat jelas. Cuplikan ini menargetkan devnet, tempat program di-deploy pada alamat yang sama dengan mainnet-beta.

Instalasi

Per 2 Oktober 2026, belum ada paket yang dipublikasikan untuk klien DvP. Keduanya dihasilkan dari IDL program di repositori dan digunakan langsung dari source.

git clone https://github.com/solana-foundation/dvp.git
cd dvp && git checkout df9919ed02c25a93620e7f6820107c9050ce3b92
pnpm install && pnpm generate-clients && pnpm build
# The client is clients/typescript/src; copy or link it into your project as ./dvp
pnpm add @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token-2022 @solana-program/memo

Halaman-halaman ini ditulis berdasarkan commit df9919e, dengan @solana/kit 8 di TypeScript dan crate solana-* 2.x di Rust.

Cuplikan kode di setiap halaman langkah saling berkesinambungan: setiap halaman menggunakan klien, penanda tangan, dan alamat yang didefinisikan di halaman sebelumnya. payerSigner, userASigner, userBSigner, dan authoritySigner adalah TransactionSigner untuk pembayar rent, kedua pihak, dan otoritas penyelesaian, misalnya dari createKeyPairSignerFromBytes. Cuplikan Rust membangun instruksi dan menyerahkan proses penandatanganan serta pengiriman kepada pemanggil.

Catatan trade adalah Program Derived Address yang diturunkan dari otoritas penyelesaian, kedua pihak, kedua mint, dan sebuah nonce. Setiap escrow adalah associated token account milik catatan tersebut untuk salah satu mint. Kedua penurunan ini tidak memerlukan akses jaringan.

Gunakan nonce 64-bit acak untuk setiap trade. Karena pembuatannya tidak memerlukan izin (permissionless), nonce yang dapat ditebak memungkinkan pihak ketiga menempati alamat yang akan dipakai oleh trade. Berikan nonce dan jumlah sebagai bigint di TypeScript; klien yang dihasilkan akan menolak number.

Ganti setiap placeholder ..._HERE dengan alamat yang sebenarnya sebelum menjalankan kode. address() memvalidasi base58 dan akan melempar error pada placeholder, sedangkan pubkey! gagal dikompilasi.

import { address, createClient } from "@solana/kit";
import { solanaRpc } from "@solana/kit-plugin-rpc";
import { signer } from "@solana/kit-plugin-signer";
import { TOKEN_2022_PROGRAM_ADDRESS } from "@solana-program/token-2022";
import { findSwapDvpEscrowAta, findSwapDvpPda } from "./dvp";
const client = createClient()
.use(signer(payerSigner))
.use(
solanaRpc({
rpcUrl: "https://api.devnet.solana.com",
rpcSubscriptionsUrl: "wss://api.devnet.solana.com",
}),
);
const settlementAuthority = address("SETTLEMENT_AUTHORITY_ADDRESS_HERE");
const userA = address("ASSET_LEG_PARTY_ADDRESS_HERE");
const userB = address("CASH_LEG_PARTY_ADDRESS_HERE");
const mintA = address("ASSET_MINT_ADDRESS_HERE");
const mintB = address("CASH_MINT_ADDRESS_HERE");
const tokenProgramA = TOKEN_2022_PROGRAM_ADDRESS;
const tokenProgramB = TOKEN_2022_PROGRAM_ADDRESS;
// A fresh random nonce per trade, as a bigint.
const nonce = new DataView(
crypto.getRandomValues(new Uint8Array(8)).buffer,
).getBigUint64(0);
const [swapDvp] = await findSwapDvpPda({
settlementAuthority,
userA,
userB,
mintA,
mintB,
nonce,
});
const [escrowA] = await findSwapDvpEscrowAta({
swapDvp,
mint: mintA,
tokenProgram: tokenProgramA,
});
const [escrowB] = await findSwapDvpEscrowAta({
swapDvp,
mint: mintB,
tokenProgram: tokenProgramB,
});

Mencatat ketentuan

CreateDvp menerima dua jumlah dalam satuan dasar, waktu kedaluwarsa, nonce, dan empat field opsional: referensi opak hingga 64 byte, tujuan penyelesaian untuk masing-masing sisi, dan waktu penyelesaian paling awal (lihat Catatan). Tujuan adalah tempat hasil dari pihak tersebut diterima saat penyelesaian, misalnya dompet setoran milik kustodian; nilai defaultnya adalah alamat pihak itu sendiri dan tidak dapat diubah setelah catatan dibuat. Pengembalian dana dan klaim ulang selalu masuk ke token account milik pihak itu sendiri untuk mint pada leg tersebut, tidak pernah ke tujuan penyelesaian, siapa pun yang mendanai escrow.

Pembayar mendanai rent untuk catatan, tombstone nonce, dan kedua escrow. Saat penutupan, rent tersebut diberikan kepada siapa pun yang menandatangani instruksi penutupan, bukan dikembalikan ke pembayar. Tombstone tidak pernah ditutup, sehingga setiap trade menyisakan saldo kecil secara permanen. Saat menganggarkan SOL pembayar, turunkan jumlah rent dengan metode RPC getMinimumBalanceForRentExemption alih-alih menuliskannya secara hardcode.

import { getCreateDvpInstruction } from "./dvp";
const nowSeconds = BigInt(Math.floor(Date.now() / 1000));
const createInstruction = getCreateDvpInstruction({
payer: payerSigner,
swapDvp,
nonceTombstone: (
await getProgramDerivedAddress({
programAddress: DVP_SWAP_PROGRAM_PROGRAM_ADDRESS,
seeds: ["nonce", getAddressEncoder().encode(swapDvp)],
})
)[0],
settlementAuthority,
userA,
userB,
mintA,
mintB,
dvpAtaA: escrowA,
dvpAtaB: escrowB,
tokenProgramA,
tokenProgramB,
amountA: 1_000_000_000n, // 1,000 units of a 6-decimal asset
amountB: 998_500_000n, // 998.50 units of a 6-decimal cash token
expiryTimestamp: nowSeconds + 60n * 60n * 24n, // one day
nonce,
refString: "ORDER-2026-10-02-0001",
userASettlementDestination: null, // defaults to userA
userBSettlementDestination: null, // defaults to userB
earliestSettlementTimestamp: null,
});
const { context } = await client.sendTransaction([createInstruction]);
console.log("Trade record:", swapDvp, "signature:", context.signature);

Cuplikan TypeScript memerlukan getProgramDerivedAddress dan getAddressEncoder dari @solana/kit, serta DVP_SWAP_PROGRAM_PROGRAM_ADDRESS dari klien, dalam scope. Builder Rust membiarkan System Program dan Associated Token Program pada nilai defaultnya.

Catatan

  • Kedaluwarsa. Hanya Settle yang memeriksa waktu kedaluwarsa. Reclaim, Cancel, dan Reject tetap dapat dijalankan setelahnya, dan setoran yang masuk setelah kedaluwarsa dapat dipulihkan oleh pihak pemilik leg tersebut. Waktu kedaluwarsa paling lama satu tahun setelah pembuatan.
  • Waktu adalah waktu jaringan. Program membaca jam onchain, yang dapat berbeda dari waktu jam dinding, terkadang hingga puluhan detik, dan dapat melompat maju. Sisakan margin antara waktu kedaluwarsa dan waktu penyelesaian yang dimaksudkan, hindari mendanai atau menyelesaikan trade di dekat kedua batas tersebut, dan jangan mengandalkan waktu kedaluwarsa untuk menegakkan tenggat hingga ke detik. README program menyarankan untuk menganggarkan selisih sekitar satu menit.
  • Penyelesaian paling awal. Opsional. Jika diatur, Settle ditolak sebelum waktu tersebut, dan waktunya tidak boleh lebih lambat dari waktu kedaluwarsa.
  • Pemeriksaan saat pembuatan. Pembuatan gagal dengan PartyNotSignerCapable jika salah satu pihak bukan akun milik sistem (ini mengecualikan multisig SPL Token), SettlementDestinationIsSwapDvp, SelfDvp, SameMint, ZeroAmount, SettlementAuthorityIsParty, atau ExpiryNotInFuture. Daftar lengkapnya ada di tabel error.

Langkah berikutnya

Is this page helpful?

Daftar Isi

Edit Halaman
© 2026 Yayasan Solana. Semua hak dilindungi.