The pipeline
A correct automated flow has four stages, and skipping any one of them produces a failure mode that only shows up in production.
- Simulate. Call triggerconstantcontract against the USDT contract with the real sender and recipient. It returns energy_used without broadcasting, and that number is the truth for this specific pair of addresses.
- Quote. Ask the provider for a price for that amount of Energy for the duration you need. A quote is a fixed price with a short validity window.
- Order. Confirm the quote with an idempotency key of your own. The provider delegates the resource to your address.
- Verify, then broadcast. Confirm the delegation is actually live on your address, then sign and send the transfer.
The order matters. Simulating after renting means you may have rented the wrong amount; broadcasting before verifying means you may be spending Energy that never arrived.
Why simulate every time
The temptation is to hardcode 65,000 and move on. It works until it does not, and when it stops working it does so silently and expensively.
- A recipient who has never held USDT needs roughly double. Any system paying new counterparties will hit this regularly.
- Contract state changes over time, and rules of thumb drift away from reality.
- A simulation costs nothing and is never broadcast, so there is no reason to economise on it.
Treat energy_used as a per-transaction input cost, computed fresh, the same way you would treat any other variable price in a payment flow.
Idempotency
Any automated system will eventually retry a request whose response it never saw. Without idempotency that means paying twice for one rental.
Send an Idempotency-Key header carrying an identifier from your own system — your internal order id works well. A repeat of the same key returns the original order rather than creating a second one, which makes retries safe by construction.
- Generate the key before the first attempt, not per attempt.
- Derive it from something stable in your domain, so a retry after a process restart produces the same key.
- Never reuse a key for a genuinely different order.
Timing, which is where automation actually breaks
A rental runs for a fixed period starting when the delegation lands. In an interactive session that is unremarkable. In a queue it is the main source of production incidents.
| Pattern | What goes wrong | What to do instead |
|---|---|---|
| Rent for a whole batch up front | The delegation expires while the batch is still running | Rent per transfer, or in small groups sized to your throughput |
| Rent at enqueue time | The job runs an hour later against an expired delegation | Rent at execution time, immediately before broadcasting |
| Assume payment means delivery | The transfer is signed against Energy that never arrived | Read the resource back from the chain before signing |
| Retry a failed transfer unchanged | It fails identically and burns the fee again | Re-simulate, re-rent, then retry |
Verifying delivery in code
Do not rely on the order status alone. The authoritative answer is on-chain, and reading it is one call.
- Call getaccountresource for your sending address.
- Compute available Energy as EnergyLimit minus EnergyUsed.
- Assert it covers the energy_used from your simulation, with margin.
- Only then sign and broadcast. If the assertion fails, do not send — you would be paying the burn rate without meaning to.
That final assertion is the single highest-value guard in the whole pipeline. It converts a silent overpayment into a caught error, and silent overpayment is the failure that costs the most over time because nothing alerts on it.
Bandwidth, which automation forgets
The 600 free Bandwidth points per day cover one transfer. A system sending dozens from one address exhausts them in the first minute and pays TRX for everything after.
- Keep a TRX float on every sending address and monitor it. Roughly 0.35 TRX per transfer beyond the free allowance.
- Alert on the float rather than discovering it through failed sends.
- If you spread sending across several addresses, each gets its own 600 points a day — which is a real, if modest, saving at volume.
What to monitor
- Energy actually consumed versus energy_used predicted. A widening gap means your simulation step has drifted or is being skipped.
- Transfers that burned TRX for Energy. Any non-zero count means rentals are not landing before broadcast.
- Rental-to-broadcast latency. If it creeps towards your rental duration, incidents are coming.
- TRX float per sending address, with an alert well before zero.