Het DvP-programma is het standaardprogramma voor delivery versus payment 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
escrow-account, en een afwikkelautoriteit wikkelt beide legs af in één transactie,
zodat of beide legs worden verplaatst, of geen van beide. De afwikkelautoriteit is een derde
adres dat in de trade wordt genoemd, zoals de handelsplaats of de 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 verzenden, kan een leg funden 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 handelt
Het aanmaken van een traderecord is permissionless, dus een record is geen bewijs van overeenstemming. Elke partij leest de opgeslagen voorwaarden voordat zij funden, en de afwikkelautoriteit voordat die afwikkelt (zie verificatie).
Hoe het werkt
Elke trade krijgt een record dat eigendom is van het programma en twee escrow-accounts, één per leg. De
partij van de asset-leg (user_a) en de partij van de cash-leg (user_b) funden elk een leg door
tokens over te maken naar het escrow-account van die leg. De afwikkelautoriteit
is de enige ondertekenaar die kan afwikkelen. Bij de afwikkeling wordt het afgesproken
bedrag van elke leg naar de andere kant overgemaakt, wordt eventueel overschot teruggegeven aan de partij die eigenaar is van
de leg, en worden het record en beide escrows gesloten. De atomiciteit komt voort uit Solana-
transacties: beide overdrachten zitten in één transactie,
dus of beide worden doorgevoerd, of geen van beide.
Elke terugbetaling, elk terugvorderen en elke teruggave van overschot 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 funden vanuit een eigen account, maar alles wat
wordt teruggegeven komt terecht in het account van de partij, niet terug bij de bewaarder. Elke trade
laat ook een permanent markeringsaccount achter (zie State).
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 funden
Controleer de opgeslagen voorwaarden en fund daarna elke leg met een gewone overdracht
De trade afwikkelen
Wikkel beide legs in één transactie af als afwikkelautoriteit
Een trade ongedaan maken
Neem een leg terug, annuleer of weiger de trade en herstel late stortingen
Een devnet-demo doorloopt een trade van begin tot eind: de demo maakt de trade aan, fundt beide escrows met standaard tokenoverdrachten en wikkelt beide legs af in één transactie.
Kiezen tussen het programma en delegatie
Delivery vs Payment (DvP) met delegatie wikkelt dezelfde uitwisseling af zonder programma: elke partij delegeert zijn positie aan een afwikkelagent, die beide legs in één transactie verplaatst.
- Het programma vereist geen delegatie, dus de limiet van één delegate per token account is niet van toepassing, en de afwikkelautoriteit kan de opbrengsten niet omleiden. Elke trade is afhankelijk van een upgradeable programma en de bijbehorende upgrade authority.
- 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 aangemaakt 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 cash-instrument 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 fundingoverdracht; Reclaim, Reject, Recover | Een keypair-wallet, of een op 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 fundingoverdracht; Reclaim, Reject, Recover | Dezelfde vereiste |
| Afwikkelautoriteit | Een derde adres dat bij het aanmaken wordt genoemd | Settle, Cancel | De enige ondertekenaar die kan afwikkelen. Deze kan de opbrengsten, die bij het aanmaken zijn vastgelegd, niet omleiden. Bij afwikkeling of annulering ontvangt deze de rent van de gesloten accounts |
| Betaler van de rent | Wie CreateDvp ondertekent | Create | Betaalt de rent (de SOL-storting die een account open houdt) voor het record, de nonce tombstone en beide escrows. Wordt niet vastgelegd als ontvanger van rent: de rent van gesloten accounts gaat naar degene die de trade sluit |
Program-ID
dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq
| Cluster | Programma | Upgrade authority | Laatst gedeployde slot |
|---|---|---|---|
| mainnet-beta | dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq | DXtFpbPjcn2hxPnw79x1Pfoj35vXh5AsWBkS37YnXMVv | 452,058,374 |
| devnet | dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq | 5EX1zFeJWj4rGYZv432WnYw8CbaSUeTdxPx4r573UgYU | 479,376,863 |
Het programma is upgradeable op beide clusters. De bovenstaande cijfers zijn wat
solana program show rapporteerde op 2 oktober 2026; voer hetzelfde commando uit voor
actuele waarden. De devnet-build is ouder dan de commit waarop de stappenpagina's
zijn gebaseerd (zie Installatie),
met dezelfde set instructies en fouten.
Levenscyclus
Een trade is open vanaf CreateDvp totdat Settle, Cancel of Reject deze
sluit. Funding heeft geen eigen instructie: een leg is gefund wanneer het escrow-
account minstens het afgesproken bedrag bevat. Reclaim geldt per leg en laat de
trade open, zodat een probleem met één leg de andere partij niet dwingt om
de hele trade te annuleren.
State
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,
waardoor ze moeten 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 afgesproken 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 authorities zoals vastgelegd bij het aanmaken; 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 afkomstig 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 bijbehorende nonce tombstone en beide escrow-accounts aan. Verplaatst geen tokens |
ReclaimDvp | user_a of user_b | Geeft de eigen leg van de ondertekenaar terug uit de escrow. De trade blijft open en de leg kan opnieuw worden gefund |
SettleDvp | Afwikkelautoriteit | Maakt amount_a over naar de bestemming van user_b en amount_b naar de bestemming van user_a, geeft eventueel overschot terug aan de partij van de leg en sluit het record en beide escrows |
CancelDvp | Afwikkelautoriteit | Betaalt wat escrow A bevat terug aan user_a en wat escrow B bevat aan user_b, en sluit het record en beide escrows |
RejectDvp | user_a of user_b | Hetzelfde effect als Cancel, maar 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 gefund.
De accounts en argumenten van elke instructie staan op de pagina van de betreffende 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 afgesproken bedrag |
| 5 | ExpiryNotInFuture | Create met een vervaltijd op of vóór de huidige netwerktijd |
| 6 | EarliestAfterExpiry | Create met een vroegste afwikkeltijd na de vervaltijd |
| 7 | SelfDvp | Create waarbij user_a gelijk is aan user_b |
| 8 | SameMint | Create waarbij mint_a gelijk is aan mint_b |
| 9 | ZeroAmount | Create met een bedrag van nul op een van beide legs |
| 10 | BlockedMintExtension | Create of Settle met een mint die TransferFee, InterestBearing, ScaledUiAmount of NonTransferable bevat |
| 11 | SettlementAuthorityIsParty | Create waarbij de afwikkelautoriteit gelijk is aan een van de partijen |
| 12 | SettlementAuthorityExecutable | Create met een uitvoerbare afwikkelautoriteit |
| 13 | NonceAlreadyUsed | Create dat een (seeds, nonce) hergebruikt waarvoor al een tombstone bestaat |
| 14 | ExpiryTooFarInFuture | Create met een vervaltijd 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 die geen tombstone hebben |
| 18 | EscrowPreloadedWithLamports | Aanmaken wanneer een niet-native escrow meer lamports bevat dan het rent-exempt minimum |
| 19 | SettlementDestinationIsSwapDvp | Aanmaken met een afwikkelingsbestemming die gelijk is aan het transactiedossier |
| 20 | SwapDvpPreloadedWithLamports | Aanmaken wanneer het dossieradres meer lamports bevat dan de rent-reserve |
| 21 | RecipientAtaMismatch | Een token account van een ontvanger of voor terugbetaling hoort niet langer bij de verwachte wallet en mint |
| 22 | PartyNotSignerCapable | Aanmaken met een partij die geen systeemeigen, niet-uitvoerbaar account is |
| 23 | MintAuthorityChanged | Afwikkelen wanneer de mint authority van een leg afwijkt van de waarde die bij het aanmaken is vastgelegd |
Events en indexering
Het programma verzendt geen onchain events. Een indexer of reconciliatiesysteem leest
de accountstatus van SwapDvp en de tokensaldi van de twee escrows en gebruikt
ref_string om een transactie te koppelen aan de bijbehorende off-chain order. Omdat het dossier
bij de afwikkeling wordt gesloten, slaat een systeem dat achteraf de voorwaarden nodig heeft
deze op wanneer het ze leest, of reconstrueert het ze uit de transactie waarmee de
transactie is aangemaakt.
Ondersteunde tokens
Een transactie 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 | Geweigerd bij Create en Settle met BlockedMintExtension |
| PermanentDelegate, Pausable, DefaultAccountState, een freeze authority, MintCloseAuthority | Geaccepteerd; elke authority kan handelen op de in escrow geplaatste tokens |
| 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 verzendt de vereiste memo vóór de overdracht |
Een transferkost 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 multiplier kan veranderen tussen het aanmaken en het afwikkelen van een transactie, waardoor de weergave van de afgesproken bedragen verandert. NonTransferable zou beide legs vastzetten.
De geaccepteerde authorities kunnen de in escrow geplaatste tokens verplaatsen, bevriezen of stopzetten gedurende de looptijd van de transactie (zie hieronder). De escrow kan niet worden geconfigureerd om vertrouwelijke overdrachten te ontvangen, dus de in escrow geplaatste en afgewikkelde bedragen op een vertrouwelijke 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 omvat het hookprogramma en het bijbehorende validatieaccount. Als de hook authority de accountlijst van de hook uitbreidt tot voorbij die limiet, mislukt elke overdracht op die leg, inclusief Reclaim, Cancel, Reject en Recover, totdat de authority dit terugdraait. De limiet voor het aantal accounts per transactie kan eerder bereikt worden dan de limiet per leg wanneer beide legs hooks hebben.
Wanneer een bestemmings- of terugbetalingsaccount memo's vereist, roept het programma het Memo-
programma aan vóór de overdracht, en 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 issuance-toolkit 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 transactie is een associated token account dat eigendom is van een program-derived address dat nieuw is voor die transactie. Bij een mint met Default Account State ingesteld op frozen wordt de escrow bevroren aangemaakt en mislukt een financieringsoverdracht ernaartoe totdat deze is ontdooid. Onder Token ACL betekent dat dat de uitgever of zijn transfer agent de escrow van de transactie toelaat vóór de financiering: ofwel door het adres van het transactiedossier (de eigenaar van de escrow) aan de allowlist toe te voegen, zodat iedereen de escrow kan ontdooien als de Token ACL-configuratie van de mint permissionless thaw toestaat, of door de freeze authority deze 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 een vertrouwde partij voor de looptijd van de transactie. Het pad met een bevroren escrow wordt hier beschreven en wordt niet uitgeoefend in de devnet-snippets.
Beperkingen
- Geen matching, prijsontdekking of orderboek. De partijen komen de voorwaarden buiten het grootboek overeen en een van hen legt ze vast.
- Geen netting, en alleen bilateraal: één dossier is één transactie tussen twee partijen.
- Geen gedeeltelijke uitvoering. Settle verplaatst precies het afgesproken bedrag van elke leg en geeft een eventueel overschot terug aan de partij van de leg.
- Geen leg buiten het grootboek. Beide legs zijn token accounts op Solana; een cash-leg via bestaande rails 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 tekenen.
- Geen events en geen protocolkosten behalve transactiekosten en rent.
Het programma neemt het hoofdsomrisico tussen de twee partijen weg: geen van beide legs wordt verplaatst tenzij beide dat worden. Het neemt het krediet- of aflossingsrisico van de uitgever op beide tokens niet weg, evenmin als de mogelijkheid voor de freeze-, pause- of permanent delegate-authority van een mint om te handelen op in escrow geplaatste tokens (zie ondersteunde tokens), of de afhankelijkheid van de beschikbaarheid van de settlement authority om te tekenen.
Verificatie vóór financiering en afwikkeling
CreateDvp is permissionless: alleen de payer tekent, en de partijen en de
settlement authority niet. Iedereen kan dus een dossier aanmaken met willekeurige
partijen en voorwaarden. Lees vóór de financiering, en opnieuw vóór de afwikkeling, het
SwapDvp-account en controleer het volgende:
- Het account is eigendom van het DvP-programma en is precies 458 bytes groot. Een account dat geen eigendom is van het programma kan worden gevuld met bytes die als een echt dossier decoderen.
user_a,user_b,mint_a,mint_bensettlement_authoritykomen overeen met de afgesproken transactie.amount_a,amount_b,expiry_timestampenearliest_settlement_timestampkomen overeen met de afgesproken voorwaarden.- Beide afwikkelingsbestemmingen zijn de afgesproken adressen. Een vervalst dossier kan opbrengsten omleiden.
De legs financieren somt de gecontroleerde readers van de gegenereerde clients op en toont de controle in code.
Beschouw een transactie 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 overeenkomsten van de partijen en de toepasselijke regelgeving.
Versiebeheer
Het SwapDvp-account heeft geen versieveld. De indeling ligt vast op 458 bytes
(SwapDvp::LEN), en de gecontroleerde readers weigeren een account met een andere lengte.
De IDL heeft een eigen versie, 0.1.0 per 2 oktober 2026.
Het programma is upgradebaar op beide clusters (zie Program ID). Een transactiedossier bestaat alleen tot het is afgewikkeld, geannuleerd of afgewezen, dus controleer in de repository hoe een upgrade met openstaande transacties omgaat, 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. Kwetsbaarheidsmeldingen 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 escrow-accounts
Is this page helpful?