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.
Creare un'operazione
Installa i client e registra i termini dell'operazione con CreateDvp
Finanziare i leg
Verifica i termini memorizzati, poi finanzia ogni leg con un semplice trasferimento
Regolare l'operazione
Regola entrambi i leg in un'unica transazione come autorità di regolamento
Annullare un'operazione
Riprendi un leg, annulla o rifiuta l'operazione e recupera i depositi tardivi
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-securitydi 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.
| Ruolo | Chi | Firma | Note |
|---|---|---|---|
| Parte del leg asset | user_a, consegna mint_a | Il proprio trasferimento di finanziamento; Reclaim, Reject, Recover | Un 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 cash | user_b, consegna mint_b | Il proprio trasferimento di finanziamento; Reclaim, Reject, Recover | Stesso requisito |
| Autorità di regolamento | Un terzo indirizzo indicato alla creazione | Settle, Cancel | L'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 rent | Chi firma CreateDvp | Create | Finanzia 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
| Cluster | Programma | Upgrade authority | Ultimo slot di distribuzione |
|---|---|---|---|
| mainnet-beta | dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq | DXtFpbPjcn2hxPnw79x1Pfoj35vXh5AsWBkS37YnXMVv | 452.058.374 |
| devnet | dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq | 5EX1zFeJWj4rGYZv432WnYw8CbaSUeTdxPx4r573UgYU | 479.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.
| Campo | Tipo | Significato |
|---|---|---|
bump | u8 | PDA bump |
user_a, user_b | Pubkey | Le due parti |
mint_a, mint_b | Pubkey | I mint del leg asset e del leg cash |
settlement_authority | Pubkey | L'unico firmatario che può regolare o annullare |
token_program_a, token_program_b | Pubkey | Il Token Program che possiede ciascun mint; un'operazione può combinare leg SPL Token e Token-2022 |
amount_a, amount_b | u64 | L'importo concordato di ciascun leg, nell'unità più piccola del mint (unità di base) |
expiry_timestamp | i64 | Dopo questo orario di rete (il clock onchain), Settle viene rifiutato. Reclaim, Cancel e Reject continuano a funzionare |
nonce | u64 | Distingue 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_destination | Pubkey | Riceve il leg cash al Settle; per impostazione predefinita è user_a |
user_b_settlement_destination | Pubkey | Riceve il leg asset al Settle; per impostazione predefinita è user_b |
mint_a_authority, mint_b_authority | Pubkey | Le mint authority acquisite alla creazione; Settle fallisce se una delle due è cambiata |
earliest_settlement_timestamp | Option<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
| Istruzione | Firmatario | Effetto |
|---|---|---|
CreateDvp | Qualsiasi pagatore | Crea il record SwapDvp, il relativo nonce tombstone e entrambi gli account escrow. Non sposta alcun token |
ReclaimDvp | user_a o user_b | Restituisce dall'escrow il leg del firmatario. L'operazione resta aperta e il leg può essere finanziato di nuovo |
SettleDvp | Autorità di regolamento | Trasferisce 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 |
CancelDvp | Autorità di regolamento | Rimborsa a user_a quanto contiene l'escrow A e a user_b quanto contiene l'escrow B, chiude il record e entrambi gli escrow |
RejectDvp | user_a o user_b | Stesso effetto di Cancel, firmato da una parte |
RecoverDvp | user_a o user_b | Dopo 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
| Codice | Errore | Quando |
|---|---|---|
| 0 | SignerNotParty | Reclaim, Reject o Recover firmati da un indirizzo che non è user_a o user_b |
| 1 | DvpExpired | Settle dopo expiry_timestamp |
| 2 | SettlementAuthorityMismatch | Settle o Cancel firmati da un indirizzo diverso dall'autorità di regolamento |
| 3 | SettlementTooEarly | Settle prima di earliest_settlement_timestamp |
| 4 | LegNotFunded | Settle mentre un escrow contiene meno dell'importo concordato |
| 5 | ExpiryNotInFuture | Create con una scadenza uguale o precedente all'orario di rete corrente |
| 6 | EarliestAfterExpiry | Create con un orario di regolamento minimo successivo alla scadenza |
| 7 | SelfDvp | Create con user_a uguale a user_b |
| 8 | SameMint | Create con mint_a uguale a mint_b |
| 9 | ZeroAmount | Create con un importo pari a zero su uno dei due leg |
| 10 | BlockedMintExtension | Create o Settle con un mint che usa TransferFee, InterestBearing, ScaledUiAmount o NonTransferable |
| 11 | SettlementAuthorityIsParty | Create con l'autorità di regolamento uguale a una delle parti |
| 12 | SettlementAuthorityExecutable | Create con un'autorità di regolamento eseguibile |
| 13 | NonceAlreadyUsed | Create che riutilizza un (seeds, nonce) che ha già un tombstone |
| 14 | ExpiryTooFarInFuture | Create con una scadenza oltre un anno in avanti |
| 15 | RefStringTooLong | Create con un riferimento più lungo di 64 byte |
| 16 | DvpStillOpen | Recover mentre l'operazione è ancora aperta; usa Reclaim |
| 17 | DvpNeverCreated | Recover con seed senza tombstone |
| 18 | EscrowPreloadedWithLamports | Create quando un escrow non nativo detiene lamport superiori al minimo rent-exempt |
| 19 | SettlementDestinationIsSwapDvp | Create con una destinazione di regolamento uguale al record dell'operazione |
| 20 | SwapDvpPreloadedWithLamports | Create quando l'indirizzo del record detiene lamport oltre la propria riserva di rent |
| 21 | RecipientAtaMismatch | Un token account del destinatario o del rimborso non appartiene più al wallet e al mint previsti |
| 22 | PartyNotSignerCapable | Create con una parte che non è un account di proprietà del sistema e non eseguibile |
| 23 | MintAuthorityChanged | Settle 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 leg | Comportamento del programma |
|---|---|
| TransferFee, InterestBearing, ScaledUiAmount, NonTransferable | Rifiutato in Create e Settle con BlockedMintExtension |
| PermanentDelegate, Pausable, DefaultAccountState, a freeze authority, MintCloseAuthority | Accettato; ogni authority può agire sui token in escrow |
| ConfidentialTransfer | Accettato; gli importi su quella leg sono pubblici |
| TransferHook | Supportato, fino a 32 account aggiuntivi per leg |
| MemoTransfer su un account di destinazione o di rimborso | Accettato; 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:
- 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.
user_a,user_b,mint_a,mint_besettlement_authoritycorrispondano all'operazione concordata.amount_a,amount_b,expiry_timestampeearliest_settlement_timestampcorrispondano ai termini concordati.- 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
- Delivery vs Payment (DvP) con delega: il pattern di delega senza un programma
- Token ACL: come un mint con restrizioni interagisce con gli account di escrow
Is this page helpful?