Energy Delegation

Delegate generated ENERGY to another TRON account without transferring ownership of the frozen TRX.

Energy Delegation

Delegate generated ENERGY to another TRON account without transferring ownership of the underlying frozen TRX.

What is Energy delegation?

On TRON, every action that touches a smart contract (including TRC-20 transfers, e.g. USDT) consumes ENERGY. ENERGY is generated by freezing TRX via /staking/delegate, the same mechanism used for BANDWIDTH and voting power.

Energy delegation lets the account that froze the TRX (the owner) share the ENERGY it generates with a different account (the receiver), without moving the frozen TRX itself and without giving up ownership of it. The owner keeps the frozen balance, its voting rights, and can reclaim the delegated resource at any time after the lock period expires.

This is the pattern used to cover gas costs for a large number of wallets from a single pool of frozen TRX — for example, an exchange or a custodian freezing TRX once and delegating ENERGY to hundreds of hot wallets so that each of them can pay for TRC-20 transfers without holding TRX of its own.

📘

Only ENERGY is supported for delegation in the current version. BANDWIDTH delegation is not available.

The full flow

Energy delegation sits between the freeze and unfreeze steps of the regular TRON staking flow:

freeze  →  delegate-resource  →  undelegate-resource  →  unfreeze  →  withdraw
StepEndpointDescription
  1. Freeze
/staking/delegateFreeze TRX and generate ENERGY on the owner account
  1. Delegate resource
/staking/delegate-resourceDelegate generated ENERGY from the owner to a receiver account.
  1. Undelegate resource
/staking/undelegate-resourceReclaim previously delegated ENERGY back to the owner, once the delegation lock period has passed.
  1. Unfreeze
/staking/undelegateUnfreeze the owner's TRX
  1. Withdraw
/staking/withdrawClaim the unfrozen TRX back to the available balance

Steps 1, 4, and 5 are the standard freeze/unfreeze/withdraw operations already described in Getting Started and Withdrawal. This guide focuses on steps 2 and 3, which sit in between.

Note that the owner does not have to unfreeze immediately after undelegating. ENERGY can be delegated and reclaimed many times over the lifetime of a single frozen balance — unfreezing is only required once the owner wants the underlying TRX back.

Signing model

As with any other operation on TRON, /staking/delegate-resource and /staking/undelegate-resource only build and return an unsigned transaction — the API never holds or uses your private key. The client is responsible for signing every transaction in the flow (freeze, delegate-resource, undelegate-resource, unfreeze, withdraw) individually with the P2P Signer SDK and broadcasting it via /transaction/send, following the steps described in Sign and Broadcast Transaction.

The owner address that signs the delegate/undelegate-resource transaction must be the same address that froze the TRX (delegatorAddress) — the receiver never signs anything as part of this flow.

1. Create delegate-resource request

To delegate generated ENERGY to a receiver account, send a POST request to /api/v1/tron/{network}/staking/delegate-resource.

Example request (for testnet-nile network):

curl --request POST \
  --url 'https://api-test.p2p.org/api/v1/tron/testnet-nile/staking/delegate-resource' \
  --header 'accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "delegatorAddress": "TVscj8F6wPZ92d1smGYjH9heZR1MaEcE9u",
    "amount": 1000000,
    "resource": "ENERGY"
}'
  • delegatorAddress — owner account address, i.e. the account that froze the TRX and generated the ENERGY.
  • amount — amount of resource to delegate in SUN. Minimum amount is 1 TRX (1 000 000 SUN)
  • resource — resource type to delegate. Only ENERGY is supported in the current version, defaults to ENERGY. Optional.

Example response:

{
  "error": null,
  "result": {
    "delegatorAddress": "TVscj8F6wPZ92d1smGYjH9heZR1MaEcE9u",
    "receiverAddress": "TNDzfERDpxLDS2w1q6yaFC7pzqaSQ3Bg3r",
    "amount": 10000000,
    "resource": "ENERGY",
    "lockPeriod": 28800,
    "unsignedTransaction": {
      "visible": false,
      "txID": "b7c4a2f1e6d9083c...",
      "raw_data_hex": "0a...",
      "raw_data": {
        "contract": [
          {
            "parameter": {
              "value": {
                "owner_address": "41da53d324a354aa5924c7117caff3ead97910a5e1",
                "receiver_address": "41700ca9ad5f162f9de000558ff04eef8f99dce7e8",
                "balance": 10000000,
                "resource": "ENERGY"
              },
              "type_url": "type.googleapis.com/protocol.DelegateResourceContract"
            },
            "type": "DelegateResourceContract"
          }
        ],
        "ref_block_bytes": "0e0c",
        "ref_block_hash": "7db974037137d39c",
        "expiration": 1750000200000,
        "timestamp": 1750000140000
      }
    },
    "unsignedTransactionSerialized": "eyJ0eElEIjoidHJ4SWQifQ==",
    "createdAt": "2025-06-03T12:00:00.000Z"
  }
}
  • delegatorAddress — owner account address.
  • receiverAddress — account address receiving the delegated resource.
  • amount — amount of resource delegated, in SUN.
  • resource — resource type delegated: ENERGY.
  • lockPeriod — 28800, i.e. blocks, ≈ 24 h at 3 s per block.
  • unsignedTransaction — original unsigned transaction object returned by tronWeb.
  • unsignedTransactionSerialized — unsigned serialized transaction in Base64 format, ready for signing.
  • createdAt — timestamp of the transaction in the ISO 8601 format.

Delegation lock

TRON enforces a protocol-level lock on delegated resources: once ENERGY has been delegated to a receiver, it cannot be undelegated for approximately 24 hours from the moment the delegation transaction is confirmed. This is a network rule, and it applies per delegation — each new /staking/delegate-resource call starts its own 24-hour lock for the amount it delegates.

Calling /staking/undelegate-resource before the lock period has elapsed will cause the transaction to fail on-chain. Plan any automated re-delegation or rebalancing logic around this window, and track the delegation's confirmation time so you know when it becomes eligible for undelegation.

The lock is amount-aware. TRON keeps one lock per (owner, receiver) pair, so an older expired portion can coexist with a freshly locked one. Undelegating within the unlocked part succeeds; only a request reaching into the locked part is rejected.

The unlock time is machine-readable. DelegationLockedException returns both the message and a structured field:

"errors": [ { "property": "delegation", "constraints": { "unlocksAt": "2026-08-19T11:48:06.000Z" } } ]

Integrators should read errors[0].constraints.unlocksAt rather than parsing the message, and use it to schedule the retry instead of polling on a fixed 24-hour timer.

2. Create undelegate-resource request

Once the lock period has passed, reclaim the delegated ENERGY back to the owner account by sending a POST request to /api/v1/tron/{network}/staking/undelegate-resource.

Example request (for testnet-nile network):

curl --request POST \
  --url 'https://api-test.p2p.org/api/v1/tron/testnet-nile/staking/undelegate-resource' \
  --header 'accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "delegatorAddress": "TVscj8F6wPZ92d1smGYjH9heZR1MaEcE9u",
    "amount": 1000000,
    "resource": "ENERGY"
}'
  • delegatorAddress — owner account address that originally delegated the resource.
  • amount — amount of resource to delegate in SUN. Minimum amount is 1 TRX (1 000 000 SUN)
  • resource — resource type to reclaim. Only ENERGY is supported, defaults to ENERGY. Optional.

Example response:

{
  "error": null,
  "result": {
    "delegatorAddress": "TVscj8F6wPZ92d1smGYjH9heZR1MaEcE9u",
    "receiverAddress": "TNDzfERDpxLDS2w1q6yaFC7pzqaSQ3Bg3r",
    "amount": 10000000,
    "resource": "ENERGY",
    "unsignedTransaction": {
      "visible": false,
      "txID": "d3f8b1a2c9e6740f...",
      "raw_data_hex": "0a...",
      "raw_data": {
        "contract": [
          {
            "parameter": {
              "value": {
                "owner_address": "41da53d324a354aa5924c7117caff3ead97910a5e1",
                "receiver_address": "41700ca9ad5f162f9de000558ff04eef8f99dce7e8",
                "balance": 10000000,
                "resource": "ENERGY"
              },
              "type_url": "type.googleapis.com/protocol.UnDelegateResourceContract"
            },
            "type": "UnDelegateResourceContract"
          }
        ],
        "ref_block_bytes": "0e0c",
        "ref_block_hash": "7db974037137d39c",
        "expiration": 1750086600000,
        "timestamp": 1750086540000
      }
    },
    "unsignedTransactionSerialized": "eyJ0eElEIjoidHJ4SWQifQ==",
    "createdAt": "2025-06-03T12:00:00.000Z"
  }
}

Field descriptions mirror the delegate-resource response above; the only difference is the underlying UnDelegateResourceContract type.

Error codes

/staking/delegate-resource and /staking/undelegate-resource can return the following 400 Bad request errors in addition to the standard 401 and 429 responses.

/staking/delegate-resource :

CodeExceptionDescription
125102InvalidDelegatorAddressExceptionInvalid delegator address provided. Please ensure the address is a valid TRON address format.
125123InvalidReceiverExceptionInvalid receiver address. The receiver must be a valid TRON address and must differ from the owner address.
125104InvalidFreezeAmountExceptionFreeze amount is below the minimum required threshold (1 TRX = 1,000,000 SUN).
125125ResourceNotSupportedExceptionResource type is not supported. Only ENERGY delegation is available.
125124ExceedsDelegatableMaxExceptionDelegation amount exceeds the maximum delegatable resource for this account. Freeze more TRX or reduce the amount.
125121DelegateResourceTransactionExceptionFailed to create the resource delegation transaction. Verify the amount does not exceed the delegatable balance and that the account has frozen ENERGY.

/staking/undelegate-resource :

CodeExceptionDescription
125102InvalidDelegatorAddressExceptionInvalid delegator address provided. Please ensure the address is a valid TRON address format.
125123InvalidReceiverExceptionInvalid receiver address. The receiver must be a valid TRON address and must differ from the owner address.
125105InvalidUnfreezeAmountExceptionUnfreeze amount exceeds the available frozen balance or is invalid. Please verify the account's frozen amount.
125125ResourceNotSupportedExceptionResource type is not supported. Only ENERGY delegation is available.
125126NoActiveDelegationExceptionNo active ENERGY delegation found for this account. There is nothing to undelegate.
125127ExceedsDelegatedAmountExceptionUndelegation amount exceeds the currently delegated ENERGY balance. Please reduce the amount.
125128DelegationLockedExceptionDelegation is still locked and cannot be undelegated until the lock period expires.
125122UndelegateResourceTransactionExceptionFailed to create the resource undelegation transaction. Locked delegations can only be undelegated after the lock period expires.

Testing on the Nile testnet

Before delegating on mainnet, validate the full flow on TRON's Nile testnet using the testnet-nile network identifier. Because of the delegation lock, a full round trip through steps will take about 24 hours to complete.

  1. Fund a Nile testnet account. Use the Nile faucet to receive test TRX on your account.

  2. Freeze TRX for ENERGY. Send a POST request to /api/v1/tron/testnet-nile/staking/delegate with resource: "ENERGY", sign, and broadcast the transaction, as described in Getting Started.

  3. Delegate the resource. Send a POST request to:

    https://api-test.p2p.org/api/v1/tron/testnet-nile/staking/delegate-resource

    with your delegatorAddress, a receiverAddress you control (a second Nile testnet account), and the amount to delegate.

  4. Sign transaction

  5. Broadcast via POST /tron/testnet-nile/transaction/send

  6. Verify the delegation. The transaction confirms as DelegateResourceContract; getDelegatedResourceV2(owner, pool) shows the delegation with an expire_time.

  7. Undelegate the resource. Once the lock has expired, send a POST request to:

    https://api-test.p2p.org/api/v1/tron/testnet-nile/staking/undelegate-resource

    with the same delegatorAddress/receiverAddress pair and amount, then sign and broadcast.

Testnet transactions use the same request/response shapes as mainnet. Only the network path parameter and the api-test.p2p.org host differ, so code validated on Nile carries over to production without changes.

What's next?


Did this page help you?