Self-Custody
Self-Custody é o modelo de execução real, em operação hoje na plataforma — o único
ExecutionCustodyMode que pode de fato ser selecionado para qualquer Environment, Sandbox ou
Production. Sob Self-Custody, a plataforma nunca guarda uma chave privada em seu nome — a wallet
é gerada e controlada inteiramente do seu lado, através de um dos SDKs oficiais.
ExecutionCustodyMode também declara ManagedCustody, ExternalCustody e
SmartContractEscrow no nível de domínio — preservados arquiteturalmente (para que o histórico
da própria plataforma e ferramentas internas, como TreasuryReconciliation, continuem
funcionando contra esse vocabulário), mas nenhum deles pode ser ativado: configurar o modo de um
Environment para qualquer valor diferente de Self-Custody é rejeitado de imediato. Trate esses
três como reservados, não como opções de configuração disponíveis hoje.
Como funciona
- Geração local da wallet. O SDK gera um mnemonic BIP39 e deriva uma chave estendida BIP32
localmente (path BIP44
m/44'/195'/0',coin_typeTRON = 195). A chave privada é criada e usada inteiramente dentro do seu processo — nunca é transmitida, logada, ou persistida pelo SDK por conta própria (INV-SC-01). - Registro público. Só a chave pública estendida (
xpub) resultante é enviada à API —POST /v1/applications/{applicationId}/wallets. A plataforma consegue derivar endereços a partir dela, mas nunca consegue assinar com ela. - Alocação de endereço de depósito. A plataforma deriva um endereço TRON real de depósito a
partir do
xpubregistrado (POST .../wallets/deposit-addresses) — o mesmo SDK consegue re-derivar e verificar esse endereço localmente, de forma independente, como uma verificação de defesa em profundidade contra um backend comprometido. - Assinatura de múltiplas Legs. Um
SigningRequestdescreve uma ou maisExecutionLegs (por exemplo, uma Leg do Seller e uma Leg de Platform Fee do mesmo Settlement). Para cada Leg, o backend calcula um hash canônico determinístico do conteúdo exato da transação; o SDK assina esse hash localmente com a chave privada e submete a assinatura de volta (POST .../legs/{executionLegId}/submit). O backend verifica cada assinatura de forma independente contra o mesmo hash canônico antes de aceitá-la — um valor ou destino adulterado produz um hash diferente e é rejeitado de imediato. - All-signatures gate. Nenhuma Leg é transmitida (broadcast) para a rede até que todas as
Legs do
SigningRequesttenham uma assinatura verificada. A primeira assinatura sozinha nunca dispara um broadcast — só a última dispara, para todas as Legs de uma vez.
Financiamento multi-source
Um Settlement pode ser financiado por mais de um endereço de depósito confirmado —
suportado: produz um SigningRequest por fonte física de financiamento
(SettlementResponse.signingRequestIds, plural), assine e confirme cada um. Um Withdrawal
sempre vem de um único SigningRequest — financiamento multi-source não é suportado para
Withdrawal hoje (Withdrawal.signingRequestId continua só singular); não construa uma integração
que presuma paridade aqui.
O que nunca acontece
- A chave privada nunca é enviada à API, em nenhuma requisição, em nenhuma etapa.
- Nenhuma Leg é transmitida antes de todas as Legs estarem assinadas e verificadas.
- Uma assinatura nunca é aceita sem recalcular e comparar o hash canônico de forma independente no lado do servidor.
Erros
Uma assinatura submetida para uma Leg cujo hash recalculado não corresponde é rejeitada com
SIGNED_TRANSACTION_MISMATCH — a Leg nunca é transmitida. Uma razão de mismatch mais granular
(valor, participante, rede ou ativo) é uma extensão futura documentada; hoje a verificação é uma
única comparação de hash opaco, que já cobre a invariante de segurança central: uma transação
adulterada nunca passa pela verificação, seja qual for o campo específico alterado.
Disponível hoje
Geração de wallet Self-Custody, registro, alocação de endereço de depósito e o protocolo
completo de assinatura de múltiplas Legs — hash canônico, verificação de assinatura, gate de
todas-as-assinaturas e broadcast — estão implementados e validados de ponta a ponta em Sandbox,
através dos quatro SDKs oficiais (Java, Node.js/TypeScript, Python, Go) — cada um traz
um exemplo completo e executável (13-self-custody-signing). Veja o
guia da jornada de marketplace para esse protocolo conectado
de ponta a ponta com um pagamento real — cadastro, Payment Intent, depósito, e um payout assinado
localmente — não apenas a etapa de assinatura isolada.
A criação de SigningRequest já está conectada automaticamente tanto a Settlement quanto a
Withdrawals — confirmado ao vivo: executeSettlement() e withdrawals.request() constroem o
SigningRequest/as ExecutionLegs por conta própria, a partir dos beneficiários e valores já
presentes no Settlement/Withdrawal; um integrador nunca constrói um SigningRequest manualmente
para esses fluxos (a rota direta POST .../signing-requests abaixo ainda existe para outros usos,
de nível mais baixo). O acompanhamento de confirmação de broadcast também é automático, orientado
a eventos de ponta a ponta — assim que todas as Legs estão assinadas e o all-signatures gate
dispara o broadcast, a própria plataforma observa a confirmação (simulada em Sandbox) e move o
Settlement/Withdrawal para seu estado terminal; o integrador nunca faz polling direto em um nó de
blockchain para isso.
Duas coisas precisam ser registradas uma vez por Organization/AssetNetwork antes que a primeira
execução real em Self-Custody possa se completar: um ExecutionDestination para cada
beneficiário que recebe pagamento (incluindo o próprio Fee da plataforma, sob um Settlement), e um
NetworkCostPayerAccount para cobrir os recursos de rede reais que um broadcast consome (ver
Transaction, Settlement, Split e Refund para ambos, e
Network Execution para ExecutionSource — um terceiro registro
relacionado, fácil de confundir com os outros dois). Execução real
de blockchain — uma transação de fato chegando a uma rede real — é exclusiva de Production e ainda
não está disponível; o broadcast e a confirmação em Sandbox são simulados de ponta a ponta.
Rotas
- Registrar uma wallet:
POST /v1/applications/{applicationId}/wallets - Alocar um endereço de depósito:
POST /v1/applications/{applicationId}/wallets/deposit-addresses - Obter uma wallet:
GET /v1/wallets/{walletId}(e/public-material) - Criar um signing request:
POST /v1/environments/{environmentId}/signing-requests - Obter um signing request:
GET /v1/signing-requests/{signingRequestId} - Submeter uma Leg assinada:
POST /v1/signing-requests/{signingRequestId}/legs/{executionLegId}/submit