⚠️Blast API (blastapi.io) ends Oct 31. Migrate to Dwellir and skip Alchemy's expensive compute units.
Switch Today →
Skip to main content

wallet/undelegateresource

Reclaim previously delegated bandwidth or energy resources from another account.

Endpoint

POST /wallet/undelegateresource

Parameters

Required Parameters

ParameterTypeDescription
owner_addressstringAccount address that delegated resources (base58)
receiver_addressstringAccount that received delegated resources (base58)
balancenumberAmount to undelegate in SUN (1 TRX = 1,000,000 SUN)
resourcestringResource type: "BANDWIDTH" or "ENERGY"

Optional Parameters

ParameterTypeDescription
permission_idnumberPermission ID for multi-signature (default: 0)
visiblebooleanReturn base58 addresses (default: false returns hex)

Response

Returns unsigned transaction containing the undelegation operation. Transaction must be signed and broadcast.

Response Fields

  • txID - Transaction hash
  • raw_data - Transaction raw data
    • contract - Undelegation contract details
    • expiration - Transaction expiration timestamp
    • timestamp - Transaction creation timestamp
  • visible - Address format indicator

Important Notes

Undelegation Rules

  1. Lock Period Check: Cannot undelegate if resources are locked
  2. Immediate Effect: Resources return to owner immediately after confirmation
  3. Partial Undelegation: Can undelegate portions of delegated amount
  4. Resource Availability: Reclaimed resources are immediately available to owner
  5. No Waiting Period: Unlike unstaking, undelegation has no waiting period

Key Differences from Unstaking

  • Undelegation: Returns delegated resources to owner (immediate)
  • Unstaking: Converts staked TRX back to liquid (14-day wait)

Implementation Examples

class TronUndelegationManager {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = `https://api-tron-mainnet.n.dwellir.com/${apiKey}`;
}

// Create undelegation transaction
async undelegateResources(ownerAddress, receiverAddress, amountTRX, resourceType) {
const response = await fetch(`${this.baseUrl}/wallet/undelegateresource`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
owner_address: ownerAddress,
receiver_address: receiverAddress,
balance: amountTRX * 1000000, // Convert TRX to SUN
resource: resourceType,
visible: true
})
});

if (!response.ok) {
const error = await response.json();
throw new Error(`Undelegation failed: ${error.message || response.statusText}`);
}

return response.json();
}

// Get all active delegations from owner
async getActiveDelegations(ownerAddress) {
const response = await fetch(`${this.baseUrl}/wallet/getdelegatedresourceaccountindex`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
value: ownerAddress,
visible: true
})
});

const index = await response.json();
const delegations = [];

if (index.toAccounts) {
for (const receiverAddress of index.toAccounts) {
const detail = await this.getDelegationDetail(ownerAddress, receiverAddress);
delegations.push({
receiver: receiverAddress,
...this.parseDelegationDetail(detail)
});
}
}

return delegations;
}

// Get delegation detail between two accounts
async getDelegationDetail(fromAddress, toAddress) {
const response = await fetch(`${this.baseUrl}/wallet/getdelegatedresource`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
fromAddress: fromAddress,
toAddress: toAddress,
visible: true
})
});

return response.json();
}

// Parse delegation details
parseDelegationDetail(detail) {
const delegatedResource = detail.delegatedResource || [];
let energyDelegated = 0;
let bandwidthDelegated = 0;
let energyExpireTime = null;
let bandwidthExpireTime = null;

for (const resource of delegatedResource) {
if (resource.frozen_balance_for_energy) {
energyDelegated = resource.frozen_balance_for_energy / 1000000; // Convert to TRX
energyExpireTime = resource.expire_time_for_energy
? new Date(resource.expire_time_for_energy)
: null;
}
if (resource.frozen_balance_for_bandwidth) {
bandwidthDelegated = resource.frozen_balance_for_bandwidth / 1000000; // Convert to TRX
bandwidthExpireTime = resource.expire_time_for_bandwidth
? new Date(resource.expire_time_for_bandwidth)
: null;
}
}

return {
energy: {
amount: energyDelegated,
locked: energyExpireTime && energyExpireTime > new Date(),
expireTime: energyExpireTime
},
bandwidth: {
amount: bandwidthDelegated,
locked: bandwidthExpireTime && bandwidthExpireTime > new Date(),
expireTime: bandwidthExpireTime
}
};
}

// Check if undelegation is possible
async canUndelegate(ownerAddress, receiverAddress, resourceType) {
const detail = await this.getDelegationDetail(ownerAddress, receiverAddress);
const parsed = this.parseDelegationDetail(detail);

const resource = resourceType.toLowerCase();
const delegation = parsed[resource];

if (!delegation || delegation.amount === 0) {
return {
canUndelegate: false,
reason: 'No resources delegated',
amount: 0
};
}

if (delegation.locked) {
const remainingTime = delegation.expireTime - new Date();
const days = Math.ceil(remainingTime / (1000 * 60 * 60 * 24));

return {
canUndelegate: false,
reason: `Resources locked for ${days} more days`,
amount: delegation.amount,
unlockTime: delegation.expireTime
};
}

return {
canUndelegate: true,
amount: delegation.amount,
reason: 'Ready to undelegate'
};
}

// Batch undelegate from multiple receivers
async batchUndelegate(ownerAddress, undelegations) {
const results = [];

for (const undelegation of undelegations) {
try {
// Check if can undelegate first
const check = await this.canUndelegate(
ownerAddress,
undelegation.receiver,
undelegation.resource
);

if (!check.canUndelegate) {
results.push({
success: false,
receiver: undelegation.receiver,
resource: undelegation.resource,
reason: check.reason
});
continue;
}

// Proceed with undelegation
const tx = await this.undelegateResources(
ownerAddress,
undelegation.receiver,
undelegation.amount || check.amount,
undelegation.resource
);

results.push({
success: true,
receiver: undelegation.receiver,
resource: undelegation.resource,
amount: undelegation.amount || check.amount,
txID: tx.txID,
transaction: tx
});

} catch (error) {
results.push({
success: false,
receiver: undelegation.receiver,
resource: undelegation.resource,
error: error.message
});
}
}

return results;
}

// Reclaim all unlocked delegations
async reclaimAllUnlocked(ownerAddress) {
const delegations = await this.getActiveDelegations(ownerAddress);
const toReclaim = [];

for (const delegation of delegations) {
// Check energy delegation
if (delegation.energy.amount > 0 && !delegation.energy.locked) {
toReclaim.push({
receiver: delegation.receiver,
resource: 'ENERGY',
amount: delegation.energy.amount
});
}

// Check bandwidth delegation
if (delegation.bandwidth.amount > 0 && !delegation.bandwidth.locked) {
toReclaim.push({
receiver: delegation.receiver,
resource: 'BANDWIDTH',
amount: delegation.bandwidth.amount
});
}
}

if (toReclaim.length === 0) {
return {
message: 'No unlocked delegations to reclaim',
transactions: []
};
}

const results = await this.batchUndelegate(ownerAddress, toReclaim);

return {
message: `Reclaiming ${toReclaim.length} delegations`,
transactions: results
};
}
}

// Resource optimization strategies
class ResourceOptimizer {
constructor(manager) {
this.manager = manager;
}

// Analyze delegation efficiency
async analyzeDelegationEfficiency(ownerAddress) {
const delegations = await this.manager.getActiveDelegations(ownerAddress);
const analysis = [];

for (const delegation of delegations) {
// Get receiver's current resource usage
const resourceResponse = await fetch(
`${this.manager.baseUrl}/wallet/getaccountresource`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
address: delegation.receiver,
visible: true
})
}
);

const resources = await resourceResponse.json();

// Calculate efficiency metrics
const energyEfficiency = resources.EnergyUsed
? (resources.EnergyUsed / resources.EnergyLimit) * 100
: 0;

const bandwidthEfficiency = resources.NetUsed
? (resources.NetUsed / resources.NetLimit) * 100
: 0;

analysis.push({
receiver: delegation.receiver,
energy: {
delegated: delegation.energy.amount,
efficiency: energyEfficiency.toFixed(2) + '%',
recommendation: energyEfficiency < 50
? 'Consider reducing delegation'
: 'Delegation well utilized'
},
bandwidth: {
delegated: delegation.bandwidth.amount,
efficiency: bandwidthEfficiency.toFixed(2) + '%',
recommendation: bandwidthEfficiency < 50
? 'Consider reducing delegation'
: 'Delegation well utilized'
}
});
}

return analysis;
}

// Optimize delegations by reclaiming underutilized resources
async optimizeDelegations(ownerAddress, utilizationThreshold = 30) {
const analysis = await this.analyzeDelegationEfficiency(ownerAddress);
const toReclaim = [];

for (const item of analysis) {
// Check energy utilization
const energyUtilization = parseFloat(item.energy.efficiency);
if (energyUtilization < utilizationThreshold && item.energy.delegated > 0) {
// Calculate amount to reclaim (keep some buffer)
const reclaimAmount = item.energy.delegated * (1 - energyUtilization / 100) * 0.8;

toReclaim.push({
receiver: item.receiver,
resource: 'ENERGY',
amount: Math.floor(reclaimAmount),
reason: `Low utilization: ${item.energy.efficiency}`
});
}

// Check bandwidth utilization
const bandwidthUtilization = parseFloat(item.bandwidth.efficiency);
if (bandwidthUtilization < utilizationThreshold && item.bandwidth.delegated > 0) {
// Calculate amount to reclaim
const reclaimAmount = item.bandwidth.delegated * (1 - bandwidthUtilization / 100) * 0.8;

toReclaim.push({
receiver: item.receiver,
resource: 'BANDWIDTH',
amount: Math.floor(reclaimAmount),
reason: `Low utilization: ${item.bandwidth.efficiency}`
});
}
}

if (toReclaim.length === 0) {
return {
message: 'All delegations are efficiently utilized',
optimizations: []
};
}

const results = await this.manager.batchUndelegate(ownerAddress, toReclaim);

return {
message: `Optimizing ${toReclaim.length} inefficient delegations`,
optimizations: results
};
}
}

// Example usage
async function manageUndelegation() {
const manager = new TronUndelegationManager('YOUR_API_KEY');
const optimizer = new ResourceOptimizer(manager);

try {
// 1. Simple undelegation
console.log('=== Simple Undelegation ===');
const simpleTx = await manager.undelegateResources(
'TOwnerAddress...',
'TReceiverAddress...',
1000, // 1000 TRX
'ENERGY'
);
console.log('Transaction ID:', simpleTx.txID);

// 2. Check if can undelegate
console.log('\n=== Checking Undelegation Status ===');
const canUndelegate = await manager.canUndelegate(
'TOwnerAddress...',
'TReceiverAddress...',
'ENERGY'
);
console.log('Can undelegate:', canUndelegate);

// 3. Get all active delegations
console.log('\n=== Active Delegations ===');
const activeDelegations = await manager.getActiveDelegations('TOwnerAddress...');

for (const delegation of activeDelegations) {
console.log(`To ${delegation.receiver}:`);
console.log(` Energy: ${delegation.energy.amount} TRX (${delegation.energy.locked ? 'LOCKED' : 'UNLOCKED'})`);
console.log(` Bandwidth: ${delegation.bandwidth.amount} TRX (${delegation.bandwidth.locked ? 'LOCKED' : 'UNLOCKED'})`);
}

// 4. Reclaim all unlocked delegations
console.log('\n=== Reclaiming All Unlocked ===');
const reclaimResults = await manager.reclaimAllUnlocked('TOwnerAddress...');
console.log(reclaimResults.message);

for (const tx of reclaimResults.transactions) {
if (tx.success) {
console.log(`✓ Reclaimed ${tx.amount} TRX ${tx.resource} from ${tx.receiver}`);
} else {
console.log(`✗ Failed to reclaim from ${tx.receiver}: ${tx.reason || tx.error}`);
}
}

// 5. Optimize delegations
console.log('\n=== Delegation Optimization ===');
const optimization = await optimizer.optimizeDelegations('TOwnerAddress...', 30);
console.log(optimization.message);

for (const opt of optimization.optimizations) {
if (opt.success) {
console.log(`✓ Optimized: Reclaimed ${opt.amount} TRX ${opt.resource} from ${opt.receiver}`);
} else {
console.log(`✗ Could not optimize ${opt.receiver}: ${opt.reason}`);
}
}

} catch (error) {
console.error('Undelegation error:', error);
}
}

Example Response

{
"visible": true,
"txID": "a9f4d3c2b1e8a7d6c5e4f3b2a1d9c8e7f6b5a4d3c2e1f9a8b7c6d5e4f3a2b1c8",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"owner_address": "TOwnerAddress...",
"receiver_address": "TReceiverAddress...",
"balance": 1000000000,
"resource": "ENERGY"
},
"type_url": "type.googleapis.com/protocol.UnDelegateResourceContract"
},
"type": "UnDelegateResourceContract"
}
],
"ref_block_bytes": "7c6d",
"ref_block_hash": "5e4f9b8a7c6d5e3f",
"expiration": 1702456849000,
"timestamp": 1702456789000
}
}

Undelegation Process Flow

graph LR
A[Delegated Resources] --> B{Check Lock Status}
B -->|Locked| C[Wait for Unlock]
B -->|Unlocked| D[Initiate Undelegation]
C --> D
D --> E[Sign Transaction]
E --> F[Broadcast]
F --> G[Resources Returned to Owner]

style A fill:#2196F3
style B fill:#FF9800
style G fill:#4CAF50

Best Practices

1. Check Lock Status First

// Always check before attempting undelegation
const status = await checkUndelegationStatus(owner, receiver, resource);
if (!status.canUndelegate) {
console.log(`Cannot undelegate: ${status.reason}`);
return;
}

2. Monitor Utilization

  • Regularly check delegation efficiency
  • Reclaim underutilized resources
  • Redistribute based on actual needs

3. Batch Operations

  • Group multiple undelegations together
  • Reduces transaction costs
  • Easier to manage

4. Grace Period Management

  • Track lock expiration dates
  • Set reminders for locked delegations
  • Plan undelegations in advance

Common Errors

ErrorDescriptionSolution
No delegation foundNo resources delegated to receiverCheck delegation status first
Delegation is lockedResources are locked for periodWait for lock period to expire
Insufficient delegated balanceTrying to undelegate more than delegatedCheck current delegation amount
Invalid resource typeMust be BANDWIDTH or ENERGYUse correct resource string

Use Cases

  • Resource Reallocation: Move resources to more active users
  • Cost Optimization: Reclaim resources from inactive accounts
  • Emergency Recovery: Quickly reclaim resources when needed
  • Delegation Cleanup: Remove old or unnecessary delegations
  • Efficiency Management: Optimize resource distribution based on usage