Programa de Entrega contra Pagamento (DvP)

O programa DvP é o programa padrão de entrega contra pagamento na Solana, mantido pela Solana Foundation e auditado pela Cantina. Duas partes combinam uma operação, cada uma envia sua perna para uma conta de escrow com uma transferência de token comum, e uma autoridade de liquidação liquida as duas pernas em uma única transação, de modo que ou ambas se movem ou nenhuma se move. A autoridade de liquidação é um terceiro endereço indicado na operação, como a plataforma ou o agente que a intermediou. Nenhuma das partes escreve ou implanta um programa, e uma carteira ou custodiante capaz de enviar uma transferência de token padrão (TransferChecked) pode financiar uma perna sem nenhuma integração específica com o DvP. Até a liquidação, qualquer uma das partes pode retirar a sua própria perna ou desfazer a operação.

Leia o registro antes de agir com base nele

A criação de um registro de operação é sem permissão, portanto um registro não é prova de acordo. Cada parte lê os termos armazenados antes de financiar, e a autoridade de liquidação antes de liquidar (veja verificação).

Como funciona

Cada operação recebe um registro pertencente ao programa e duas contas de escrow, uma por perna. A parte da perna de ativo (user_a) e a parte da perna de dinheiro (user_b) financiam cada uma sua perna transferindo tokens para a conta de escrow dessa perna. A autoridade de liquidação é o único signatário que pode liquidar. A liquidação transfere o valor acordado de cada perna para a outra parte, devolve qualquer excedente à parte dona da perna e encerra o registro e ambos os escrows. A atomicidade vem das transações da Solana: as duas transferências estão em uma única transação, então ou ambas entram em vigor ou nenhuma entra.

Todo reembolso, resgate e devolução de excedente vai para a associated token account da própria parte: a conta de user_a para mint_a, a de user_b para mint_b. Um custodiante ou sistema de tesouraria pode financiar uma perna a partir de sua própria conta, mas tudo o que for devolvido cai na conta da parte, não de volta ao custodiante. Cada operação também deixa uma conta marcadora permanente (veja Estado).

Guias

As páginas passo a passo conduzem uma operação da criação à liquidação, com TypeScript e Rust para cada instrução.

Uma demonstração em devnet executa uma operação de ponta a ponta: ela cria a operação, financia os dois escrows com transferências de token padrão e liquida as duas pernas em uma única transação.

Como escolher entre o programa e a delegação

Entrega contra Pagamento (DvP) usando delegação liquida a mesma troca sem um programa: cada lado delega sua posição a um agente de liquidação, que move as duas pernas em uma única transação.

  • O programa não exige delegação, então o limite de um delegado por token account não se aplica, e a autoridade de liquidação não pode redirecionar os recursos. Cada operação depende de um programa atualizável e de sua upgrade authority.
  • O padrão de delegação não tem dependência de programa e funciona com mints que usam Scaled UI Amount. O programa rejeita esses mints, o que exclui qualquer mint criado a partir do modelo tokenized-security do Mosaic (veja restrições de configuração de mint).

Papéis

O programa é simétrico. Em sua interface, as duas partes são user_a, que entrega mint_a, e user_b, que entrega mint_b. O README e os clientes gerados chamam mint_a de perna de ativo e mint_b de perna de dinheiro, e estas páginas seguem essa convenção, mas nada no programa exige que a perna de dinheiro seja um instrumento financeiro em dinheiro. Dois ativos, ou duas stablecoins, são liquidados da mesma forma.

PapelQuemAssinaObservações
Parte da perna de ativouser_a, entrega mint_aSua própria transferência de financiamento; Reclaim, Reject, RecoverUma carteira keypair ou uma carteira inteligente baseada em PDA, como um cofre multisig. Uma conta multisig do SPL Token ou uma program account não pode ser uma parte: Create falha com PartyNotSignerCapable
Parte da perna de dinheirouser_b, entrega mint_bSua própria transferência de financiamento; Reclaim, Reject, RecoverMesmo requisito
Autoridade de liquidaçãoUm terceiro endereço indicado na criaçãoSettle, CancelO único signatário que pode liquidar. Não pode redirecionar os recursos, que são fixados na criação. Recebe o rent das contas encerradas quando liquida ou cancela
Pagador de rentQuem assinar CreateDvpCreateFinancia o rent (o depósito em SOL que mantém uma conta aberta) do registro, do tombstone do nonce e dos dois escrows. Não é registrado como destinatário de rent: o rent das contas encerradas vai para quem encerrar a operação

ID do programa

dvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq
ClusterProgramaUpgrade authorityÚltimo slot implantado
mainnet-betadvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZqDXtFpbPjcn2hxPnw79x1Pfoj35vXh5AsWBkS37YnXMVv452.058.374
devnetdvp34bdbcEm4f4FCUjGV4mDAkDshaQR4LkK8fdcsyZq5EX1zFeJWj4rGYZv432WnYw8CbaSUeTdxPx4r573UgYU479.376.863

O programa é atualizável nos dois clusters. Os valores acima são o que solana program show informou em 2 de outubro de 2026; execute o mesmo comando para obter os valores atuais. O build da devnet é mais antigo que o commit com base no qual as páginas passo a passo foram escritas (veja Instalação), com o mesmo conjunto de instruções e erros.

Ciclo de vida

Uma operação fica aberta desde CreateDvp até que uma das instruções Settle, Cancel ou Reject a encerre. O financiamento não tem instrução própria: uma perna é considerada financiada quando sua conta de escrow contém pelo menos o valor acordado. Reclaim funciona por perna e mantém a operação aberta, de modo que um problema em uma perna não obriga a outra parte a cancelar toda a operação.

Estado

Cada operação tem uma conta SwapDvp de 458 bytes, pertencente ao programa. Seu endereço é derivado da autoridade de liquidação, das duas partes, dos dois mints e de um nonce (as seeds ["dvp", settlement_authority, user_a, user_b, mint_a, mint_b, nonce]). Os valores e os horários são armazenados dentro da conta e não afetam o endereço, razão pela qual precisam ser lidos em vez de presumidos. Uma pequena conta marcadora, o tombstone do nonce em ["nonce", swap_dvp], é criada junto com a operação e nunca é encerrada, de modo que cada combinação de partes, mints, autoridade e nonce só pode ser usada em uma única operação.

CampoTipoSignificado
bumpu8Bump do PDA
user_a, user_bPubkeyAs duas partes
mint_a, mint_bPubkeyOs mints da perna de ativo e da perna de dinheiro
settlement_authorityPubkeyO único signatário que pode liquidar ou cancelar
token_program_a, token_program_bPubkeyO token program dono de cada mint; uma operação pode misturar pernas SPL Token e Token-2022
amount_a, amount_bu64O valor acordado de cada perna, na menor unidade do mint (unidades base)
expiry_timestampi64Após esse horário da rede (o relógio onchain), Settle é rejeitada. Reclaim, Cancel e Reject continuam funcionando
nonceu64Diferencia operações que compartilham as demais seeds. Uso único
ref_string[u8; 64]Uma referência opaca do cliente, preenchida com zeros; o programa nunca a lê
user_a_settlement_destinationPubkeyRecebe a perna de dinheiro em Settle; o padrão é user_a
user_b_settlement_destinationPubkeyRecebe a perna de ativo em Settle; o padrão é user_b
mint_a_authority, mint_b_authorityPubkeyAs mint authorities capturadas na criação; Settle falha se qualquer uma delas tiver mudado
earliest_settlement_timestampOption<i64>Se definido, Settle é rejeitada antes desse horário da rede

A lista de campos foi extraída do IDL do programa no commit indicado em Criar uma operação.

Instruções

InstruçãoSignatárioEfeito
CreateDvpQualquer pagadorCria o registro SwapDvp, seu tombstone do nonce e as duas contas de escrow. Não move tokens
ReclaimDvpuser_a ou user_bDevolve do escrow a perna do próprio signatário. A operação permanece aberta e a perna pode ser financiada novamente
SettleDvpAutoridade de liquidaçãoTransfere amount_a para o destino de user_b e amount_b para o destino de user_a, devolve qualquer excedente à parte da perna e encerra o registro e os dois escrows
CancelDvpAutoridade de liquidaçãoReembolsa a user_a o que o escrow A contiver e a user_b o que o escrow B contiver, e encerra o registro e os dois escrows
RejectDvpuser_a ou user_bMesmo efeito de Cancel, assinada por uma das partes
RecoverDvpuser_a ou user_bApós o encerramento da operação: esvazia um escrow recriado para a token account do próprio signatário e o encerra. Cobre um depósito que chegou depois de Settle, Cancel ou Reject

Todo reembolso vai para a associated token account da própria parte referente ao mint daquela perna, independentemente de quem financiou o escrow.

As contas e os argumentos de cada instrução estão na página da respectiva etapa.

Erros

CódigoErroQuando
0SignerNotPartyReclaim, Reject ou Recover assinada por um endereço que não é user_a nem user_b
1DvpExpiredSettle após expiry_timestamp
2SettlementAuthorityMismatchSettle ou Cancel assinada por um endereço diferente da autoridade de liquidação
3SettlementTooEarlySettle antes de earliest_settlement_timestamp
4LegNotFundedSettle enquanto um escrow contém menos que o valor acordado
5ExpiryNotInFutureCreate com uma expiração igual ou anterior ao horário atual da rede
6EarliestAfterExpiryCreate com um horário mínimo de liquidação posterior à expiração
7SelfDvpCreate com user_a igual a user_b
8SameMintCreate com mint_a igual a mint_b
9ZeroAmountCreate com valor zero em qualquer uma das pernas
10BlockedMintExtensionCreate ou Settle com um mint que possui TransferFee, InterestBearing, ScaledUiAmount ou NonTransferable
11SettlementAuthorityIsPartyCreate com a autoridade de liquidação igual a uma das partes
12SettlementAuthorityExecutableCreate com uma autoridade de liquidação executável
13NonceAlreadyUsedCreate reutilizando um (seeds, nonce) que já possui um tombstone
14ExpiryTooFarInFutureCreate com uma expiração superior a um ano no futuro
15RefStringTooLongCreate com uma referência maior que 64 bytes
16DvpStillOpenRecover enquanto a operação ainda está aberta; use Reclaim
17DvpNeverCreatedRecover com seeds que não têm tombstone
18EscrowPreloadedWithLamportsCreate quando um escrow não nativo mantém lamports acima do seu mínimo isento de rent
19SettlementDestinationIsSwapDvpCreate com um destino de liquidação igual ao registo da operação
20SwapDvpPreloadedWithLamportsCreate quando o endereço do registo mantém lamports acima da sua reserva de rent
21RecipientAtaMismatchUma token account de destinatário ou de reembolso deixou de pertencer à carteira e à mint esperadas
22PartyNotSignerCapableCreate com uma parte que não é uma conta não executável pertencente ao sistema
23MintAuthorityChangedSettle quando a mint authority de uma perna difere do valor capturado na criação

Eventos e indexação

O programa não emite eventos on-chain. Um indexador ou sistema de reconciliação lê o estado da conta SwapDvp e os saldos de tokens dos dois escrows, e usa ref_string para correlacionar uma operação com a respetiva ordem off-chain. Como o registo é encerrado na liquidação, um sistema que precise dos termos posteriormente guarda-os quando os lê, ou reconstrói-os a partir da transação que criou a operação.

Tokens suportados

Uma operação pode combinar uma perna SPL Token com uma perna Token-2022; cada perna transporta o seu próprio token program. As pernas de Wrapped SOL são suportadas.

Extensão Token-2022 na mint de uma pernaComportamento do programa
TransferFee, InterestBearing, ScaledUiAmount, NonTransferableRejeitada em Create e Settle com BlockedMintExtension
PermanentDelegate, Pausable, DefaultAccountState, uma freeze authority, MintCloseAuthorityAceite; cada authority pode atuar sobre os tokens em escrow
ConfidentialTransferAceite; os montantes dessa perna são públicos
TransferHookSuportado, até 32 contas adicionais por perna
MemoTransfer numa conta de destino ou de reembolsoAceite; o programa emite o memo necessário antes da transferência

Uma taxa de transferência deixaria o lado recetor aquém do montante acordado. Interest Bearing e Scaled UI Amount não alteram os montantes brutos, mas a sua taxa ou multiplicador pode mudar entre a criação e a liquidação de uma operação, o que altera a forma como os montantes acordados são apresentados. NonTransferable deixaria ambas as pernas bloqueadas.

As authorities aceites podem mover, congelar ou suspender os tokens em escrow durante toda a vida da operação (ver abaixo). O escrow não pode ser configurado para receber transferências confidenciais, pelo que os montantes em escrow e liquidados numa perna confidencial são públicos.

Para uma mint com hook, o cliente resolve as contas adicionais do hook e acrescenta-as a Settle, Cancel, Reject, Reclaim e Recover. O limite de 32 por perna inclui o programa do hook e a respetiva conta de validação. Se a hook authority aumentar a lista de contas do hook para além desse limite, todas as transferências nessa perna falham, incluindo Reclaim, Cancel, Reject e Recover, até que a authority reverta a alteração. O limite de contas por transação pode ser atingido antes do limite por perna quando ambas as pernas têm hooks.

Quando uma conta de destino ou de reembolso exige memos, o programa chama o programa Memo antes da transferência, razão pela qual todas as instruções que movem tokens para fora do escrow recebem uma conta memo_program.

Restrições de configuração da mint

Scaled UI Amount. O modelo tokenized-security no Mosaic, o kit de ferramentas de emissão da Solana Foundation, adiciona sempre Scaled UI Amount, pelo que o programa não aceita uma mint criada a partir desse modelo como perna. Uma mint destinada a este programa pode ser criada sem a extensão (ver Token Extensions); DvP com delegação liquida através de autoridade delegada e não aplica esta verificação.

Mints congeladas por defeito. O escrow de cada operação é uma associated token account pertencente a um program-derived address novo para essa operação. Numa mint com Default Account State definido como congelado, o escrow é criado congelado, e uma transferência de financiamento para o mesmo falha até ser descongelado. Com Token ACL, isso significa que o emitente ou o seu agente de transferência admite o escrow da operação antes do financiamento: quer adicionando o endereço do registo da operação (o owner do escrow) à allowlist, para que qualquer pessoa possa descongelar o escrow quando a configuração Token ACL da mint ativa o descongelamento sem permissões, quer fazendo com que a freeze authority o descongele diretamente. Um escrow congelado também bloqueia Settle, Reclaim, Cancel, Reject e Recover nessa perna, pelo que a freeze authority, e numa mint com hook a hook authority, é uma parte de confiança durante toda a vida da operação. O caminho do escrow congelado é descrito aqui e não é exercitado nos snippets da devnet.

Limites

  • Sem correspondência de ordens, descoberta de preços ou livro de ordens. As partes acordam os termos fora do ledger e uma delas regista-os.
  • Sem compensação (netting) e apenas bilateral: um registo é uma operação entre duas partes.
  • Sem execuções parciais. Settle move exatamente o montante acordado de cada perna e devolve qualquer excedente à parte dessa perna.
  • Sem perna fora do ledger. Ambas as pernas são token accounts na Solana; uma perna em dinheiro nos canais existentes é liquidada separadamente e reconciliada.
  • Sem verificação de elegibilidade, allowlist ou KYC. Os controlos da própria mint impõem a elegibilidade dos detentores.
  • Sem liquidação automática. A settlement authority tem de assinar.
  • Sem eventos e sem taxa de protocolo para além das taxas de transação e da rent.

O programa elimina o risco de principal entre as duas partes: nenhuma perna se move a menos que ambas se movam. Não elimina o risco de crédito do emitente nem o risco de resgate em qualquer um dos tokens, a capacidade de a freeze, pause ou permanent delegate authority de uma mint atuar sobre os tokens em escrow (ver tokens suportados), nem a dependência de a settlement authority estar disponível para assinar.

Verificação antes do financiamento e da liquidação

CreateDvp não requer permissões: apenas o payer assina, e as partes e a settlement authority não. Por isso, qualquer pessoa pode criar um registo que nomeie quaisquer partes e quaisquer termos. Antes de financiar, e novamente antes de liquidar, leia a conta SwapDvp e confirme:

  1. A conta pertence ao programa DvP e tem exatamente 458 bytes. Uma conta que não pertença ao programa pode ser preenchida com bytes que se descodificam como um registo real.
  2. user_a, user_b, mint_a, mint_b e settlement_authority correspondem à operação acordada.
  3. amount_a, amount_b, expiry_timestamp e earliest_settlement_timestamp correspondem aos termos acordados.
  4. Ambos os destinos de liquidação são os endereços acordados. Um registo forjado pode redirecionar os fundos.

Financiar as pernas lista os leitores verificados dos clientes gerados e mostra a verificação em código.

Considere uma operação liquidada quando a transação Settle atinge finalized. Trata-se de um nível de commitment da rede; se também marca a finalidade da liquidação para efeitos legais depende dos acordos das partes e dos regimes aplicáveis.

Versionamento

A conta SwapDvp não tem campo de versão. O seu layout é fixo em 458 bytes (SwapDvp::LEN), e os leitores verificados rejeitam uma conta de qualquer outro tamanho. O IDL tem a sua própria versão, 0.1.0 a 2 de outubro de 2026.

O programa é atualizável em ambos os clusters (ver Program ID). Um registo de operação existe apenas até ser liquidado, cancelado ou rejeitado, pelo que consulte o repositório para saber como uma atualização trata as operações em aberto, e regenere os clientes a partir do IDL da build implementada.

Repositório e auditoria

O código-fonte, o IDL, os clientes gerados e os testes encontram-se em solana-foundation/dvp sob a licença MIT. O programa é um programa Pinocchio no_std; os clientes são gerados a partir do IDL com Codama. Os relatórios de vulnerabilidades são feitos através da ligação de security advisory do repositório, conforme o respetivo SECURITY.md.

O programa foi auditado pela Cantina.

Relacionado

Is this page helpful?

© 2026 Fundação Solana. Todos os direitos reservados.