Como Automatizar o Aluguel de Energia TRON com a API
Por Que Automatizar o Aluguel de Energia
Se você opera uma carteira quente, um motor de saques de exchange ou um contrato que dispara transferências TRC-20 em nome dos usuários, já conhece a dor: você precisa de energia TRON pronta no exato segundo em que uma transação é disparada. Recarregar energia manualmente por uma interface não escala além de algumas transferências por dia. Perca a janela e a transação queima TRX do endereço remetente, frequentemente a um custo muito mais alto do que a energia pré-alugada.
A solução é chamar a API de aluguel no momento em que seu backend está prestes a transmitir uma transação, de modo que a energia seja provisionada programaticamente, sem nenhum humano no circuito. Este artigo mostra exatamente como fazer isso contra o tronenergyrent.com: o formato real da requisição, o ciclo de vida assíncrono do pedido, escolhas sensatas de duração e um exemplo Python funcional que você pode plugar no seu serviço.
O Que a API Realmente Faz On-Chain
Antes de escrever código, vale a pena entender a mecânica on-chain para não depurar às cegas.
O modelo de recursos da TRON separa computação (energia) do tamanho da transação (bandwidth). Uma transferência USDT TRC-20 padrão consome aproximadamente 65,000 de energia quando o destinatário já possui USDT, e cerca de 130,000 quando o saldo USDT do destinatário é zero. A primeira transferência recebida paga o custo de armazenamento da criação do registro de saldo, e é por isso que o custo depende inteiramente do destinatário, não do remetente. O uso de bandwidth para uma transferência é de cerca de 345 bytes, pequeno o suficiente para que a maioria das contas cubra esse valor com sua cota gratuita diária.
Quando você chama a API de aluguel, o serviço faz o stake do próprio TRX e delega a energia resultante ao endereço que você especificar, usando DelegateResourceContract do Stake 2.0. A delegação é específica por endereço e tem prazo limitado. Quando o período de aluguel expira, a energia é recuperada automaticamente pelo provedor.
Um detalhe importante: o aluguel é assíncrono. A chamada da API retorna imediatamente com um orderId e um estado PAID_BY_USER, mas a transação de delegação on-chain é transmitida em segundo plano e normalmente é confirmada em poucos segundos. Sua integração deve tratar a resposta inicial como confirmação de que o pedido foi aceito e pago, e então fazer polling no endpoint de detalhes do pedido até o estado mudar para ENERGY_DELEGATED.
Escolhendo a Duração Certa do Aluguel
A API aceita um parâmetro period com quatro valores permitidos: 1h, 1d, 3d, 30d. Os preços flutuam com o mercado de energia on-chain e mudam ao longo do dia, então os valores ao vivo ficam sempre na página de preços. A ordem relativa é estável: 1h é a mais barata por chamada, 30d é a mais barata quando amortizada entre muitas transferências do mesmo endereço.
Para um sistema orientado a eventos, no qual você dispara um aluguel por transferência de saída, o nível 1h é quase sempre a escolha correta. Você paga o menor custo absoluto e a energia é consumida em segundos após ser delegada. Os níveis 1d e mais longos fazem sentido quando você roda cargas em lote previsíveis, por exemplo um job noturno de pagamentos, e quer alugar um grande bloco de energia de uma vez em vez de chamar a API dezenas de vezes.
Se seu sistema dispara consistentemente mais de 20-30 transferências por hora a partir do mesmo endereço, alugar um bloco 1d dimensionado para cobrir seu volume esperado é mais limpo do que chamadas por transferência. O custo inicial sobe, mas o overhead da API e a latência de confirmação on-chain saem do caminho crítico.
Autenticação e Estrutura da Requisição
O endpoint de aluguel fica em:
GET https://api.tronenergyrent.com/place-energy-order
É uma requisição GET simples com parâmetros de query. A autenticação é o parâmetro de query apiKey, que você gera no seu painel depois de se registrar e adicionar saldo à conta. Não há autenticação por header e não há corpo JSON de requisição para este endpoint.
Os parâmetros são:
apiKey(obrigatório): sua chave de API obtida no painel.period(obrigatório): duração do aluguel, um dentre1h,1d,3d,30d.energyAmount(obrigatório): quanta energia delegar. O mínimo é15000. Para uma transferência USDT padrão a um destinatário que já possui USDT,65000é o número seguro; para uma primeira transferência a um novo holder de USDT, use130000.destinationAddress(obrigatório): o endereço TRON (base58check, começa comT) que receberá a energia delegada.preActivateDestinationAddress(opcional, padrão0): defina como1se o endereço de destino nunca recebeu TRX e portanto não está ativado on-chain. O serviço então envia1.5 TRXdo seu saldo pré-pago para ativar o endereço antes de delegar energia. Se o endereço já estiver ativo, deixe em0para evitar o custo extra.
A resposta é sempre retornada com status HTTP 200, independentemente de o pedido ter tido sucesso ou falhado. Faça o branching pelo campo status do corpo JSON em vez do status HTTP. Um corpo de sucesso fica assim:
{
"status": "SUCCESS",
"errorCode": null,
"errorDescription": null,
"requestId": "2651eacd-2428",
"payload": {
"orderId": "128de799-501e-44b2-8d6f-1fa825c2deed",
"totalPriceSun": 5662800,
"totalPriceTrx": 5.6628,
"state": "PAID_BY_USER"
}
}
Um corpo de erro tem status: "ERROR", um errorCode legível por máquina e um errorDescription legível por humanos:
{
"status": "ERROR",
"errorCode": "INVALID_ENERGY_AMOUNT",
"errorDescription": "energyAmount is less than 15000",
"requestId": "71431087-4",
"payload": null
}
Sempre registre o requestId em ambos os ramos. Se você um dia precisar pedir ao suporte para rastrear um aluguel específico, é por esse ID que eles fazem a busca.
O Ciclo de Vida do Pedido
O campo state no payload avança por uma pequena sequência fixa:
PAID_BY_USER: estado inicial, o pedido foi pago a partir do seu saldo, mas nenhuma ação on-chain aconteceu ainda.WAITING_DELEGATION: o serviço pegou o pedido e está preparando a transação de delegação.ENERGY_DELEGATED: a transação de delegação foi confirmada on-chain. O endereço de destino agora possui a energia alugada e pode gastá-la na próxima transação de saída.ERROR_DELEGATION: a delegação falhou por algum motivo. Raro, mas possível durante congestionamento intenso da rede.CANCELLED: o pedido foi cancelado e os fundos devolvidos ao seu saldo.
Para checar o estado atual, chame:
GET https://api.tronenergyrent.com/single-order-details?apiKey=YOUR_API_KEY&orderId=ORDER_ID
A resposta usa o mesmo envelope status / errorCode / payload, com o state atual dentro de payload. Faça polling a cada um ou dois segundos após colocar o pedido e prossiga com sua transferência TRC-20 somente depois de ver ENERGY_DELEGATED. Na prática, normalmente isso são uma ou duas consultas.
Uma Integração Python Funcional
Aqui está um padrão mínimo, mas com cara de produção. Ele coloca o aluguel, faz polling até a delegação estar on-chain e expõe um erro claro se algo der errado.
import logging
import time
import requests
API_BASE = "https://api.tronenergyrent.com"
API_KEY = "your_api_key_here"
ENERGY_FOR_TRANSFER = 65_000 # use 130_000 if recipient has zero USDT balance
HTTP_TIMEOUT_SECS = 10
POLL_INTERVAL_SECS = 1
POLL_TIMEOUT_SECS = 30
def place_order(destination_address: str, period: str = "1h",
energy_amount: int = ENERGY_FOR_TRANSFER) -> dict:
resp = requests.get(
f"{API_BASE}/place-energy-order",
params={
"apiKey": API_KEY,
"period": period,
"energyAmount": energy_amount,
"destinationAddress": destination_address,
"preActivateDestinationAddress": 0,
},
timeout=HTTP_TIMEOUT_SECS,
)
resp.raise_for_status()
body = resp.json()
if body.get("status") != "SUCCESS":
raise RuntimeError(
f"place-energy-order failed: {body.get('errorCode')} "
f"({body.get('errorDescription')}) requestId={body.get('requestId')}"
)
return body["payload"]
def wait_for_delegation(order_id: str) -> dict:
deadline = time.monotonic() + POLL_TIMEOUT_SECS
while time.monotonic() < deadline:
resp = requests.get(
f"{API_BASE}/single-order-details",
params={"apiKey": API_KEY, "orderId": order_id},
timeout=HTTP_TIMEOUT_SECS,
)
resp.raise_for_status()
body = resp.json()
if body.get("status") != "SUCCESS":
raise RuntimeError(
f"single-order-details failed: {body.get('errorCode')} "
f"({body.get('errorDescription')})"
)
state = body["payload"]["state"]
if state == "ENERGY_DELEGATED":
return body["payload"]
if state == "ERROR_DELEGATION":
raise RuntimeError(f"Delegation failed for order {order_id}")
if state == "CANCELLED":
raise RuntimeError(f"Order {order_id} was cancelled")
time.sleep(POLL_INTERVAL_SECS)
raise TimeoutError(f"Order {order_id} did not reach ENERGY_DELEGATED in {POLL_TIMEOUT_SECS}s")
def rent_energy(destination_address: str) -> dict:
placed = place_order(destination_address)
logging.info(
"Order placed: id=%s priceSun=%s priceTrx=%s",
placed["orderId"], placed["totalPriceSun"], placed["totalPriceTrx"],
)
delegated = wait_for_delegation(placed["orderId"])
logging.info("Order delegated: id=%s", delegated["orderId"])
return delegated
Vale destacar alguns pontos. A checagem explícita de status == "SUCCESS" é importante porque o status HTTP é sempre 200, então o resp.raise_for_status() sozinho não diz nada sobre o resultado real. O laço de polling tem um timeout rígido, de modo que um pedido travado não pode bloquear seu pipeline de transferências indefinidamente. O branching por state trata os três desfechos terminais (ENERGY_DELEGATED, ERROR_DELEGATION, CANCELLED) de forma explícita, em vez de depender de um genérico "não foi sucesso".
No seu fluxo de transferência, chame rent_energy() primeiro e depois transmita a transferência TRC-20. A ordem das operações importa: transmitir primeiro fará a transação queimar TRX do remetente, porque a delegação ainda não foi confirmada.
Dimensionando Seu Saldo Pré-Pago
O custo do aluguel é debitado de um saldo pré-pago que você mantém na sua conta do tronenergyrent.com. Configure um alerta ou uma recarga automática quando o saldo cair abaixo de um limite. Um piso razoável é o que cobrir duas horas de volume de pico.
Para ler o saldo atual programaticamente:
GET https://api.tronenergyrent.com/account-info?apiKey=YOUR_API_KEY
O payload inclui seu saldo atual e o estado da conta. Plugue isso no seu stack de monitoramento e você nunca mais será pego de surpresa por um saldo zerado às 2h da manhã. Observe que a recarga mínima do seu saldo no tronenergyrent.com é 10 TRX.
Tratamento de Erros na Prática
Três modos de falha aparecem com mais frequência em produção. Os códigos de erro abaixo vêm da API real e você pode fazer branching neles com segurança.
INSUFFICIENT_BALANCE: seu saldo pré-pago é baixo demais para cobrir o aluguel solicitado mais qualquer pré-ativação. Não tente de novo, repetir não vai resolver. Capture esse caso especificamente e dispare um alerta ou um fluxo de recarga. Inclua orequestIdno payload do alerta.INVALID_ADDRESS: odestinationAddressfalhou no decode base58check no servidor. Se seu sistema constrói endereços dinamicamente, por exemplo a partir de input fornecido pelo usuário, valide-os localmente antes de chamar a API. A biblioteca Pythontronpytemis_address()para isso; rejeitar input ruim no client é mais rápido do que esperar pela ida e volta.INACTIVE_DESTINATION_ADDRESS_ERROR: o endereço de destino nunca foi ativado on-chain e você não pediu ao serviço para ativá-lo. Corrija pré-financiando o endereço com uma pequena quantidade de TRX de outra fonte, ou passandopreActivateDestinationAddress=1na próxima chamada para que o serviço o ative por1.5 TRX.
Um caso mais sutil: ORDER_IS_ALREADY_IN_PROGRESS pode voltar se você tiver múltiplos workers colocando aluguéis para o mesmo destino ao mesmo tempo. A correção é no lado do processo, não da API. Pegue um lock distribuído (Redis funciona bem) com chave no endereço de destino e mantido até a delegação ser concluída.
Verificando On-Chain
Para a maioria das integrações, fazer polling em /single-order-details até ENERGY_DELEGATED já basta. Se você quiser uma verificação com cinto e suspensórios, também pode consultar o nó completo da TRON diretamente após a delegação ser confirmada:
GET https://api.trongrid.io/v1/accounts/{destinationAddress}
A resposta contém o estado atual de recursos do endereço, incluindo a energia delegada a ele a partir de endereços externos. O nome exato do campo depende da visão atual do Stake 2.0, então consulte a documentação ao vivo da TRON HTTP API ao integrar isso. Como uma checagem leve, que apenas registra um aviso em vez de bloquear a transferência, ela é um canário útil para o raro caso em que algo dá errado downstream da própria API de aluguel.
Essa checagem extra vai te salvar horas de depuração na única vez em que o aluguel parecer bem-sucedido na API, mas algo mais sair errado on-chain.