solana-mobile
Solana Mobileの技術を活用し、モバイルウォレットアダプターや安全なストレージ、React NativeのdAppパターンを用いて、スマホに最適化されたSolanaアプリを開発するSkill。
📜 元の英語説明(参考)
Solana Mobile development with Mobile Wallet Adapter (MWA), Seeker device integration, SeedVault secure storage, and React Native dApp patterns for building mobile-first Solana applications.
🇯🇵 日本人クリエイター向け解説
Solana Mobileの技術を活用し、モバイルウォレットアダプターや安全なストレージ、React NativeのdAppパターンを用いて、スマホに最適化されたSolanaアプリを開発するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o solana-mobile.zip https://jpskill.com/download/10111.zip && unzip -o solana-mobile.zip && rm solana-mobile.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10111.zip -OutFile "$d\solana-mobile.zip"; Expand-Archive "$d\solana-mobile.zip" -DestinationPath $d -Force; ri "$d\solana-mobile.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
solana-mobile.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
solana-mobileフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Solana Mobile 開発スキル
Mobile Wallet Adapter、Seeker デバイス統合、SeedVault サポートを使用して、Solana 上でモバイル dApp を構築するための専門知識。
概要
このスキルは、Solana ブロックチェーン上でモバイルアプリケーションを開発するための包括的なガイダンスを提供します。特に以下に焦点を当てています。
- Mobile Wallet Adapter (MWA) - モバイル dApp をウォレットに接続するためのプロトコル
- Solana Mobile Seeker - Seeker デバイスの検出と最適化
- SeedVault - Solana Mobile デバイス上の安全な鍵ストレージ
- React Native 統合 - クロスプラットフォームのモバイル dApp の構築
- dApp Store 公開 - Solana dApp Store へのアプリの提出
このスキルを使用するタイミング
以下の場合にこのスキルを有効にします。
- Solana 用の React Native dApp を構築する場合
- Mobile Wallet Adapter を実装する場合
- Solana Mobile Seeker ユーザーを検出する場合
- 安全な鍵ストレージのために SeedVault と統合する場合
- Solana dApp Store に公開する場合
- モバイルユーザーエクスペリエンスを最適化する場合
- Sign-In With Solana (SIWS) を実装する場合
コアコンセプト
Mobile Wallet Adapter (MWA)
MWA は、モバイル dApp とウォレットアプリ間の安全な通信を可能にするプロトコルです。
主な機能:
- 安全な WebSocket ベースの通信
- セッションベースの認証
- トランザクション署名
- メッセージ署名
- 複数ウォレットのサポート
プロトコルフロー:
- 関連付け (Association) - URI スキームを介して接続を確立
- セッション確立 (Session Establishment) - ECDH 鍵交換
- 認証 (Authorization) - ウォレットアクセスをリクエスト
- 特権メソッド (Privileged Methods) - トランザクション/メッセージに署名
Solana Mobile Seeker
Seeker は、暗号機能が組み込まれた Solana のフラッグシップモバイルデバイスです。
検出方法:
- プラットフォーム定数 (Platform Constants) (クライアント側、偽装可能)
- Genesis Token 検証 (Genesis Token Verification) (オンチェーン、保証)
Seeker の機能:
- SeedVault 安全なストレージ
- 最適化された Solana パフォーマンス
- Seeker Genesis Token (SGT)
- ネイティブ dApp Store 統合
SeedVault
Solana Mobile デバイスで秘密鍵を保存するための安全なエンクレーブ。
利点:
- ハードウェアベースのセキュリティ
- 生体認証
- 安全な鍵導出
- アプリメモリから隔離
実装パターン
1. Mobile Wallet Adapter のセットアップ
依存関係のインストール
npm install @solana-mobile/mobile-wallet-adapter-protocol \
@solana-mobile/mobile-wallet-adapter-protocol-web3js \
@solana/web3.js \
react-native-quick-crypto
Polyfill の設定
polyfill.js を作成:
import { install } from 'react-native-quick-crypto';
install();
index.js を作成:
import './polyfill';
import 'expo-router/entry';
package.json を更新:
{
"main": "./index.js"
}
MWA プロバイダーのセットアップ
import {
ConnectionProvider,
RPC_ENDPOINT,
} from '@solana/web3.js';
import {
SolanaMobileWalletAdapter,
} from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
export function MobileWalletProvider({ children }) {
return (
<ConnectionProvider endpoint={RPC_ENDPOINT}>
<SolanaMobileWalletAdapter
cluster="mainnet-beta"
appIdentity={{
name: 'Your dApp',
uri: 'https://yourdapp.com',
icon: 'favicon.ico',
}}
>
{children}
</SolanaMobileWalletAdapter>
</ConnectionProvider>
);
}
2. 認証フロー
import { transact } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
async function authorizeWallet() {
const result = await transact(async (wallet) => {
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: {
name: 'Obscura DEX',
uri: 'https://obscura.finance',
icon: 'icon.png',
},
features: [
'solana:signMessages',
'solana:signAndSendTransaction',
],
});
return {
accounts: authResult.accounts,
authToken: authResult.auth_token,
walletUriBase: authResult.wallet_uri_base,
};
});
return result;
}
3. トランザクションの署名と送信
import { Transaction } from '@solana/web3.js';
import { transact } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
async function signAndSendTransaction(transaction: Transaction) {
const result = await transact(async (wallet) => {
// Authorize if needed
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: APP_IDENTITY,
});
// Get latest blockhash
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = authResult.accounts[0].publicKey;
// Sign and send
const signedTxs = await wallet.signAndSendTransactions({
transactions: [transaction],
});
return signedTxs[0];
});
return result;
}
4. メッセージの署名
async function signMessage(message: string) {
const result = await transact(async (wallet) => {
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: APP_IDENTITY,
});
const encodedMessage = new TextEncoder().encode(message);
const signedMessages = await wallet.signMessages({
addresses: [authResult.accounts[0].address],
payloads: [encodedMessage],
});
return {
signature: signedMessages.signed_payloads[0],
address: authResult.accounts[0].address,
};
});
return result;
}
5. Seeker の検出 (プラットフォーム定数)
import { Platform } from 'react-native';
function isSeekerDevice(): boolean {
return Platform.constants?.Model === 'Seeker';
}
function getSeekerInfo() {
if (!isSeekerDevice()) {
return null;
}
return {
model: Platform.constants.Model,
brand: Platform.constants.Brand,
manufacturer: Platform.constants.Manufacturer,
fingerprint: Platform.constants.Fingerprint,
};
}
// Usage
if (isSeekerDevice()) {
console.log('Running on Seeker device!');
// Show Seeker-specific UI
}
(原文がここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Solana Mobile Development Skill
Expert knowledge for building mobile dApps on Solana with Mobile Wallet Adapter, Seeker device integration, and SeedVault support.
Overview
This skill provides comprehensive guidance for developing mobile applications on the Solana blockchain, with focus on:
- Mobile Wallet Adapter (MWA) - Protocol for connecting mobile dApps to wallets
- Solana Mobile Seeker - Detecting and optimizing for Seeker devices
- SeedVault - Secure key storage on Solana Mobile devices
- React Native Integration - Building cross-platform mobile dApps
- dApp Store Publishing - Submitting apps to Solana dApp Store
When to Use This Skill
Activate this skill when:
- Building React Native dApps for Solana
- Implementing Mobile Wallet Adapter
- Detecting Solana Mobile Seeker users
- Integrating with SeedVault for secure key storage
- Publishing to Solana dApp Store
- Optimizing mobile user experience
- Implementing Sign-In With Solana (SIWS)
Core Concepts
Mobile Wallet Adapter (MWA)
MWA is a protocol that enables secure communication between mobile dApps and wallet apps.
Key Features:
- Secure WebSocket-based communication
- Session-based authorization
- Transaction signing
- Message signing
- Multi-wallet support
Protocol Flow:
- Association - Establish connection via URI scheme
- Session Establishment - ECDH key exchange
- Authorization - Request wallet access
- Privileged Methods - Sign transactions/messages
Solana Mobile Seeker
Seeker is Solana's flagship mobile device with built-in crypto features.
Detection Methods:
- Platform Constants (Client-side, spoofable)
- Genesis Token Verification (On-chain, guaranteed)
Seeker Features:
- SeedVault secure storage
- Optimized Solana performance
- Seeker Genesis Token (SGT)
- Native dApp Store integration
SeedVault
Secure enclave for storing private keys on Solana Mobile devices.
Benefits:
- Hardware-backed security
- Biometric authentication
- Secure key derivation
- Isolated from app memory
Implementation Patterns
1. Mobile Wallet Adapter Setup
Install Dependencies
npm install @solana-mobile/mobile-wallet-adapter-protocol \
@solana-mobile/mobile-wallet-adapter-protocol-web3js \
@solana/web3.js \
react-native-quick-crypto
Configure Polyfills
Create polyfill.js:
import { install } from 'react-native-quick-crypto';
install();
Create index.js:
import './polyfill';
import 'expo-router/entry';
Update package.json:
{
"main": "./index.js"
}
MWA Provider Setup
import {
ConnectionProvider,
RPC_ENDPOINT,
} from '@solana/web3.js';
import {
SolanaMobileWalletAdapter,
} from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
export function MobileWalletProvider({ children }) {
return (
<ConnectionProvider endpoint={RPC_ENDPOINT}>
<SolanaMobileWalletAdapter
cluster="mainnet-beta"
appIdentity={{
name: 'Your dApp',
uri: 'https://yourdapp.com',
icon: 'favicon.ico',
}}
>
{children}
</SolanaMobileWalletAdapter>
</ConnectionProvider>
);
}
2. Authorization Flow
import { transact } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
async function authorizeWallet() {
const result = await transact(async (wallet) => {
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: {
name: 'Obscura DEX',
uri: 'https://obscura.finance',
icon: 'icon.png',
},
features: [
'solana:signMessages',
'solana:signAndSendTransaction',
],
});
return {
accounts: authResult.accounts,
authToken: authResult.auth_token,
walletUriBase: authResult.wallet_uri_base,
};
});
return result;
}
3. Sign and Send Transaction
import { Transaction } from '@solana/web3.js';
import { transact } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
async function signAndSendTransaction(transaction: Transaction) {
const result = await transact(async (wallet) => {
// Authorize if needed
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: APP_IDENTITY,
});
// Get latest blockhash
const { blockhash } = await connection.getLatestBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = authResult.accounts[0].publicKey;
// Sign and send
const signedTxs = await wallet.signAndSendTransactions({
transactions: [transaction],
});
return signedTxs[0];
});
return result;
}
4. Sign Message
async function signMessage(message: string) {
const result = await transact(async (wallet) => {
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: APP_IDENTITY,
});
const encodedMessage = new TextEncoder().encode(message);
const signedMessages = await wallet.signMessages({
addresses: [authResult.accounts[0].address],
payloads: [encodedMessage],
});
return {
signature: signedMessages.signed_payloads[0],
address: authResult.accounts[0].address,
};
});
return result;
}
5. Seeker Detection (Platform Constants)
import { Platform } from 'react-native';
function isSeekerDevice(): boolean {
return Platform.constants?.Model === 'Seeker';
}
function getSeekerInfo() {
if (!isSeekerDevice()) {
return null;
}
return {
model: Platform.constants.Model,
brand: Platform.constants.Brand,
manufacturer: Platform.constants.Manufacturer,
fingerprint: Platform.constants.Fingerprint,
};
}
// Usage
if (isSeekerDevice()) {
console.log('Running on Seeker device!');
// Show Seeker-specific UI
}
6. Seeker Genesis Token Verification
Client-Side: Sign-In With Solana (SIWS)
async function signInWithSolana() {
const result = await transact(async (wallet) => {
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: APP_IDENTITY,
sign_in_payload: {
domain: 'obscura.finance',
statement: 'Sign in to verify Seeker ownership',
uri: 'https://obscura.finance',
version: '1',
chainId: 'solana:mainnet',
nonce: generateNonce(),
issuedAt: new Date().toISOString(),
},
});
return {
walletAddress: authResult.accounts[0].address,
signInResult: authResult.sign_in_result,
};
});
// Send to backend for verification
const isVerified = await verifyOnBackend(result);
return isVerified;
}
Server-Side: Verify SIWS + Check SGT
import { verifySignIn } from '@solana/wallet-standard-util';
import { Connection, PublicKey } from '@solana/web3.js';
// Step 1: Verify SIWS signature
async function verifySIWS(signInPayload, signInResult): Promise<boolean> {
const serializedOutput = {
account: {
publicKey: new Uint8Array(signInResult.account.publicKey),
...signInResult.account,
},
signature: new Uint8Array(signInResult.signature),
signedMessage: new Uint8Array(signInResult.signedMessage),
};
return verifySignIn(signInPayload, serializedOutput);
}
// Step 2: Check for Seeker Genesis Token
async function checkSeekerGenesisToken(
walletAddress: string,
heliusApiKey: string
): Promise<boolean> {
const response = await fetch(
`https://api.helius.xyz/v0/addresses/${walletAddress}/balances?api-key=${heliusApiKey}`
);
const data = await response.json();
// Check for Seeker Genesis Token
// SGT Collection: https://solscan.io/collection/...
const hasSGT = data.tokens?.some(
(token) => token.mint === 'SEEKER_GENESIS_TOKEN_MINT'
);
return hasSGT;
}
// Step 3: Combined verification
async function verifySeekerUser(signInResult, heliusApiKey): Promise<boolean> {
// Verify SIWS signature
const siwsVerified = await verifySIWS(
signInResult.payload,
signInResult.result
);
if (!siwsVerified) {
return false;
}
// Check SGT ownership
const hasSGT = await checkSeekerGenesisToken(
signInResult.walletAddress,
heliusApiKey
);
return hasSGT;
}
7. SeedVault Integration
// SeedVault is automatically used by MWA-compatible wallets
// No additional code needed - keys are stored securely
// To leverage SeedVault features:
async function requestBiometricAuth() {
// Wallet apps handle biometric auth automatically
// when accessing SeedVault keys
const result = await transact(async (wallet) => {
// This will trigger biometric prompt if enabled
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: APP_IDENTITY,
});
return authResult;
});
return result;
}
8. Reauthorization (Persistent Sessions)
// Store auth token securely
import AsyncStorage from '@react-native-async-storage/async-storage';
async function saveAuthToken(authToken: string) {
await AsyncStorage.setItem('mwa_auth_token', authToken);
}
async function getAuthToken(): Promise<string | null> {
return await AsyncStorage.getItem('mwa_auth_token');
}
// Reauthorize with stored token
async function reauthorize() {
const authToken = await getAuthToken();
if (!authToken) {
return authorizeWallet(); // First time auth
}
try {
const result = await transact(async (wallet) => {
const authResult = await wallet.authorize({
cluster: 'solana:mainnet',
identity: APP_IDENTITY,
auth_token: authToken, // Reuse token
});
// Save new token if updated
await saveAuthToken(authResult.auth_token);
return authResult;
});
return result;
} catch (error) {
// Token expired, request new auth
await AsyncStorage.removeItem('mwa_auth_token');
return authorizeWallet();
}
}
Best Practices
Security
-
Never Request Private Keys
- Always use MWA signing methods
- Never ask users for seed phrases
- Trust wallet apps for key management
-
Verify Signatures
- Always verify SIWS signatures on backend
- Use on-chain verification for critical features
- Don't trust client-side checks alone
-
Secure Token Storage
- Use AsyncStorage for auth tokens
- Encrypt sensitive data
- Clear tokens on logout
User Experience
-
Handle Wallet Not Installed
try { await transact(async (wallet) => { // ... wallet operations }); } catch (error) { if (error.message.includes('No wallet found')) { // Show wallet installation prompt showInstallWalletDialog(); } } -
Loading States
const [isConnecting, setIsConnecting] = useState(false); async function connect() { setIsConnecting(true); try { await authorizeWallet(); } finally { setIsConnecting(false); } } -
Error Handling
try { await signAndSendTransaction(tx); } catch (error) { if (error.message.includes('User rejected')) { showToast('Transaction cancelled'); } else if (error.message.includes('Insufficient funds')) { showToast('Insufficient SOL balance'); } else { showToast('Transaction failed'); } }
Performance
-
Reuse Connections
- Store auth tokens
- Reauthorize instead of fresh auth
- Use wallet_uri_base for faster connections
-
Batch Transactions
await wallet.signAndSendTransactions({ transactions: [tx1, tx2, tx3], // Batch multiple }); -
Optimize for Seeker
if (isSeekerDevice()) { // Use optimized settings for Seeker connection.commitment = 'confirmed'; // Faster }
Common Patterns
Pattern 1: Connect Button
function ConnectWalletButton() {
const [wallet, setWallet] = useState(null);
const [loading, setLoading] = useState(false);
async function handleConnect() {
setLoading(true);
try {
const result = await reauthorize();
setWallet(result.accounts[0]);
} catch (error) {
console.error('Connection failed:', error);
} finally {
setLoading(false);
}
}
if (wallet) {
return (
<View>
<Text>Connected: {wallet.address.slice(0, 8)}...</Text>
</View>
);
}
return (
<Button
title={loading ? 'Connecting...' : 'Connect Wallet'}
onPress={handleConnect}
disabled={loading}
/>
);
}
Pattern 2: Seeker-Specific UI
function SeekerBanner() {
const isSeeker = isSeekerDevice();
const [hasGenesisToken, setHasGenesisToken] = useState(false);
useEffect(() => {
if (isSeeker) {
verifyGenesisToken().then(setHasGenesisToken);
}
}, [isSeeker]);
if (!isSeeker) return null;
return (
<View style={styles.seekerBanner}>
<Text>🎉 Seeker Device Detected!</Text>
{hasGenesisToken && (
<Text>✅ Genesis Token Verified</Text>
)}
</View>
);
}
Pattern 3: Transaction with Confirmation
async function sendTransactionWithConfirmation(transaction: Transaction) {
// Sign and send
const signature = await signAndSendTransaction(transaction);
// Wait for confirmation
const confirmation = await connection.confirmTransaction(
signature,
'confirmed'
);
if (confirmation.value.err) {
throw new Error('Transaction failed');
}
return signature;
}
Publishing to dApp Store
1. Build APK
# For Expo
eas build --platform android --profile production
# For React Native
cd android
./gradlew assembleRelease
2. Sign APK
# Generate keystore
keytool -genkey -v -keystore my-release-key.keystore \
-alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
# Sign APK
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 \
-keystore my-release-key.keystore \
app-release-unsigned.apk my-key-alias
3. Submit to dApp Store
# Install publishing CLI
npm install -g @solana-mobile/dapp-store-cli
# Login
dapp-store login
# Create app NFT (first time only)
dapp-store create
# Submit release
dapp-store publish \
--apk ./app-release.apk \
--requestor-is-authorized \
--complies-with-solana-dapp-store-policies
Troubleshooting
Issue: Wallet Not Connecting
Solutions:
- Check if wallet app is installed
- Verify network (devnet/mainnet)
- Clear app cache
- Reinstall wallet app
Issue: Transaction Fails
Solutions:
- Check SOL balance for fees
- Verify recent blockhash
- Check transaction size
- Ensure correct cluster
Issue: Seeker Not Detected
Solutions:
- Verify Platform.constants.Model
- Check device fingerprint
- Use Genesis Token verification
- Test on actual Seeker device
Issue: Auth Token Expired
Solutions:
- Clear stored token
- Request fresh authorization
- Implement token refresh logic
- Handle ERROR_AUTHORIZATION_FAILED
Resources
Documentation
Tools
Example Apps
Integration with Obscura DEX
Mobile-Specific Features
-
Seeker Rewards
- Detect Seeker users
- Offer reduced trading fees
- Exclusive features for SGT holders
-
Mobile-Optimized UI
- Touch-friendly controls
- Simplified trading interface
- Biometric authentication
-
Push Notifications
- Price alerts
- Order fills
- Market updates
-
Offline Capabilities
- Cache market data
- Queue transactions
- Sync when online
Last Updated: February 18, 2026