> For the complete documentation index, see [llms.txt](https://tron-energy-doc.crypto-chief.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tron-energy-doc.crypto-chief.com/api-reference/simulate.md).

# Simulate a Transaction

## Simulate a Transaction

Send the transaction you are about to make, unsigned, and the node tells you exactly how much energy it needs.

Nothing is signed, nothing is broadcast, nothing is charged.

{% hint style="success" %}
**Use this for anything that is not a plain token transfer.** For a straightforward USDT transfer, leave `energy` out of a [quote](/api-reference/quote.md) and we size it from the recipient. A contract call, a multi-send, a token whose contract does more work — those cost something no heuristic can know, and this is how you find out.
{% endhint %}

#### **Simulate a Transaction**

<mark style="color:green;">`POST`</mark> `https://energy.crypto-chief.com/v1/simulate`

**Headers**

| Name         | Value                                                     |
| ------------ | --------------------------------------------------------- |
| Content-Type | `application/json`                                        |
| Merchant     | Your project UUID                                         |
| Signature    | [Signed request body](/getting-started/authentication.md) |

**Body**

| Name                | Type    | Required    | Description                                                                    |
| ------------------- | ------- | ----------- | ------------------------------------------------------------------------------ |
| `owner_address`     | string  | true        | The sender — the account that will spend the energy.                           |
| `contract_address`  | string  | true        | The contract being called.                                                     |
| `function_selector` | string  | conditional | e.g. `transfer(address,uint256)`. Required unless you send `data`.             |
| `parameter`         | string  | false       | ABI-encoded arguments, hex. Used with `function_selector`.                     |
| `data`              | string  | conditional | Raw calldata, hex. Use instead of selector and parameter.                      |
| `call_value`        | integer | false       | TRX sent with the call, in SUN. Zero for a token transfer.                     |
| `duration_sec`      | integer | false       | How long you would need the energy. Default `3600`.                            |
| `quote`             | boolean | false       | Return a redeemable [quote](/api-reference/quote.md) for the simulated amount. |

Send either `function_selector` with `parameter`, or `data` — whichever your client already has.

```json
{
  "owner_address": "TDijWGe2r6pTxAufDYGcQyx591Wuyvq4xp",
  "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "function_selector": "transfer(address,uint256)",
  "parameter": "0000000000000000000000418840e6c55b9ada326d211d818c34a994aeced808000000000000000000000000000000000000000000000000000000003b9aca00"
}
```

**Response**

{% tabs %}
{% tab title="200" %}

```json
{
  "energy_used": 64285,
  "energy_needed": 70713,
  "burn_price_sun": 7071300,
  "burn_price_trx": "7.071300",
  "burn_price_usd": "2.12"
}
```

{% endtab %}

{% tab title="200 — would fail" %}

```json
{
  "energy_used": 1274,
  "energy_needed": 0,
  "burn_price_sun": 0,
  "would_fail": true,
  "reason": "CONTRACT_VALIDATE_ERROR: ERC20: transfer amount exceeds balance"
}
```

{% endtab %}

{% tab title="200 — needs activation" %}

```json
{
  "energy_used": 8624,
  "energy_needed": 0,
  "burn_price_sun": 0,
  "would_fail": true,
  "needs_activation": true,
  "reason": "the sender is not activated on chain: it has never received anything, so it cannot send or hold delegated energy"
}
```

{% endtab %}

{% tab title="400" %}

```json
{
  "ok": false,
  "error": "INVALID_REQUEST",
  "msg": "give either data, or function_selector with parameter"
}
```

{% endtab %}

{% tab title="502" %}

```json
{
  "ok": false,
  "error": "SIMULATION_FAILED",
  "msg": "the node could not simulate this call"
}
```

{% endtab %}
{% endtabs %}

**Fields**

| Field                                                  | Description                                                                                         |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
| `energy_used`                                          | The node's own figure for this call.                                                                |
| `energy_needed`                                        | **What to rent.** `energy_used` plus a 10% margin.                                                  |
| `burn_price_sun` / `burn_price_trx` / `burn_price_usd` | What this call costs with no energy on the wallet.                                                  |
| `would_fail`                                           | The call reverts. Present only when it does.                                                        |
| `needs_activation`                                     | The sender does not exist on chain. [Activate it](/api-reference/activate.md), then simulate again. |
| `reason`                                               | Why it reverts, in words.                                                                           |

### Rent `energy_needed`, not `energy_used`

A simulation runs against the chain's **current** state. By the time your transaction is actually included, storage may have moved under it — a recipient who received something in between, an allowance written, a different branch taken — and the call costs a little more than it did a moment ago.

`energy_needed` is `energy_used` plus 10% for exactly that. Renting the raw figure is how a transfer reverts, having consumed the fee, for want of a few percent.

The asymmetry is the whole argument: slightly too much energy costs you the difference, slightly too little costs you everything.

### It works when the wallet has no energy

That is the point. This is a read-only call against the chain, so it consumes no energy and does not care whether the sender holds any. A wallet with nothing on it gets the same answer as a funded one.

### When the call would fail

`would_fail: true` means no amount of energy makes this work. `energy_needed` is `0` and there is nothing to rent.

This is the more valuable answer of the two. Finding out here costs nothing; finding out by broadcasting costs the entire fee and delivers nothing.

```json
{
  "would_fail": true,
  "reason": "CONTRACT_VALIDATE_ERROR: ERC20: transfer amount exceeds balance"
}
```

Fix what `reason` says, then simulate again.

**If the sender is not activated**, the response says so specifically:

```json
{
  "would_fail": true,
  "needs_activation": true,
  "reason": "the sender is not activated on chain: ..."
}
```

The chain does not distinguish these on its own — an unactivated sender and one that simply has nothing to send both revert with the same message and the same few thousand energy. We look the account up separately so the answer is something you can act on: call [`/v1/activate`](/api-reference/activate.md), then simulate again.

### Simulate and buy in one call

Set `quote: true` and the response carries a redeemable [quote](/api-reference/quote.md) for the simulated amount, priced. Pass its `ref` to [`POST /v1/orders`](/api-reference/create-order.md).

This saves you carrying the energy figure between two calls — and a number carried by hand is a number that can be mistyped.

```json
{
  "owner_address": "TDijWGe2r6pTxAufDYGcQyx591Wuyvq4xp",
  "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  "function_selector": "transfer(address,uint256)",
  "parameter": "0000…0000",
  "quote": true
}
```

```json
{
  "energy_used": 64285,
  "energy_needed": 70713,
  "burn_price_trx": "7.071300",
  "quote": {
    "ref": "q_7bxk4m2npqrs8tvw3yz5a6c9d1e4f7g2",
    "energy": 70713,
    "price_trx": "3.217441",
    "price_usd": "0.97",
    "credits": 9652323,
    "saving_trx": "3.853859",
    "expires_in_sec": 90
  }
}
```

### Rate limit

Shares the quote budget: **120 per minute** per project. Simulation is free to you and costs us a node call.

### Example

`sign()`, `canonical()`, `BASE`, `MERCHANT` and `API_KEY` are from [Authentication](/getting-started/authentication.md).

{% tabs %}
{% tab title="JavaScript" %}

```javascript
const body = {
  owner_address: "TDijWGe2r6pTxAufDYGcQyx591Wuyvq4xp",
  contract_address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
  function_selector: "transfer(address,uint256)",
  parameter: PARAM_HEX,
  quote: true,
};
const raw = canonical(body);

const res = await fetch(BASE + "/v1/simulate", {
  method: "POST",
  body: raw,
  headers: {
    Merchant: MERCHANT,
    Signature: sign(body, API_KEY),
    "Content-Type": "application/json",
  },
});

const sim = await res.json();
if (sim.would_fail) throw new Error(sim.reason);
console.log("needs", sim.energy_needed, "energy");
```

{% endtab %}

{% tab title="PHP" %}

```php
$body = [
    'owner_address'     => 'TDijWGe2r6pTxAufDYGcQyx591Wuyvq4xp',
    'contract_address'  => 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
    'function_selector' => 'transfer(address,uint256)',
    'parameter'         => PARAM_HEX,
    'quote'             => true,
];
$raw = canonical($body);

$ch = curl_init(BASE . '/v1/simulate');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $raw,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        'Merchant: ' . MERCHANT,
        'Signature: ' . sign($body, API_KEY),
    ],
]);

$sim = json_decode(curl_exec($ch), true);
if (!empty($sim['would_fail'])) throw new RuntimeException($sim['reason']);
echo "needs {$sim['energy_needed']} energy\n";
```

{% endtab %}

{% tab title="GO" %}

```go
body := map[string]any{
	"owner_address":     "TDijWGe2r6pTxAufDYGcQyx591Wuyvq4xp",
	"contract_address":  "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
	"function_selector": "transfer(address,uint256)",
	"parameter":         paramHex,
	"quote":             true,
}
raw, _ := json.Marshal(body)

req, _ := http.NewRequest("POST", base+"/v1/simulate", bytes.NewReader(raw))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Merchant", merchant)
req.Header.Set("Signature", sign(raw, apiKey))

res, err := http.DefaultClient.Do(req)
```

{% endtab %}

{% tab title="Python" %}

```python
body = {
    "owner_address": "TDijWGe2r6pTxAufDYGcQyx591Wuyvq4xp",
    "contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
    "function_selector": "transfer(address,uint256)",
    "parameter": PARAM_HEX,
    "quote": True,
}
raw = json.dumps(body, separators=(",", ":"), sort_keys=True)

res = requests.post(
    BASE + "/v1/simulate",
    data=raw,
    headers={
        "Content-Type": "application/json",
        "Merchant": MERCHANT,
        "Signature": sign(body, API_KEY),
    },
)

sim = res.json()
if sim.get("would_fail"):
    raise RuntimeError(sim["reason"])
print("needs", sim["energy_needed"], "energy")
```

{% endtab %}

{% tab title="curl" %}

```bash
BODY='{"contract_address":"TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","function_selector":"transfer(address,uint256)","owner_address":"$SENDER","parameter":"$PARAM_HEX","quote":true}'

curl "$BASE/v1/simulate" \
  -H "Content-Type: application/json" \
  -H "Merchant: $MERCHANT" \
  -H "Signature: $(sign "$BODY")" \
  -d "$BODY"
```

{% endtab %}
{% endtabs %}
