Self-Custody
Self-Custody es el modelo de ejecución real, en operación hoy en la plataforma — el único
ExecutionCustodyMode que realmente puede seleccionarse para cualquier Environment, Sandbox o
Production. Bajo Self-Custody, la plataforma nunca guarda una clave privada en su nombre — la
wallet se genera y controla enteramente de su lado, a través de uno de los
SDKs oficiales.
ExecutionCustodyMode también declara ManagedCustody, ExternalCustody y
SmartContractEscrow a nivel de dominio — preservados arquitectónicamente (para que el historial
propio de la plataforma y herramientas internas, como TreasuryReconciliation, sigan funcionando
contra ese vocabulario), pero ninguno de ellos puede activarse: configurar el modo de un
Environment en cualquier valor distinto de Self-Custody se rechaza de inmediato. Trate esos tres
como reservados, no como opciones de configuración disponibles hoy.
Cómo funciona
- Generación local de la wallet. El SDK genera un mnemonic BIP39 y deriva una clave
extendida BIP32 localmente (ruta BIP44
m/44'/195'/0',coin_typede TRON = 195). La clave privada se crea y se usa enteramente dentro de su proceso — nunca se transmite, registra, ni persiste por el SDK por su cuenta (INV-SC-01). - Registro público. Solo la clave pública extendida (
xpub) resultante se envía a la API —POST /v1/applications/{applicationId}/wallets. La plataforma puede derivar direcciones a partir de ella, pero nunca puede firmar con ella. - Asignación de dirección de depósito. La plataforma deriva una dirección TRON real de
depósito a partir del
xpubregistrado (POST .../wallets/deposit-addresses) — el mismo SDK puede re-derivar y verificar esa dirección localmente, de forma independiente, como una verificación de defensa en profundidad contra un backend comprometido. - Firma de múltiples Legs. Un
SigningRequestdescribe una o másExecutionLegs (por ejemplo, una Leg de Seller y una Leg de Platform Fee del mismo Settlement). Para cada Leg, el backend calcula un hash canónico determinístico del contenido exacto de la transacción; el SDK firma ese hash localmente con la clave privada y envía la firma de vuelta (POST .../legs/{executionLegId}/submit). El backend verifica cada firma de forma independiente contra el mismo hash canónico antes de aceptarla — un monto o destino alterado produce un hash distinto y es rechazado de inmediato. - All-signatures gate. Ninguna Leg se transmite (broadcast) a la red hasta que todas las
Legs del
SigningRequesttengan una firma verificada. La primera firma sola nunca dispara un broadcast — solo la última lo dispara, para todas las Legs a la vez.
Financiamiento multi-source
Un Settlement puede financiarse con más de una dirección de depósito confirmada —
soportado: produce un SigningRequest por cada fuente física de financiamiento
(SettlementResponse.signingRequestIds, plural), firma y confirma cada uno. Un Withdrawal
siempre proviene de un único SigningRequest — el financiamiento multi-source no está
soportado para Withdrawal hoy (Withdrawal.signingRequestId sigue siendo solo singular); no
construyas una integración que asuma paridad aquí.
Lo que nunca sucede
- La clave privada nunca se envía a la API, en ninguna solicitud, en ninguna etapa.
- Ninguna Leg se transmite antes de que todas las Legs estén firmadas y verificadas.
- Una firma nunca se acepta sin recalcular y comparar el hash canónico de forma independiente en el servidor.
Errores
Una firma enviada para una Leg cuyo hash recalculado no coincide se rechaza con
SIGNED_TRANSACTION_MISMATCH — la Leg nunca se transmite. Una razón de discrepancia más
granular (monto, participante, red o activo) es una extensión futura documentada; hoy la
verificación es una única comparación de hash opaco, que ya cubre la invariante de seguridad
central: una transacción alterada nunca pasa la verificación, sea cual sea el campo específico
modificado.
Disponible hoy
La generación de wallets Self-Custody, el registro, la asignación de dirección de depósito y el
protocolo completo de firma de múltiples Legs — hash canónico, verificación de firma, el gate
de todas-las-firmas y el broadcast — están implementados y validados de extremo a extremo en
Sandbox, a través de los cuatro SDKs oficiales (Java, Node.js/TypeScript, Python, Go) —
cada uno incluye un ejemplo completo y ejecutable (13-self-custody-signing). Vea la
guía del recorrido de marketplace para este protocolo
conectado de extremo a extremo con un pago real — registro, Payment Intent, depósito, y un payout
firmado localmente — no solo el paso de firma de forma aislada.
La creación de SigningRequest ya está conectada automáticamente tanto a Settlement como a
Withdrawals — confirmado en vivo: executeSettlement() y withdrawals.request() construyen el
SigningRequest/las ExecutionLegs por su cuenta, a partir de los beneficiarios y montos ya
presentes en el Settlement/Withdrawal; un integrador nunca construye un SigningRequest
manualmente para esos flujos (la ruta directa POST .../signing-requests de abajo sigue
existiendo para otros usos, de nivel más bajo). El seguimiento de confirmación de broadcast
también es automático, orientado a eventos de extremo a extremo — en cuanto todas las Legs están
firmadas y el all-signatures gate dispara el broadcast, la propia plataforma observa la
confirmación (simulada en Sandbox) y mueve el Settlement/Withdrawal a su estado terminal; el
integrador nunca hace polling directo a un nodo de blockchain para esto.
Dos cosas deben registrarse una vez por Organization/AssetNetwork antes de que la primera
ejecución real en Self-Custody pueda completarse: un ExecutionDestination para cada
beneficiario que recibe pago (incluyendo el propio Fee de la plataforma, bajo un Settlement), y un
NetworkCostPayerAccount para cubrir los recursos de red reales que consume un broadcast (vea
Transaction, Settlement, Split y Refund para ambos, y
Network Execution para ExecutionSource — un tercer registro
relacionado, fácil de confundir con los otros dos). La ejecución
real de blockchain — una transacción que efectivamente llega a una red real — es exclusiva de
Production y todavía no está disponible; el broadcast y la confirmación en Sandbox se simulan de
extremo a extremo.
Rutas
- Registrar una wallet:
POST /v1/applications/{applicationId}/wallets - Asignar una dirección de depósito:
POST /v1/applications/{applicationId}/wallets/deposit-addresses - Obtener una wallet:
GET /v1/wallets/{walletId}(y/public-material) - Crear un signing request:
POST /v1/environments/{environmentId}/signing-requests - Obtener un signing request:
GET /v1/signing-requests/{signingRequestId} - Enviar una Leg firmada:
POST /v1/signing-requests/{signingRequestId}/legs/{executionLegId}/submit