How To Make Token Accounts Immutable

The role of the immutable Owner extension is very easy to understand. What this extension does is, it ensures that ownership of a Token Account cannot be reassigned.

For example, if the owner of an existing Associated Token Account is changed, users may unintentionally transfer funds to an account under the assumption that it belongs to the original owner.

With Token Extensions, Associated Token Accounts have the ImmutableOwner extension enabled by default, preventing the ownership from being changed.

The Immutable Owner extension can also be enabled for any new Token Account created by the Token Extension program.

So Devs, this is your guide:

Step 1: Open this Solana Playground link with the following starter code:

// Clientconsole.log("My address:", pg.wallet.publicKey.toString());const balance = await pg.connection.getBalance(pg.wallet.publicKey);console.log(`My balance: ${balance / web3.LAMPORTS_PER_SOL} SOL`);

P.S: If it is your first time using Solana Playground, you'll first need to create a Playground Wallet and fund the wallet with devnet SOL.

To get devnet SOL, run the solana airdrop command in the Playground's terminal, or visit this devnet faucet.

Step 2: Add Dependencies:

- Set up your script. For this article, we’ll be using:

@solana/web3.js and @solana/spl-token libraries.

- Replace the starter code with the following:

import { clusterApiUrl, sendAndConfirmTransaction, Connection, Keypair, SystemProgram, Transaction,} from "@solana/web3.js";import { createAssociatedTokenAccount, createMint, createInitializeImmutableOwnerInstruction, createInitializeAccountInstruction, getAccountLen, ExtensionType, TOKEN_2022_PROGRAM_ID, setAuthority, AuthorityType,} from "@solana/spl-token"; // Playground walletconst payer = pg.wallet.keypair; // Connection to devnet clusterconst connection = new Connection(clusterApiUrl("devnet"), "confirmed"); // Transaction signature returned from sent transactionlet transactionSignature: string;

Step 3: Mint Setup.

- Create a new mint account before token account.

// Authority that can mint new tokensconst mintAuthority = pg.wallet.publicKey;// Decimals for Mint Accountconst decimals = 2; // Create Mint Accountconst mint = await createMint( connection, payer, // Payer of the transaction and initialization fees mintAuthority, // Mint Authority null, // Optional Freeze Authority decimals, // Decimals of Mint undefined, // Optional keypair undefined, // Options for confirming the transaction TOKEN_2022_PROGRAM_ID, // Token Extension Program ID);

Step 4: Create Associated Token Account

// Create Associated Token Account for Playground walletconst associatedTokenAccount = await createAssociatedTokenAccount( connection, payer, // Payer to create Token Account mint, // Mint Account address payer.publicKey, // Token Account owner undefined, // Confirmation options TOKEN_2022_PROGRAM_ID, // Token Extension Program ID);

*Attempting to change the owner of the Associated Token Account will result in an error.

try { // Attempt to change owner of Associated Token Account await setAuthority( connection, // Connection to use payer, // Payer of the transaction fee associatedTokenAccount, // Associated Token Account payer.publicKey, // Owner of the Associated Token Account AuthorityType.AccountOwner, // Type of Authority new Keypair().publicKey, // New Account Owner undefined, // Additional signers undefined, // Confirmation options TOKEN_2022_PROGRAM_ID, // Token Extension Program ID );} catch (error) { console.log("Expect Error:", error);}

Step 5: Create Immutable Owner Token Account

Generate a new keypair for the Token Account and determine the required lamports for rent exemption.

// Random keypair to use as owner of Token Accountconst tokenAccountKeypair = Keypair.generate();// Address for Token Accountconst tokenAccount = tokenAccountKeypair.publicKey;

Build and send the transaction to create a Token Account with the Immutable Owner extension enabled.

// Instruction to invoke System Program to create new accountconst createAccountInstruction = SystemProgram.createAccount({ fromPubkey: payer.publicKey, // Account that will transfer lamports to created account newAccountPubkey: tokenAccount, // Address of the account to create space: accountLen, // Amount of bytes to allocate to the created account lamports, // Amount of lamports transferred to created account programId: TOKEN_2022_PROGRAM_ID, // Program assigned as owner of created account});

// Instruction to initialize the ImmutableOwner Extensionconst initializeImmutableOwnerInstruction = createInitializeImmutableOwnerInstruction( tokenAccount, // Token Account address TOKEN_2022_PROGRAM_ID, // Token Extension Program ID );

// Instruction to initialize Token Account dataconst initializeAccountInstruction = createInitializeAccountInstruction( tokenAccount, // Token Account Address mint, // Mint Account payer.publicKey, // Token Account Owner TOKEN_2022_PROGRAM_ID, // Token Extension Program ID);

Step 6: Send Transaction

// Add instructions to new transactionconst transaction = new Transaction().add( createAccountInstruction, initializeImmutableOwnerInstruction, initializeAccountInstruction,); // Send transactiontransactionSignature = await sendAndConfirmTransaction( connection, transaction, [payer, tokenAccountKeypair], // Signers); console.log( "Create Token Account:", `https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`,);

Run the script by clicking the Run button. Inspect the transaction details on SolanaFM.

Attempting to change the owner of the Token Account will result in the same error as before.

try { // Attempt to change owner of Token Account await setAuthority( connection, // Connection to use payer, // Payer of the transaction fee tokenAccount, // Token Account payer.publicKey, // Owner of the Token Account AuthorityType.AccountOwner, // Type of Authority new Keypair().publicKey, // New Account Owner undefined, // Additional signers undefined, // Confirmation options TOKEN_2022_PROGRAM_ID, // Token Extension Program ID );} catch (error) { console.log("Expect Error:", error);}

And these steps dearest Devs, are your guide to using the Immutable owner extension.

Last updated