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.gitcd dvp && git checkout df9919ed02c25a93620e7f6820107c9050ce3b92pnpm install && pnpm generate-clients && pnpm build# The client is clients/typescript/src; copy or link it into your project as ./dvppnpm 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.
Menurunkan alamat
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 assetamountB: 998_500_000n, // 998.50 units of a 6-decimal cash tokenexpiryTimestamp: nowSeconds + 60n * 60n * 24n, // one daynonce,refString: "ORDER-2026-10-02-0001",userASettlementDestination: null, // defaults to userAuserBSettlementDestination: null, // defaults to userBearliestSettlementTimestamp: 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
PartyNotSignerCapablejika salah satu pihak bukan akun milik sistem (ini mengecualikan multisig SPL Token),SettlementDestinationIsSwapDvp,SelfDvp,SameMint,ZeroAmount,SettlementAuthorityIsParty, atauExpiryNotInFuture. Daftar lengkapnya ada di tabel error.
Langkah berikutnya
- Mendanai kedua leg: setiap pihak mentransfer leg-nya ke escrow trade
Is this page helpful?