Change authority for accounts
Outcome
We will understand on how to transfer authority to others.
The are totally 4 types of authorities
- Mint Tokens - Authority to mint new tokens
- Freeze Accounts - Authority to freeze any account associated with the Mint
- Account Owner - Owner of a given token account
- CloseAccount - Authority to close a token account
We will look at each of these authority type and understand how to perform these operations
The outcome of this chapter is found here
Prerequisite
For the demonstration purpose, we will retain only create_mint, transfer_mint instructions.
So the remove the following from the previous chapter
burn_tokeninstructionBurnTokencontext
And remove test case related to it.
Or you could clone the Chapter - 5 repo for getting started.
How to set authority for token mints ?
It's is a 2-step process.
- Create a
SetMintTokenAuthoritycontext - Create a
set_mint_token_authorityinstruction
Step-1 : Create a SetMintTokenAuthority context
Let us create a set mint token authority like below. We will transfer the mint token authority to anotherAuthority. And we pass that account as Signer in the context.
// Set Mint Token Authority context
#[derive(Accounts)]
pub struct SetMintTokenAuthority<'info> {
#[account(
mut,
seeds = [
b"spl-token-mint".as_ref(),
],
bump = vault.spl_token_mint_bump,
)]
pub spl_token_mint: Account<'info, Mint>, // ---> 1
#[account(
seeds = [
b"vault"
],
bump = vault.bump, // --> 2
)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub payer: Signer<'info>, // ---> 3
pub another_authority: Signer<'info>, // ---> 4
pub system_program: Program<'info, System>, // ---> 5
pub token_program: Program<'info, Token>, // ---> 6
pub rent: Sysvar<'info, Rent>, // ---> 7
}
- We pass
spl_token_mintaccount. We are changing this mint's authority - We
vaultaccount as it containsspl_token_mint_bumpvalue payeraccount is the original authority ofspl_token_mintanother_authorityaccount to which we are passing the authority tosystem_programto manage accounts- We invoke
set_authorityinstruction oftoken_programthrough CPI.
Step-2 : Create a set_mint_token_authority instruction
Let us create an instruction to change the authority.
Import the following dependencies
use anchor_lang::prelude::*;
use anchor_spl::token::spl_token::instruction::AuthorityType;
use anchor_spl::{
associated_token::AssociatedToken,
token::{self, Mint, Token, TokenAccount},
And add the following instruction.
pub fn set_mint_authority(ctx: Context<SetMintTokenAuthority>) -> Result<()> {
let cpi_context = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
token::SetAuthority {
current_authority: ctx.accounts.payer.to_account_info(),
account_or_mint: ctx.accounts.spl_token_mint.to_account_info(),
},
);
token::set_authority(
cpi_context,
AuthorityType::MintTokens,
Some(ctx.accounts.another_authority.key()),
)?;
Ok(())
}
With this instruction above, it is easy to change the authority. We use AuthorityType::MintTokens to change the authority. Let us test this out.
Before proceeding to write test cases, do make sure that you have added anotherWallet as another wallet in the describe block.
const anotherWallet = anchor.web3.Keypair.generate(); // newly created another wallet
And add some sols to it in the before block of the test file
before("Add sols to wallet ", async () => {
await addSols(provider, payer.publicKey); // add some sols before calling test cases
await addSols(provider, anotherWallet.publicKey); // add sols to another wallet
});
In the spl-token.ts file add the following test case
//set mint authority to another wallet test
it("should set mint authority to anotherWallet", async () => {
const [splTokenMint, _1] = await findSplTokenMintAddress();
const [vaultMint, _2] = await findVaultAddress();
const tx = await program.methods
.setMintAuthority()
.accounts({
splTokenMint: splTokenMint,
vault: vaultMint,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
anotherAuthority: anotherWallet.publicKey,
payer: payer.publicKey,
})
.signers([payer, anotherWallet])
.rpc();
console.log("Your transaction signature", tx);
});
And run the following command
anchor test
You should be able to see the following output.

Now we will look at how to change the FreezeAccount authority.
How to set Freeze Authority for an account ?
If we observe carefully, when we created mint instruction and created spl_token_mint we had set the freeze authority to payer.
Now let us change that to another authority.
Again, it is a 2-step process.
It's is a 2-step process.
- Create a
SetFreezeAccountAuthoritycontext - Create a
set_freeze_account_authorityinstruction
Step-1 : Create a SetFreezeAccountAuthority context
We create SetFreezeAccountAuthorityContext as below.
// Set Freeze Account Authority context
#[derive(Accounts)]
pub struct SetFreezeAccountAuthority<'info> {
#[account(
mut,
seeds = [
b"spl-token-mint".as_ref(),
],
bump = vault.spl_token_mint_bump,
)]
pub spl_token_mint: Account<'info, Mint>, // ---> 1
#[account(
seeds = [
b"vault"
],
bump = vault.bump, // --> 2
)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub payer: Signer<'info>, // ---> 3
pub another_authority: Signer<'info>, // ---> 4
pub system_program: Program<'info, System>, // ---> 5
pub token_program: Program<'info, Token>, // ---> 6
}
- We pass
spl_token_mintaccount. We are changing freeze authority for this mint - We
vaultaccount as it containsspl_token_mint_bumpvalue payeraccount is the original authority ofspl_token_mintanother_authorityaccount to which we are passing the authority tosystem_programto manage accounts- We invoke
set_authorityinstruction oftoken_programthrough CPI.
Step-2: Create a set_freeze_account_authority instruction
Let us create an instruction to change the authority.
pub fn set_freeze_account_authority(ctx: Context<SetFreezeAccountAuthority>) -> Result<()> {
let cpi_context = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
token::SetAuthority {
current_authority: ctx.accounts.payer.to_account_info(),
account_or_mint: ctx.accounts.spl_token_mint.to_account_info(),
},
);
token::set_authority(
cpi_context,
AuthorityType::FreezeAccount,
Some(ctx.accounts.another_authority.key()),
)?;
Ok(())
}
Let's test this out using the following test case. Write the test case in spl-token.ts
//set freeze account authority to another wallet test
it("should set freeze account authority to anotherWallet", async () => {
const [splTokenMint, _1] = await findSplTokenMintAddress();
const [vaultMint, _2] = await findVaultAddress();
const tx = await program.methods
.setFreezeAccountAuthority()
.accounts({
splTokenMint: splTokenMint,
vault: vaultMint,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
anotherAuthority: anotherWallet.publicKey,
payer: payer.publicKey,
})
.signers([payer, anotherWallet])
.rpc();
console.log("Your transaction signature", tx);
});
Run the following command
anchor test
You should be able to see the following

Next, we will look at AccountOwner authority type.
How to set AccountOwner authority to a token account?
This is used in the cases where we want to delegate token account ownership to another authority.
In the following code example, we will transfer the payer_mint_ata authority to another_authority account.
We will follow the 2-step process again.
- Create a
SetAccountOwnerAuthoritycontext. - Create a
set_account_ownerinstruction.
Step-1 : Create a SetAccountOwnerAuthority context.
Let create the context as below.
// Set Account Owner Authority context
#[derive(Accounts)]
pub struct SetAccountOwnerAuthority<'info> {
#[account(
mut,
seeds = [
b"spl-token-mint".as_ref(),
],
bump = vault.spl_token_mint_bump,
)]
pub spl_token_mint: Account<'info, Mint>, // ---> 1
#[account(
seeds = [
b"vault"
],
bump = vault.bump, // --> 2
)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub payer: Signer<'info>, // ---> 3
#[account(
mut,
associated_token::mint = spl_token_mint,
associated_token::authority = payer
)]
pub payer_mint_ata: Account<'info, TokenAccount>, // ---> 4
pub another_authority: Signer<'info>, // ---> 5
pub system_program: Program<'info, System>, // ---> 6
pub token_program: Program<'info, Token>, // ---> 7
}
- We pass
spl_token_mintaccount. This is used bypayer_mint_ataaccount - We
vaultaccount as it containsspl_token_mint_bumpvalue payeraccount is the original authority ofpayer_mint_atapayer_mint_ataaccount authority is passed toanother_authorityanother_authorityaccount to which we are passing the authority tosystem_programto manage accounts- We invoke
set_authorityinstruction oftoken_programthrough CPI.
Step-2 : Create a set_account_owner instruction.
Let us create an instruction to achieve this.
pub fn set_account_owner_authority(ctx: Context<SetAccountOwnerAuthority>) -> Result<()> {
let cpi_context = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
token::SetAuthority {
current_authority: ctx.accounts.payer.to_account_info(),
account_or_mint: ctx.accounts.payer_mint_ata.to_account_info(),
},
);
token::set_authority(
cpi_context,
AuthorityType::AccountOwner, // authority type is AccountOwner
Some(ctx.accounts.another_authority.key()),
)?;
Ok(())
}
As you can above, we have set the AuthorityType to AccountOwner.
Write a test in spl-token.ts to test the instruction.
//set account owner to another wallet test
it("should set account owner of payer_mint_ata to another wallet ", async () => {
try {
const [splTokenMint, _1] = await findSplTokenMintAddress();
const [vaultMint, _2] = await findVaultAddress();
const [payerMintAta, _3] = await findAssociatedTokenAccount(
payer.publicKey,
splTokenMint
);
const tx = await program.methods
.setAccountOwnerAuthority()
.accounts({
splTokenMint: splTokenMint,
vault: vaultMint,
tokenProgram: TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
payerMintAta: payerMintAta,
payer: payer.publicKey,
anotherAuthority: anotherWallet.publicKey,
})
.signers([payer, anotherWallet])
.rpc();
console.log("Your transaction signature", tx);
} catch (err) {
console.log(err);
}
});
Run the following command to test
anchor test
You should be able to see the following output.

Next we will look at CloseAccount Authority type.
How to set a CloseAccount Authority for a token account ?
We can set a Close Account authority for a token account. For the below example, we will set the another_mint_ata close authority to payer as authority.
We use this authority to close and transfer remaining lamports to the authority account.
Let us follow the 2-step process to achieve our goal
- Create a
CloseAccountAuthoritycontext - Create an instruction
close_account_authority
Step-1 : Create a CloseAccountAuthority context.
To create a CloseAccountAuthority context, we will create a struct in the lib.rs file as below.
// Set Close Account Authority context
#[derive(Accounts)]
pub struct SetCloseAccountAuthority<'info> {
#[account(
mut,
seeds = [
b"spl-token-mint".as_ref(),
],
bump = vault.spl_token_mint_bump,
)]
pub spl_token_mint: Account<'info, Mint>, // ---> 1
#[account(
seeds = [
b"vault"
],
bump = vault.bump, // --> 2
)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub payer: Signer<'info>, // ---> 3
#[account(
init,
associated_token::mint = spl_token_mint,
associated_token::authority = another_authority,
payer = payer
)]
pub another_mint_ata: Account<'info, TokenAccount>, // ---> 4
pub another_authority: Signer<'info>, // ---> 5
pub system_program: Program<'info, System>, // ---> 6
pub token_program: Program<'info, Token>, // ---> 7
pub associated_token_program : Program<'info, AssociatedToken>, // ---> 8,
pub rent: Sysvar<'info, Rent>, // ---> 9
}
- We pass
spl_token_mintaccount. - We
vaultaccount as it containsspl_token_mint_bumpvalue payeraccount paysanother_mint_ataaccount creation.another_mint_ataaccount from which we want to transfer close authority to payeranother_authorityaccount. We use this to createanother_mint_ataaccount.system_programto manage accounts- We invoke
set_authorityinstruction oftoken_programthrough CPI. associated_token_accountis for creatinganother_mint_ataaccountrentused bysystem_programto create a new account.
Step-2 : Create an instruction close_account_authority
Let us create an instruction to set close authority on another_mint_ata.
pub fn set_close_account_authority(ctx: Context<SetCloseAccountAuthority>) -> Result<()> {
let cpi_context = CpiContext::new(
ctx.accounts.token_program.to_account_info(),
token::SetAuthority {
current_authority: ctx.accounts.another_authority.to_account_info(),
account_or_mint: ctx.accounts.another_mint_ata.to_account_info(),
},
);
token::set_authority(
cpi_context,
AuthorityType::CloseAccount,
Some(ctx.accounts.payer.key()),
)?;
Ok(())
}
In the above instruction we are setting CloseAccount authority to payer.
We write the test case for this to test in spl-token.ts file.
it("should set close account authority of another_mint_ata to payer wallet", async () => {
try {
const [splTokenMint, _1] = await findSplTokenMintAddress();
const [vaultMint, _2] = await findVaultAddress();
const [another_mint_ata, _3] = await findAssociatedTokenAccount(
anotherWallet.publicKey,
splTokenMint
);
const tx = await program.methods
.setCloseAccountAuthority()
.accounts({
splTokenMint: splTokenMint,
vault: vaultMint,
tokenProgram: TOKEN_PROGRAM_ID,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
systemProgram: SystemProgram.programId,
anotherMintAta: another_mint_ata,
payer: payer.publicKey,
anotherAuthority: anotherWallet.publicKey,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
})
.signers([payer, anotherWallet])
.rpc();
console.log("Your transaction signature", tx);
} catch (err) {
console.log(err);
}
});
Let us run the test case by running the following command
anchor test
You should be able to see the following after running the command.

That's it for SetAuthority functionality. In the next chapter we will look at approve instruction for delegating tokens to another account.