SPL Associate Token Account & Merge
In the Ethereum world, we only need an Eth address, you can use this address to receive ETH and all kinds of ERC-20 tokens.
However, in the Solana system, SPL token is basically an deposit account which is managed by the Token on-chain program(like smart contract). In wallet, you can see that every SPL token has an individual account/address and you can have even multiple accounts for a single SPL token, I know this is confusing, right ? Don’t worry, let us dive deep into the program to see how it happens.
Multiple accounts for a single SPL token
This is the code where we create accounts for our SPL token:
// step: 1 caculate balance
const balanceNeeded = await Token.getMinBalanceRentForExemptAccount(
this._connection,
);
// step2: create createAccount transaction instrument
const createAccountTrxi = SystemProgram.createAccount({
fromPubkey: account.publicKey,
newAccountPubkey: splAccount.publicKey,
lamports: balanceNeeded,
space: 165,
programId: new PublicKey(TOKEN_PROGRAM),
})
// step3: ceate init account transaction instrucment
const initAccountTrx = Token.createInitAccountInstruction(
new PublicKey(TOKEN_PROGRAM),
new PublicKey(mint),
splAccount.publicKey,
account.publicKey,
)
// step4: create transaction
const transaction = new Transaction()
transaction.add(createAccountTrxi)
transaction.add(initAccountTrx)
as you can see, we need two TransactionInstruction here:
- createAccountTrxi: Create an Account with size of 165 bytes
- initAccountTrx: Initialize the Account
This is the SPL account structure:
/// Account data.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Account {
/// The mint associated with this account
pub mint: Pubkey,
/// The owner of this account.
pub owner: Pubkey,
/// The amount of tokens this account holds.
pub amount: u64,
/// If `delegate` is `Some` then `delegated_amount` represents
/// the amount authorized by the delegate
pub delegate: COption<Pubkey>,
/// The account's state
pub state: AccountState,
/// If is_some, this is a native token, and the value logs the rent-exempt reserve. An Account
/// is required to be rent-exempt, so the value is used by the Processor to ensure that wrapped
/// SOL accounts do not drop below this threshold.
pub is_native: COption<u64>,
/// The amount delegated
pub delegated_amount: u64,
/// Optional authority to close the account.
pub close_authority: COption<Pubkey>,
}
mint is the mint address of the SPL token, owner is the SOL account, let’s ignore the other parts of the code for now. This piece of code can be executed multiple times, there is no restriction here that you can only have one SPL account for a specific mint for an owner, so that’s why you can may have multiple accounts.
Associate account
Multiple accounts are hard to manage and cause chaos. Users easily lost track of their assets and it also brings inconvenience for wallet developers. In order the optimize it, Solana has brought up a solution in the latest Wallet Integration Guide to encourage the use of associate program, meaning you can get all the SPL deposit justing using the owner address(SOL address). Woot! That’s just what we want need right?
So, how ?
Code never lie, let us look into it.
/**
* Find a valid program address
*
* Valid program addresses must fall off the ed25519 curve. This function
* iterates a nonce until it finds one that when combined with the seeds
* results in a valid program address.
*/
static async findProgramAddress(
seeds: Array<Buffer | Uint8Array>,
programId: PublicKey,
): Promise<PublicKeyNonce>
findProgramAddress
is a function of PublicKey provided byweb3.js,what it does is to use program_id and a random number to generate a public key,this key can be used as an Account address, by using this function:
/**
* Get the address for the associated token account
*
* @param associatedProgramId SPL Associated Token program account
* @param programId SPL Token program account
* @param mint Token mint account
* @param owner Owner of the new account
* @return Public key of the associated token account
*/
static async getAssociatedTokenAddress(
associatedProgramId: PublicKey,
programId: PublicKey,
mint: PublicKey,
owner: PublicKey,
): Promise<PublicKey> {
return (
await PublicKey.findProgramAddress(
[owner.toBuffer(), programId.toBuffer(), mint.toBuffer()],
associatedProgramId,
)
)[0];
}
The Token program use the owner address, mint address, and AssociatedProgramId program address as nounce to generate the unique address of a SPL token for the owner. As long as we use this address, we will never lose track of the token assets.
Merge
To help our users to manage their assets all in one address, we create a merge function to help transfer the token assets in other addresses to associate address. If you have balance more that 0 for a token in other addresses othan the associate address, we will show this Merge button to combine the assets for you.
And for transfer, you do not need to specifically indicate which deposit address of a token, you can always use SOL address(owner account) to receive SPL assets.
Conclusion
The Associate token program solves the problem caused by multiple deposit addresses for a single token assets, generally the whole deposit address concept for different tokens is hidden. The token management and transfer are very intuitive, especially for the users who has been used to the Ethereum operations. Solana experience is getting better and better, looking forward to the bright future of it!