Close Mint Extension
Create a mint that can be closed once the tokens are burnt.
Summary
- The original Token Program only allowed closing token accounts, but not mint accounts.
- Token Extensions Program includes the
close mint
extension which allows mint accounts to be closed. - To close a mint with the
close mint
extension, the supply of said mint needs to be 0. - The
mintCloseAuthority
can be updated by callingsetAuthority
Overview
The original Token Program only allows owners to close token accounts, not mint
accounts. So if you create a mint, you’ll never be able to close the account.
This has resulted in a lot of wasted space on the blockchain. To remedy this,
the Token Extensions Program introduced the close mint
extension. This simply
allows a mint account to be closed and the lamports refunded. The only caveat,
is the supply of said mint needs to be 0.
This extension is a nice improvement for developers, who may have thousands of
mint accounts that could be cleaned up and be refunded for. Additionally it’s
great for NFT holders who wish to burn their NFT. They will now be able to
recuperate all of the costs, ie closing the mint, metadata and token accounts.
Whereas before, if someone burned an NFT would only recuperate the metadata and
token account’s rents. Note, the burner would also have to be the
mintCloseAuthority
.
The close mint
extension, adds an additional field mintCloseAuthority
to the
mint account. This is the address of the authority to actually close the
account.
Again, for a mint to be closed with this extension, the supply has to be 0. So if any of this token is minted, it will have to be burned first.
Create Mint with Close Authority
Initializing the mint with the close authority extension involves three instructions:
SystemProgram.createAccount
createInitializeMintCloseAuthorityInstruction
createInitializeMintInstruction
The first instruction SystemProgram.createAccount
allocates space on the
blockchain for the mint account. However like all Token Extensions Program
mints, we need to calculate the size and cost of the mint. This can be
accomplished by using getMintLen
and getMinimumBalanceForRentExemption
. In
this case, we’ll call getMintLen
with only the
ExtensionType.MintCloseAuthority
.
To get the mint length and create account instruction, do the following:
The second instruction createInitializeMintCloseAuthorityInstruction
initializes the close authority extension. The only notable parameter is the
mintCloseAuthority
in the second position. This is the address that can close
the mint.
The last instruction createInitializeMintInstruction
initializes the mint.
Finally we add the instructions to the transaction and submit it to the Nexis Native Chain network.
When the transaction is sent, a new mint account is created with the specified close authority.
Close Mint with Close Authority
To close a mint with the close mint
extension, all that is needed is to call
the closeAccount
function.
Remember, that to close the mint account, the total supply has to be 0. So if
any tokens exist, they have to be burned first. You can do this with the burn
function.
Update Close Mint Authority
To change the closeMintAuthority
you can call the setAuthority
function and
pass in the right accounts, as well as the authorityType
, which in this case
is AuthorityType.CloseMint
Lab
In this lab, we’ll create a mint with the close mint
extension. We will then
mint some of the tokens and see what happens when we try to close it with a
non-zero supply (hint, the close transaction will fail). Lastly, we will burn
the supply and close the account.
1. Getting Started
To get started, create an empty directory named close-mint
and navigate to it.
We’ll be initializing a brand new project. Run npm init
and follow through the
prompts.
Next, we’ll need to add our dependencies. Run the following to install the required packages:
Create a directory named src
. In this directory, create a file named
index.ts
. This is where we will run checks against the rules of this
extension. Paste the following code in index.ts
:
index.ts
creates a connection to the specified validator node and calls
initializeKeypair
. This is where we’ll end up calling the rest of our script
once we’ve written it.
Go ahead and run the script. You should see the payer
and mint
public key
logged to your terminal.
If you run into an error in initializeKeypair
with airdropping, follow the
next step.
2. Run validator node
For the sake of this guide, we’ll be running our own validator node.
In a separate terminal, run the following command: solana-test-validator
. This
will run the node and also log out some keys and values. The value we need to
retrieve and use in our connection is the JSON RPC URL, which in this case is
http://127.0.0.1:8899
. We then use that in the connection to specify to use
the local RPC URL.
Alternatively, if you’d like to use testnet or devnet, import the
clusterApiUrl
from @nexis-network/web3.js
and pass it to the connection as such:
If you decide to use devnet, and have issues with airdropping NZT, feel free to
add the keypairPath
parameter to initializeKeypair
. You can get this from
running solana config get
in your terminal. And then go to
faucet.nexis.network and airdrop some NZT to your
address. You can get your address from running solana address
in your
terminal.
3. Create a mint with close authority
Let’s create a closable mint by creating the function createClosableMint
in a
new file src/create-mint.ts
.
To create a closable mint, we need several instructions:
getMintLen
: Gets the space needed for the mint accountSystemProgram.getMinimumBalanceForRentExemption
: Tells us the cost of the rent for the mint accountSystemProgram.createAccount
: Creates the instruction to allocates space on Nexis Native Chain for the mint accountcreateInitializeMintCloseAuthorityInstruction
: Creates the instruction to initialize the close mint extension - this takes thecloseMintAuthority
as a parameter.createInitializeMintInstruction
: Creates the instruction to initialize the mintsendAndConfirmTransaction
: Sends the transaction to the blockchain
We’ll call all of these functions in turn. But before that, let’s define the
inputs to our createClosableMint
function:
connection: Connection
: The connection objectpayer: Keypair
: Payer for the transactionmintKeypair: Keypair
: Keypair for new mintdecimals: number
: Mint decimals
Putting it all together we get:
Now let’s call this function in src/index.ts
. First you’ll need to import our
new function. Then paste the following under the right comment section:
This will create a transaction with close mint instruction.
Feel free to run this and check that everything is working:
4. Closing the mint
We’re going to close the mint, but first, lets explore what happens when we have a supply when trying to close (hint, it’ll fail).
To do this, we are going to mint some tokens, try to close, then burn the tokens and then actually close.
4.1 Mint a token
In src/index.ts
, create an account and mint 1 token to that account.
We can accomplish this by calling 2 functions: createAccount
and mintTo
:
Now we can verify that the mint supply is non-zero by fetching the mint info. Underneath the minting functions, add the following code block:
Let’s run the script and check the initial supply:
You should see the following in your terminal:
4.2 Closing the mint with non zero supply
Now we’ll attempt to close the mint when supply is non-zero. We know this is
going to fail, since the close mint
extension requires a non-zero supply. So
to see the resulting error message, we’ll wrap the closeAccount
function in a
try catch and log out the error:
Give this a run:
We’ll see that the program throws an error along with the program logs. You should see the following:
4.3 Burning the supply
Let’s burn the whole supply so we can actually close the mint. We do this by
calling burn
:
4.4 Close the mint
With no tokens in circulation, we can now close the mint. At this point, we can
simply call closeAccount
, however, for the sake of visualizing how this works,
we’ll do the following:
-
Retrieve Mint Information: Initially, we fetch and inspect the mint’s details, particularly focusing on the supply, which should be zero at this stage. This shows that the mint is eligible to be closed.
-
Verify Account Status: Next, we confirm the status of the account to ensure that it is still open and active.
-
Close the Account: Once we’ve verified the account’s open status, we proceed to close the mint account.
-
Confirm Closure: Finally, after invoking the
closeAccount
function, we check the account status once more to confirm that it has indeed been closed successfully.
We can accomplish all of this with the following functions:
getMint
: Grabs the mint account and deserializes the informationgetAccountInfo
: Grabs the mint account, so we can check it exists - we’ll call this before and after the close.closeAccount
: Closes the mint
Putting this all together we get:
Run the script one last time.
You should see the whole process of creating a closable mint, minting a token, trying to close, burning the token, and finally closing the account.
That’s it! We have successfully created a mint with close authority. If you get
stuck at any point, you can find working code in the solution
branch of
this repository.
Challenge
For the challenge, try and create your own mint and mint to several token accounts, then create a script to burn all of those token accounts, then close the mint.