OUT_OF_ENERGY: el error de TRON que gasta la comisión y no envía nada
Sale una transferencia USDT, la cartera muestra una comisión cobrada y el destinatario no tiene nada. La transacción está en un bloque — no fue rechazada y ningún nodo se cayó — y donde una transferencia completada pone SUCCESS, esta pone OUT_OF_ENERGY. En TRON ese error significa justo lo que dice: a la llamada se le acabó la energía a mitad de camino y se detuvo. Aquí está el mecanismo, las tres formas de tropezar con él en una tanda de pagos, y las soluciones, de la más rápida a la que de verdad cuesta menos.
Qué dice en realidad el resultado
Enviar USDT es una llamada a un contrato inteligente, y la ejecución de contratos en TRON se mide en energía en vez de cobrarse como una comisión plana (qué es la energía). Primero se gasta la energía propia del remitente. Cuando no cubre la llamada, la red no se detiene ahí: compra el resto quemando el TRX del remitente a la tarifa del protocolo de 100 sun por cada unidad, pero solo hasta donde permita el fee_limit de la propia transacción. Ese campo no es una comisión que cobre nadie. Es un techo sobre cuánto TRX del remitente puede quemar esta llamada concreta.
Si se llega al techo con la llamada sin terminar, la ejecución se para. Todo cambio de estado que hubiera hecho se deshace, así que ningún token se mueve, y la red escribe su veredicto en la transacción, en el lugar donde una llamada completada lleva SUCCESS. Ese veredicto es la palabra que un explorador muestra junto a una transacción fallida, y el campo que un nodo devuelve como contractRet. Nada de la transacción dejó de llegar a la red. Llegó a la red y se ejecutó hasta que se acabó el dinero para ella.
El TRX se gasta igualmente
La reversión deshace la transferencia. No deshace la quema: la energía consumida es energía pagada, y al remitente le falta lo que el intento quemó camino del techo, sin que se moviera ningún token, y con un hash de transacción que un script de conciliación archivará tan contento como si fuera un pago.
Lo que convierte al reintento reflejo en la jugada cara. La misma transferencia con el mismo límite gasta el mismo TRX para el mismo resultado, y un bucle de pagos que reintenta sus fallos solo puede hacerlo varias veces antes de que una persona lea la cadena de resultado. La mayoría de los fallos con los que se topa una mesa de pagos cuestan dinero en silencio. Este cuesta dinero a gritos y aun así se pasa por alto, porque la cartera informa de una comisión y el dinero no está en ninguna parte.
Por qué un límite que ayer funcionaba deja de funcionar
Cambió el destinatario y el límite no. Este es el primero con el que se topa una tanda de pagos. Una transferencia a una dirección que ya tiene USDT consume unas 65,000 unidades de energía; a una dirección que nunca lo ha tenido, la transferencia además debe crear la cuenta de token del destinatario, y eso son unas 131,000: el doble de apetito para mover la misma cantidad de dinero. Quemar por la primera cuesta 6.5 TRX a la tarifa del protocolo, y por la segunda 13.1 TRX. Un techo dimensionado para el caso corriente se queda corto por la mitad la primera vez que se paga a un cliente nuevo, y nada en el lote se ve distinto: es una propiedad del destinatario, no de la transferencia.
La energía estaba y ya no está. Una delegación es una cantidad por un plazo, no una suscripción. Lo que gasta la primera transferencia no está ahí para la segunda, y cuando el plazo termina el resto vuelve a su dueño. Una cartera que ya envió una vez dentro de la misma ventana tiene menos de lo que sugiere la cifra que anuncia la delegación, y es la transferencia posterior la que se para — lo que desde fuera parece la misma transferencia fallando al azar.
El límite es cero. Cero es el valor correcto cuando la energía es segura, y en el mode B, donde entregamos la energía y emitimos nosotros la transacción, fee_limit es justo lo que le pedimos que deje sin poner: un límite ahí no sería más que un permiso permanente para quemar el TRX del remitente si algo saliera mal. También es un tope duro. Permiso cero significa que una llamada a la que le falta una sola unidad se para en vez de pagarla, así que un límite dejado en cero es una decisión que vale solo mientras valga la energía.
Verlo antes de firmar la transacción
La pregunta que hay detrás del primer disparador — cuánta energía cuesta este destinatario — se puede responder antes de firmar nada, con dos llamadas que no reservan nada ni cobran nada.
GET /v1/address-check responde por una dirección: activated, holds_usdt, blacklisted, is_contract, y el expected_kind que se deduce de ellos. holds_usdt es el que fija el tamaño de la llamada.
curl -s -H "Authorization: Bearer $KEY" \ "https://api.nrg.market/v1/address-check?address=TN3W4H6rK2ce4vX9YnFQHwKENnHjoxb3m9" # expected_kind es "single", "double" o "custom"
POST /v1/estimate responde por un lote — hasta 500 destinatarios en una llamada, cada uno con su kind, las energy_units que hay detrás y los warnings que haya. single es la transferencia corriente y double la que abre una cuenta de token. custom es el ítem que ninguna regla general cubre: el destinatario resulta ser un contrato con su propia lógica de transfer, así que no vale ninguna de las dos cifras estándar y energy_units sale de una simulación de la llamada real. Esos son los ítems a partir de los cuales dimensionar un límite uno a uno, y el aviso contract_recipient que llevan al lado es a menudo la primera señal de que una dirección de pago no es una cartera en absoluto.
Las soluciones, de la más fácil en adelante
Suba el límite. Un campo, ninguna infraestructura, y el bloqueo desaparece: la llamada termina y la red toma lo que necesita. El coste no desaparece con él. Un límite es permiso para quemar, así que un límite generoso es una quema generosa: la transferencia que antes se paraba ahora se completa por 13.1 TRX. Correcto como suelo bajo una tanda de pagos, equivocado como plan.
Ponga energía en el remitente. Entonces no hay nada que el límite tenga que permitir. La energía sale de poner TRX en staking, lo que significa inmovilizar un saldo de trabajo y vigilar un presupuesto de recursos, o de alquilar una delegación por los pocos minutos que necesita una transferencia (lo que cuesta ahora mismo). En cualquiera de los dos casos la llamada se paga en energía y no hay quema alguna.
Envíe dentro de la ventana. La energía alquilada está en la cartera durante un plazo, y la respuesta de un pedido lleva send_before: el momento en que se cierra la ventana de entrega, tres segundos antes de que acabe el plazo que compró. Vigile la aparición de ese campo y no la palabra ready: el pedido se cumple con la entrega de energía, así que completed llega inmediatamente después. Enviar después de send_before mete la transferencia en la red cuando la energía quizá ya se haya ido a casa, que es exactamente la carencia de la que trata esta entrada.
Entregue la transacción firmada. El mode B le quita la ventana de encima por completo: usted envía una transferencia ya firmada, nosotros la guardamos y la emitimos en cuanto la energía se confirma on-chain. Si una transacción que emitimos aun así llega a un bloque sin ejecutarse, la posición se cierra como failed con transaction_reverted y la reserva se libera entera — esa causa, como todas las demás de la lista, no se cobra nunca. Lea el nombre por lo que es: transaction_reverted es nuestra palabra para «llegó a un bloque y no se ejecutó», sea cual sea la palabra que la red use para el rechazo, así que un OUT_OF_ENERGY y un REVERT del propio contrato llegan bajo el mismo estado. El TRX que una transacción así quemó camino de ese veredicto es del remitente y no nuestro, que es el argumento a favor de la estimación del principio de esta sección y no de un bucle de reintentos al final de ella.