# wallet/undelegateresource - Reclaim Delegated R...

Reclaim previously delegated bandwidth or energy resources from another account.

## Endpoint

```
POST /wallet/undelegateresource
```

## Request Parameters

- `owner_address` (`string, required`): Required parameter: Account address that delegated resources (base58)
- `receiver_address` (`string, required`): Required parameter: Account that received delegated resources (base58)
- `balance` (`number, required`): Required parameter: Amount to undelegate in SUN (1 TRX = 1,000,000 SUN)
- `resource` (`string, required`): Required parameter: Resource type: "BANDWIDTH" or "ENERGY"
- `permission_id` (`number, required`): Optional parameter: Permission ID for multi-signature (default: 0)
- `visible` (`boolean, required`): Optional parameter: Return base58 addresses (default: false returns hex)

## Request Example

```bash
# Basic undelegation of energy
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TOwnerAddress...",
        "receiver_address": "TReceiverAddress...",
        "balance": 1000000000,
        "resource": "ENERGY",
        "visible": true
      }'

    # Undelegate bandwidth
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
      -H "Content-Type: application/json" \
      -d '{
        "owner_address": "TOwnerAddress...",
        "receiver_address": "TReceiverAddress...",
        "balance": 500000000,
        "resource": "BANDWIDTH",
        "visible": true
      }'

    # Check delegation index (to find all delegations)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresourceaccountindex \
      -H "Content-Type: application/json" \
      -d '{
        "value": "TOwnerAddress...",
        "visible": true
      }'

    # Get specific delegation details
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresource \
      -H "Content-Type: application/json" \
      -d '{
        "fromAddress": "TOwnerAddress...",
        "toAddress": "TReceiverAddress...",
        "visible": true
      }'

    # Check receiver's resource usage (to analyze efficiency)
    curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountresource \
      -H "Content-Type: application/json" \
      -d '{
        "address": "TReceiverAddress...",
        "visible": true
      }'
```

## Response Fields

- `result` (`OBJECT, required`): `txID` - Transaction hash `raw_data` - Transaction raw data `contract` - Undelegation contract details `expiration` - Transaction expiration timestamp `timestamp` - Transaction creation timestamp `visible` - Address format indicator

## Successful Response

```json
{
  "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
  }
}
```

## 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

cURL
JavaScript
Python

```bash
# Basic undelegation of energy
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TOwnerAddress...",
    "receiver_address": "TReceiverAddress...",
    "balance": 1000000000,
    "resource": "ENERGY",
    "visible": true
  }'

# Undelegate bandwidth
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/undelegateresource \
  -H "Content-Type: application/json" \
  -d '{
    "owner_address": "TOwnerAddress...",
    "receiver_address": "TReceiverAddress...",
    "balance": 500000000,
    "resource": "BANDWIDTH",
    "visible": true
  }'

# Check delegation index (to find all delegations)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresourceaccountindex \
  -H "Content-Type: application/json" \
  -d '{
    "value": "TOwnerAddress...",
    "visible": true
  }'

# Get specific delegation details
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getdelegatedresource \
  -H "Content-Type: application/json" \
  -d '{
    "fromAddress": "TOwnerAddress...",
    "toAddress": "TReceiverAddress...",
    "visible": true
  }'

# Check receiver's resource usage (to analyze efficiency)
curl -X POST https://api-tron-mainnet.n.dwellir.com/YOUR_API_KEY/wallet/getaccountresource \
  -H "Content-Type: application/json" \
  -d '{
    "address": "TReceiverAddress...",
    "visible": true
  }'
```

```javascript
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);
  }
}
```

```python
import requests
import json
from datetime import datetime
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass

@dataclass
class UndelegationRequest:
    receiver: str
    resource: str
    amount: Optional[float] = None  # If None, undelegate all

class TronUndelegationManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = f"https://api-tron-mainnet.n.dwellir.com/{api_key}"
    
    def undelegate_resources(
        self,
        owner_address: str,
        receiver_address: str,
        amount_trx: float,
        resource: str
    ) -> Dict:
        """Create an undelegation transaction"""
        
        response = requests.post(
            f"{self.base_url}/wallet/undelegateresource",
            json={
                "owner_address": owner_address,
                "receiver_address": receiver_address,
                "balance": int(amount_trx * 1_000_000),  # Convert to SUN
                "resource": resource,
                "visible": True
            }
        )
        response.raise_for_status()
        return response.json()
    
    def get_delegation_index(self, owner_address: str) -> List[str]:
        """Get list of accounts that have received delegations"""
        
        response = requests.post(
            f"{self.base_url}/wallet/getdelegatedresourceaccountindex",
            json={
                "value": owner_address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        data = response.json()
        return data.get('toAccounts', [])
    
    def get_delegation_detail(
        self,
        from_address: str,
        to_address: str
    ) -> Tuple[Dict, Dict]:
        """Get detailed delegation info between accounts"""
        
        response = requests.post(
            f"{self.base_url}/wallet/getdelegatedresource",
            json={
                "fromAddress": from_address,
                "toAddress": to_address,
                "visible": True
            }
        )
        response.raise_for_status()
        
        data = response.json()
        delegated_resources = data.get('delegatedResource', [])
        
        energy_info = {'amount': 0, 'locked': False, 'expire_time': None}
        bandwidth_info = {'amount': 0, 'locked': False, 'expire_time': None}
        
        for resource in delegated_resources:
            if 'frozen_balance_for_energy' in resource:
                energy_info['amount'] = resource['frozen_balance_for_energy'] / 1_000_000
                if 'expire_time_for_energy' in resource:
                    expire_time = datetime.fromtimestamp(resource['expire_time_for_energy'] / 1000)
                    energy_info['locked'] = expire_time > datetime.now()
                    energy_info['expire_time'] = expire_time
            
            if 'frozen_balance_for_bandwidth' in resource:
                bandwidth_info['amount'] = resource['frozen_balance_for_bandwidth'] / 1_000_000
                if 'expire_time_for_bandwidth' in resource:
                    expire_time = datetime.fromtimestamp(resource['expire_time_for_bandwidth'] / 1000)
                    bandwidth_info['locked'] = expire_time > datetime.now()
                    bandwidth_info['expire_time'] = expire_time
        
        return energy_info, bandwidth_info
    
    def check_undelegation_status(
        self,
        owner_address: str,
        receiver_address: str,
        resource: str
    ) -> Dict:
        """Check if undelegation is possible"""
        
        energy_info, bandwidth_info = self.get_delegation_detail(
            owner_address,
            receiver_address
        )
        
        info = energy_info if resource == "ENERGY" else bandwidth_info
        
        if info['amount'] == 0:
            return {
                'can_undelegate': False,
                'reason': f'No {resource} delegated to this address',
                'amount': 0
            }
        
        if info['locked']:
            days_remaining = (info['expire_time'] - datetime.now()).days
            return {
                'can_undelegate': False,
                'reason': f'Locked for {days_remaining} more days',
                'amount': info['amount'],
                'unlock_time': info['expire_time']
            }
        
        return {
            'can_undelegate': True,
            'reason': 'Ready to undelegate',
            'amount': info['amount']
        }
    
    def get_all_delegations(self, owner_address: str) -> List[Dict]:
        """Get all active delegations with details"""
        
        receivers = self.get_delegation_index(owner_address)
        delegations = []
        
        for receiver in receivers:
            energy_info, bandwidth_info = self.get_delegation_detail(
                owner_address,
                receiver
            )
            
            delegations.append({
                'receiver': receiver,
                'energy': energy_info,
                'bandwidth': bandwidth_info,
                'total_delegated': energy_info['amount'] + bandwidth_info['amount']
            })
        
        return delegations
    
    def batch_undelegate(
        self,
        owner_address: str,
        requests: List[UndelegationRequest]
    ) -> List[Dict]:
        """Execute multiple undelegations"""
        
        results = []
        
        for req in requests:
            try:
                # Check status first
                status = self.check_undelegation_status(
                    owner_address,
                    req.receiver,
                    req.resource
                )
                
                if not status['can_undelegate']:
                    results.append({
                        'success': False,
                        'receiver': req.receiver,
                        'resource': req.resource,
                        'reason': status['reason']
                    })
                    continue
                
                # Determine amount
                amount = req.amount if req.amount else status['amount']
                
                # Execute undelegation
                tx = self.undelegate_resources(
                    owner_address,
                    req.receiver,
                    amount,
                    req.resource
                )
                
                results.append({
                    'success': True,
                    'receiver': req.receiver,
                    'resource': req.resource,
                    'amount': amount,
                    'txID': tx['txID']
                })
                
            except Exception as e:
                results.append({
                    'success': False,
                    'receiver': req.receiver,
                    'resource': req.resource,
                    'error': str(e)
                })
        
        return results
    
    def reclaim_all_unlocked(self, owner_address: str) -> Dict:
        """Reclaim all unlocked delegations"""
        
        delegations = self.get_all_delegations(owner_address)
        requests = []
        
        for delegation in delegations:
            # Check energy
            if delegation['energy']['amount'] > 0 and not delegation['energy']['locked']:
                requests.append(UndelegationRequest(
                    receiver=delegation['receiver'],
                    resource='ENERGY',
                    amount=delegation['energy']['amount']
                ))
            
            # Check bandwidth
            if delegation['bandwidth']['amount'] > 0 and not delegation['bandwidth']['locked']:
                requests.append(UndelegationRequest(
                    receiver=delegation['receiver'],
                    resource='BANDWIDTH',
                    amount=delegation['bandwidth']['amount']
                ))
        
        if not requests:
            return {
                'message': 'No unlocked delegations to reclaim',
                'total_reclaimed': 0,
                'transactions': []
            }
        
        results = self.batch_undelegate(owner_address, requests)
        
        total_reclaimed = sum(
            r['amount'] for r in results if r['success']
        )
        
        return {
            'message': f'Reclaimed {len(requests)} delegations',
            'total_reclaimed': total_reclaimed,
            'transactions': results
        }

class DelegationAnalyzer:
    """Analyze and optimize delegation efficiency"""
    
    def __init__(self, manager: TronUndelegationManager):
        self.manager = manager
    
    def analyze_utilization(
        self,
        owner_address: str
    ) -> List[Dict]:
        """Analyze delegation utilization rates"""
        
        delegations = self.manager.get_all_delegations(owner_address)
        analysis = []
        
        for delegation in delegations:
            # Get receiver's resource usage
            response = requests.post(
                f"{self.manager.base_url}/wallet/getaccountresource",
                json={
                    "address": delegation['receiver'],
                    "visible": True
                }
            )
            resources = response.json()
            
            # Calculate utilization
            energy_used = resources.get('EnergyUsed', 0)
            energy_limit = resources.get('EnergyLimit', 0)
            net_used = resources.get('NetUsed', 0)
            net_limit = resources.get('NetLimit', 0)
            
            energy_utilization = (energy_used / energy_limit * 100) if energy_limit > 0 else 0
            bandwidth_utilization = (net_used / net_limit * 100) if net_limit > 0 else 0
            
            analysis.append({
                'receiver': delegation['receiver'],
                'energy': {
                    'delegated_trx': delegation['energy']['amount'],
                    'utilization': f"{energy_utilization:.1f}%",
                    'utilization_rate': energy_utilization,
                    'locked': delegation['energy']['locked']
                },
                'bandwidth': {
                    'delegated_trx': delegation['bandwidth']['amount'],
                    'utilization': f"{bandwidth_utilization:.1f}%",
                    'utilization_rate': bandwidth_utilization,
                    'locked': delegation['bandwidth']['locked']
                }
            })
        
        return analysis
    
    def recommend_optimizations(
        self,
        owner_address: str,
        min_utilization: float = 30.0
    ) -> List[Dict]:
        """Recommend delegations to reclaim based on utilization"""
        
        analysis = self.analyze_utilization(owner_address)
        recommendations = []
        
        for item in analysis:
            # Energy recommendations
            if (item['energy']['delegated_trx'] > 0 and 
                item['energy']['utilization_rate'] < min_utilization and
                not item['energy']['locked']):
                
                recommendations.append({
                    'action': 'RECLAIM',
                    'receiver': item['receiver'],
                    'resource': 'ENERGY',
                    'amount': item['energy']['delegated_trx'],
                    'reason': f"Low utilization: {item['energy']['utilization']}",
                    'potential_savings': item['energy']['delegated_trx']
                })
            
            # Bandwidth recommendations
            if (item['bandwidth']['delegated_trx'] > 0 and
                item['bandwidth']['utilization_rate'] < min_utilization and
                not item['bandwidth']['locked']):
                
                recommendations.append({
                    'action': 'RECLAIM',
                    'receiver': item['receiver'],
                    'resource': 'BANDWIDTH',
                    'amount': item['bandwidth']['delegated_trx'],
                    'reason': f"Low utilization: {item['bandwidth']['utilization']}",
                    'potential_savings': item['bandwidth']['delegated_trx']
                })
        
        total_savings = sum(r['potential_savings'] for r in recommendations)
        
        return {
            'recommendations': recommendations,
            'total_potential_savings': total_savings,
            'summary': f"Can reclaim {total_savings:.2f} TRX from {len(recommendations)} inefficient delegations"
        }

# Example usage
def main():
    manager = TronUndelegationManager('YOUR_API_KEY')
    analyzer = DelegationAnalyzer(manager)
    
    owner_address = 'TOwnerAddress...'
    
    # 1. View all delegations
    print("=== Current Delegations ===")
    delegations = manager.get_all_delegations(owner_address)
    
    for d in delegations:
        print(f"\nTo: {d['receiver']}")
        print(f"  Energy: {d['energy']['amount']:.2f} TRX", 
              "(LOCKED)" if d['energy']['locked'] else "(UNLOCKED)")
        print(f"  Bandwidth: {d['bandwidth']['amount']:.2f} TRX",
              "(LOCKED)" if d['bandwidth']['locked'] else "(UNLOCKED)")
        print(f"  Total: {d['total_delegated']:.2f} TRX")
    
    # 2. Check specific undelegation
    print("\n=== Undelegation Status Check ===")
    status = manager.check_undelegation_status(
        owner_address,
        'TReceiverAddress...',
        'ENERGY'
    )
    print(f"Can undelegate: {status['can_undelegate']}")
    print(f"Reason: {status['reason']}")
    print(f"Amount available: {status['amount']:.2f} TRX")
    
    # 3. Analyze utilization
    print("\n=== Delegation Utilization Analysis ===")
    utilization = analyzer.analyze_utilization(owner_address)
    
    for u in utilization:
        print(f"\n{u['receiver']}:")
        print(f"  Energy: {u['energy']['delegated_trx']:.2f} TRX @ {u['energy']['utilization']} usage")
        print(f"  Bandwidth: {u['bandwidth']['delegated_trx']:.2f} TRX @ {u['bandwidth']['utilization']} usage")
    
    # 4. Get optimization recommendations
    print("\n=== Optimization Recommendations ===")
    recommendations = analyzer.recommend_optimizations(owner_address, 30.0)
    
    print(recommendations['summary'])
    for rec in recommendations['recommendations']:
        print(f"\n  • {rec['action']}: {rec['resource']} from {rec['receiver']}")
        print(f"    Amount: {rec['amount']:.2f} TRX")
        print(f"    Reason: {rec['reason']}")
    
    # 5. Reclaim all unlocked
    print("\n=== Reclaiming Unlocked Delegations ===")
    reclaim_result = manager.reclaim_all_unlocked(owner_address)
    
    print(reclaim_result['message'])
    print(f"Total reclaimed: {reclaim_result['total_reclaimed']:.2f} TRX")
    
    for tx in reclaim_result['transactions']:
        if tx['success']:
            print(f"  ✓ {tx['resource']} from {tx['receiver']}: {tx['amount']:.2f} TRX")
        else:
            print(f"  ✗ {tx['resource']} from {tx['receiver']}: {tx.get('reason', tx.get('error'))}")

if __name__ == "__main__":
    main()
```

## Undelegation Process Flow

```mermaid
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**

```javascript
// 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

| Error                            | Description                              | Solution                        |
| -------------------------------- | ---------------------------------------- | ------------------------------- |
| `No delegation found`            | No resources delegated to receiver       | Check delegation status first   |
| `Delegation is locked`           | Resources are locked for period          | Wait for lock period to expire  |
| `Insufficient delegated balance` | Trying to undelegate more than delegated | Check current delegation amount |
| `Invalid resource type`          | Must be BANDWIDTH or ENERGY              | Use 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

## Related Methods

- [wallet/delegateresource](https://www.dwellir.com/docs/tron/wallet-delegateresource) - Delegate resources to others
- [wallet/freezebalancev2](https://www.dwellir.com/docs/tron/wallet-freezebalancev2) - Stake TRX for resources
- [wallet/unfreezebalancev2](https://www.dwellir.com/docs/tron/wallet-unfreezebalancev2) - Unstake TRX resources
