Programma Delivery vs Payment (DvP)

Il programma DvP è il programma standard per la consegna contro pagamento su Solana, mantenuto dalla Solana Foundation e sottoposto ad audit da Cantina. Due parti concordano un'operazione, ciascuna invia la propria gamba a un account escrow con un normale trasferimento di token, e un'autorità di regolamento regola entrambe le gambe in un'unica transazione, così o si muovono entrambe o nessuna delle due. L'autorità di regolamento è un terzo indirizzo indicato nell'operazione, come la sede di negoziazione o l'agente che l'ha organizzata. Nessuna delle parti scrive o distribuisce un programma, e un wallet o un custode in grado di inviare un trasferimento di token standard (TransferChecked) può finanziare una gamba senza alcuna integrazione specifica per DvP. Fino al regolamento, ciascuna parte può riprendersi la propria gamba o annullare l'operazione.

Leggi il record prima di agire

La creazione di un record di operazione è permissionless, quindi un record non è una prova di accordo. Ogni parte legge i termini memorizzati prima di finanziare, e l'autorità di regolamento prima di regolare (vedi verifica).

Come funziona

Ogni operazione ottiene un record di proprietà del programma e due account escrow, uno per gamba. La parte della gamba di asset (user_a) e la parte della gamba di cassa (user_b) finanziano ciascuna una gamba trasferendo token nell'account escrow di quella gamba. L'autorità di regolamento è l'unico firmatario che può regolare. Il regolamento trasferisce l'importo concordato di ciascuna gamba all'altra parte, restituisce l'eventuale eccedenza alla parte che possiede la gamba e chiude il record e entrambi gli escrow. L'atomicità deriva dalle transazioni di Solana: entrambi i trasferimenti sono in un'unica transazione, quindi o hanno effetto entrambi o nessuno dei due.

Ogni rimborso, recupero e restituzione di eccedenza va all'associated token account della parte stessa: quello di user_a per mint_a, quello di user_b per mint_b. Un custode o un sistema di tesoreria può finanziare una gamba dal proprio account, ma tutto ciò che viene restituito finisce nell'account della parte, non torna al custode. Ogni operazione lascia inoltre un account marcatore permanente (vedi Stato).

Guide

Le pagine dei passaggi seguono un'operazione dalla creazione al regolamento, con TypeScript e Rust per ogni istruzione.

Una demo su devnet esegue un'operazione dall'inizio alla fine: crea l'operazione, finanzia entrambi gli escrow con trasferimenti di token standard e regola entrambe le gambe in un'unica transazione.

Scegliere tra il programma e la delega

Delivery vs Payment (DvP) con delega regola lo stesso scambio senza un programma: ciascuna parte delega la propria posizione a un agente di regolamento, che muove entrambe le gambe in un'unica transazione.

  • Il programma non richiede delega, quindi il limite di un delegato per token account non si applica, e l'autorità di regolamento non può dirottare i proventi. Ogni operazione dipende da un programma aggiornabile e dalla sua upgrade authority.
  • Il pattern di delega non ha dipendenze da programmi e funziona con i mint che usano Scaled UI Amount. Il programma rifiuta quei mint, il che esclude qualsiasi mint creato dal template tokenized-security di Mosaic (vedi vincoli di configurazione del mint).

Ruoli

Il programma è simmetrico. Nella sua interfaccia le due parti sono user_a, che consegna mint_a, e user_b, che consegna mint_b. Il README e i client generati chiamano mint_a la gamba di asset e mint_b la gamba di cassa, e queste pagine seguono tale convenzione, ma nulla nel programma richiede che la gamba di cassa sia uno strumento di cassa. Due asset, o due stablecoin, si regolano allo stesso modo.

RuoloChiFirmaNote
Parte della gamba di assetuser_a, consegna mint_aIl proprio trasferimento di finanziamento; Reclaim, Reject, RecoverUn wallet keypair, o uno smart wallet basato su PDA come un vault multisig. Un account multisig SPL Token o un program account non può essere una parte: Create fallisce con PartyNotSignerCapable
Parte della gamba di cassauser_b, consegna mint_bIl proprio trasferimento di finanziamento; Reclaim, Reject, RecoverStesso requisito
Autorità di regolamentoUn terzo indirizzo indicato alla creazioneSettle, CancelL'unico firmatario che può regolare. Non può dirottare i proventi, che sono fissati alla creazione. Riceve il rent degli account chiusi quando regola o annulla
Pagatore del rentChiunque firmi CreateDvpCreateFinanzia il rent (il deposito in SOL che mantiene aperto un account) per il record, il tombstone del nonce e entrambi gli escrow. Non è registrato come destinatario del rent: il rent degli account chiusi va a chi chiude l'operazione

ID del programma

dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq
ClusterProgrammaAutorità di aggiornamentoUltimo slot di deploy
mainnet-betadvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZqDXtFpbPjcn2hxPnw79x1Pfoj35vXh5AsWBkS37YnXMVv452.058.374
devnetdvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq5EX1zFeJWj4rGYZv432WnYw8CbaSUeTdxPx4r573UgYU479.376.863

Il programma è aggiornabile su entrambi i cluster. I valori sopra sono quelli riportati da solana program show il 2 ottobre 2026; esegui lo stesso comando per i valori attuali. La build su devnet è più vecchia del commit su cui sono scritte le pagine dei passaggi (vedi Installazione), con lo stesso insieme di istruzioni ed errori.

Ciclo di vita

Un'operazione è aperta da CreateDvp finché una tra Settle, Cancel o Reject non la chiude. Il finanziamento non ha un'istruzione propria: una gamba è finanziata quando il suo account escrow contiene almeno l'importo concordato. Reclaim agisce su una singola gamba e lascia l'operazione aperta, quindi un problema con una gamba non costringe l'altra parte ad annullare l'intera operazione.

Stato

Ogni operazione ha un account SwapDvp di 458 byte, di proprietà del programma. Il suo indirizzo è derivato dall'autorità di regolamento, dalle due parti, dai due mint e da un nonce (i seed ["dvp", settlement_authority, user_a, user_b, mint_a, mint_b, nonce]). Gli importi e i tempi sono memorizzati all'interno dell'account e non influiscono sull'indirizzo, motivo per cui devono essere letti anziché dedotti. Un piccolo account marcatore, il tombstone del nonce in ["nonce", swap_dvp], viene creato con l'operazione e non viene mai chiuso, quindi ogni combinazione di parti, mint, autorità e nonce può essere usata per una sola operazione.

CampoTipoSignificato
bumpu8Bump della PDA
user_a, user_bPubkeyLe due parti
mint_a, mint_bPubkeyI mint della gamba di asset e della gamba di cassa
settlement_authorityPubkeyL'unico firmatario che può regolare o annullare
token_program_a, token_program_bPubkeyIl token program proprietario di ciascun mint; un'operazione può combinare gambe SPL Token e Token-2022
amount_a, amount_bu64L'importo concordato di ciascuna gamba, nell'unità più piccola del mint (unità di base)
expiry_timestampi64Dopo questo orario di rete (il clock onchain), Settle viene rifiutata. Reclaim, Cancel e Reject continuano a funzionare
nonceu64Distingue le operazioni che condividono gli altri seed. Monouso
ref_string[u8; 64]Un riferimento opaco del client, riempito con zeri; il programma non lo legge mai
user_a_settlement_destinationPubkeyRiceve la gamba di cassa al momento di Settle; per impostazione predefinita è user_a
user_b_settlement_destinationPubkeyRiceve la gamba di asset al momento di Settle; per impostazione predefinita è user_b
mint_a_authority, mint_b_authorityPubkeyLe mint authority acquisite alla creazione; Settle fallisce se una delle due è cambiata
earliest_settlement_timestampOption<i64>Se impostato, Settle viene rifiutata prima di questo orario di rete

L'elenco dei campi è tratto dall'IDL del programma al commit indicato in Crea un'operazione.

Istruzioni

IstruzioneFirmatarioEffetto
CreateDvpQualsiasi pagatoreCrea il record SwapDvp, il relativo tombstone del nonce e entrambi gli account escrow. Non sposta alcun token
ReclaimDvpuser_a o user_bRestituisce dall'escrow la gamba del firmatario. L'operazione resta aperta e la gamba può essere finanziata di nuovo
SettleDvpAutorità di regolamentoTrasferisce amount_a alla destinazione di user_b e amount_b alla destinazione di user_a, restituisce l'eventuale eccedenza alla parte della gamba, chiude il record e entrambi gli escrow
CancelDvpAutorità di regolamentoRimborsa a user_a quanto contiene l'escrow A e a user_b quanto contiene l'escrow B, chiude il record e entrambi gli escrow
RejectDvpuser_a o user_bStesso effetto di Cancel, firmata da una parte
RecoverDvpuser_a o user_bDopo la chiusura dell'operazione: svuota un escrow ricreato verso il token account del firmatario e lo chiude. Copre un deposito arrivato dopo Settle, Cancel o Reject

Ogni rimborso va all'associated token account della parte per il mint di quella gamba, indipendentemente da chi abbia finanziato l'escrow.

Gli account e gli argomenti di ciascuna istruzione si trovano nella pagina del relativo passaggio.

Errori

CodiceErroreQuando
0SignerNotPartyFirma di Reclaim, Reject o Recover da parte di un indirizzo che non è user_a o user_b
1DvpExpiredSettle dopo expiry_timestamp
2SettlementAuthorityMismatchFirma di Settle o Cancel da parte di un indirizzo diverso dall'autorità di regolamento
3SettlementTooEarlySettle prima di earliest_settlement_timestamp
4LegNotFundedSettle mentre un escrow contiene meno dell'importo concordato
5ExpiryNotInFutureCreate con una scadenza pari o precedente all'orario di rete corrente
6EarliestAfterExpiryCreate con un orario di regolamento più anticipato successivo alla scadenza
7SelfDvpCreate con user_a uguale a user_b
8SameMintCreate con mint_a uguale a mint_b
9ZeroAmountCreate con un importo pari a zero su una delle due gambe
10BlockedMintExtensionCreate o Settle con un mint che usa TransferFee, InterestBearing, ScaledUiAmount o NonTransferable
11SettlementAuthorityIsPartyCreate con l'autorità di regolamento uguale a una delle parti
12SettlementAuthorityExecutableCreate con un'autorità di regolamento eseguibile
13NonceAlreadyUsedCreate che riutilizza una (seeds, nonce) che ha già un tombstone
14ExpiryTooFarInFutureCreate con una scadenza oltre un anno nel futuro
15RefStringTooLongCreate con un riferimento più lungo di 64 byte
16DvpStillOpenRecover mentre l'operazione è ancora aperta; usa Reclaim
17DvpNeverCreatedRecover con seed privi di tombstone
18EscrowPreloadedWithLamportsCreate quando un escrow non nativo detiene lamports oltre il proprio minimo rent-exempt
19SettlementDestinationIsSwapDvpCreate con una destinazione di regolamento uguale al record dello scambio
20SwapDvpPreloadedWithLamportsCreate quando l'indirizzo del record detiene lamports oltre la propria riserva di rent
21RecipientAtaMismatchUn token account del destinatario o di rimborso non appartiene più al wallet e al mint previsti
22PartyNotSignerCapableCreate con una parte che non è un account di proprietà del sistema e non eseguibile
23MintAuthorityChangedSettle quando la mint authority di un leg differisce dal valore acquisito alla creazione

Eventi e indicizzazione

Il programma non emette eventi on-chain. Un indexer o un sistema di riconciliazione legge lo stato dell'account SwapDvp e i saldi di token dei due escrow, e usa ref_string per correlare uno scambio al relativo ordine off-chain. Poiché il record viene chiuso al regolamento, un sistema che ha bisogno dei termini a posteriori li memorizza al momento della lettura, oppure li ricostruisce dalla transazione che ha creato lo scambio.

Token supportati

Uno scambio può abbinare un leg SPL Token a un leg Token-2022; ciascun leg riporta il proprio token program. I leg con Wrapped SOL sono supportati.

Estensione Token-2022 sul mint di un legComportamento del programma
TransferFee, InterestBearing, ScaledUiAmount, NonTransferableRifiutata in Create e Settle con BlockedMintExtension
PermanentDelegate, Pausable, DefaultAccountState, una freeze authority, MintCloseAuthorityAccettate; ciascuna authority può agire sui token in escrow
ConfidentialTransferAccettata; gli importi su quel leg sono pubblici
TransferHookSupportata, fino a 32 account aggiuntivi per leg
MemoTransfer su un account di destinazione o di rimborsoAccettata; il programma emette il memo richiesto prima del trasferimento

Una commissione di trasferimento lascerebbe la parte ricevente al di sotto dell'importo concordato. Interest Bearing e Scaled UI Amount non modificano gli importi grezzi, ma il loro tasso o moltiplicatore può cambiare tra la creazione e il regolamento di uno scambio, e ciò modifica il modo in cui vengono visualizzati gli importi concordati. NonTransferable bloccherebbe entrambi i leg.

Le authority accettate possono spostare, congelare o bloccare i token in escrow per tutta la durata dello scambio (vedi sotto). L'escrow non può essere configurato per ricevere trasferimenti confidenziali, quindi gli importi in escrow e regolati su un leg confidenziale sono pubblici.

Per un mint con hook, il client risolve gli account aggiuntivi dell'hook e li accoda a Settle, Cancel, Reject, Reclaim e Recover. Il limite di 32 per leg conteggia il programma dell'hook e il relativo account di validazione. Se la hook authority amplia l'elenco di account dell'hook oltre tale limite, ogni trasferimento su quel leg fallisce, inclusi Reclaim, Cancel, Reject e Recover, finché la authority non annulla la modifica. Il limite di account della transazione può diventare vincolante prima del limite per leg quando entrambi i leg hanno hook.

Quando un account di destinazione o di rimborso richiede memo, il programma chiama il programma Memo prima del trasferimento, motivo per cui ogni istruzione che sposta token fuori dall'escrow richiede un account memo_program.

Vincoli di configurazione del mint

Scaled UI Amount. Il template tokenized-security in Mosaic, il toolkit di emissione della Solana Foundation, aggiunge sempre Scaled UI Amount, quindi il programma non accetta come leg un mint creato da quel template. Un mint destinato a questo programma può essere creato senza l'estensione (vedi Token Extensions); DvP con delega regola tramite autorità delegata e non applica questo controllo.

Mint congelati per impostazione predefinita. L'escrow di ogni scambio è un associated token account di proprietà di un program-derived address nuovo per quello scambio. Su un mint con Default Account State impostato su frozen, l'escrow viene creato congelato e un trasferimento di finanziamento verso di esso fallisce finché non viene sbloccato. Con Token ACL ciò significa che l'emittente o il suo transfer agent ammette l'escrow dello scambio prima del finanziamento: aggiungendo l'indirizzo del record dello scambio (il proprietario dell'escrow) alla allowlist, in modo che chiunque possa sbloccare l'escrow se la configurazione Token ACL del mint abilita lo sblocco senza permessi, oppure facendolo sbloccare direttamente alla freeze authority. Un escrow congelato blocca anche Settle, Reclaim, Cancel, Reject e Recover su quel leg, quindi la freeze authority, e su un mint con hook la hook authority, è una parte fidata per tutta la durata dello scambio. Il percorso dell'escrow congelato è descritto qui e non viene eseguito negli snippet su devnet.

Limiti

  • Nessun matching, price discovery o order book. Le parti concordano i termini fuori dal ledger e una di esse li registra.
  • Nessun netting, e solo bilaterale: un record è uno scambio tra due parti.
  • Nessun riempimento parziale. Settle sposta esattamente l'importo concordato per ciascun leg e restituisce l'eventuale eccedenza alla parte del leg.
  • Nessun leg off-ledger. Entrambi i leg sono token account su Solana; un leg in contanti su canali esistenti viene regolato separatamente e riconciliato.
  • Nessun controllo di idoneità, allowlist o KYC. I controlli propri del mint impongono l'idoneità dei detentori.
  • Nessun regolamento automatico. La settlement authority deve firmare.
  • Nessun evento e nessuna commissione di protocollo oltre alle commissioni di transazione e al rent.

Il programma elimina il rischio di capitale tra le due parti: nessun leg si muove a meno che non si muovano entrambi. Non elimina il rischio di credito o di rimborso dell'emittente su nessuno dei due token, la possibilità per la freeze authority, la pause authority o la permanent delegate authority di un mint di agire sui token in escrow (vedi token supportati), né la dipendenza dalla disponibilità della settlement authority a firmare.

Verifica prima del finanziamento e del regolamento

CreateDvp è senza permessi: firma solo il payer, mentre le parti e la settlement authority non firmano. Chiunque può quindi creare un record che indichi qualsiasi parte e qualsiasi termine. Prima del finanziamento, e di nuovo prima del regolamento, leggi l'account SwapDvp e conferma che:

  1. L'account sia di proprietà del programma DvP e sia esattamente di 458 byte. Un account non di proprietà del programma può essere riempito con byte che si decodificano come un record reale.
  2. user_a, user_b, mint_a, mint_b e settlement_authority corrispondano allo scambio concordato.
  3. amount_a, amount_b, expiry_timestamp e earliest_settlement_timestamp corrispondano ai termini concordati.
  4. Entrambe le destinazioni di regolamento siano gli indirizzi concordati. Un record contraffatto può reindirizzare i proventi.

Finanziare i leg elenca i lettori con controllo dei client generati e mostra il controllo nel codice.

Considera uno scambio regolato quando la transazione Settle raggiunge finalized. Si tratta di un livello di commitment della rete; se segni anche la definitività del regolamento a fini legali dipende dagli accordi tra le parti e dai regimi applicabili.

Versioning

L'account SwapDvp non include un campo di versione. Il suo layout è fisso a 458 byte (SwapDvp::LEN) e i lettori con controllo rifiutano un account di qualsiasi altra lunghezza. L'IDL ha una propria versione, 0.1.0 al 2 ottobre 2026.

Il programma è aggiornabile su entrambi i cluster (vedi Program ID). Un record di scambio esiste solo finché non viene regolato, annullato o rifiutato, quindi consulta il repository per sapere come un aggiornamento tratta gli scambi aperti e rigenera i client dall'IDL della build distribuita.

Repository e audit

Sorgente, IDL, client generati e test si trovano in solana-foundation/dvp con licenza MIT. Il programma è un programma Pinocchio no_std; i client sono generati dall'IDL con Codama. Le segnalazioni di vulnerabilità passano per il link degli security advisory del repository, come indicato in SECURITY.md.

Il programma è stato sottoposto ad audit da Cantina.

Correlati

Is this page helpful?

Indice dei contenuti

Modifica pagina
© 2026 Solana Foundation. Tutti i diritti riservati.