From Scratch: How to Create Your Own Token on Solana with Solana Cli and Typescript
Published: 2023-03-18 13:40:50

---
title: From Scratch: How to Create Your Own Token on Solana with Solana Cli and Typescript
published: true
date: 2023-03-18 12:40:42 UTC
tags: 
canonical_url: https://ajaysingh.hashnode.dev/from-scratch-how-to-create-your-own-token-on-solana-with-solana-cli-and-typescript
---

Recently, I came across a video by Harkirat Singh where he gave a step-by-step guide to create your own custom token on the Solana blockchain, and at the end of the video, he gave some assignments to be completed. In this article, I am going to tell you how I completed those assignments and by the end of this article, you will have a basic understanding of how tokens and wallets work on the Solana blockchain. You will also be able to create your own Solana token and have basic knowledge about working with CLI and TypeScript on Solana.

### **Prerequisite:**

- Basic javascript knowledge to understand code

### **Takeaway:**

- Beginners will get hands-on experience with WEB3

- Deep understanding of token transfer

So now we have set the context, let's get started.

One thing to keep in mind is that we will be doing all the steps in Solana Devnet. The Solana Devnet is an environment that replicates the actual Solana network (i.e. Mainnet) environment, where you can access all functions of the main net for testing and development purposes without actually interacting or risking real assets on the mainnet.

## **How token creation and transfer work in Solana network**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679137227558/6015e652-70f8-4660-ad8a-a1736f78a5b2.png)

1. **Solana network:** It consists of multiple nodes that validate the transaction done on Solana network.

2. **Smart Contract:** Smart Contracts are contracts that can be deployed on the Solana network. One of these Smart contracts is already deployed on the network that will help us in building our token. We will not go into much detail of smart contract as we are not going to create smart contract of our own instead we will be using already existing smart contract under the hood.

3. **Mint:** Mint is a unique address referring to a particular token which can be used to identify that token. Each token will have its own mint address. From the diagram, you can see our custom token C1 has its own mint. For easy understanding, you can consider C1 as a 100 rupee note and Mint for C1 is a machine that can print only 100 rupee notes.

4. **Bank Wallet:** Bank Wallet is the wallet address of the owner(person who created the token) of the token. For a real-world analogy, you can consider it as the government that owns the currency and can print it. Wallet can have multiple accounts under it for holding multiple types of tokens. More about it under the next few points.

5. **User Wallet:** User wallet is the wallet address of the person to whom the token is to be sent. This can be considered as the wallet for general people like us.

6. **Account:** Account is something that can hold a particular type of token and is related to the mint address of that token to uniquely identify it. So an account that is made to hold a C1 token will not be able to hold any other token. To hold the C2 token a new account needs to be created specifically for holding C2.

7. **Bank Account:** Bank Account is the account that is the owner of the mint and can hold tokens specified by that mint. All the tokens created by that mint will go to this bank account initially and later it can be sent to where ever the bank wallet owner wants to send it to.

8. **User Account:** User account is the account of the user to whom the token is being sent.

**_Note:_** If the token is being sent to any User's wallet address and that user is not having an account already created for that particular token then first the account needs to be created for that user so that the user can hold that token under that account.

Now that you have an understanding of how it works, let's get straight into the action and create our first Solana token.

### **Step 1: Creation of user wallet**

First, let's create the user wallet for that we will use backpack. It is a chrome extension that can be added from here [https://www.backpack.app/](https://www.backpack.app/). For the invite code, you can use any of the ones provided in this sheet [backpack invite codes](https://docs.google.com/spreadsheets/d/10FxnMcDEq7mOCFG6EkAeQh2clpYkbIv1NWzUpwIP8yY/edit#gid=2103114699).

While setting up the wallet select Solana network. It's not necessary to use this wallet you can use any wallet supporting Solana network.

### **Step 2: Setting up Solana tools in your local system**

For setting up the Solana tools refer to this [link](https://docs.solana.com/cli/install-solana-cli-tools). I am using mac I didn't face any issues. For Windows users I will suggest installing WSL(Windows Subsystem for Linux) and then installing Solana tools.

If you have successfully installed you can check the version using the below given command.

> solana --version

### **Step 3: Creation of Bank Wallet**

For creating bank wallet we are going to use the terminal. So open terminal/Solana CLI and enter this command:

> solana-keygen new

It will create the wallet and show you the public key in the terminal. It will put the private key in /Users/username/.config/solana/id.json location in your system. It will show the location in the terminal as well. Also, it will show you passphrase in the terminal. Keep that passphrase somewhere safe. This passphrase can be used to recover your private key.

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--wJyoY8yO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwmvvy5fellrd53e3xo9.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--wJyoY8yO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwmvvy5fellrd53e3xo9.png)

### **Step 4: Creating a custom token**

As we discussed in starting we will be doing operation in devnet as it will not cost us anything so to configure devnet in your local run the below given command in your terminal.

> solana config set --url [https://api.devnet.solana.com](https://api.devnet.solana.com)

One more thing to take care, performing any operation in Solana network cost you some sol tokens called gas fees. As we just created our wallet we don't have any sol tokens and the balance is 0. You can verify that with the below command.

> solana balance

As devnet is only for development purposes you can airdrop yourself some sol token without paying anything in actual. To airdrop 1 Sol to your wallet run the below command

> solana airdrop 1  
> solana balance

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--i9LHfcJc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esvwjnxfmxbhhac2jkd7.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--i9LHfcJc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/esvwjnxfmxbhhac2jkd7.png)

Now that we have both user and bank wallet, and bank wallet is having sol to perform operations on solana network let's create our first token. For that run the following command

> spl-token create-token

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--ynjtW8iZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgz8bk6lnzrrnh3frurb.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--ynjtW8iZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sgz8bk6lnzrrnh3frurb.png)

After running the above given command you can see that your token is created as shown in the image. It will give you the _mintaddress_ of the token and decimal. By default, it will be 9. Decimal means up to what fraction level your token can be broken while transferring.

You can go to [https://explorer.solana.com/](https://explorer.solana.com/) and search for your token address. It will start showing you your newly created token. **Solana explorer** allows you to look up transactions and accounts on Solana network. Few things to keep in mind when we refer to transactions in Solana network, it is not only the transfer of tokens instead every operation you perform is considered a transaction and has a transaction id attached to it which can be used to look into the operation performed. Also as you have created a token on devnet so don't forget to change the cluster on the top right corner to devnet in Solana explorer.

Currently, your token will be shown as an **Unknown Token** as we have not given any name to it.

Now your token is created but there is no supply for it. This means you need to mint(print) your token(money) to provide supply for it and also you will need a bank account to hold the minted token. So let's do that For that run the below commands:

> spl-token create-account _mintAddress_
> 
> spl-token mint _mintAddress_ 10000

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--8fy86roy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wuq4c7hajsdynj18s71y.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--8fy86roy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wuq4c7hajsdynj18s71y.png)

Now 10000 custom token has been minted and are present in your bank account from where they can be sent to any other wallet to bring them into circulation.

On solana explorer it will look something like this

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--IHL8Io6r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4c03lzl8p4e46xpfp2y.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--IHL8Io6r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e4c03lzl8p4e46xpfp2y.png)

Now Let's tranfer some tokens to user wallet and see what happens. To transfer the token run the below given command

> spl-token transfer _mintAddress_ 3000 _userWalletAddress_ --allow-unfunded-recipient --fund-recipient

Here as the user wallet is not having the account to hold this token and this token is first time being sent to the user wallet we need to add **--allow-unfunded-recipient --fund-recipient** in command.

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--YE_uYFXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xx5q8fsg13jtf925gd0u.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--YE_uYFXR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xx5q8fsg13jtf925gd0u.png)

If you go and check in Solana explorer through your user wallet public key you will be able to see these tokens under the user wallet but directly under your backpack user wallet interface under devnet cluster, these will not be visible. The reason for this is that we have not attached metadata to it like name, image etc. Once we attach the metadata it will start showing in the wallet interface also.

### **Step 5: Updating metadata for token**

Previously token metadata was stored in a GitHub repository but recently Solana has adopted [Metaplex's Fungible Token Standard](https://docs.metaplex.com/programs/token-metadata/token-standard#the-fungible-standard). Using the standard with your token mint will enable platforms like backpack, Phantom wallet, Solana Explorer and others to easily recognize your token and make it viewable by their users.

To attach metadata to a token we will do it through a typescript program but before moving to code let's understand why we attach metadata separately and how it is stored.

Metadata files are generally small in size but still, it is neither economically nor technically sound to store them on the blockchain. That's why decentralized storage solutions typically host metadata files, and **IPFS** remains one of the most popular **decentralized storage protocols**. So the image can be put on some hosting site and its URL can be referred to in metadata json. This metadata json should also be kept on some **decentralized storage solution** for example **arweave** and this arweave url can be kept provided in metadata account which is attached to the mint. Here is a sample arweave url having this [data](https://p7bqbi5ckmgzsm7c6qstl557svhozfxzwgn7teckfx3hhtgad4pa.arweave.net/f8MAo6JTDZkz4vQlNfe_lU7slvmxm_mQSi32c8zAHx4). We will see all of this happening in code as well.  
I will also recommend you to go through the _introduction_ and _json standard_ section of this doc to get a basic understanding of [token-metadata](https://docs.metaplex.com/programs/token-metadata/overview).

So now once we have an understanding of what we want to do, **let's look into the code**.  
First, upload your token image to any decentralized storage solution and get the public URL. This URL we will provide in metadata. I used the [web3 image host](https://web3-image-hosting.vercel.app/)

Then we will create a connection with the Solana network in devnet cluster.

```
const endpoint = 'https://api.devnet.solana.com/'; 
const solanaConnection = new Connection(endpoint);

```

Next, we will create the metadata objects which we will be uploading to arweave. For the image provide the URL that we created above.

```
const MY_TOKEN_METADATA: UploadMetadataInput = {
    name: "HippoCoin",
    symbol: "HIPP0",
    description: "This is a hippo token!",
    image: "https://ipfs.io/ipfs/bafybeidljnhkf3oaoyux7gubcl6glv5sptqvbmqpg2dgmk7lkliai5g7de?filename=DALL%C2%B7E%202023-03-16%2017.26.56%20-%20Cute%20cartoon%20hippo%20looking%20in%20front.png" 
}

const ON_CHAIN_METADATA = {
    name: MY_TOKEN_METADATA.name, 
    symbol: MY_TOKEN_METADATA.symbol,
    uri: 'TO_UPDATE_LATER',
    sellerFeeBasisPoints: 0,
    creators: null,
    collection: null,
    uses: null
} as DataV2;

```

Next, this method will help us in uploading the metadata json and getting the arweave URL. It takes bank wallet KeyPair and token metadata object as parameters. We are using metaplex library to upload this.

```
const uploadMetadata = async(keypair: Keypair, tokenMetadata: UploadMetadataInput):Promise => {
    //create metaplex instance on devnet using this wallet
    const metaplex = Metaplex.make(solanaConnection)
        .use(keypairIdentity(keypair))
        .use(bundlrStorage({
        address: 'https://devnet.bundlr.network',
        providerUrl: endpoint,
        timeout: 60000,
        }));

    //Upload to Arweave
    const { uri } = await metaplex.nfts().uploadMetadata(tokenMetadata);
    console.log(`Arweave URL: `, uri);
    return uri;
}

```

Now we will create another method that will create a transaction to attach this to your token. In this method also we require two parameter i.e PublicKey of mint with which we want to attach metadata and mintAuthority which is the PublicKey of the bank wallet.

Note that in this method we are using _createCreateMetadataAccountV2Instruction_ method that is used to attach the metadata account first time to the mint. Once the metadata account is attached you can keep updating the metadata account values using _createUpdateMetadataAccountV2Instruction_ method.

```
const addMetaDataTransaction = async (mintKeypair: PublicKey, mintAuthority: PublicKey)=>{
    const metadataPDA = await findMetadataPda(mintKeypair);

    const addMetaDataTransaction = new Transaction().add(
        createCreateMetadataAccountV2Instruction({
            metadata: metadataPDA, 
            mint: mintKeypair, 
            mintAuthority: mintAuthority,
            payer: mintAuthority,
            updateAuthority: mintAuthority,
          },
          { createMetadataAccountArgsV2: 
            { 
              data: ON_CHAIN_METADATA, 
              isMutable: true 
            } 
          }
        )
    );

    return addMetaDataTransaction;
}

```

Now that we have all the things in place let's create the main method by which we will execute this transaction.

```
const main = async() => {
    console.log(`---STEP 1: Uploading MetaData---`);
    const bankWalletKeyPair = Keypair.fromSecretKey(new Uint8Array(secret));
    let metadataUri = await uploadMetadata(bankWalletKeyPair, MY_TOKEN_METADATA);
    ON_CHAIN_METADATA.uri = metadataUri;

    console.log(`---STEP 2: Creating Transaction---`);

    const MINT_ADDRESS = "9e5H7DWECb69zDifMHAnx2R7r1SWMAa3xHF9NYQr76gM";
    const mintKeypair = new PublicKey(MINT_ADDRESS);
    const addMetaDataTx:Transaction = await addMetaDataTransaction(
        mintKeypair,
        bankWalletKeyPair.publicKey
    );

    console.log(`---STEP 3: Executing Transaction---`);
    const transactionId = await solanaConnection.sendTransaction(addMetaDataTx, [bankWalletKeyPair,bankWalletKeyPair]);
    console.log(`Transaction ID: `, transactionId);
    console.log(`View Transaction: https://explorer.solana.com/tx/${transactionId}?cluster=devnet`);
}

main();

```

To create bankWalletKeyPair in the above code we are using the private key of our wallet from the JSON file present in /Users/username/.config/solana/id.json that came after we ran **_solana-keygen new_** command in the terminal while creating bank wallet.  
Below are the imports. Here we have used Solana and metaplex libraries.

```
import { Transaction, Keypair, Connection, PublicKey } from "@solana/web3.js";
import { bundlrStorage, findMetadataPda, keypairIdentity, Metaplex, UploadMetadataInput } from '@metaplex-foundation/js';
import { DataV2, createCreateMetadataAccountV2Instruction,createUpdateMetadataAccountV2Instruction } from '@metaplex-foundation/mpl-token-metadata';
import secret from './walletSecret.json';

```

To run this file you can give this command.

> ts-node filename

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--ZAjgk3IN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/65er55g7d2ddzonyfcdk.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--ZAjgk3IN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/65er55g7d2ddzonyfcdk.png)

Now that you have added metadata to your token, it will start displaying the metadata details like name and image in Solana explorer. Also, it will start showing in your user wallet now.

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--gq7gexri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zytph16ndaruxdhbrjvh.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--gq7gexri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zytph16ndaruxdhbrjvh.png)

### **Step 6: Transferring the token programmatically**

In step 4 we have already seen how we can transfer tokens using terminal/CLI so now let's transfer tokens using code.

First, we will import the below things from the library and also define the mint address and KeyPair of the source wallet from which the token is to be sent. walletSecret.json will contain the private key of the wallet.

```
import { getOrCreateAssociatedTokenAccount, createTransferInstruction } from "@solana/spl-token";
import { Connection, Keypair, ParsedAccountData, PublicKey, sendAndConfirmTransaction, Transaction } from "@solana/web3.js";
import secret from './walletSecret.json';

const FROM_KEYPAIR = Keypair.fromSecretKey(new Uint8Array(secret));
const MINT_ADDRESS = 'BQi3xCLLJferBFX9vr1g68cV8nKpBGLJ6825izTkNUF2';

```

Then we will create the connection with the solana network on devnet

```
/**
 * Creating connection with solana network
 */
const endpoint = 'https://api.devnet.solana.com/';
const solanaConnection = new Connection(endpoint);

```

Next, we will have a method that will fetch the numberOfDecimals defined for our token or mint. This will be useful for sending the token as a whole number. While specifying the numberOfTokens to be sent in _createTransferInstruction_ method we will have to multiply the numberOfTokens with 10\*numberOfDecimals otherwise fractional part of the token will be sent.

```
async function getNumberDecimals(mintAddress: string):Promise {
    const info = await solanaConnection.getParsedAccountInfo(new PublicKey(MINT_ADDRESS));
    const result = (info.value?.data as ParsedAccountData).parsed.info.decimals as number;
    return result;
}

```

Now finally we will have _sendTokens_ method that will take the destination wallet address and the transfer amount as parameters.

```
async function sendTokens(destination_Wallet: String, transfer_Amount: number) {
    console.log(`Sending ${transfer_Amount} ${(MINT_ADDRESS)} from ${(FROM_KEYPAIR.publicKey.toString())} to ${(destination_Wallet)}.`)
    //Step 1
    console.log(`1 - Getting Source Token Account`);
    let sourceAccount = await getOrCreateAssociatedTokenAccount(
        solanaConnection, 
        FROM_KEYPAIR,
        new PublicKey(MINT_ADDRESS),
        FROM_KEYPAIR.publicKey
    );
    console.log(` Source Account: ${sourceAccount.address.toString()}`);

        //Step 2
        console.log(`2 - Getting Destination Token Account`);
        let destinationAccount = await getOrCreateAssociatedTokenAccount(
            solanaConnection, 
            FROM_KEYPAIR,
            new PublicKey(MINT_ADDRESS),
            new PublicKey(destination_Wallet)
        );
        console.log(` Destination Account: ${destinationAccount.address.toString()}`);

            //Step 3
    console.log(`3 - Fetching Number of Decimals for Mint: ${MINT_ADDRESS}`);
    const numberDecimals = await getNumberDecimals(MINT_ADDRESS);
    console.log(` Number of Decimals: ${numberDecimals}`);

        //Step 4
        console.log(`4 - Creating and Sending Transaction`);
        const tx = new Transaction();
        tx.add(createTransferInstruction(
            sourceAccount.address,
            destinationAccount.address,
            FROM_KEYPAIR.publicKey,
            transfer_Amount * Math.pow(10, numberDecimals)
        ))

        const latestBlockHash = await solanaConnection.getLatestBlockhash('confirmed');
        tx.recentBlockhash = await latestBlockHash.blockhash;    
        const signature = await sendAndConfirmTransaction(solanaConnection,tx,[FROM_KEYPAIR]);
        console.log(
            '\x1b[32m', //Green Text
            ` Transaction Success!🎉`,
            `\n https://explorer.solana.com/tx/${signature}?cluster=devnet`
        );

}

sendTokens("9e5H7DWECb69zDifMHAnx2R7r1SWMAa3xHF9NYQr76gM", 10);

```

In the above code notice _getOrCreateAssociatedTokenAccount_ method. We already discussed before in case the destination wallet is not having the account to hold the token, then a new account needs to be created under that wallet for that token or mint so that it can hold the token. So _getOrCreateAssociatedTokenAccount_ will fetch the existing token account if it exists for that wallet, in case it is not there it will create a new one.

_createTransferInstruction_ method is used to create instruction to transfer the tokens and is added to the transaction.  
Also, we are fetching recent blockhash before sending the transaction.

To run this file you can give this command

> ts-node filename

[![Image description](https://res.cloudinary.com/practicaldev/image/fetch/s--YgGRViI2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it3uxma4hz7f51k3i35v.png)](https://res.cloudinary.com/practicaldev/image/fetch/s--YgGRViI2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it3uxma4hz7f51k3i35v.png)

**You can find the code** [here](https://github.com/AJcodes42/fungible-token-operator).

### Step 7: Limiting the supply of token

Now that we have minted the tokens and started transferring them, let's limit their supply so that no more tokens can be minted. For limiting their supply we need to disable the mint authority of that token.

One thing to keep in mind, once you have disabled the mint authority, you will no longer be able to update the metadata of the token.

To disable the mint authority we will run the below given command in terminal/CLI.

> spl-token authorize 9e5H7DWECb69zDifMHAnx2R7r1SWMAa3xHF9NYQr76gM mint --disable

Now we no longer will be able to mint more of this token and the supply for this token is fixed.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679142523488/bb374526-2594-4dec-9646-6c8a3787850e.png)

You can verify this from Solana explorer as well. Previous to disabling the mint authority it would have shown you the token like in the below image.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679142926866/2bf12b6d-fa3b-46fd-a9bf-369bad0b4971.png)

After disabling the mint authority it will show you the token with Fixed Supply.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1679142871161/31335f7f-023e-4247-b8f9-3bae0094d022.png)

### Conclusion

To conclude, in this article we understood how wallets, account and token transfer works. We created a wallet and a custom Solana token through the terminal/CLI. Then we attached metadata(name, image etc.) to that token using typescript code and then transferred it to another wallet address using typescript code. Finally, we fixed its supply by disabling the mintAuthority so that no more tokens can be minted.

Here is a list of wallets provided by quicknode that you can use for transferring your tokens to different wallet addresses: [test wallets](https://github.com/quiknode-labs/qn-guide-examples/blob/main/solana/bulk-sol-drop/dropList.ts).

**Github code** [here](https://github.com/AJcodes42/fungible-token-operator).

**References:**

1. [https://www.youtube.com/watch?v=8NeZgmSfbYg&t=2436s](https://www.youtube.com/watch?v=8NeZgmSfbYg&t=2436s%EF%BF%BC2)

2. [https://www.quicknode.com/guides/solana-development/spl-tokens/how-to-transfer-spl-tokens-on-solana/](https://www.quicknode.com/guides/solana-development/spl-tokens/how-to-transfer-spl-tokens-on-solana/)