Het DvP-programma is het standaardprogramma voor delivery versus payment (levering tegen betaling) op Solana,
onderhouden door de Solana Foundation en geaudit door Cantina. Twee partijen komen
een trade overeen, elk stuurt zijn leg met een gewone tokenoverdracht naar een escrowaccount,
en een afwikkelautoriteit wikkelt beide legs af in één transactie, zodat
ofwel beide worden verplaatst, ofwel geen van beide. De afwikkelautoriteit is een derde adres
dat in de trade wordt genoemd, zoals de handelsplaats of agent die de trade heeft geregeld. Geen van beide partijen
schrijft of deployt een programma, en een wallet of bewaarder die een standaard
tokenoverdracht (TransferChecked) kan versturen, kan een leg financieren zonder DvP-specifieke
integratie. Tot de afwikkeling kan elke partij zijn eigen leg terugnemen of de
trade ongedaan maken.
Lees het record voordat je erop afgaat
Het aanmaken van een traderecord vereist geen toestemming, dus een record is geen bewijs van overeenstemming. Elke partij leest de opgeslagen voorwaarden voordat ze financiert, en de afwikkelautoriteit voordat ze afwikkelt (zie verificatie).
Hoe het werkt
Elke trade krijgt een record dat eigendom is van het programma en twee escrowaccounts, één per leg. De
partij van de asset-leg (user_a) en de partij van de cash-leg (user_b) financieren elk een leg door
tokens over te maken naar het escrowaccount van die leg. De afwikkelautoriteit
is de enige ondertekenaar die kan afwikkelen. Bij afwikkeling wordt het overeengekomen
bedrag van elke leg naar de andere kant overgemaakt, wordt eventueel overschot teruggestuurd naar de partij die
de leg bezit, en worden het record en beide escrows gesloten. De atomiciteit komt voort uit de
transacties van Solana: beide overdrachten zitten in één transactie,
dus ofwel gebeuren ze allebei, ofwel geen van beide.
Elke terugbetaling, terugvordering en overschotretour gaat naar het eigen associated
token account van de partij: dat van user_a voor mint_a, dat van user_b voor mint_b. Een
bewaarder of treasury-systeem kan een leg vanuit zijn eigen account financieren, maar alles wat
wordt teruggestuurd komt terecht in het account van de partij, niet terug bij de bewaarder. Elke trade
laat ook een permanent markeringsaccount achter (zie Status).
Handleidingen
De stappenpagina's volgen één trade van het aanmaken tot de afwikkeling, met TypeScript en Rust voor elke instructie.
Een trade aanmaken
Installeer de clients en leg de voorwaarden van de trade vast met CreateDvp
De legs financieren
Controleer de opgeslagen voorwaarden en financier daarna elke leg met een gewone overdracht
De trade afwikkelen
Wikkel als afwikkelautoriteit beide legs in één transactie af
Een trade ongedaan maken
Vorder een leg terug, annuleer of weiger de trade en haal late stortingen terug
Een devnet-demo doorloopt een trade van begin tot eind: de demo maakt de trade aan, financiert beide escrows met standaard tokenoverdrachten en wikkelt beide legs in één transactie af.
Kiezen tussen het programma en delegatie
Delivery vs Payment (DvP) met delegatie wikkelt dezelfde uitwisseling af zonder programma: elke kant delegeert zijn positie aan een afwikkelagent, die beide legs in één transactie verplaatst.
- Het programma vereist geen delegatie, dus de limiet van één gedelegeerde per token account geldt niet, en de afwikkelautoriteit kan de opbrengsten niet omleiden. Elke trade is afhankelijk van een upgradebaar programma en de bijbehorende upgrade-autoriteit.
- Het delegatiepatroon heeft geen programma-afhankelijkheid en werkt met mints die
Scaled UI Amount gebruiken. Het programma weigert die mints, wat elke
mint uitsluit die is gemaakt op basis van de
tokenized-security-template van Mosaic (zie beperkingen voor mintconfiguratie).
Rollen
Het programma is symmetrisch. In de interface zijn de twee partijen user_a, die
mint_a levert, en user_b, die mint_b levert. De README en de
gegenereerde clients noemen mint_a de asset-leg en mint_b de cash-leg, en
deze pagina's volgen die conventie, maar niets in het programma vereist dat de cash-leg
een cashinstrument is. Twee assets, of twee stablecoins, worden op dezelfde
manier afgewikkeld.
| Rol | Wie | Ondertekent | Opmerkingen |
|---|---|---|---|
| Partij van de asset-leg | user_a, levert mint_a | Eigen financieringsoverdracht; Reclaim, Reject, Recover | Een keypair-wallet of een PDA-gebaseerde smart wallet zoals een multisig-vault. Een SPL Token multisig-account of een program account kan geen partij zijn: Create mislukt met PartyNotSignerCapable |
| Partij van de cash-leg | user_b, levert mint_b | Eigen financieringsoverdracht; Reclaim, Reject, Recover | Dezelfde vereiste |
| Afwikkelautoriteit | Een derde adres dat bij het aanmaken wordt genoemd | Settle, Cancel | De enige ondertekenaar die kan afwikkelen. Kan de opbrengsten, die bij het aanmaken vastliggen, niet omleiden. Ontvangt de rent van de gesloten accounts wanneer de trade wordt afgewikkeld of geannuleerd |
| Rent-betaler | Wie CreateDvp ondertekent | Create | Financiert de rent (het SOL-depot dat een account open houdt) voor het record, de nonce-tombstone en beide escrows. Niet vastgelegd als rent-ontvanger: de rent van gesloten accounts gaat naar wie de trade sluit |
Program-ID
dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq
| Cluster | Programma | Upgrade-autoriteit | Slot van laatste deployment |
|---|---|---|---|
| mainnet-beta | dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq | DXtFpbPjcn2hxPnw79x1Pfoj35vXh5AsWBkS37YnXMVv | 452,058,374 |
| devnet | dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq | 5EX1zFeJWj4rGYZv432WnYw8CbaSUeTdxPx4r573UgYU | 479,376,863 |
Het programma is upgradebaar op beide clusters. De bovenstaande cijfers zijn wat
solana program show op 2 oktober 2026 meldde; voer dezelfde opdracht uit voor
actuele waarden. De devnet-build is ouder dan de commit waartegen de stappenpagina's
zijn geschreven (zie Installeren),
met dezelfde set instructies en fouten.
Levenscyclus
Een trade is open vanaf CreateDvp totdat Settle, Cancel of Reject hem
sluit. Financiering heeft geen eigen instructie: een leg is gefinancierd wanneer het escrow-
account ten minste het overeengekomen bedrag bevat. Reclaim geldt per leg en laat de
trade open, zodat een probleem met één leg de andere partij niet dwingt de
hele trade te annuleren.
Status
Elke trade heeft één SwapDvp-account van 458 bytes, dat eigendom is van het programma. Het
adres wordt afgeleid van de afwikkelautoriteit, de twee partijen, de twee
mints en een nonce (de seeds
["dvp", settlement_authority, user_a, user_b, mint_a, mint_b, nonce]). De
bedragen en tijden worden in het account opgeslagen en hebben geen invloed op het adres,
en daarom moeten ze worden uitgelezen in plaats van afgeleid. Een klein markeringsaccount,
de nonce-tombstone op ["nonce", swap_dvp], wordt samen met de trade aangemaakt en
nooit gesloten, zodat elke combinatie van partijen, mints, autoriteit en nonce voor
slechts één trade kan worden gebruikt.
| Veld | Type | Betekenis |
|---|---|---|
bump | u8 | PDA-bump |
user_a, user_b | Pubkey | De twee partijen |
mint_a, mint_b | Pubkey | De mints van de asset-leg en de cash-leg |
settlement_authority | Pubkey | De enige ondertekenaar die kan afwikkelen of annuleren |
token_program_a, token_program_b | Pubkey | Het token program dat eigenaar is van elke mint; een trade kan SPL Token- en Token-2022-legs combineren |
amount_a, amount_b | u64 | Het overeengekomen bedrag van elke leg, in de kleinste eenheid van de mint (basiseenheden) |
expiry_timestamp | i64 | Na deze netwerktijd (de onchain-klok) wordt Settle geweigerd. Reclaim, Cancel en Reject werken nog steeds |
nonce | u64 | Maakt onderscheid tussen trades die de overige seeds delen. Eenmalig te gebruiken |
ref_string | [u8; 64] | Een ondoorzichtige clientreferentie, aangevuld met nullen; het programma leest deze nooit |
user_a_settlement_destination | Pubkey | Ontvangt de cash-leg bij Settle; standaard user_a |
user_b_settlement_destination | Pubkey | Ontvangt de asset-leg bij Settle; standaard user_b |
mint_a_authority, mint_b_authority | Pubkey | De mint-autoriteiten die bij het aanmaken zijn vastgelegd; Settle mislukt als een van beide is gewijzigd |
earliest_settlement_timestamp | Option<i64> | Indien ingesteld, wordt Settle vóór deze netwerktijd geweigerd |
De veldenlijst is overgenomen uit de IDL van het programma bij de commit die wordt genoemd onder Een trade aanmaken.
Instructies
| Instructie | Ondertekenaar | Effect |
|---|---|---|
CreateDvp | Elke betaler | Maakt het SwapDvp-record, de nonce-tombstone en beide escrowaccounts aan. Verplaatst geen tokens |
ReclaimDvp | user_a of user_b | Stuurt de eigen leg van de ondertekenaar terug uit escrow. De trade blijft open en de leg kan opnieuw worden gefinancierd |
SettleDvp | Afwikkelautoriteit | Maakt amount_a over naar de bestemming van user_b en amount_b naar de bestemming van user_a, stuurt eventueel overschot terug naar de partij van de leg, sluit het record en beide escrows |
CancelDvp | Afwikkelautoriteit | Stort alles wat escrow A bevat terug aan user_a en wat escrow B bevat aan user_b, sluit het record en beide escrows |
RejectDvp | user_a of user_b | Zelfde effect als Cancel, ondertekend door een partij |
RecoverDvp | user_a of user_b | Nadat de trade is gesloten: leegt een opnieuw aangemaakte escrow naar het eigen token account van de ondertekenaar en sluit deze. Dekt een storting die na Settle, Cancel of Reject is binnengekomen |
Elke terugbetaling gaat naar het eigen associated token account van de partij voor de mint van die leg, ongeacht wie de escrow heeft gefinancierd.
De accounts en argumenten van elke instructie staan op de pagina van die stap.
Fouten
| Code | Fout | Wanneer |
|---|---|---|
| 0 | SignerNotParty | Reclaim, Reject of Recover ondertekend door een adres dat niet user_a of user_b is |
| 1 | DvpExpired | Settle na expiry_timestamp |
| 2 | SettlementAuthorityMismatch | Settle of Cancel ondertekend door een ander adres dan de afwikkelautoriteit |
| 3 | SettlementTooEarly | Settle vóór earliest_settlement_timestamp |
| 4 | LegNotFunded | Settle terwijl een escrow minder bevat dan het overeengekomen bedrag |
| 5 | ExpiryNotInFuture | Create met een vervaldatum op of vóór de huidige netwerktijd |
| 6 | EarliestAfterExpiry | Create met een vroegste afwikkeltijd na de vervaldatum |
| 7 | SelfDvp | Create met user_a gelijk aan user_b |
| 8 | SameMint | Create met mint_a gelijk aan mint_b |
| 9 | ZeroAmount | Create met een bedrag van nul op een van beide legs |
| 10 | BlockedMintExtension | Create of Settle met een mint met TransferFee, InterestBearing, ScaledUiAmount of NonTransferable |
| 11 | SettlementAuthorityIsParty | Create met de afwikkelautoriteit gelijk aan een partij |
| 12 | SettlementAuthorityExecutable | Create met een uitvoerbare afwikkelautoriteit |
| 13 | NonceAlreadyUsed | Create dat een (seeds, nonce) hergebruikt die al een tombstone heeft |
| 14 | ExpiryTooFarInFuture | Create met een vervaldatum die meer dan een jaar vooruit ligt |
| 15 | RefStringTooLong | Create met een referentie die langer is dan 64 bytes |
| 16 | DvpStillOpen | Recover terwijl de trade nog open is; gebruik Reclaim |
| 17 | DvpNeverCreated | Herstellen met seeds zonder tombstone |
| 18 | EscrowPreloadedWithLamports | Create wanneer een niet-native escrow meer lamports bevat dan het rent-exempt minimum |
| 19 | SettlementDestinationIsSwapDvp | Create met een afwikkelbestemming die gelijk is aan het handelsrecord |
| 20 | SwapDvpPreloadedWithLamports | Create wanneer het recordadres meer lamports bevat dan de rent-reserve |
| 21 | RecipientAtaMismatch | Een token account voor de ontvanger of terugbetaling hoort niet meer bij de verwachte wallet en mint |
| 22 | PartyNotSignerCapable | Create met een partij die geen niet-uitvoerbaar account is dat eigendom is van het systeem |
| 23 | MintAuthorityChanged | Settle wanneer de mint authority van een leg afwijkt van de waarde die bij het aanmaken is vastgelegd |
Events en indexering
Het programma zendt geen onchain events uit. Een indexer of reconciliatiesysteem leest
de accountstatus van SwapDvp en de tokensaldi van de twee escrows, en gebruikt
ref_string om een trade te koppelen aan de bijbehorende offchain-order. Omdat het record
bij de afwikkeling wordt gesloten, slaat een systeem dat achteraf de voorwaarden nodig heeft
de voorwaarden op op het moment dat het ze leest, of reconstrueert het ze uit de transactie
waarmee de trade is aangemaakt.
Ondersteunde tokens
Een trade kan een SPL Token-leg combineren met een Token-2022-leg; elke leg heeft zijn eigen token program. Wrapped SOL-legs worden ondersteund.
| Token-2022-extensie op de mint van een leg | Gedrag van het programma |
|---|---|
| TransferFee, InterestBearing, ScaledUiAmount, NonTransferable | Afgewezen bij Create en Settle met BlockedMintExtension |
| PermanentDelegate, Pausable, DefaultAccountState, een freeze authority, MintCloseAuthority | Geaccepteerd; elke authority kan handelen op de tokens in escrow |
| ConfidentialTransfer | Geaccepteerd; bedragen op die leg zijn openbaar |
| TransferHook | Ondersteund, tot 32 extra accounts per leg |
| MemoTransfer op een bestemmings- of terugbetalingsaccount | Geaccepteerd; het programma zendt de vereiste memo uit vóór de transfer |
Een transfer fee zou ertoe leiden dat de ontvangende partij minder krijgt dan het afgesproken bedrag. Interest Bearing en Scaled UI Amount wijzigen de ruwe bedragen niet, maar hun rente of vermenigvuldiger kan veranderen tussen het aanmaken en het afwikkelen van een trade, waardoor de weergave van de afgesproken bedragen verandert. NonTransferable zou beide legs vastzetten.
De geaccepteerde authorities kunnen de tokens in escrow verplaatsen, bevriezen of stilleggen gedurende de looptijd van de trade (zie hieronder). De escrow kan niet worden geconfigureerd om confidential transfers te ontvangen, dus de bedragen in escrow en na afwikkeling op een confidential leg zijn openbaar.
Voor een mint met een hook lost de client de extra accounts van de hook op en voegt ze toe aan Settle, Cancel, Reject, Reclaim en Recover. De limiet van 32 per leg geldt inclusief het hookprogramma en het bijbehorende validatieaccount. Als de hook authority de accountlijst van de hook uitbreidt tot boven die limiet, mislukt elke transfer op die leg, inclusief Reclaim, Cancel, Reject en Recover, totdat de authority dit terugdraait. De accountlimiet van de transactie kan eerder worden bereikt dan de limiet per leg als beide legs hooks hebben.
Wanneer een bestemmings- of terugbetalingsaccount memo's vereist, roept het programma het Memo-programma
aan vóór de transfer. Daarom heeft elke instructie die tokens
uit escrow verplaatst een memo_program-account nodig.
Beperkingen voor mintconfiguratie
Scaled UI Amount. Het tokenized-security-sjabloon in
Mosaic, de uitgiftetoolkit van de Solana Foundation, voegt altijd Scaled UI Amount toe, dus het programma accepteert geen
mint die met dat sjabloon is aangemaakt als leg. Een mint die voor dit programma bedoeld is, kan
zonder de extensie worden aangemaakt (zie
Token Extensions);
DvP met delegatie wordt afgewikkeld via gedelegeerde
autoriteit en past deze controle niet toe.
Standaard bevroren mints. De escrow van elke trade is een associated token account dat eigendom is van een program-derived address dat nieuw is voor die trade. Bij een mint met Default Account State ingesteld op frozen wordt de escrow bevroren aangemaakt en mislukt een financieringstransfer ernaartoe totdat deze is ontdooid. Onder Token ACL betekent dat dat de uitgever of diens transferagent de escrow van de trade toelaat vóór de financiering: ofwel door het adres van het traderecord (de eigenaar van de escrow) aan de allowlist toe te voegen, zodat iedereen de escrow kan ontdooien als de Token ACL-config van de mint permissionless thaw inschakelt, ofwel door de freeze authority de escrow rechtstreeks te laten ontdooien. Een bevroren escrow blokkeert ook Settle, Reclaim, Cancel, Reject en Recover op die leg, dus de freeze authority, en bij een mint met een hook de hook authority, is gedurende de looptijd van de trade een vertrouwde partij. Het pad met een bevroren escrow wordt hier beschreven en wordt niet uitgevoerd in de devnet-snippets.
Beperkingen
- Geen matching, prijsontdekking of orderboek. De partijen spreken de voorwaarden buiten het grootboek af en een van hen legt ze vast.
- Geen netting, en alleen bilateraal: één record is één trade tussen twee partijen.
- Geen gedeeltelijke uitvoering. Settle verplaatst precies het afgesproken bedrag van elke leg en stort een eventueel overschot terug aan de partij van de leg.
- Geen leg buiten het grootboek. Beide legs zijn token accounts op Solana; een cashleg via bestaande kanalen wordt apart afgewikkeld en gereconcilieerd.
- Geen geschiktheidscontrole, allowlist of KYC. De eigen controles van de mint dwingen de geschiktheid van houders af.
- Geen automatische afwikkeling. De settlement authority moet ondertekenen.
- Geen events en geen protocolkosten naast transactiekosten en rent.
Het programma neemt het principale risico tussen de twee partijen weg: geen van beide legs verplaatst tenzij beide dat doen. Het neemt het krediet- of aflossingsrisico van de uitgever op beide tokens niet weg, evenmin als de mogelijkheid van de freeze-, pause- of permanent delegate-authority van een mint om te handelen op tokens in escrow (zie ondersteunde tokens), of de afhankelijkheid van de beschikbaarheid van de settlement authority om te ondertekenen.
Verificatie vóór financiering en afwikkeling
CreateDvp is permissionless: alleen de payer ondertekent, de partijen en de
settlement authority niet. Iedereen kan dus een record aanmaken met willekeurige
partijen en voorwaarden. Lees vóór de financiering, en opnieuw vóór de afwikkeling, het
SwapDvp-account en controleer:
- Het account is eigendom van het DvP-programma en is precies 458 bytes groot. Een account dat niet eigendom is van het programma kan worden gevuld met bytes die eruitzien als een echt record.
user_a,user_b,mint_a,mint_bensettlement_authoritykomen overeen met de afgesproken trade.amount_a,amount_b,expiry_timestampenearliest_settlement_timestampkomen overeen met de afgesproken voorwaarden.- Beide afwikkelbestemmingen zijn de afgesproken adressen. Een vervalst record kan de opbrengsten omleiden.
De legs financieren somt de gecontroleerde readers van de gegenereerde clients op en toont de controle in code.
Beschouw een trade als afgewikkeld wanneer de Settle-transactie
finalized bereikt. Dat is een
commitmentniveau van het netwerk; of het ook de definitiviteit van de afwikkeling in juridische zin markeert,
hangt af van de afspraken tussen de partijen en de toepasselijke regelgeving.
Versiebeheer
Het SwapDvp-account heeft geen versieveld. De indeling is vastgelegd op 458 bytes
(SwapDvp::LEN) en de gecontroleerde readers weigeren een account met een andere lengte.
De IDL heeft zijn eigen versie, 0.1.0 per 2 oktober 2026.
Het programma is upgradeable op beide clusters (zie Program-ID). Een traderecord bestaat alleen totdat het is afgewikkeld, geannuleerd of afgewezen. Raadpleeg dus de repository om te zien hoe een upgrade omgaat met openstaande trades, en genereer clients opnieuw op basis van de IDL van de gedeployde build.
Repository en audit
Broncode, IDL, gegenereerde clients en tests staan in
solana-foundation/dvp onder de
MIT-licentie. Het programma is een no_std Pinocchio-programma; de clients worden
gegenereerd uit de IDL met Codama. Meldingen van kwetsbaarheden verlopen via de
link naar het security advisory van de repository, conform SECURITY.md.
Het programma is geaudit door Cantina.
Gerelateerd
- Delivery vs Payment (DvP) met delegatie: het delegatiepatroon zonder programma
- Token ACL: hoe een afgeschermde mint samenwerkt met de escrowaccounts
Is this page helpful?