トークンアカウントの作成

トークンアカウントとは

トークンアカウントは、Solana上の1つのミントと1つのトークンアカウントオーナーのためのトークンを保管します。

Token Account Type
/// 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_native.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>,
}

ここで、*rsowner*とは、token accountからトークンを転送、バーン、または委任できる権限を意味します。アカウントのprogram ownerは依然としてToken ProgramまたはToken Extensions Programです。

各token accountは正確に1つのミントに紐付けられています。つまり、token accountはtoken accountの*rsmint*フィールドで識別される1つのトークンの単位のみを保持できます。

Associated Token Accountとは

associated token account(ATA)は、ウォレットとミントのデフォルトのtoken accountです。 Associated Token Programは、ウォレットアドレス、トークンプログラムアドレス、およびミントアドレスからATAアドレスを導出します。

Associated Token Programによって作成されたtoken accountのみがassociated token accountと呼ばれます。

Associated Token Programは、標準的で決定論的なアドレスでtoken accountを作成する方法です。作成されたアカウントは依然としてToken ProgramまたはToken Extensions Programが所有するtoken accountであり、Associated Token Programが所有するわけではありません。

Associated Token Programは、 address.rsに示されているようにATAアドレスを導出します:

Associated Token Account Address Derivation
pub fn get_associated_token_address_and_bump_seed_internal(
wallet_address: &Pubkey,
token_mint_address: &Pubkey,
program_id: &Pubkey,
token_program_id: &Pubkey,
) -> (Pubkey, u8) {
Pubkey::find_program_address(
&[
&wallet_address.to_bytes(), // Owner's public key
&token_program_id.to_bytes(), // Token Program or Token Extension Program
&token_mint_address.to_bytes(), // Token mint address
],
program_id, // Associated Token Program ID
)
}

ウォレット、トークンプログラム、ミントの組み合わせごとに、正確に1つのATAアドレスが存在します。Associated Token Programはそのアドレスに標準的なtoken accountを作成し、作成されたアカウントは依然としてToken ProgramまたはToken Extensions Programで定義された*rsAccount*タイプを使用します。

Associated Token Accountの作成方法

Associated Token Accountの作成には、Associated Token Programの*rsCreateまたはrsCreateIdempotent*インストラクションを使用します。Associated Token ProgramはATAアドレスを導出し、ATAアドレスにアカウントを作成し、そのアカウントをToken ProgramまたはToken Extension Programが所有するtoken accountとして初期化します。

推奨

ほとんどのアプリケーションでは、System ProgramとToken Programのinstructionsを直接呼び出してtoken accountを作成するのではなく、Associated Token Programを通じてtoken accountを作成してください。associated token accountは、所有者、Token Program、およびMintから導出される決定論的なアドレスを使用するため、ウォレットやアプリケーションが特定のMintのデフォルトtoken accountを見つけやすくなります。

ソースリファレンス

項目説明ソース
Create導出されたATAアドレスにassociated token accountを作成します。ソース
CreateIdempotentassociated token accountを作成しますが、同じ所有者とMintのATAが既に存在する場合でも成功します。ソース
process_create_associated_token_accountATAアドレスを導出し、*rscreate_pda_account*と選択されたToken ProgramへのCPIを使用してtoken accountを初期化します。選択されたProgramがToken Extension Programの場合、ATAプロセッサは不変の所有者拡張機能も初期化します。ソース
create_pda_account*rsprocess_create_associated_token_account*が使用するヘルパーで、System ProgramへのCPIによってPDAアカウントを作成します。ソース

Typescript

以下のKit例は、@solana/kitを使用した推奨アプローチを示しています。 @solana/web3.jsを使用したレガシー例も参考として含まれています。

Kit

import { generateKeyPairSigner } from "@solana/kit";
import { createLocalClient } from "@solana/kit-client-rpc";
import {
associatedTokenProgram,
findAssociatedTokenPda,
tokenProgram,
TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";
const client = await createLocalClient()
.use(tokenProgram())
.use(associatedTokenProgram());
const result = await client.associatedToken.instructions
.createAssociatedToken({
payer: client.payer, // Account funding account creation.
mint: mint.address, // Mint for the token this account holds.
owner: client.payer.address // Account that owns the token account.
})
.sendTransaction();
const [associatedTokenAddress] = await findAssociatedTokenPda({
mint: mint.address,
owner: client.payer.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS
});
const tokenAccountData = await client.token.accounts.token.fetch(
associatedTokenAddress
);
console.log("Mint Address:", mint.address);
console.log("\nAssociated Token Account Address:", associatedTokenAddress);
console.log("Associated Token Account:", tokenAccountData.data);
console.log("\nTransaction Signature:", result.context.signature);
Console
Click to execute the code.

Web3.js

import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";
import {
createAssociatedTokenAccount,
createMint,
getAccount,
TOKEN_PROGRAM_ID
} from "@solana/spl-token";
const associatedTokenAccount = await createAssociatedTokenAccount(
connection, // Connection to the local validator.
feePayer, // Account funding account creation.
mintPubkey, // Mint for the token this account holds.
feePayer.publicKey, // Account that owns the token account.
{
commitment: "confirmed" // Confirmation options for the transaction.
},
TOKEN_PROGRAM_ID // Token program to invoke.
);
const tokenAccountData = await getAccount(
connection,
associatedTokenAccount,
"confirmed",
TOKEN_PROGRAM_ID
);
console.log("Mint Address:", mintPubkey.toBase58());
console.log(
"\nAssociated Token Account Address:",
associatedTokenAccount.toBase58()
);
console.log("Associated Token Account:", tokenAccountData);
Console
Click to execute the code.

Rust

Rust
use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{
program_pack::Pack,
signature::{Keypair, Signer},
transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_associated_token_account_interface::{
address::get_associated_token_address, instruction::create_associated_token_account,
};
use spl_token_interface::{
id as token_program_id,
instruction::initialize_mint,
state::{Account, Mint},
};
#[tokio::main]
async fn main() -> Result<()> {
let client = RpcClient::new_with_commitment(
String::from("http://localhost:8899"),
CommitmentConfig::confirmed(),
);
let transaction = Transaction::new_signed_with_payer(
&[
create_associated_token_account(
&fee_payer.pubkey(), // Account funding account creation.
&fee_payer.pubkey(), // Account that owns the token account.
&mint.pubkey(), // Mint for the token this account holds.
&token_program_id(), // Token program that owns the account.
),
],
Some(&fee_payer.pubkey()),
&[&fee_payer],
latest_blockhash,
);
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
let associated_token_account = get_associated_token_address(&fee_payer.pubkey(), &mint.pubkey());
let token_account = client.get_account(&associated_token_account).await?;
let token_data = Account::unpack(&token_account.data)?;
println!("Mint Address: {}", mint.pubkey());
println!(
"\nAssociated Token Account Address: {}",
associated_token_account
);
println!("Associated Token Account: {:#?}", token_data);
println!("\nTransaction Signature: {}", transaction_signature);
Ok(())
}
Console
Click to execute the code.

Python

Python
#!/usr/bin/env python3
import asyncio
import json
from solana.rpc.async_api import AsyncClient
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.system_program import create_account, CreateAccountParams
from solders.transaction import Transaction
from spl.token.async_client import AsyncToken
from spl.token.instructions import (
create_associated_token_account,
get_associated_token_address,
initialize_mint,
InitializeMintParams,
)
from spl.token.constants import MINT_LEN, TOKEN_PROGRAM_ID
async def main():
rpc = AsyncClient("http://localhost:8899")
fee_payer = Keypair()
owner = Keypair()
async with rpc:
create_associated_token_account_instruction = create_associated_token_account(
payer=fee_payer.pubkey(), # Account funding account creation.
owner=owner.pubkey(), # Account that owns the token account.
mint=mint.pubkey(), # Mint for the token this account holds.
token_program_id=TOKEN_PROGRAM_ID, # Token program that owns the new token account.
)
latest_blockhash = await rpc.get_latest_blockhash()
transaction = Transaction(
[fee_payer],
Message([create_associated_token_account_instruction], fee_payer.pubkey()),
latest_blockhash.value.blockhash,
)
result = await rpc.send_transaction(transaction)
token_account_info = await token.get_account_info(associated_token_account)
token_account = {
key: str(value) if isinstance(value, Pubkey) else value
for key, value in token_account_info._asdict().items()
}
print("Mint Address:", mint.pubkey())
print("\nToken Account Address:", associated_token_account)
print("Token Account:")
print(json.dumps(token_account, indent=2))
print("\nTransaction Signature:", result.value)
if __name__ == "__main__":
asyncio.run(main())
Console
Click to execute the code.

token accountの作成方法

token accountの作成には2つのinstructionsが必要です:

  1. System ProgramのCreateAccount instructionは、新しいrent免除アカウントを作成し、Token Programを新しいアカウントのプログラム所有者として割り当てます。
  2. Token ProgramのInitializeAccountInitializeAccount2、またはInitializeAccount3 instructionは、ミントと所有者用に新しいアカウントを初期化します。

CreateAccount instructionとtoken account初期化instructionを同じトランザクションに含めてください。

token accountの初期化中、Token Programはアカウントがまだ初期化されておらず、rent免除されていることを確認します。

以下のセクションでは、System ProgramとToken Program instructionsを直接呼び出してtoken accountを作成する方法を示しています。ほとんどのアプリケーションでは、代わりにAssociated Token Programを使用してください。associated token accountを使用しない特定の理由がある場合、または独自のSolanaプログラムからSystem ProgramとToken Program instructionsにCPIを行ってカスタムPDA token accountsを作成する必要がある場合は、System ProgramとToken Programの直接呼び出しを使用してください。

ソース参照

項目説明Token ProgramToken Extensions Program
Accountすべてのtoken accountに保存される基本的なtoken accountフィールド。ソースソース
InitializeAccountアカウントリストに所有者とrent sysvarアカウントを期待するtoken account初期化instruction。ソースソース
InitializeAccount2アカウントリストの代わりにinstruction dataで所有者を渡すtoken account初期化instruction。ソースソース
InitializeAccount3instruction dataで所有者を渡し、rent sysvarアカウントを必要としないtoken account初期化instruction。ソースソース
_process_initialize_accounttoken account初期化のための共有プロセッサロジック。ソースソース
process_initialize_account*rsInitializeAccount*のパブリックハンドラ。ソースソース
process_initialize_account2*rsInitializeAccount2*のパブリックハンドラ。ソースソース
process_initialize_account3*rsInitializeAccount3*のパブリックハンドラ。ソースソース

Typescript

以下の Kit の例は、@solana/kit を使用した推奨アプローチを示しています。 @solana/web3.js を使用したレガシー例も参考として含まれています。

Kit

import { generateKeyPairSigner } from "@solana/kit";
import { createLocalClient } from "@solana/kit-client-rpc";
import { systemProgram } from "@solana-program/system";
import {
getTokenSize,
tokenProgram,
TOKEN_PROGRAM_ADDRESS
} from "@solana-program/token";
const client = await createLocalClient()
.use(systemProgram())
.use(tokenProgram());
const result = await client.sendTransaction([
client.system.instructions.createAccount({
newAccount: tokenAccount, // New token account to create.
lamports: rent, // Lamports funding the new account rent.
space, // Account size in bytes.
programAddress: TOKEN_PROGRAM_ADDRESS // Program that owns the new account.
}),
client.token.instructions.initializeAccount({
account: tokenAccount.address, // Token account to initialize.
mint: mint.address, // Mint for the token this account holds.
owner: client.payer.address // Account that owns the token account.
})
]);
const tokenAccountData = await client.token.accounts.token.fetch(
tokenAccount.address
);
console.log("Mint Address:", mint.address);
console.log("\nToken Account Address:", tokenAccount.address);
console.log("Token Account:", tokenAccountData.data);
console.log("\nTransaction Signature:", result.context.signature);
Console
Click to execute the code.

Web3.js

import { Connection, Keypair, LAMPORTS_PER_SOL } from "@solana/web3.js";
import {
createAccount,
createMint,
getAccount,
TOKEN_PROGRAM_ID
} from "@solana/spl-token";
const tokenAccount = await createAccount(
connection, // Connection to the local validator.
feePayer, // Account paying transaction fees.
mintPubkey, // Mint for the token this account holds.
feePayer.publicKey, // Account that owns the token account.
Keypair.generate(), // New token account to create.
{
commitment: "confirmed" // Confirmation options for the transaction.
},
TOKEN_PROGRAM_ID // Token program to invoke.
);
const tokenAccountData = await getAccount(
connection,
tokenAccount,
"confirmed",
TOKEN_PROGRAM_ID
);
console.log("Mint Address:", mintPubkey.toBase58());
console.log("\nToken Account Address:", tokenAccount.toBase58());
console.log("Token Account:", tokenAccountData);
Console
Click to execute the code.

Rust

Rust
use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{
program_pack::Pack,
signature::{Keypair, Signer},
transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_token_interface::{
id as token_program_id,
instruction::{initialize_account, initialize_mint},
state::{Account, Mint},
};
#[tokio::main]
async fn main() -> Result<()> {
let client = RpcClient::new_with_commitment(
String::from("http://localhost:8899"),
CommitmentConfig::confirmed(),
);
let token_account = Keypair::new();
let token_account_rent = client
.get_minimum_balance_for_rent_exemption(Account::LEN)
.await?;
let transaction = Transaction::new_signed_with_payer(
&[
create_account(
&fee_payer.pubkey(), // Account funding account creation.
&token_account.pubkey(), // New token account to create.
token_account_rent, // Lamports funding the new account rent.
Account::LEN as u64, // Account size in bytes.
&token_program_id(), // Program that owns the new account.
),
initialize_account(
&token_program_id(),
&token_account.pubkey(), // Token account to initialize.
&mint.pubkey(), // Mint for the token this account holds.
&fee_payer.pubkey(), // Account that owns the token account.
)?,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &token_account],
latest_blockhash,
);
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
let token_account_data = client.get_account(&token_account.pubkey()).await?;
let token_data = Account::unpack(&token_account_data.data)?;
println!("Mint Address: {}", mint.pubkey());
println!("\nToken Account Address: {}", token_account.pubkey());
println!("Token Account: {:#?}", token_data);
println!("\nTransaction Signature: {}", transaction_signature);
Ok(())
}
Console
Click to execute the code.

Python

Python
#!/usr/bin/env python3
import asyncio
import json
from solana.rpc.async_api import AsyncClient
from solders.keypair import Keypair
from solders.message import Message
from solders.pubkey import Pubkey
from solders.system_program import create_account, CreateAccountParams
from solders.transaction import Transaction
from spl.token.async_client import AsyncToken
from spl.token.instructions import (
initialize_account,
InitializeAccountParams,
initialize_mint,
InitializeMintParams,
)
from spl.token.constants import ACCOUNT_LEN, MINT_LEN, TOKEN_PROGRAM_ID
async def main():
rpc = AsyncClient("http://localhost:8899")
async with rpc:
token_account = Keypair()
token_account_rent = (await rpc.get_minimum_balance_for_rent_exemption(ACCOUNT_LEN)).value
create_token_account_instructions = [
create_account(
CreateAccountParams(
from_pubkey=fee_payer.pubkey(), # Account funding account creation.
to_pubkey=token_account.pubkey(), # New token account to create.
lamports=token_account_rent, # Lamports funding the new account rent.
space=ACCOUNT_LEN, # Account size in bytes.
owner=TOKEN_PROGRAM_ID, # Program that owns the new token account.
)
),
initialize_account(
InitializeAccountParams(
program_id=TOKEN_PROGRAM_ID, # Token program to invoke.
account=token_account.pubkey(), # Token account to initialize.
mint=mint.pubkey(), # Mint for the token this account holds.
owner=fee_payer.pubkey(), # Account that owns the token account.
)
),
]
latest_blockhash = await rpc.get_latest_blockhash()
transaction = Transaction(
[fee_payer, token_account],
Message(create_token_account_instructions, fee_payer.pubkey()),
latest_blockhash.value.blockhash,
)
result = await rpc.send_transaction(transaction)
token_account_info = await token.get_account_info(token_account.pubkey())
token_account_data = {
key: str(value) if isinstance(value, Pubkey) else value
for key, value in token_account_info._asdict().items()
}
print("Mint Address:", mint.pubkey())
print("\nToken Account Address:", token_account.pubkey())
print("Token Account:")
print(json.dumps(token_account_data, indent=2))
print("\nTransaction Signature:", result.value)
if __name__ == "__main__":
asyncio.run(main())
Console
Click to execute the code.

Is this page helpful?

目次

ページを編集

管理運営

© 2026 Solana Foundation.
無断転載を禁じます。
つながろう