Summary
- The
required memo
extension allows developers to mandate that all incoming transfers to a token account include a memo, facilitating enhanced transaction tracking and user identification. - When a transfer is initiated without a memo, the transaction will fail.
- The
required memo
extension can be disabled by callingdisableRequiredMemoTransfers
.
Overview
For certain applications, such as exchanges or financial services, tracking the
purpose or origin of a transaction is crucial. The required memo
extension
specifies that a memo is necessary for every incoming transfer to a token
account. This requirement ensures that each transaction is accompanied by
additional information, which can be used for compliance, auditing, or
user-specific purposes. If the need for strict tracking diminishes, the
requirement can be adjusted to make memos optional, offering flexibility in how
transactions are handled and recorded.
It is important to note that this is a token account extension, not a mint extension. This means individual token accounts need to enable this feature. And like all extensions, this will only work with Token Extensions Program tokens.
Creating token with required memo
Initializing a token account with required memo involves three instructions:
SystemProgram.createAccount
initializeAccountInstruction
createEnableRequiredMemoTransfersInstruction
The first instruction SystemProgram.createAccount
allocates space on the
blockchain for the token account. This instruction accomplishes three things:
- Allocates
space
- Transfers
lamports
for rent - Assigns to it's owning program
The second instruction createInitializeAccountInstruction
initializes the
account instruction.
The third instruction createEnableRequiredMemoTransfersInstruction
initializes
the token account with required memo.
When the transaction with these three instructions is sent, a new token account is created with the required memo extension.
Transferring with required memo
When transferring to a token account with the required memo
instruction
enabled, you need to send a memo first within the same transaction. We do this
by creating a memo instruction to call the Memo program. Then, we add in our
transfer instruction.
Disabling required memo
The required memo extension can be disabled given you have the authority to
modify the token account. To do this, simply call the
disableRequiredMemoTransfers
function and pass in the required arguments.
Lab
In this lab, we'll create a token account with the required memo extension. We'll then write tests to check if the extension is working as intended by attempting to transfer funds with and without a memo.
1. Setup Environment
To get started, create an empty directory named required-memo
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
:
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.
const connection = new Connection("http://127.0.0.1:8899", "confirmed");
Alternatively, if you'd like to use testnet or devnet, import the
clusterApiUrl
from @solana/web3.js
and pass it to the connection as such:
3. Helpers
When we pasted the index.ts
code from earlier, we added the following helpers
provided by the @solana-developers/helpers
package and some starting
variables.
initializeKeypair
: This function creates the keypair for thepayer
and also airdrops 1 testnet SOL to itmakeKeypairs
: This function creates keypairs without airdropping any SOL
4. Create the mint
First things first, since the required memo
extension is a token extension, we
don't need to do anything fancy with the mint. It just needs to be a Token
Extensions Program mint. That being said, we can just create one using the
createMint
function.
Let's do this in src/index.ts
:
5. Create Token Account with required memo
Let's create a new file src/token-helper.ts
and create a new function within
it called createTokenWithMemoExtension
. As the name implies, we'll use this to
create our token accounts with the required memo
extension enabled. The
function will take the following arguments:
connection
: The connection objectmint
: Public key for the new mintpayer
: Payer for the transactiontokenAccountKeypair
: The token account keypair associated with the token account
Let's start adding our code.
The first step in creating the token account is reserving space on Solana with
the SystemProgram.createAccount
method:
Now we need to initialize the token account. To create this instruction we call
createInitializeAccountInstruction
and pass in the required arguments. This
function is provided by the SPL Token package and it constructs a transaction
instruction that initializes a new token account.
The last instruction we need is the one that enables the required memo. We get
this by calling the createEnableRequiredMemoTransfersInstruction
function.
When the required memos are enabled, any transfer of tokens into the account
must include a memo.
Lastly, let's add all of the instructions to a transaction, send it to the blockchain and return the signature
Let's go back to index.ts
and create two new token accounts:
ourTokenAccountKeypair
and otherTokenAccountKeypair
using our newly created
function.
Lastly, let's call mintTo
to mint some initial tokens to
ourTokenAccountKeypair
:
Note: The required memo
extension only requires a memo on transferring, not
minting.
6. Tests
Now that we've created some accounts with the required memo
instruction. Let's
write some tests to see how they function.
We'll write 3 tests in total:
- Transferring without a memo
- Transferring with a memo
- Disabling Required Memo extension and transferring without a memo
6.1 Transfer without Memo
This first test will attempt to transfer tokens from ourTokenAccount
to
otherTokenAccount
. This test is expected to fail as there is no memo attached
to the transaction.
Run this test, you should see the following error logged out in the terminal,
meaning the extension is working as intended:
✅ - We expected this to fail because you need to send a memo with the transfer.
6.2 Test transfer with memo
This test will attempt to transfer tokens with a memo. This test is expected to pass. Pay extra attention to the first instruction - It is the part of the transaction that adds the memo instruction to it:
Run the test and see that it passes:
6.3 Test transfer with disabled memo
In our last test, we'll disable the required memo
extension on the
otherTokenAccount
and send it some tokens without a memo. We expect this to
pass.
Run the tests. You will notice that otherTokenAccount
now has 600 tokens,
meaning it has successfully transferred without a memo after disabling the
extension.
Congratulations! We've just tested the required memo extension!
Challenge
Go create your own token account with required memo.