Programma Consegna contro pagamento (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 il proprio leg a un account escrow con un normale trasferimento di token, e un'autorità di regolamento regola entrambi i leg in un'unica transazione, così o si muovono entrambi o nessuno dei 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 un leg senza alcuna integrazione specifica per DvP. Fino al regolamento, ciascuna parte può riprendersi il proprio leg o annullare l'operazione.

Leggi il record prima di agire

La creazione di un record di operazione non richiede autorizzazioni, quindi un record non è prova di accordo. Ciascuna parte legge i termini memorizzati prima di finanziare il proprio leg, e l'autorità di regolamento prima di regolare (vedi verifica).

Come funziona

Ogni operazione ha un record di proprietà del programma e due account escrow, uno per leg. La parte del leg asset (user_a) e la parte del leg cash (user_b) finanziano ciascuna un leg trasferendo token nell'account escrow di quel leg. L'autorità di regolamento è l'unico firmatario che può regolare. Il regolamento trasferisce l'importo concordato di ciascun leg alla controparte, restituisce l'eventuale eccedenza alla parte proprietaria del leg 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 un leg dal proprio account, ma qualsiasi cosa venga restituita 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 normali trasferimenti di token e regola entrambi i leg in un'unica transazione.

Scegliere tra il programma e la delega

Consegna contro pagamento (DvP) tramite delega regola lo stesso scambio senza un programma: ciascuna parte delega la propria posizione a un agente di regolamento, che muove entrambi i leg 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ò reindirizzare 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 il leg asset e mint_b il leg cash, e queste pagine seguono tale convenzione, ma nulla nel programma richiede che il leg cash sia uno strumento di cassa. Due asset, o due stablecoin, si regolano allo stesso modo.

RuoloChiFirmaNote
Parte del leg assetuser_a, consegna mint_aIl proprio trasferimento di finanziamento; Reclaim, Reject, RecoverUn wallet keypair, oppure uno smart wallet basato su PDA come un vault multisig. Un account multisig di SPL Token o un program account non può essere una parte: Create fallisce con PartyNotSignerCapable
Parte del leg cashuser_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ò reindirizzare i proventi, che sono fissati alla creazione. Riceve il rent degli account chiusi quando regola o annulla
Pagatore del rentChi firma CreateDvpCreateFinanzia il rent (il deposito di SOL che mantiene aperto un account) per il record, il nonce tombstone 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
ClusterProgrammaUpgrade authorityUltimo slot di distribuzione
mainnet-betadvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZqDXtFpbPjcn2hxPnw79x1Pfoj35vXh5AsWBkS37YnXMVv452.058.374
devnetdvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq5EX1zFeJWj4rGYZv432WnYw8CbaSUeTdxPx4r573UgYU479.376.863

Il programma è aggiornabile su entrambi i cluster. I valori sopra riportati sono quelli restituiti da solana program show il 2 ottobre 2026; esegui lo stesso comando per ottenere i valori attuali. La build su devnet è più vecchia del commit rispetto al quale 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: un leg è finanziato quando il suo account escrow contiene almeno l'importo concordato. Reclaim agisce per singolo leg e lascia l'operazione aperta, quindi un problema con un leg non obbliga 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 nell'account e non influiscono sull'indirizzo, motivo per cui devono essere letti anziché dedotti. Un piccolo account marcatore, il nonce tombstone 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 utilizzata per una sola operazione.

CampoTipoSignificato
bumpu8PDA bump
user_a, user_bPubkeyLe due parti
mint_a, mint_bPubkeyI mint del leg asset e del leg cash
settlement_authorityPubkeyL'unico firmatario che può regolare o annullare
token_program_a, token_program_bPubkeyIl Token Program che possiede ciascun mint; un'operazione può combinare leg SPL Token e Token-2022
amount_a, amount_bu64L'importo concordato di ciascun leg, nell'unità più piccola del mint (unità di base)
expiry_timestampi64Dopo questo orario di rete (il clock onchain), Settle viene rifiutato. Reclaim, Cancel e Reject continuano a funzionare
nonceu64Distingue le operazioni che condividono gli altri seed. Monouso
ref_string[u8; 64]Un riferimento client opaco, riempito con zeri; il programma non lo legge mai
user_a_settlement_destinationPubkeyRiceve il leg cash al Settle; per impostazione predefinita è user_a
user_b_settlement_destinationPubkeyRiceve il leg asset al 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 rifiutato prima di questo orario di rete

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

Istruzioni

IstruzioneFirmatarioEffetto
CreateDvpQualsiasi pagatoreCrea il record SwapDvp, il relativo nonce tombstone e entrambi gli account escrow. Non sposta alcun token
ReclaimDvpuser_a o user_bRestituisce dall'escrow il leg del firmatario. L'operazione resta aperta e il leg può essere finanziato 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 del leg, 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, firmato 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 al proprio associated token account della parte per il mint di quel leg, indipendentemente da chi ha finanziato l'escrow.

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

Errori

CodiceErroreQuando
0SignerNotPartyReclaim, Reject o Recover firmati da un indirizzo che non è user_a o user_b
1DvpExpiredSettle dopo expiry_timestamp
2SettlementAuthorityMismatchSettle o Cancel firmati da 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 uguale o precedente all'orario di rete corrente
6EarliestAfterExpiryCreate con un orario di regolamento minimo 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 uno dei due leg
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 un (seeds, nonce) che ha già un tombstone
14ExpiryTooFarInFutureCreate con una scadenza oltre un anno in avanti
15RefStringTooLongCreate con un riferimento più lungo di 64 byte
16DvpStillOpenRecover mentre l'operazione è ancora aperta; usa Reclaim
17DvpNeverCreatedRecover con seed senza tombstone
18EscrowPreloadedWithLamportsCreate quando un escrow non nativo detiene lamport superiori al minimo rent-exempt
19SettlementDestinationIsSwapDvpCreate con una destinazione di regolamento uguale al record dell'operazione
20SwapDvpPreloadedWithLamportsCreate quando l'indirizzo del record detiene lamport oltre la propria riserva di rent
21RecipientAtaMismatchUn token account del destinatario o del 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 una leg differisce dal valore acquisito alla creazione

Eventi e indicizzazione

Il programma non emette eventi onchain. 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 un'operazione al relativo ordine off-chain. Poiché il record viene chiuso al momento del regolamento, un sistema che ha bisogno dei termini a posteriori li memorizza quando li legge, oppure li ricostruisce dalla transazione che ha creato l'operazione.

Token supportati

Un'operazione può abbinare una leg SPL Token a una leg Token-2022; ogni leg porta con sé il proprio token program. Sono supportate le leg in wrapped SOL.

Estensione Token-2022 sul mint di una legComportamento del programma
TransferFee, InterestBearing, ScaledUiAmount, NonTransferableRifiutato in Create e Settle con BlockedMintExtension
PermanentDelegate, Pausable, DefaultAccountState, a freeze authority, MintCloseAuthorityAccettato; ogni authority può agire sui token in escrow
ConfidentialTransferAccettato; gli importi su quella leg sono pubblici
TransferHookSupportato, fino a 32 account aggiuntivi per leg
MemoTransfer su un account di destinazione o di rimborsoAccettato; il programma emette il memo richiesto prima del trasferimento

Una commissione di trasferimento lascerebbe il lato ricevente con un importo inferiore a quello 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 un'operazione, modificando il modo in cui vengono visualizzati gli importi concordati. NonTransferable bloccherebbe entrambe le leg.

Le authority accettate possono spostare, congelare o bloccare i token in escrow per tutta la durata dell'operazione (vedi sotto). L'escrow non può essere configurato per ricevere trasferimenti confidenziali, quindi gli importi in escrow e regolati su una 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 comprende il programma hook e il relativo account di validazione. Se la hook authority amplia l'elenco di account dell'hook oltre tale limite, ogni trasferimento su quella leg fallisce, inclusi Reclaim, Cancel, Reject e Recover, finché l'authority non annulla la modifica. Il limite di account della transazione può diventare vincolante prima del limite per leg quando entrambe le leg hanno hook.

Quando un account di destinazione o di rimborso richiede memo, il programma chiama il Memo program prima del trasferimento, ed è per questo che 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 authority delegata e non applica questo controllo.

Mint congelati per impostazione predefinita. L'escrow di ogni operazione è un associated token account di proprietà di un Program Derived Address nuovo per quell'operazione. 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 scongelato. Con Token ACL ciò significa che l'emittente o il suo transfer agent ammette l'escrow dell'operazione prima del finanziamento: aggiungendo l'indirizzo del record dell'operazione (il proprietario dell'escrow) alla allowlist, in modo che chiunque possa scongelare l'escrow dove la configurazione Token ACL del mint abilita il thaw permissionless, oppure facendolo scongelare direttamente alla freeze authority. Un escrow congelato blocca inoltre Settle, Reclaim, Cancel, Reject e Recover su quella leg, quindi la freeze authority, e su un mint con hook la hook authority, è una parte di fiducia per tutta la durata dell'operazione. Il percorso con escrow congelato è descritto qui e non viene esercitato negli snippet 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 è un'operazione tra due parti.
  • Nessun riempimento parziale. Settle sposta esattamente l'importo concordato di ciascuna leg e restituisce l'eventuale eccedenza alla parte della leg.
  • Nessuna leg off-ledger. Entrambe le leg sono token account su Solana; una leg in contanti su circuiti esistenti viene regolata separatamente e riconciliata.
  • Nessun controllo di idoneità, allowlist o KYC. Sono i controlli propri del mint a verificare l'idoneità dei detentori.
  • Nessun regolamento automatico. L'autorità di regolamento 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: nessuna leg si muove a meno che non lo facciano entrambe. Non elimina il rischio di credito dell'emittente o di rimborso su nessuno dei due token, la possibilità che la freeze, pause o permanent delegate authority di un mint agisca sui token in escrow (vedi token supportati), né la dipendenza dalla disponibilità dell'autorità di regolamento a firmare.

Verifica prima del finanziamento e del regolamento

CreateDvp è permissionless: firma solo il payer, mentre le parti e l'autorità di regolamento no. 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 verifica che:

  1. L'account sia di proprietà del programma DvP e sia esattamente di 458 byte. Un account che 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 all'operazione concordata.
  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 le leg elenca i reader con verifica dei client generati e mostra il controllo nel codice.

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

Versionamento

L'account SwapDvp non ha un campo di versione. Il suo layout è fisso a 458 byte (SwapDvp::LEN) e i reader con verifica 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 operazione esiste solo finché non viene regolato, annullato o rifiutato, quindi consulta il repository per sapere come un aggiornamento tratta le operazioni aperte 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 dal 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.