Program Delivery vs Payment (DvP)

Program DvP adalah program standar untuk delivery versus payment di Solana, dikelola oleh Solana Foundation dan diaudit oleh Cantina. Dua pihak menyepakati sebuah trade, masing-masing mengirim sisinya (leg) ke akun escrow melalui transfer token biasa, lalu otoritas penyelesaian menyelesaikan kedua sisi dalam satu transaksi, sehingga keduanya berpindah atau tidak sama sekali. Otoritas penyelesaian adalah alamat ketiga yang disebutkan dalam trade, seperti venue atau agen yang mengaturnya. Tidak ada pihak yang perlu menulis atau men-deploy program, dan wallet atau kustodian yang dapat mengirim transfer token standar (TransferChecked) dapat mendanai sebuah leg tanpa integrasi khusus DvP. Sebelum penyelesaian, masing-masing pihak dapat menarik kembali legnya sendiri atau membatalkan trade.

Baca catatan sebelum bertindak berdasarkan catatan tersebut

Pembuatan catatan trade bersifat permissionless, sehingga sebuah catatan bukan bukti kesepakatan. Setiap pihak membaca ketentuan yang tersimpan sebelum mendanai, dan otoritas penyelesaian membacanya sebelum menyelesaikan (lihat verifikasi).

Cara kerjanya

Setiap trade mendapatkan satu catatan milik program dan dua akun escrow, satu per leg. Pihak asset-leg (user_a) dan pihak cash-leg (user_b) masing-masing mendanai satu leg dengan mentransfer token ke akun escrow untuk leg tersebut. Otoritas penyelesaian adalah satu-satunya penanda tangan yang dapat menyelesaikan. Penyelesaian mentransfer jumlah yang disepakati dari setiap leg ke pihak lawan, mengembalikan kelebihan apa pun kepada pihak yang memiliki leg tersebut, dan menutup catatan beserta kedua escrow. Sifat atomik berasal dari transaksi Solana: kedua transfer berada dalam satu transaksi, sehingga keduanya berlaku atau tidak sama sekali.

Setiap refund, penarikan kembali, dan pengembalian kelebihan masuk ke associated token account milik pihak tersebut: akun user_a untuk mint_a, akun user_b untuk mint_b. Sistem kustodian atau treasury dapat mendanai sebuah leg dari akunnya sendiri, tetapi apa pun yang dikembalikan masuk ke akun pihak tersebut, bukan kembali ke kustodian. Setiap trade juga meninggalkan akun penanda permanen (lihat State).

Panduan

Halaman langkah membahas satu trade dari pembuatan hingga penyelesaian, dengan TypeScript dan Rust untuk setiap instruksi.

Sebuah demo devnet menjalankan trade dari awal hingga akhir: membuat trade, mendanai kedua escrow dengan transfer token standar, dan menyelesaikan kedua leg dalam satu transaksi.

Memilih antara program dan delegasi

Delivery vs Payment (DvP) menggunakan delegasi menyelesaikan pertukaran yang sama tanpa program: masing-masing pihak mendelegasikan posisinya ke agen penyelesaian, yang memindahkan kedua leg dalam satu transaksi.

  • Program tidak memerlukan delegasi, sehingga batas satu delegate per token account tidak berlaku, dan otoritas penyelesaian tidak dapat mengalihkan hasil. Setiap trade bergantung pada program yang dapat di-upgrade dan upgrade authority-nya.
  • Pola delegasi tidak memiliki dependensi program dan bekerja dengan mint yang memiliki Scaled UI Amount. Program menolak mint tersebut, yang berarti mengecualikan setiap mint yang dibuat dari template tokenized-security milik Mosaic (lihat batasan konfigurasi mint).

Peran

Program ini bersifat simetris. Dalam antarmukanya, kedua pihak adalah user_a, yang mengirimkan mint_a, dan user_b, yang mengirimkan mint_b. README dan klien yang dihasilkan menyebut mint_a sebagai asset leg dan mint_b sebagai cash leg, dan halaman ini mengikuti konvensi tersebut, tetapi tidak ada ketentuan dalam program yang mengharuskan cash leg berupa instrumen kas. Dua aset, atau dua stablecoin, diselesaikan dengan cara yang sama.

PeranSiapaMenandatanganiCatatan
Pihak asset-leguser_a, mengirimkan mint_aTransfer pendanaannya sendiri; Reclaim, Reject, RecoverWallet keypair, atau smart wallet berbasis PDA seperti vault multisig. Akun multisig SPL Token atau program account tidak dapat menjadi pihak: Create gagal dengan PartyNotSignerCapable
Pihak cash-leguser_b, mengirimkan mint_bTransfer pendanaannya sendiri; Reclaim, Reject, RecoverPersyaratan yang sama
Otoritas penyelesaianAlamat ketiga yang disebutkan saat pembuatanSettle, CancelSatu-satunya penanda tangan yang dapat menyelesaikan. Tidak dapat mengalihkan hasil, yang ditetapkan saat pembuatan. Menerima rent dari akun yang ditutup saat menyelesaikan atau membatalkan
Pembayar rentSiapa pun yang menandatangani CreateDvpCreateMendanai rent (deposit SOL yang menjaga akun tetap terbuka) untuk catatan, nonce tombstone, dan kedua escrow. Tidak dicatat sebagai penerima rent: rent dari akun yang ditutup diberikan kepada siapa pun yang menutup trade

ID Program

dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq
ClusterProgramUpgrade authoritySlot deploy terakhir
mainnet-betadvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZqDXtFpbPjcn2hxPnw79x1Pfoj35vXh5AsWBkS37YnXMVv452,058,374
devnetdvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq5EX1zFeJWj4rGYZv432WnYw8CbaSUeTdxPx4r573UgYU479,376,863

Program ini dapat di-upgrade di kedua cluster. Angka di atas adalah yang dilaporkan solana program show pada 2 Oktober 2026; jalankan perintah yang sama untuk mendapatkan nilai terkini. Build devnet lebih lama daripada commit yang menjadi acuan halaman langkah (lihat Install), dengan kumpulan instruksi dan error yang sama.

Siklus hidup

Sebuah trade terbuka sejak CreateDvp hingga salah satu dari Settle, Cancel, atau Reject menutupnya. Pendanaan tidak memiliki instruksi tersendiri: sebuah leg dianggap terdanai ketika akun escrow-nya menyimpan setidaknya jumlah yang disepakati. Reclaim berlaku per leg dan membiarkan trade tetap terbuka, sehingga masalah pada satu leg tidak memaksa pihak lain membatalkan seluruh trade.

State

Setiap trade memiliki satu akun SwapDvp berukuran 458 byte, dimiliki oleh program. Alamatnya diturunkan dari otoritas penyelesaian, kedua pihak, kedua mint, dan sebuah nonce (seed ["dvp", settlement_authority, user_a, user_b, mint_a, mint_b, nonce]). Jumlah dan waktu disimpan di dalam akun dan tidak memengaruhi alamat, sehingga harus dibaca dan tidak boleh diasumsikan. Sebuah akun penanda kecil, nonce tombstone di ["nonce", swap_dvp], dibuat bersama trade dan tidak pernah ditutup, sehingga setiap kombinasi pihak, mint, otoritas, dan nonce hanya dapat digunakan untuk satu trade.

FieldTipeArti
bumpu8PDA bump
user_a, user_bPubkeyKedua pihak
mint_a, mint_bPubkeyMint untuk asset leg dan cash leg
settlement_authorityPubkeySatu-satunya penanda tangan yang dapat menyelesaikan atau membatalkan
token_program_a, token_program_bPubkeytoken program yang memiliki setiap mint; sebuah trade dapat mencampur leg SPL Token dan Token-2022
amount_a, amount_bu64Jumlah yang disepakati untuk setiap leg, dalam satuan terkecil mint (base unit)
expiry_timestampi64Setelah waktu jaringan ini (jam onchain), Settle ditolak. Reclaim, Cancel, dan Reject tetap berfungsi
nonceu64Membedakan trade yang memiliki seed lain yang sama. Sekali pakai
ref_string[u8; 64]Referensi klien yang opaque, diisi nol (zero-padded); program tidak pernah membacanya
user_a_settlement_destinationPubkeyMenerima cash leg saat Settle; secara default user_a
user_b_settlement_destinationPubkeyMenerima asset leg saat Settle; secara default user_b
mint_a_authority, mint_b_authorityPubkeyMint authority yang dicatat saat pembuatan; Settle gagal jika salah satunya berubah
earliest_settlement_timestampOption<i64>Jika diatur, Settle ditolak sebelum waktu jaringan ini

Daftar field diambil dari IDL program pada commit yang disebutkan di bawah Buat trade.

Instruksi

InstruksiPenanda tanganEfek
CreateDvpPembayar mana punMembuat catatan SwapDvp, nonce tombstone-nya, dan kedua akun escrow. Tidak memindahkan token
ReclaimDvpuser_a atau user_bMengembalikan leg milik penanda tangan dari escrow. Trade tetap terbuka dan leg dapat didanai kembali
SettleDvpOtoritas penyelesaianMentransfer amount_a ke tujuan user_b dan amount_b ke tujuan user_a, mengembalikan kelebihan apa pun kepada pihak pemilik leg, menutup catatan dan kedua escrow
CancelDvpOtoritas penyelesaianMe-refund isi escrow A ke user_a dan escrow B ke user_b, menutup catatan dan kedua escrow
RejectDvpuser_a atau user_bEfek sama seperti Cancel, ditandatangani oleh salah satu pihak
RecoverDvpuser_a atau user_bSetelah trade ditutup: menguras escrow yang dibuat ulang ke token account milik penanda tangan dan menutupnya. Mencakup deposit yang masuk setelah Settle, Cancel, atau Reject

Setiap refund masuk ke associated token account milik pihak tersebut untuk mint leg itu, siapa pun yang mendanai escrow.

Akun dan argumen setiap instruksi tersedia di halaman untuk langkah tersebut.

Error

KodeErrorKapan
0SignerNotPartyReclaim, Reject, atau Recover ditandatangani oleh alamat yang bukan user_a atau user_b
1DvpExpiredSettle setelah expiry_timestamp
2SettlementAuthorityMismatchSettle atau Cancel ditandatangani oleh alamat selain otoritas penyelesaian
3SettlementTooEarlySettle sebelum earliest_settlement_timestamp
4LegNotFundedSettle saat sebuah escrow menyimpan kurang dari jumlah yang disepakati
5ExpiryNotInFutureCreate dengan expiry pada atau sebelum waktu jaringan saat ini
6EarliestAfterExpiryCreate dengan waktu penyelesaian paling awal setelah expiry
7SelfDvpCreate dengan user_a sama dengan user_b
8SameMintCreate dengan mint_a sama dengan mint_b
9ZeroAmountCreate dengan jumlah nol pada salah satu leg
10BlockedMintExtensionCreate atau Settle dengan mint yang memiliki TransferFee, InterestBearing, ScaledUiAmount, atau NonTransferable
11SettlementAuthorityIsPartyCreate dengan otoritas penyelesaian yang sama dengan salah satu pihak
12SettlementAuthorityExecutableCreate dengan otoritas penyelesaian yang executable
13NonceAlreadyUsedCreate yang menggunakan kembali (seeds, nonce) yang sudah memiliki tombstone
14ExpiryTooFarInFutureCreate dengan expiry lebih dari satu tahun ke depan
15RefStringTooLongCreate dengan referensi lebih panjang dari 64 byte
16DvpStillOpenRecover saat trade masih terbuka; gunakan Reclaim
17DvpNeverCreatedRecover dengan seed yang tidak memiliki tombstone
18EscrowPreloadedWithLamportsCreate saat escrow non-native menyimpan lamport di atas minimum rent-exempt-nya
19SettlementDestinationIsSwapDvpCreate dengan tujuan settlement yang sama dengan catatan trade
20SwapDvpPreloadedWithLamportsCreate saat alamat catatan menyimpan lamport di atas cadangan rent-nya
21RecipientAtaMismatchSebuah token account penerima atau refund tidak lagi dimiliki oleh wallet dan mint yang diharapkan
22PartyNotSignerCapableCreate dengan party yang bukan akun milik sistem dan non-executable
23MintAuthorityChangedSettle saat mint authority suatu leg berbeda dari nilai yang dicatat saat pembuatan

Event dan indexing

Program ini tidak mengeluarkan event onchain. Indexer atau sistem rekonsiliasi membaca status akun SwapDvp dan saldo token dari kedua escrow, serta menggunakan ref_string untuk mengorelasikan trade dengan order off-chain-nya. Karena catatan ditutup saat settlement, sistem yang membutuhkan ketentuan tersebut setelahnya menyimpannya saat membacanya, atau merekonstruksinya dari transaksi yang membuat trade tersebut.

Token yang didukung

Sebuah trade dapat memasangkan leg SPL Token dengan leg Token-2022; setiap leg membawa token program-nya sendiri. Leg Wrapped SOL didukung.

Ekstensi Token-2022 pada mint sebuah legPerilaku program
TransferFee, InterestBearing, ScaledUiAmount, NonTransferableDitolak saat Create dan Settle dengan BlockedMintExtension
PermanentDelegate, Pausable, DefaultAccountState, freeze authority, MintCloseAuthorityDiterima; setiap authority dapat bertindak atas token yang di-escrow
ConfidentialTransferDiterima; jumlah pada leg tersebut bersifat publik
TransferHookDidukung, hingga 32 akun tambahan per leg
MemoTransfer pada akun tujuan atau refundDiterima; program mengeluarkan memo yang diperlukan sebelum transfer

Biaya transfer akan membuat sisi penerima kekurangan dari jumlah yang disepakati. Interest Bearing dan Scaled UI Amount tidak mengubah jumlah mentah, tetapi rate atau multiplier-nya dapat berubah antara pembuatan dan settlement trade, yang mengubah cara jumlah yang disepakati ditampilkan. NonTransferable akan membuat kedua leg terjebak.

Authority yang diterima dapat memindahkan, membekukan, atau menghentikan token yang di-escrow selama masa berlaku trade (lihat di bawah). Escrow tidak dapat dikonfigurasi untuk menerima transfer rahasia (confidential), sehingga jumlah yang di-escrow dan di-settle pada leg confidential bersifat publik.

Untuk mint dengan hook, klien me-resolve akun tambahan milik hook dan menambahkannya ke Settle, Cancel, Reject, Reclaim, dan Recover. Batas 32 per leg menghitung program hook dan akun validasinya. Jika hook authority memperbesar daftar akun hook melebihi batas tersebut, setiap transfer pada leg itu gagal, termasuk Reclaim, Cancel, Reject, dan Recover, sampai authority membatalkannya. Batas akun transaksi dapat tercapai lebih dulu sebelum batas per leg jika kedua leg memiliki hook.

Ketika akun tujuan atau refund mewajibkan memo, program memanggil program Memo sebelum transfer, itulah sebabnya setiap instruksi yang memindahkan token keluar dari escrow membutuhkan akun memo_program.

Batasan konfigurasi mint

Scaled UI Amount. Template tokenized-security di Mosaic, toolkit penerbitan Solana Foundation, selalu menambahkan Scaled UI Amount, sehingga program ini tidak menerima mint yang dibuat dari template tersebut sebagai leg. Mint yang ditujukan untuk program ini dapat dibuat tanpa ekstensi tersebut (lihat Token Extensions); DvP menggunakan delegasi melakukan settlement melalui otoritas yang didelegasikan dan tidak menerapkan pemeriksaan ini.

Mint yang dibekukan secara default. Escrow setiap trade adalah associated token account yang dimiliki oleh Program Derived Address yang baru untuk trade tersebut. Pada mint dengan Default Account State yang diatur ke frozen, escrow dibuat dalam keadaan frozen, dan transfer pendanaan ke dalamnya gagal sampai di-thaw. Di bawah Token ACL itu berarti penerbit atau transfer agent-nya mengizinkan escrow trade sebelum pendanaan: baik dengan menambahkan alamat catatan trade (pemilik escrow) ke allowlist, sehingga siapa pun dapat men-thaw escrow tersebut jika konfigurasi Token ACL mint mengaktifkan permissionless thaw, atau dengan meminta freeze authority men-thaw-nya secara langsung. Escrow yang dibekukan juga memblokir Settle, Reclaim, Cancel, Reject, dan Recover pada leg tersebut, sehingga freeze authority, dan pada mint dengan hook, hook authority, merupakan pihak tepercaya selama masa berlaku trade. Jalur escrow yang dibekukan dijelaskan di sini dan tidak dijalankan dalam snippet devnet.

Batasan

  • Tidak ada pencocokan, penemuan harga, atau order book. Para pihak menyepakati ketentuan di luar ledger dan salah satunya mencatatnya.
  • Tidak ada netting, dan hanya bilateral: satu catatan adalah satu trade antara dua pihak.
  • Tidak ada partial fill. Settle memindahkan tepat jumlah yang disepakati dari setiap leg dan mengembalikan kelebihan apa pun kepada party leg tersebut.
  • Tidak ada leg off-ledger. Kedua leg adalah token account di Solana; leg tunai pada rel yang sudah ada diselesaikan secara terpisah dan direkonsiliasi.
  • Tidak ada pemeriksaan kelayakan, allowlist, atau KYC. Kontrol milik mint sendiri yang menegakkan kelayakan pemegang.
  • Tidak ada settlement otomatis. Settlement authority harus menandatangani.
  • Tidak ada event, dan tidak ada biaya protokol selain biaya transaksi dan rent.

Program ini menghilangkan risiko pokok (principal risk) antara kedua pihak: tidak ada leg yang bergerak kecuali keduanya bergerak. Program ini tidak menghilangkan risiko kredit penerbit atau risiko penebusan pada kedua token, kemampuan freeze, pause, atau permanent delegate authority suatu mint untuk bertindak atas token yang di-escrow (lihat token yang didukung), atau ketergantungan pada ketersediaan settlement authority untuk menandatangani.

Verifikasi sebelum pendanaan dan settlement

CreateDvp bersifat permissionless: hanya payer yang menandatangani, sedangkan para pihak dan settlement authority tidak. Karena itu, siapa pun dapat membuat catatan yang menyebut pihak dan ketentuan apa pun. Sebelum pendanaan, dan lagi sebelum settlement, baca akun SwapDvp dan pastikan:

  1. Akun dimiliki oleh program DvP dan berukuran tepat 458 byte. Akun yang tidak dimiliki oleh program dapat diisi dengan byte yang ter-decode seperti catatan asli.
  2. user_a, user_b, mint_a, mint_b, dan settlement_authority sesuai dengan trade yang disepakati.
  3. amount_a, amount_b, expiry_timestamp, dan earliest_settlement_timestamp sesuai dengan ketentuan yang disepakati.
  4. Kedua tujuan settlement adalah alamat yang disepakati. Catatan palsu dapat mengalihkan hasilnya.

Danai leg mencantumkan checked reader dari klien yang dihasilkan dan menunjukkan pemeriksaannya dalam kode.

Anggap sebuah trade telah selesai (settled) ketika transaksi Settle mencapai finalized. Itu adalah tingkat commitment jaringan; apakah itu juga menandai finalitas settlement untuk tujuan hukum bergantung pada perjanjian para pihak dan rezim yang berlaku.

Pembuatan versi

Akun SwapDvp tidak memiliki field versi. Tata letaknya tetap pada 458 byte (SwapDvp::LEN), dan checked reader menolak akun dengan panjang lain. IDL memiliki versinya sendiri, 0.1.0 per 2 Oktober 2026.

Program ini dapat di-upgrade di kedua cluster (lihat Program ID). Catatan trade hanya ada sampai di-settle, dibatalkan, atau ditolak, jadi periksa repositori untuk mengetahui bagaimana upgrade memperlakukan trade yang masih terbuka, dan buat ulang klien dari IDL build yang di-deploy.

Repositori dan audit

Source, IDL, klien yang dihasilkan, dan pengujian ada di solana-foundation/dvp di bawah lisensi MIT. Program ini adalah program Pinocchio no_std; klien dihasilkan dari IDL dengan Codama. Laporan kerentanan disampaikan melalui tautan security advisory repositori, sesuai SECURITY.md-nya.

Program ini telah diaudit oleh Cantina.

Terkait

Is this page helpful?

Daftar Isi

Edit Halaman
© 2026 Yayasan Solana. Semua hak dilindungi.