Gas and Energy Efficiency — Research & Implementation Map
Goal: Make user wallet generation, withdrawals, and sweeps as cost-efficient as possible on TRON, EVM, and BTC, using our existing hot wallet / user wallet structure and TWC where applicable.
Last updated: 2026-02-04
See also: TWC Audit & Zero-Fee Strategy — how Trust Wallet (app) works, what we have in TWC (batch/UserOp/Paymaster), and goals for zero fees, liquidity, and bridge as infrastructure.
1. Executive Summary
| Chain | Current State | Best Levers | Where in Codebase |
|---|---|---|---|
| TRON | Pay-per-tx (no freeze); TRC20 uses energy | Freeze TRX for energy; energy rental; set feelimit; avoid dust |
tronresource/manager.go, txbuilder/tron.go, twc/tron_builder.go |
| EVM | Legacy + EIP-1559; multisend for batch withdrawals | EIP-1559; batch transfers; ERC-2612 permit (approve+transfer in one tx) | txbuilder/evm.go, twc/evm_builder.go, withdrawal v2 |
| BTC | UTXO builder not yet implemented | UTXO selection, fee rate (sat/vB), batch not typical | txbuilder (BTC builder), sweep executor |
We already have a place for improvements and testing: packages/blockchain (tronresource, txbuilder, twc, fee) and services/wallet (sweeper) and services/withdrawal (batch + multisend).
2. Trust Wallet Core (TWC) — Contracts We Leverage
2.1 What We Use Today
- EVM (ETH, BSC): Native transfer, ERC20 transfer, MultiSend (batch) via protobuf
SigningInputinpackages/blockchain/twc/evm_builder.go. Withdrawal service uses multisend for EVM when batching. - TRON: Native TRX, TRC20 transfer via
tron_builder.go(ref_block, timestamp, feelimit). - TON: Native TON, Jetton transfer via
ton_builder.go(seqno, cell encoding).
2.2 TWC Protobufs (No Extra Contracts)
TWC does not deploy our contracts; it builds signed transactions that call:
- Standard chain APIs (native transfer, contract call with ABI-encoded data).
- Any contract we choose (e.g. Gnosis MultiSendCallOnly, or our own batch contract) by encoding the call in
dataand having TWC sign the outer tx.
So “contracts we could leverage” = contracts we call from our signed tx, not TWC internals:
| Chain | Contract / Pattern | Purpose |
|---|---|---|
| EVM | Gnosis MultiSendCallOnly (0x40A2...) or custom |
Batch native/ERC20 transfers in one tx (we already use this path). |
| EVM | ERC-2612 Permit | Approve + transfer in one tx (no prior approve tx); requires token to support permit(). |
| TRON | Native / TRC20 | No standard “multisend” contract; we do one tx per withdrawal. Energy optimization is the main lever. |
| TON | Native / Jetton | Same; batching is per-tx design (e.g. one message with multiple internal transfers). |
2.3 L2 / New Chains (Future)
- L2 (Arbitrum, Optimism, Base, etc.): Same EVM flow: TWC EVM signer + our txbuilder; we only change chain ID and RPC. Gas is cheaper on L2; batch/multisend still wins.
- New TWC-supported chains: Add a SigningInput builder in
packages/blockchain/twcand route in wallet/withdrawal signer.
3. TRON — Energy, Dust, and Cost
3.1 How TRON Costs Work
- Bandwidth: Free quota per account; after that, burn TRX (sun).
- Energy: Needed for smart contract calls (TRC20 transfer, etc.). Without energy, you burn TRX (often 6–14 TRX per TRC20 tx).
- Ways to get energy: (1) Freeze TRX (receive energy proportionally), (2) Rent energy from third parties (often 50–80% cheaper than paying in TRX).
3.2 What We Have
packages/blockchain/tronresource/manager.go: Phase 1 = pay-per-tx (always allow; record usage). Phase 2 = freeze/rent and limits (TODO in file).- TRON tx build:
packages/blockchain/txbuilder/tron.go,packages/blockchain/twc/tron_builder.go. We setfeelimit(max TRX to burn); if energy is insufficient, the rest is paid in TRX up to feelimit. - TWC proto: DelegateResourceContract / UnDelegateResourceContract in
packages/blockchain/twc/proto/tron— we can sign delegate/undelegate resource txs when we have TRX to freeze and delegate to our hot wallet.
3.2a Sending USDT (TRC20) for users with minimal TRX — Research summary
Problem: We send USDT (TRC20) from our hot wallet to users. A TRC20 transfer needs energy (~40k energy ≈ 6–14 TRX burn if we have no energy). If we don’t hold much TRX, we must avoid burning it.
Ways to get energy (newest methods):
| Method | Description | Use case for us |
|---|---|---|
| 1. Energy rental (required when we have little TRX) | Third-party APIs delegate energy to our hot wallet. We pay in USDT/fiat to the provider; they stake TRX and delegate energy to our address. Non-custodial; no private keys shared. | Primary: Hot wallet sends USDT/TRC20 without burning our TRX. |
| 2. Freeze TRX + delegate (TWC already supports) | We freeze our own TRX and delegate energy to our hot wallet (or to a fee-payer). We have the proto: DelegateResourceContract. |
When we do hold enough TRX to freeze (e.g. 14-day lock); then we don’t need rental. |
| 3. TRON “Gas-Free” (pay fee in USDT) | TRON/wallet feature: user pays network fee in USDT (e.g. 10 USDT activation + ~10 USDT per transfer). Implemented in wallets like TronLink (GasFree). | End-users with 0 TRX; we don’t use this for our hot wallet—we need energy on our side to send. |
Conclusion: For our backend sending USDT to users when we don’t have much TRON, we must use energy rental. Integrate with an energy rental API so the provider delegates energy to our hot wallet before we build/broadcast TRC20 withdrawals and sweeps.
Provider references (programmatic / API):
- Tronex Energy — tronex.energy, API — Transit/hot wallet focus; API key; auto replenishment; Get Balance, Buy, Buy Activation, Get Order Status.
- TronX Energy — tronxenergy.com — Rental API; non-custodial delegation.
- Smart Delegate (iTRX) — Auto-delegate API (e.g.
POST /api/v1/frontend/auto-delegate-policy); commission period, recipient address, max energy threshold; auto replenish when below limit. - TronNRG — Developer docs for TronWeb / PHP integration.
How we send USDT today: We build a TRC20 tx via TriggerSmartContract (transfer), set fee_limit (e.g. 10 TRX in TWC tron_builder.go). If the hot wallet has no energy, the network burns TRX up to fee_limit. So the fix is: ensure the hot wallet has delegated energy (via rental or our own freeze) before sending, so the tx consumes energy and we burn zero or minimal TRX.
Further reading: TRON Energy docs, FeeLimit; TronLink GasFree (user-facing pay-in-USDT); Tronex API.
3.3 Best Practices (Avoid Dust, Lower Cost)
Freeze TRX for energy (hot wallet / operational account)
- Freeze TRX on the hot wallet (or a dedicated “fee payer”) to get daily energy.
- Where: Implement Phase 2 in
tronresource/manager.go: e.g.FreezeForEnergy(amount),GetAvailableEnergy(), and have withdrawal/sweep check before sending TRC20.
- Freeze TRX on the hot wallet (or a dedicated “fee payer”) to get daily energy.
Energy rental (required when we don’t hold enough TRX)
- Integrate with an energy rental API so the provider delegates energy to our hot wallet. Before building/broadcasting any TRC20 (USDT) withdrawal or sweep, ensure the hot wallet has enough energy (query via TRON RPC or provider API); if low, call the rental API to top up or use auto-replenishment.
- Where: New client in
packages/blockchain/tronresource(e.g.rental_client.go) or a smallpackages/blockchain/tronenergypackage: config (API key, provider URL),EnsureEnergy(ctx, address string, minEnergy int64), optionalGetEnergyBalance(address). Wallet/withdrawal service calls this before TRON TRC20 send.
- Config: e.g.
TRON_ENERGY_RENTAL_ENABLED,TRON_ENERGY_RENTAL_API_URL,TRON_ENERGY_RENTAL_API_KEY,TRON_ENERGY_MIN_BEFORE_SEND(e.g. 50_000).
- Integrate with an energy rental API so the provider delegates energy to our hot wallet. Before building/broadcasting any TRC20 (USDT) withdrawal or sweep, ensure the hot wallet has enough energy (query via TRON RPC or provider API); if low, call the rental API to top up or use auto-replenishment.
Freeze TRX + delegate (when we have TRX)
- Use TWC
DelegateResourceContractto freeze TRX and delegate energy to the hot wallet. Implement Phase 2 intronresource/manager.go: e.g.FreezeForEnergy(amount),GetAvailableEnergy(). Withdrawal/sweep checks energy before TRC20; if we have TRX and rental is off, use freeze+delegate.
- Use TWC
Set
feelimitcorrectly- TRON docs: set
feelimit(max 15,000 TRX) so the tx doesn’t fail mid-execution. We should set it to the estimated burn (energy cost in TRX) + margin.
- Where:
txbuilder/tron.go/twc/tron_builder.gowhen building TRC20; optionally usetronresourceto estimate and cap.
- TRON docs: set
Avoid dust
- Don’t create tiny TRC20 transfers that cost more in energy than value. Enforce a minimum withdrawal/sweep amount in IRT/USDT.
- Where: Withdrawal validation (gateway/withdrawal service); sweep planner (min amount already exists, can tune per chain).
- Don’t create tiny TRC20 transfers that cost more in energy than value. Enforce a minimum withdrawal/sweep amount in IRT/USDT.
3.4 Implementation Checklist (TRON)
- [ ] Energy rental (must when we have little TRX): Add
tronresource/rental_client.go(ortronenergypackage) withEnsureEnergy(ctx, hotWalletAddress, minEnergy); call before every TRON TRC20 withdrawal/sweep; wire config (API URL, key, min energy threshold). Prefer a provider with auto-replenishment (e.g. Tronex, TronX Energy). - [ ] Phase 2 tronresource: Freeze/unfreeze, get available energy/bandwidth, estimate cost per tx type (TRX vs TRC20). Use when we hold TRX and don’t rely on rental.
- [ ] Sweep/withdrawal: Before TRC20 tx, check energy (from rental or freeze); if low, trigger rental API or freeze+delegate.
- [ ] feelimit: Set from estimation + margin in all TRC20 build paths.
- [ ] Dust: Enforce min transfer size for TRC20 in product/validation layer.
4. EVM — Gas and Batch Efficiency
4.1 What We Have
- EIP-1559: Supported in
packages/blockchain/twc/evm_builder.go(Enveloped tx withMaxFeePerGas/MaxPriorityFeePerGas). Gas safety in withdrawal:services/withdrawal/.../gas_safety.go. - Multisend: Withdrawal v2 batches EVM withdrawals into one tx via multisend contract (
txbuilder/evm.go+ TWCBuildMultisendSigningInput). Gnosis MultiSendCallOnly address per chain. - Sweep: Per-address sweep (one tx per sweep); no batch across users (by design for security/attribution).
4.2 Best Practices (Gas-Efficient Wallet / Withdrawals / Sweeps)
EIP-1559 everywhere for user-facing and sweep txs
- Use EIP-1559 (maxFeePerGas + priorityFee) instead of legacy gas price so the network can pack txs more predictably and we avoid overpaying.
- Where: Already in TWC EVM builder; ensure txbuilder and fee calculator always fill EIP-1559 when chain supports it.
- Use EIP-1559 (maxFeePerGas + priorityFee) instead of legacy gas price so the network can pack txs more predictably and we avoid overpaying.
Batch withdrawals (already in place)
- We already batch EVM withdrawals via multisend in
withdrawal_service_v2.go(processMultisendBatch). Keep using it; ensure gas estimate includes per-recipient overhead (e.g. 50k base + 30k per recipient).
- We already batch EVM withdrawals via multisend in
ERC-2612 Permit (approve + transfer in one tx)
- For tokens that support EIP-2612
permit(), we can do “approve + transferFrom” in a single tx (or permit signed off-chain, then one transferFrom). Saves ~35k gas vs separate approve + transfer.
- Where: New code path in
packages/blockchain/txbuilderortwc: build contract call that invokespermitthentransferFrom, or use a helper contract that does both. Only for tokens that implement permit.
- For tokens that support EIP-2612
Sweep gas
- Sweeps already use low-priority gas (see PRODUCTION_READY_CHECKLIST). Keep gas limits tight (no unnecessary padding) and use EIP-1559 for sweeps on ETH/BSC.
4.3 Implementation Checklist (EVM)
- [ ] Gas safety: Ensure EIP-1559 margin (e.g. 20%) and atomic reservation are used for every EVM withdrawal (gas_safety.go already exists; wire and test).
- [ ] Permit (optional): For high-volume ERC20 withdrawal/sweep, add permit-based flow for supported tokens; document which tokens support it.
- [ ] Multisend gas formula: Confirm and document formula (e.g. 50k + 30k*n) and use it in withdrawal batch and fee quote.
5. BTC — UTXO and Fees
5.1 Current State
- Deposit detection: Implemented (watcher); UTXO model documented in blockchain production status.
- Sweep / withdrawal: BTC UTXO transaction builder is not yet implemented (see remaining-tasks.md). We need UTXO selection, fee (sat/vB), and signed tx.
5.2 Best Practices (When We Implement)
- UTXO selection: Largest-first or coin selection to minimize inputs and change; avoid dust outputs (e.g. min 546 sat output).
- Fee: Use RPC or external API for fee rate (e.g. 1–10 sat/vB); apply to estimated vsize.
- Batch: BTC doesn’t have “multisend” in the same way; one tx can have many outputs (we can batch several withdrawals into one tx with many outputs to reduce total fee per user).
5.3 Implementation Checklist (BTC)
- [ ] UTXO tx builder: Implement in
packages/blockchain/txbuilder(e.g.btc.go): list UTXOs, select inputs, build outputs (recipients + change), estimate vsize, sign (TWC or pure-Go). - [ ] Sweep executor: Add BTC case in
services/wallet/.../sweeper/executor.goto use BTC builder. - [ ] Withdrawal: Add BTC path in withdrawal service to use same builder and broadcaster.
6. Wallet Generation — Cost-Efficiency at Creation Time
6.1 User Wallets (Deposit Addresses)
- We generate one deposit address per user per chain (HD derivation). This is already cost-efficient: one address, no on-chain “creation” for ETH/TRON/TON (addresses are derived).
- EVM: No contract deployment for basic EOA; first tx pays for gas. No change needed at generation time.
- TRON: Account activation (first TRX receive) can be done when we credit first deposit; no extra “creation” cost at wallet generation.
- TON: Similar; address exists once we derive it; first inbound transfer activates if needed.
So wallet generation itself doesn’t need gas/energy optimization; the savings are in how we use those addresses (sweep strategy, batch, and fee/energy management).
6.2 Hot Wallet
- One hot wallet per chain (index 0). For TRON, adding freeze TRX for energy (Phase 2 tronresource) reduces ongoing TRC20 cost. For EVM, ensuring EIP-1559 and multisend is enough.
7. Where to Implement (File Map)
| Improvement | Package / Service | File(s) |
|---|---|---|
| TRON energy Phase 2 | packages/blockchain/tronresource |
manager.go (FreezeForEnergy, GetAvailableEnergy, EstimateTransactionCost) |
| TRON feelimit | packages/blockchain/txbuilder, packages/blockchain/twc |
tron.go, tron_builder.go |
| TRON energy rental | New or under tronresource | e.g. tronresource/rental.go (optional) |
| EVM EIP-1559 everywhere | packages/blockchain/txbuilder, packages/blockchain/fee |
evm.go, calculator.go |
| EVM permit | packages/blockchain/txbuilder or twc |
New: permit + transferFrom encoding (optional) |
| EVM multisend gas | services/withdrawal |
withdrawal_service_v2.go (processMultisendBatch) |
| Gas safety wiring | services/withdrawal |
gas_safety.go, call from process flow |
| BTC UTXO builder | packages/blockchain/txbuilder |
New btc.go |
| BTC sweep/withdrawal | services/wallet, services/withdrawal |
sweeper/executor.go, withdrawal v2 |
8. Testing and Rollout
- TRON: Test freeze + TRC20 withdrawal/sweep on Nile/Shasta; then mainnet with small amounts.
- EVM: Test EIP-1559 + multisend on testnet (Sepolia, BSC testnet); verify gas_safety reservation.
- BTC: After UTXO builder is done, test sweep and withdrawal on testnet, then mainnet with small amounts.
We already have a place for further improvements and testing in the monorepo; the above table and checklists align with that structure.
9. References
- TRON energy: developers.tron.network/docs/energy, FeeLimit.
- EVM batch: e.g. Gnosis MultiSendCallOnly; ERC-2612 (EIP-2612) permit.
- Internal:
docs/production/remaining-tasks.md,BLOCKCHAIN_PRODUCTION_STATUS.md,PRODUCTION_READY_CHECKLIST.md,docs/portal/technical-onboarding.md.