Membuat Trade

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

Cuplikan kode menggunakan klien yang dihasilkan secara langsung, dengan alamat placeholder, sehingga akun dan signer 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 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 berkelanjutan: setiap halaman menggunakan klien, signer, 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 penandatanganan serta pengiriman kepada pemanggil.

Record trade adalah program-derived address yang diturunkan dari otoritas penyelesaian, kedua pihak, kedua mint, dan sebuah nonce. Setiap escrow adalah associated token account milik record untuk salah satu mint. Kedua penurunan ini tidak memerlukan akses jaringan.

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

Ganti setiap placeholder ..._HERE dengan alamat yang sebenarnya sebelum dijalankan. address() memvalidasi base58 dan 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 bidang opsional: referensi opak hingga 64 byte, tujuan penyelesaian untuk masing-masing sisi, dan waktu penyelesaian paling awal (lihat Catatan). Tujuan tersebut adalah tempat hasil dari pihak itu diterima saat penyelesaian, misalnya dompet deposit milik kustodian; secara default berupa alamat pihak itu sendiri dan tidak dapat diubah setelah record dibuat. Refund dan reclaim selalu masuk ke token account milik pihak itu sendiri untuk mint pada sisi tersebut, tidak pernah ke tujuan penyelesaian, siapa pun yang mendanai escrow.

Payer mendanai rent untuk record, tombstone nonce, dan kedua escrow. Saat ditutup, rent tersebut diberikan kepada siapa pun yang menandatangani instruksi penutupan, bukan dikembalikan ke payer. Tombstone tidak pernah ditutup, sehingga setiap trade menyisakan saldo permanen yang kecil. Saat menganggarkan SOL payer, 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, tersedia 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 berfungsi setelahnya, dan deposit yang masuk setelah kedaluwarsa dapat dipulihkan oleh pihak pemilik sisi 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 direncanakan, hindari pendanaan atau penyelesaian mendekati salah satu batas, dan jangan mengandalkan waktu kedaluwarsa untuk menegakkan tenggat waktu hingga hitungan detik. README program menyarankan menganggarkan sekitar satu menit untuk selisih waktu.
  • Penyelesaian paling awal. Opsional. Jika diatur, Settle akan ditolak sebelum waktu tersebut, dan waktunya tidak boleh lebih lambat dari waktu kedaluwarsa.
  • Pemeriksaan saat pembuatan. Create gagal dengan PartyNotSignerCapable jika suatu pihak bukan akun milik System Program (ini menyingkirkan 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.