---
title: Revoke Delegate
description:
  Remove a token account's current delegate and clear its remaining delegated
  allowance.
url: /docs/tokens/basics/revoke-delegate
type: tutorial
prerequisites:
  - /docs/tokens/basics/approve-delegate
related:
  - /docs/tokens/basics/approve-delegate
  - /docs/tokens/basics/transfer-tokens
  - /docs/tokens/basics/burn-tokens
  - /docs/tokens/basics/set-authority
---

## What Does Revoking a Delegate Do?

Revoking a delegate clears the token account's current delegate and resets the
delegated amount to zero.

After revocation, the previous delegate no longer has authority to transfer or
burn tokens on behalf of the token account.

## How to Revoke a Delegate

Revoking a delegate uses the Token Program's _rs`Revoke`_ instruction.

The _rs`Revoke`_ instruction clears the delegate fields on the source token
account. In the Token Program, the token account owner signs the revocation. In
the Token Extension Program, the current delegate can also revoke the
delegation.

### Source Reference

| Item                 | Description                                                            | Token Program                                                                                                  | Token Extension Program                                                                                              |
| -------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| _rs`Account`_        | The token account state stores the delegate and delegated amount.      | [Source](https://github.com/solana-program/token/blob/program%40v9.0.0/interface/src/state.rs#L84-L108)        | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/state.rs#L99-L123)        |
| _rs`Revoke`_         | An instruction that removes the current delegate from a token account. | [Source](https://github.com/solana-program/token/blob/program%40v9.0.0/interface/src/instruction.rs#L128-L140) | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/interface/src/instruction.rs#L170-L182) |
| _rs`process_revoke`_ | Shared processor logic for delegate revocation.                        | [Source](https://github.com/solana-program/token/blob/program%40v9.0.0/program/src/processor.rs#L395-L420)     | [Source](https://github.com/solana-program/token-2022/blob/program%40v10.0.0/program/src/processor.rs#L643-L674)     |

### Typescript

The `Kit` examples below show the recommended approach using `@solana/kit`.
Legacy examples using `@solana/web3.js` are included for reference.

#### Kit

<CodeTabs storage="token-ts-kit" flags="r">

```ts !! title="Plugin"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import {
  findAssociatedTokenPda,
  tokenProgram,
  TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)))
  // !mark[/\.use\(tokenProgram\(\)\)/]
  .use(tokenProgram());

const mint = await generateKeyPairSigner();
const delegate = await generateKeyPairSigner();

const [tokenAccount] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_PROGRAM_ADDRESS
});

// !collapse(1:24) collapsed
// Setup: create a mint, fund the payer's ATA, and approve a delegate first.
await client.sendTransaction([
  client.token.instructions.createMint({
    newMint: mint,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  }),
  await client.token.instructions.mintToATA({
    mint: mint.address,
    owner: client.payer.address,
    mintAuthority: client.payer,
    amount: 100n,
    decimals: 2
  }),
  client.token.instructions.approveChecked({
    source: tokenAccount,
    mint: mint.address,
    delegate: delegate.address,
    owner: client.payer,
    amount: 25n,
    decimals: 2
  })
]);

const result = await client.token.instructions
  // !mark(1:4)
  .revoke({
    source: tokenAccount, // Token account whose delegate approval changes.
    owner: client.payer // Owner approving this delegate change.
  })
  .sendTransaction();

const tokenAccountData = await client.token.accounts.token.fetch(tokenAccount);

console.log("Mint Address:", mint.address);
console.log("\nToken Account Address:", tokenAccount);
console.log("Token Account:", tokenAccountData.data);
console.log("\nDelegate Address:", delegate.address);
console.log("\nTransaction Signature:", result.context.signature);
```

```ts !! title="Instructions"
import { createClient, generateKeyPairSigner, lamports } from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import {
  fetchToken,
  findAssociatedTokenPda,
  getApproveCheckedInstruction,
  getCreateMintInstructionPlan,
  getMintToATAInstructionPlanAsync,
  getRevokeInstruction,
  TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";

const client = await createClient()
  .use(generatedPayer())
  .use(
    solanaRpc({
      rpcUrl: "http://localhost:8899",
      rpcSubscriptionsUrl: "ws://localhost:8900"
    })
  )
  .use(rpcAirdrop())
  .use(airdropPayer(lamports(1_000_000_000n)));

const mint = await generateKeyPairSigner();
const delegate = await generateKeyPairSigner();

const [tokenAccount] = await findAssociatedTokenPda({
  mint: mint.address,
  owner: client.payer.address,
  tokenProgram: TOKEN_PROGRAM_ADDRESS
});

// !collapse(1:26) collapsed
// Setup: create a mint, fund the payer's ATA, and approve a delegate first.
await client.sendTransaction([
  getCreateMintInstructionPlan({
    payer: client.payer,
    newMint: mint,
    decimals: 2,
    mintAuthority: client.payer.address,
    freezeAuthority: client.payer.address
  }),
  await getMintToATAInstructionPlanAsync({
    payer: client.payer,
    mint: mint.address,
    owner: client.payer.address,
    mintAuthority: client.payer,
    amount: 100n,
    decimals: 2
  }),
  getApproveCheckedInstruction({
    source: tokenAccount,
    mint: mint.address,
    delegate: delegate.address,
    owner: client.payer,
    amount: 25n,
    decimals: 2
  })
]);

const result = await client.sendTransaction([
  // !mark(1:4)
  getRevokeInstruction({
    source: tokenAccount, // Token account whose delegate approval changes.
    owner: client.payer // Owner approving this delegate change.
  })
]);

const tokenAccountData = await fetchToken(client.rpc, tokenAccount);

console.log("Mint Address:", mint.address);
console.log("\nToken Account Address:", tokenAccount);
console.log("Token Account:", tokenAccountData.data);
console.log("\nDelegate Address:", delegate.address);
console.log("\nTransaction Signature:", result.context.signature);
```

</CodeTabs>

#### Web3.js

<CodeTabs storage="token-ts-legacy" flags="r">

```ts !! title="Helper Function"
import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";
import {
  createAssociatedTokenAccount,
  approveChecked,
  createMint,
  getAccount,
  mintToChecked,
  revoke,
  TOKEN_PROGRAM_ID
} from "@solana/spl-token";

// !collapse(1:71) collapsed
// Setup: create a mint, fund the payer's ATA, and approve a delegate first.
const connection = new Connection("http://localhost:8899", "confirmed");
const latestBlockhash = await connection.getLatestBlockhash();

const feePayer = Keypair.generate();
const delegate = Keypair.generate();

const airdropSignature = await connection.requestAirdrop(
  feePayer.publicKey,
  LAMPORTS_PER_SOL
);
await connection.confirmTransaction({
  blockhash: latestBlockhash.blockhash,
  lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
  signature: airdropSignature
});

const mintPubkey = await createMint(
  connection,
  feePayer,
  feePayer.publicKey,
  feePayer.publicKey,
  2,
  Keypair.generate(),
  {
    commitment: "confirmed"
  },
  TOKEN_PROGRAM_ID
);

const associatedTokenAccount = await createAssociatedTokenAccount(
  connection,
  feePayer,
  mintPubkey,
  feePayer.publicKey,
  {
    commitment: "confirmed"
  },
  TOKEN_PROGRAM_ID
);

await mintToChecked(
  connection,
  feePayer,
  mintPubkey,
  associatedTokenAccount,
  feePayer,
  100,
  2,
  [],
  {
    commitment: "confirmed"
  },
  TOKEN_PROGRAM_ID
);

await approveChecked(
  connection,
  feePayer,
  mintPubkey,
  associatedTokenAccount,
  delegate.publicKey,
  feePayer,
  25,
  2,
  [],
  {
    commitment: "confirmed"
  },
  TOKEN_PROGRAM_ID
);

// !mark(1:11)
const result = await revoke(
  connection, // Connection to the local validator.
  feePayer, // Account paying transaction fees.
  associatedTokenAccount, // Token account whose delegate approval changes.
  feePayer, // Owner approving this delegate change.
  [], // Additional multisig signers.
  {
    commitment: "confirmed" // Confirmation options for the transaction.
  },
  TOKEN_PROGRAM_ID // Token program to invoke.
);

const tokenAccountData = await getAccount(
  connection,
  associatedTokenAccount,
  "confirmed",
  TOKEN_PROGRAM_ID
);

console.log("Mint Address:", mintPubkey.toBase58());
console.log(
  "\nAssociated Token Account Address:",
  associatedTokenAccount.toBase58()
);
console.log("Associated Token Account:", tokenAccountData);
console.log("\nDelegate Address:", delegate.publicKey.toBase58());
console.log("\nTransaction Signature:", result);
```

```ts !! title="Instructions"
import {
  Connection,
  Keypair,
  sendAndConfirmTransaction,
  SystemProgram,
  Transaction,
  LAMPORTS_PER_SOL
} from "@solana/web3.js";
import {
  ASSOCIATED_TOKEN_PROGRAM_ID,
  createApproveCheckedInstruction,
  createAssociatedTokenAccountInstruction,
  createInitializeMintInstruction,
  createMintToCheckedInstruction,
  createRevokeInstruction,
  getAccount,
  getAssociatedTokenAddressSync,
  getMinimumBalanceForRentExemptMint,
  MINT_SIZE,
  TOKEN_PROGRAM_ID
} from "@solana/spl-token";

// !collapse(1:80) collapsed
// Setup: create a mint, fund the payer's ATA, and approve a delegate first.
const connection = new Connection("http://localhost:8899", "confirmed");
const latestBlockhash = await connection.getLatestBlockhash();

const feePayer = Keypair.generate();
const delegate = Keypair.generate();

const airdropSignature = await connection.requestAirdrop(
  feePayer.publicKey,
  LAMPORTS_PER_SOL
);
await connection.confirmTransaction({
  blockhash: latestBlockhash.blockhash,
  lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
  signature: airdropSignature
});

const mint = Keypair.generate();
const mintRent = await getMinimumBalanceForRentExemptMint(connection);
const associatedTokenAccount = getAssociatedTokenAddressSync(
  mint.publicKey,
  feePayer.publicKey,
  false, // allowOwnerOffCurve
  TOKEN_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID
);

await sendAndConfirmTransaction(
  connection,
  new Transaction({
    feePayer: feePayer.publicKey,
    blockhash: latestBlockhash.blockhash,
    lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
  }).add(
    SystemProgram.createAccount({
      fromPubkey: feePayer.publicKey,
      newAccountPubkey: mint.publicKey,
      space: MINT_SIZE,
      lamports: mintRent,
      programId: TOKEN_PROGRAM_ID
    }),
    createInitializeMintInstruction(
      mint.publicKey,
      2,
      feePayer.publicKey,
      feePayer.publicKey,
      TOKEN_PROGRAM_ID
    ),
    createAssociatedTokenAccountInstruction(
      feePayer.publicKey,
      associatedTokenAccount,
      feePayer.publicKey,
      mint.publicKey,
      TOKEN_PROGRAM_ID,
      ASSOCIATED_TOKEN_PROGRAM_ID
    ),
    createMintToCheckedInstruction(
      mint.publicKey,
      associatedTokenAccount,
      feePayer.publicKey,
      100,
      2,
      [],
      TOKEN_PROGRAM_ID
    ),
    createApproveCheckedInstruction(
      associatedTokenAccount,
      mint.publicKey,
      delegate.publicKey,
      feePayer.publicKey,
      25,
      2,
      [],
      TOKEN_PROGRAM_ID
    )
  ),
  [feePayer, mint]
);

const revokeBlockhash = await connection.getLatestBlockhash();

const result = await sendAndConfirmTransaction(
  connection,
  new Transaction({
    feePayer: feePayer.publicKey,
    blockhash: revokeBlockhash.blockhash,
    lastValidBlockHeight: revokeBlockhash.lastValidBlockHeight
  }).add(
    // !mark(1:6)
    createRevokeInstruction(
      associatedTokenAccount, // Token account whose delegate approval changes.
      feePayer.publicKey, // Owner approving this delegate change.
      [], // Additional multisig signers.
      TOKEN_PROGRAM_ID // Token program to invoke.
    )
  ),
  [feePayer]
);

const tokenAccountData = await getAccount(
  connection,
  associatedTokenAccount,
  "confirmed",
  TOKEN_PROGRAM_ID
);

console.log("Mint Address:", mint.publicKey.toBase58());
console.log(
  "\nAssociated Token Account Address:",
  associatedTokenAccount.toBase58()
);
console.log("Associated Token Account:", tokenAccountData);
console.log("\nDelegate Address:", delegate.publicKey.toBase58());
console.log("\nTransaction Signature:", result);
```

</CodeTabs>

### Rust

<CodeTabs storage="token-rs" flags="r">

```rust !! title="Rust"
use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{
    program_pack::Pack,
    signature::{Keypair, Signer},
    transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_associated_token_account_interface::{
    address::get_associated_token_address, instruction::create_associated_token_account,
};
use spl_token_interface::{
    id as token_program_id,
    instruction::{approve_checked, initialize_mint, mint_to_checked, revoke},
    state::{Account, Mint},
};

#[tokio::main]
async fn main() -> Result<()> {
    let client = RpcClient::new_with_commitment(
        String::from("http://localhost:8899"),
        CommitmentConfig::confirmed(),
    );
    let delegate = Keypair::new();

    // !collapse(1:72) collapsed
    // Setup: create a mint, fund the payer's ATA, and approve a delegate first.
    let fee_payer = Keypair::new();
    let decimals = 2;

    let airdrop_signature = client
        .request_airdrop(&fee_payer.pubkey(), 1_000_000_000)
        .await?;
    loop {
        let confirmed = client.confirm_transaction(&airdrop_signature).await?;
        if confirmed {
            break;
        }
    }

    let mint = Keypair::new();
    let mint_rent = client
        .get_minimum_balance_for_rent_exemption(Mint::LEN)
        .await?;
    let associated_token_address = get_associated_token_address(
        &fee_payer.pubkey(),
        &mint.pubkey(),
    );
    let latest_blockhash = client.get_latest_blockhash().await?;
    let setup_transaction = Transaction::new_signed_with_payer(
        &[
            create_account(
                &fee_payer.pubkey(),
                &mint.pubkey(),
                mint_rent,
                Mint::LEN as u64,
                &token_program_id(),
            ),
            initialize_mint(
                &token_program_id(),
                &mint.pubkey(),
                &fee_payer.pubkey(),
                Some(&fee_payer.pubkey()),
                decimals,
            )?,
            create_associated_token_account(
                &fee_payer.pubkey(),
                &fee_payer.pubkey(),
                &mint.pubkey(),
                &token_program_id(),
            ),
            mint_to_checked(
                &token_program_id(),
                &mint.pubkey(),
                &associated_token_address,
                &fee_payer.pubkey(),
                &[],
                100,
                decimals,
            )?,
            approve_checked(
                &token_program_id(),
                &associated_token_address,
                &mint.pubkey(),
                &delegate.pubkey(),
                &fee_payer.pubkey(),
                &[],
                25,
                decimals,
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer, &mint],
        latest_blockhash,
    );
    client
        .send_and_confirm_transaction(&setup_transaction)
        .await?;

    let transaction = Transaction::new_signed_with_payer(
        &[
            // !mark(1:6)
            revoke(
                &token_program_id(), // Token program to invoke.
                &associated_token_address, // Token account whose delegate approval changes.
                &fee_payer.pubkey(), // Owner approving this delegate change.
                &[], // Additional multisig signers.
            )?,
        ],
        Some(&fee_payer.pubkey()),
        &[&fee_payer],
        latest_blockhash,
    );

    let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
    let token_account = client.get_account(&associated_token_address).await?;
    let token_data = Account::unpack(&token_account.data)?;

    println!("Mint Address: {}", mint.pubkey());
    println!(
        "\nAssociated Token Account Address: {}",
        associated_token_address
    );
    println!("Associated Token Account: {:#?}", token_data);
    println!("\nDelegate Address: {}", delegate.pubkey());
    println!("\nTransaction Signature: {}", transaction_signature);

    Ok(())
}
```

</CodeTabs>

### Python

<CodeTabs flags="r">

```py !! title="Python"
#!/usr/bin/env python3

import asyncio
import json
from solana.rpc.async_api import AsyncClient
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.system_program import create_account, CreateAccountParams
from solders.transaction import Transaction
from spl.token.async_client import AsyncToken
from spl.token.instructions import (
    approve_checked,
    ApproveCheckedParams,
    create_associated_token_account,
    get_associated_token_address,
    initialize_mint,
    InitializeMintParams,
    mint_to_checked,
    MintToCheckedParams,
    revoke,
    RevokeParams,
)
from spl.token.constants import MINT_LEN, TOKEN_PROGRAM_ID

DECIMALS = 2
AMOUNT_TO_MINT = 100
AMOUNT_TO_APPROVE = 25

async def main():
    rpc = AsyncClient("http://localhost:8899")

    delegate = Keypair()

    async with rpc:
        # !collapse(1:22) collapsed
        # Setup: create a mint, token account, and delegate approval before revoking the delegate.
        fee_payer = Keypair()
        airdrop_signature = (await rpc.request_airdrop(fee_payer.pubkey(), 1_000_000_000)).value
        await rpc.confirm_transaction(airdrop_signature)
        mint = Keypair()
        token_account_address = get_associated_token_address(fee_payer.pubkey(), mint.pubkey())
        mint_rent = (await rpc.get_minimum_balance_for_rent_exemption(MINT_LEN)).value
        setup_instructions = [
            create_account(CreateAccountParams(from_pubkey=fee_payer.pubkey(), to_pubkey=mint.pubkey(), lamports=mint_rent, space=MINT_LEN, owner=TOKEN_PROGRAM_ID)),
            initialize_mint(InitializeMintParams(decimals=DECIMALS, program_id=TOKEN_PROGRAM_ID, mint=mint.pubkey(), mint_authority=fee_payer.pubkey())),
            create_associated_token_account(fee_payer.pubkey(), fee_payer.pubkey(), mint.pubkey(), TOKEN_PROGRAM_ID),
            mint_to_checked(MintToCheckedParams(program_id=TOKEN_PROGRAM_ID, mint=mint.pubkey(), dest=token_account_address, mint_authority=fee_payer.pubkey(), amount=AMOUNT_TO_MINT, decimals=DECIMALS)),
            approve_checked(ApproveCheckedParams(program_id=TOKEN_PROGRAM_ID, source=token_account_address, mint=mint.pubkey(), delegate=delegate.pubkey(), owner=fee_payer.pubkey(), amount=AMOUNT_TO_APPROVE, decimals=DECIMALS)),
        ]
        setup_blockhash = await rpc.get_latest_blockhash()
        setup_transaction = Transaction(
            [fee_payer, mint],
            Message(setup_instructions, fee_payer.pubkey()),
            setup_blockhash.value.blockhash,
        )
        await rpc.send_transaction(setup_transaction)
        token = AsyncToken(rpc, mint.pubkey(), TOKEN_PROGRAM_ID, fee_payer)

        # !mark(1:7)
        revoke_delegate_instruction = revoke(
            RevokeParams(
                program_id=TOKEN_PROGRAM_ID,  # Token program to invoke.
                account=token_account_address,  # Token account whose delegate approval changes.
                owner=fee_payer.pubkey(),  # Account that owns the token account.
            )
        )
        latest_blockhash = await rpc.get_latest_blockhash()
        transaction = Transaction(
            [fee_payer],
            Message([revoke_delegate_instruction], fee_payer.pubkey()),
            latest_blockhash.value.blockhash,
        )
        result = await rpc.send_transaction(transaction)

        token_account_info = await token.get_account_info(token_account_address)
        token_account = {
            key: str(value) if isinstance(value, Pubkey) else value
            for key, value in token_account_info._asdict().items()
        }

        print("Mint Address:", mint.pubkey())
        print("\nToken Account Address:", token_account_address)
        print("Token Account:")
        print(json.dumps(token_account, indent=2))
        print("\nDelegate Address:", delegate.pubkey())
        print("\nTransaction Signature:", result.value)

if __name__ == "__main__":
    asyncio.run(main())
```

</CodeTabs>
