Basic Token Transfer
Copy
import { useWallet, useConnection } from '@hermis/solana-headless-react';
import { getAssociatedTokenAddress, createTransferInstruction, Transaction } from '@solana/spl-token';
import { PublicKey } from '@solana/web3.js';
function TransferTokens() {
const { publicKey, sendTransaction } = useWallet();
const { connection } = useConnection();
const transfer = async (
mintAddress: string,
recipient: string,
amount: number
) => {
if (!publicKey) return;
const mint = new PublicKey(mintAddress);
const recipientPubKey = new PublicKey(recipient);
// Get token accounts
const fromTokenAccount = await getAssociatedTokenAddress(
mint,
publicKey
);
const toTokenAccount = await getAssociatedTokenAddress(
mint,
recipientPubKey
);
// Create transaction
const transaction = new Transaction();
transaction.add(
createTransferInstruction(
fromTokenAccount,
toTokenAccount,
publicKey,
amount * Math.pow(10, 9) // With decimals
)
);
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
const signature = await sendTransaction(transaction, connection);
await connection.confirmTransaction(signature);
return signature;
};
return (
<button onClick={() => transfer('mint...', 'recipient...', 100)}>
Transfer 100 Tokens
</button>
);
}
With Associated Token Account Creation
Copy
import { useWallet, useConnection, useAnchorWallet } from '@hermis/solana-headless-react';
import { getOrCreateAssociatedTokenAccount, createTransferInstruction, Transaction } from '@solana/spl-token';
import { PublicKey } from '@solana/web3.js';
function TransferWithAccountCreation() {
const { publicKey, sendTransaction } = useWallet();
const { connection } = useConnection();
const wallet = useAnchorWallet(); // Provides Signer interface for getOrCreateAssociatedTokenAccount
const transferWithAccountCreation = async (
mint: PublicKey,
recipient: PublicKey,
amount: number
) => {
if (!publicKey || !wallet) return;
// Get or create sender's token account
const fromAccount = await getOrCreateAssociatedTokenAccount(
connection,
wallet, // AnchorWallet as fee payer
mint,
publicKey
);
// Get or create recipient's token account
const toAccount = await getOrCreateAssociatedTokenAccount(
connection,
wallet, // AnchorWallet as fee payer
mint,
recipient
);
// Transfer
const transaction = new Transaction();
transaction.add(
createTransferInstruction(
fromAccount.address,
toAccount.address,
publicKey,
amount
)
);
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = publicKey;
return await sendTransaction(transaction, connection);
};
return (
<button
onClick={() => transferWithAccountCreation(mintPubkey, recipientPubkey, 1000000)}
disabled={!wallet}
>
Transfer Tokens
</button>
);
}
Complete Component
Copy
function TokenTransfer() {
const [mint, setMint] = useState('');
const [recipient, setRecipient] = useState('');
const [amount, setAmount] = useState('');
const [sending, setSending] = useState(false);
const [signature, setSignature] = useState('');
const { publicKey, sendTransaction } = useWallet();
const { connection } = useConnection();
const handleTransfer = async () => {
setSending(true);
try {
const sig = await transfer(mint, recipient, parseFloat(amount));
setSignature(sig);
alert('Transfer successful!');
} catch (error) {
console.error('Transfer failed:', error);
alert(`Error: ${error.message}`);
} finally {
setSending(false);
}
};
return (
<div>
<input
placeholder="Token Mint Address"
value={mint}
onChange={(e) => setMint(e.target.value)}
/>
<input
placeholder="Recipient Address"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
/>
<input
type="number"
placeholder="Amount"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<button onClick={handleTransfer} disabled={sending || !publicKey}>
{sending ? 'Sending...' : 'Transfer'}
</button>
{signature && (
<p>
<a
href={`https://explorer.solana.com/tx/${signature}`}
target="_blank"
>
View Transaction
</a>
</p>
)}
</div>
);
}
Token Transfer (@solana/kit)
Copy
import { useWallet, useConnection, createKitTransaction } from '@hermis/solana-headless-react';
import { createKitSignersFromAdapter } from '@hermis/solana-headless-adapter-base';
import { HermisError, HERMIS_ERROR__WALLET_INTERACTION__FEATURE_NOT_SUPPORTED } from '@hermis/errors';
import { address } from '@solana/web-sdk';
import { getTransferCheckedInstruction, getAssociatedTokenAddressSync } from '@solana/spl-token';
import { PublicKey } from '@solana/web3.js';
function TransferTokensKit() {
const { wallet, publicKey, addressString } = useWallet();
const { connection } = useConnection();
const transfer = async (
mintAddress: string,
recipient: string,
amount: number,
decimals: number = 9
) => {
if (!wallet || !publicKey || !addressString) return;
// Create Kit signers from adapter
const { transactionSigner } = createKitSignersFromAdapter(
wallet.adapter,
connection
);
if (!transactionSigner) {
throw new HermisError(
HERMIS_ERROR__WALLET_INTERACTION__FEATURE_NOT_SUPPORTED,
{ feature: 'transactions' }
);
}
const mint = new PublicKey(mintAddress);
const recipientPubKey = new PublicKey(recipient);
// Get associated token accounts
const fromTokenAccount = getAssociatedTokenAddressSync(mint, publicKey);
const toTokenAccount = getAssociatedTokenAddressSync(mint, recipientPubKey);
// Create transfer instruction
const instruction = getTransferCheckedInstruction(
fromTokenAccount,
mint,
toTokenAccount,
publicKey,
amount * Math.pow(10, decimals),
decimals
);
// Create Kit transaction with automatic blockhash
const transaction = await createKitTransaction(
connection,
address(addressString),
[instruction]
);
// Sign and send
const [signature] = await transactionSigner.signAndSendTransactions([transaction]);
console.log('Transfer signature:', signature);
return signature;
};
return (
<button onClick={() => transfer('mint...', 'recipient...', 100)}>
Transfer 100 Tokens (Kit)
</button>
);
}
- Building with @solana/kit architecture
- Need modern type-safe transaction building
- Want to integrate with Kit-native programs
- Prefer createKitTransaction for automatic blockhash handling
@solana/spl-token for token account addresses and instructions, but wraps them in a Kit transaction. For fully Kit-native token operations, watch for @solana/spl-token Kit equivalents as they become available.