Stake2.0
Prerequisite: The DApp connection has been authorized via
eth_requestAccounts(see Start Developing).
When a DApp asks TronLink to sign a DelegateResourceContract or UnDelegateResourceContract transaction, the signing popup shows the resource type and an estimated resource amount:
- Resource type — read from
raw_data.contract[0].parameter.value.resource.tronWeb.transactionBuilder.delegateResource/undelegateResourcealready set this field to"ENERGY"for energy. For bandwidth the field is omitted (it is the protobuf default), and TronLink (4.1.4 and later) treats a missing value as"BANDWIDTH". You do not need to add it yourself. - Estimated amount — read from a top-level
__optionsobject that you add to the transaction:estimatedBandwidthis the estimated bandwidth,estimatedEnergyis the estimated energy. Only the value matching the resource type is shown. If__optionsis missing, the popup shows0; signing still works.
__options sits outside raw_data, so adding it does not change txID or raw_data_hex. In contrast, parameter.value.resource is part of the signed protocol data. Do not change it after building: a modified value no longer matches raw_data_hex / txID. trx.sign rejects such a transaction ('Invalid transaction provided'; extension 4.4.3 and later), and trx.multiSign recomputes txID from the modified data, so the signed transaction differs from the one you built. To change the resource type, rebuild the transaction.
![Delegate transaction object with raw_data.contract[0].parameter.value.resource and the top-level __options.estimatedBandwidth highlighted](../../images/dapp_stake2.0_img_0.jpg)
For example:
// ENERGY — tronWeb sets parameter.value.resource = "ENERGY"
const energyTx = await tronWeb.transactionBuilder.delegateResource(10e6, 'receiverAddress', 'ENERGY', 'ownerAddress', false);
energyTx.__options = { estimatedEnergy: 1 }; // placeholder — calculate it as described below
// BANDWIDTH — resource is omitted and displayed as BANDWIDTH
const bandwidthTx = await tronWeb.transactionBuilder.delegateResource(10e6, 'receiverAddress', 'BANDWIDTH', 'ownerAddress', false);
bandwidthTx.__options = { estimatedBandwidth: 1 }; // placeholder — calculate it as described below
const signed = await tronWeb.trx.sign(energyTx);
undelegateResource transactions use the same __options fields.
The specific calculation logic of estimatedEnergy and estimatedBandwidth can be found in the last chapter of the "Stake 2.0 Adaptation FAQ": "How to convert resource share to amount?"
Errors
Error shape: On the TronLink-injected tronWeb (extension 4.0.0 and later), when the user rejects trx.sign, trx.multiSign, or trx.signMessageV2, the promise rejects with the plain string 'Confirmation declined by user' — not an Error object, and without a numeric code. The { code: 4001, message: 'User rejected the request.' } object is returned only by window.tron.request(...) methods such as eth_requestAccounts. Other failures (locked wallet, invalid payload, watch-only account) use other values — see Handling rejections. Do not automatically retry signing.
| Code | Meaning | Where it comes from | Retryable? |
|---|---|---|---|
'Confirmation declined by user' (string) | User clicked Reject in the signing popup | tronWeb.trx.sign(tx) for the delegate / undelegate tx | No — user declined |
| (thrown) | Insufficient TRX staked / nothing to undelegate | delegateResource / undelegateResource builder | No — fix the on-chain state first |
REVERT / OUT_OF_ENERGY / FAILED | Broadcast succeeded but execution failed on-chain | sendRawTransaction result or getTransactionInfo | No — the tx is final; never auto-retry |
For cross-surface translation see the Error Code Map.