> ## Documentation Index
> Fetch the complete documentation index at: https://docs.portalhq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage Token Delegations

> Learn how to approve, revoke, and manage token delegations using Portal's iOS SDK.

Portal's iOS SDK provides token delegation capabilities through the `portal.delegations` API. This enables approving token spending, revoking approvals, checking delegation status, and transferring tokens as a delegate on both EVM and Solana chains.

## Overview

The delegations functionality allows you to:

* **Approve** other addresses to spend tokens on behalf of your wallet
* **Revoke** existing delegations to remove spending permissions
* **Check status** of active delegations and balances
* **Transfer tokens** as a delegate from another address

## Prerequisites

Before using delegation operations, ensure you have:

* A properly initialized Portal client
* An active wallet with tokens on the target network (see [Create a wallet](./create-a-wallet))
* Understanding of [token delegations concepts](/resources/delegations)

<Warning>
  Delegations apply to ERC-20 tokens (EVM) and SPL Tokens (Solana) only. Native assets like ETH, MON, and SOL cannot be delegated — they have no on-chain `approve` / `transferFrom` (or SPL delegate) semantics. Calls using a native asset identifier will be rejected. See [Delegations](/resources/delegations#what-are-token-delegations) for the protocol-level reason and workarounds.
</Warning>

## Approving Delegations

Use `approve` to grant another address permission to spend tokens on your behalf. This method works for both EVM and Solana chains.

### EVM Approval

```swift theme={null}
Task {
    do {
        let request = ApproveDelegationRequest(
            chain: "eip155:11155111",
            token: "USDC",
            delegateAddress: "0xa944e86eb36f039becd1843132347eb5b8501562",
            amount: "0.01"
        )

        let response = try await portal.delegations.approve(request: request)

        // Sign and send EVM transactions sequentially
        if let transactions = response.transactions {
            for (index, tx) in transactions.enumerated() {
                var txDict: [String: String] = [
                    "from": tx.from,
                    "to": tx.to
                ]
                if let data = tx.data { txDict["data"] = data }
                if let value = tx.value { txDict["value"] = value }

                let txResponse = try await portal.request(
                    chainId: "eip155:11155111",
                    method: .eth_sendTransaction,
                    params: [txDict],
                    options: nil
                )
                print("Tx \(index + 1) hash: \(txResponse.result as? String ?? "Unknown")")
            }
        }
    } catch {
        print("Error approving EVM delegation: \(error)")
    }
}
```

### Solana Approval

```swift theme={null}
Task {
    do {
        let request = ApproveDelegationRequest(
            chain: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
            token: "USDC",
            delegateAddress: "7smgSuU5mjP7QY5yWGdaTfgKn8hUWwvQgfvgcZB3HmJi",
            amount: "0.01"
        )

        let response = try await portal.delegations.approve(request: request)

        // Sign and send Solana transactions sequentially
        if let encodedTransactions = response.encodedTransactions {
            for (index, encodedTx) in encodedTransactions.enumerated() {
                let txResponse = try await portal.request(
                    chainId: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
                    method: .sol_signAndSendTransaction,
                    params: [encodedTx],
                    options: nil
                )
                print("Tx \(index + 1) hash: \(txResponse.result as? String ?? "Unknown")")
            }
        }
    } catch {
        print("Error approving Solana delegation: \(error)")
    }
}
```

***

## Checking Delegation Status

Use `getStatus` to check current delegations and token balances for a specific delegate address.

### EVM Status Check

```swift theme={null}
Task {
    do {
        let request = GetDelegationStatusRequest(
            chain: "eip155:11155111",
            token: "USDC",
            delegateAddress: "0xa944e86eb36f039becd1843132347eb5b8501562"
        )

        let response = try await portal.delegations.getStatus(request: request)

        print("Chain ID: \(response.chainId)")
        print("Token: \(response.token)")
        print("Token Address: \(response.tokenAddress)")
        if let balance = response.balance { print("Balance: \(balance)") }
        print("Delegations: \(response.delegations.count)")

        for delegation in response.delegations {
            print("  - Address: \(delegation.address), Amount: \(delegation.delegateAmount)")
        }
    } catch {
        print("Error getting EVM delegation status: \(error)")
    }
}
```

### Solana Status Check

```swift theme={null}
Task {
    do {
        let request = GetDelegationStatusRequest(
            chain: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
            token: "USDC",
            delegateAddress: "7smgSuU5mjP7QY5yWGdaTfgKn8hUWwvQgfvgcZB3HmJi"
        )

        let response = try await portal.delegations.getStatus(request: request)

        print("Chain ID: \(response.chainId)")
        print("Token: \(response.token)")
        print("Delegations: \(response.delegations.count)")

        for delegation in response.delegations {
            print("  - Address: \(delegation.address), Amount: \(delegation.delegateAmount)")
        }
    } catch {
        print("Error getting Solana delegation status: \(error)")
    }
}
```

***

## Revoking Delegations

Use `revoke` to remove spending permissions from a delegate address.

### EVM Revoke

```swift theme={null}
Task {
    do {
        let request = RevokeDelegationRequest(
            chain: "eip155:11155111",
            token: "USDC",
            delegateAddress: "0xa944e86eb36f039becd1843132347eb5b8501562"
        )

        let response = try await portal.delegations.revoke(request: request)

        // Sign and send EVM transactions sequentially
        if let transactions = response.transactions {
            for (index, tx) in transactions.enumerated() {
                var txDict: [String: String] = [
                    "from": tx.from,
                    "to": tx.to
                ]
                if let data = tx.data { txDict["data"] = data }
                if let value = tx.value { txDict["value"] = value }

                let txResponse = try await portal.request(
                    chainId: "eip155:11155111",
                    method: .eth_sendTransaction,
                    params: [txDict],
                    options: nil
                )
                print("Tx \(index + 1) hash: \(txResponse.result as? String ?? "Unknown")")
            }
        }
    } catch {
        print("Error revoking EVM delegation: \(error)")
    }
}
```

### Solana Revoke

```swift theme={null}
Task {
    do {
        let request = RevokeDelegationRequest(
            chain: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
            token: "USDC",
            delegateAddress: "7smgSuU5mjP7QY5yWGdaTfgKn8hUWwvQgfvgcZB3HmJi"
        )

        let response = try await portal.delegations.revoke(request: request)

        // Sign and send Solana transactions sequentially
        if let encodedTransactions = response.encodedTransactions {
            for (index, encodedTx) in encodedTransactions.enumerated() {
                let txResponse = try await portal.request(
                    chainId: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
                    method: .sol_signAndSendTransaction,
                    params: [encodedTx],
                    options: nil
                )
                print("Tx \(index + 1) hash: \(txResponse.result as? String ?? "Unknown")")
            }
        }
    } catch {
        print("Error revoking Solana delegation: \(error)")
    }
}
```

<Warning>
  Always revoke unused delegations after completing operations to minimize security risks.
</Warning>

***

## Transferring as a Delegate

Use `transferFrom` to transfer tokens from another address that has delegated spending permission to you.

### EVM Transfer From

```swift theme={null}
Task {
    do {
        let request = TransferFromRequest(
            chain: "eip155:11155111",
            token: "USDC",
            fromAddress: "0x099699ed181517d4ce0ba4487bea671d31bb1db5", // Token owner
            toAddress: "0xdFd8302f44727A6348F702fF7B594f127dE3A902",   // Recipient
            amount: "0.01"
        )

        let response = try await portal.delegations.transferFrom(request: request)

        // Sign and send EVM transactions sequentially
        if let transactions = response.transactions {
            for (index, tx) in transactions.enumerated() {
                var txDict: [String: String] = [
                    "from": tx.from,
                    "to": tx.to
                ]
                if let data = tx.data { txDict["data"] = data }
                if let value = tx.value { txDict["value"] = value }

                let txResponse = try await portal.request(
                    chainId: "eip155:11155111",
                    method: .eth_sendTransaction,
                    params: [txDict],
                    options: nil
                )
                print("Tx \(index + 1) hash: \(txResponse.result as? String ?? "Unknown")")
            }
        }
    } catch {
        print("Error transferring EVM delegation: \(error)")
    }
}
```

### Solana Transfer From

```swift theme={null}
Task {
    do {
        let request = TransferFromRequest(
            chain: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
            token: "USDC",
            fromAddress: "ARttPLesu9RiX6H111Pfdc9Y2DhGy1B8P8jyyrD8Cj5b", // Token owner
            toAddress: "GPsPXxoQA51aTJJkNHtFDFYui5hN5UxcFPnheJEHa5Du",   // Recipient
            amount: "0.01"
        )

        let response = try await portal.delegations.transferFrom(request: request)

        // Sign and send Solana transactions sequentially
        if let encodedTransactions = response.encodedTransactions {
            for (index, encodedTx) in encodedTransactions.enumerated() {
                let txResponse = try await portal.request(
                    chainId: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
                    method: .sol_signAndSendTransaction,
                    params: [encodedTx],
                    options: nil
                )
                print("Tx \(index + 1) hash: \(txResponse.result as? String ?? "Unknown")")
            }
        }
    } catch {
        print("Error transferring Solana delegation: \(error)")
    }
}
```

<Note>
  **Delegation Roles**: `fromAddress` is the token owner who approved the delegation. Your wallet (the delegate) signs the transaction to transfer tokens from the owner to the `toAddress` recipient.
</Note>

***

## Supported Networks

Delegations work on all Portal-supported EVM and Solana chains:

* **EVM**: Ethereum, Polygon, Base, Arbitrum, Optimism, Monad, and all other EVM-compatible chains
* **Solana**: Solana Mainnet and Devnet

For a complete list, see [Blockchain Support](/resources/blockchain-support).

***

## Next Steps

* Learn about [signing transactions](./sign-a-transaction)
* Explore [Portal API methods](./portal-api-methods)
* Review [delegation concepts](/resources/delegations)
* Check out [wallet lifecycle management](./manage-wallet-lifecycle-states)
