mobile wallet fixes
This commit is contained in:
parent
a9313f8b0f
commit
8c1a5760ce
202
app/page.tsx
202
app/page.tsx
|
|
@ -182,6 +182,30 @@ export default function Home() {
|
||||||
publicKey
|
publicKey
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check user's token account status and balance
|
||||||
|
console.log('Checking user token account status...');
|
||||||
|
const userTokenAccountInfo = await connection.getAccountInfo(userTokenAccount);
|
||||||
|
if (!userTokenAccountInfo) {
|
||||||
|
throw new Error('DINO token account not found. Please ensure you have DINO tokens in your wallet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get token balance
|
||||||
|
const userTokenAccounts = await connection.getParsedTokenAccountsByOwner(
|
||||||
|
publicKey,
|
||||||
|
{ mint: dinoMint }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userTokenAccounts.value.length === 0) {
|
||||||
|
throw new Error('No DINO tokens found in your wallet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const userBalance = userTokenAccounts.value[0].account.data.parsed.info.tokenAmount.uiAmount;
|
||||||
|
console.log('User DINO balance:', userBalance);
|
||||||
|
|
||||||
|
if (userBalance < ENTRY_FEE_DINO) {
|
||||||
|
throw new Error(`Insufficient DINO tokens. You have ${userBalance} DINO, but need ${ENTRY_FEE_DINO} DINO to play.`);
|
||||||
|
}
|
||||||
|
|
||||||
// Get or create the fee collector's DINO token account
|
// Get or create the fee collector's DINO token account
|
||||||
const feeCollectorTokenAccount = await getAssociatedTokenAddress(
|
const feeCollectorTokenAccount = await getAssociatedTokenAddress(
|
||||||
dinoMint,
|
dinoMint,
|
||||||
|
|
@ -193,34 +217,50 @@ export default function Home() {
|
||||||
// Check if fee collector token account exists, if not create it
|
// Check if fee collector token account exists, if not create it
|
||||||
const feeCollectorAccountInfo = await connection.getAccountInfo(feeCollectorTokenAccount);
|
const feeCollectorAccountInfo = await connection.getAccountInfo(feeCollectorTokenAccount);
|
||||||
if (!feeCollectorAccountInfo) {
|
if (!feeCollectorAccountInfo) {
|
||||||
transaction.add(
|
console.log('Creating fee collector token account...');
|
||||||
createAssociatedTokenAccountInstruction(
|
const createAccountIx = createAssociatedTokenAccountInstruction(
|
||||||
publicKey,
|
publicKey,
|
||||||
feeCollectorTokenAccount,
|
feeCollectorTokenAccount,
|
||||||
FEE_COLLECTOR,
|
FEE_COLLECTOR,
|
||||||
dinoMint
|
dinoMint
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
transaction.add(createAccountIx);
|
||||||
|
console.log('Added create account instruction');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the transfer instruction (10 DINO tokens = 10,000,000,000 lamports for 9 decimals)
|
// Add the transfer instruction (10 DINO tokens = 10,000,000,000 lamports for 9 decimals)
|
||||||
const transferAmount = ENTRY_FEE_DINO * 1_000_000_000; // 10 DINO tokens
|
const transferAmount = ENTRY_FEE_DINO * 1_000_000_000; // 10 DINO tokens
|
||||||
|
console.log('Adding transfer instruction for', ENTRY_FEE_DINO, 'DINO tokens (', transferAmount, 'lamports)');
|
||||||
|
|
||||||
transaction.add(
|
const transferIx = createTransferInstruction(
|
||||||
createTransferInstruction(
|
|
||||||
userTokenAccount,
|
userTokenAccount,
|
||||||
feeCollectorTokenAccount,
|
feeCollectorTokenAccount,
|
||||||
publicKey,
|
publicKey,
|
||||||
transferAmount
|
transferAmount
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Validate the transfer instruction
|
||||||
|
if (!transferIx.programId.equals(dinoMint)) {
|
||||||
|
console.warn('Transfer instruction program ID mismatch');
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.add(transferIx);
|
||||||
|
console.log('Added transfer instruction');
|
||||||
|
|
||||||
// Get recent blockhash with higher commitment for mobile wallets
|
// Get recent blockhash with higher commitment for mobile wallets
|
||||||
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('finalized');
|
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
|
||||||
transaction.recentBlockhash = blockhash;
|
transaction.recentBlockhash = blockhash;
|
||||||
transaction.lastValidBlockHeight = lastValidBlockHeight;
|
transaction.lastValidBlockHeight = lastValidBlockHeight;
|
||||||
transaction.feePayer = publicKey;
|
transaction.feePayer = publicKey;
|
||||||
|
|
||||||
|
// Ensure the transaction is properly formatted for mobile wallets
|
||||||
|
console.log('Transaction details before preflight:');
|
||||||
|
console.log('- Recent blockhash:', transaction.recentBlockhash);
|
||||||
|
console.log('- Last valid block height:', transaction.lastValidBlockHeight);
|
||||||
|
console.log('- Fee payer:', transaction.feePayer?.toString());
|
||||||
|
console.log('- Number of instructions:', transaction.instructions.length);
|
||||||
|
console.log('- Instructions:', transaction.instructions.map((ix, i) => `${i}: ${ix.programId.toString()}`));
|
||||||
|
|
||||||
// Validate transaction for mobile wallets
|
// Validate transaction for mobile wallets
|
||||||
const validationErrors = validateTransactionForMobile(transaction);
|
const validationErrors = validateTransactionForMobile(transaction);
|
||||||
if (validationErrors.length > 0) {
|
if (validationErrors.length > 0) {
|
||||||
|
|
@ -233,30 +273,89 @@ export default function Home() {
|
||||||
|
|
||||||
// Preflight check for mobile wallets
|
// Preflight check for mobile wallets
|
||||||
try {
|
try {
|
||||||
const { value: { err } } = await connection.simulateTransaction(transaction);
|
console.log('Running preflight check for transaction...');
|
||||||
|
const { value: { err, logs } } = await connection.simulateTransaction(transaction);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
console.warn('Preflight check failed:', err);
|
||||||
|
console.log('Preflight logs:', logs);
|
||||||
|
|
||||||
|
// For mobile wallets, we'll try to fix common issues and retry
|
||||||
|
if (isMobileDevice()) {
|
||||||
|
console.log('Attempting to fix transaction for mobile wallet...');
|
||||||
|
|
||||||
|
// Refresh blockhash and retry preflight
|
||||||
|
const { blockhash: newBlockhash, lastValidBlockHeight: newLastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
|
||||||
|
transaction.recentBlockhash = newBlockhash;
|
||||||
|
transaction.lastValidBlockHeight = newLastValidBlockHeight;
|
||||||
|
|
||||||
|
// Retry preflight with fresh blockhash
|
||||||
|
const retryResult = await connection.simulateTransaction(transaction);
|
||||||
|
if (retryResult.value.err) {
|
||||||
|
console.warn('Preflight retry also failed:', retryResult.value.err);
|
||||||
|
// On mobile, we might want to proceed anyway as some wallets handle this differently
|
||||||
|
console.log('Proceeding with transaction despite preflight failure (mobile wallet behavior)');
|
||||||
|
} else {
|
||||||
|
console.log('Preflight retry successful!');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// On desktop, be more strict about preflight failures
|
||||||
throw new Error(`Transaction simulation failed: ${err}`);
|
throw new Error(`Transaction simulation failed: ${err}`);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Preflight check passed successfully');
|
||||||
|
}
|
||||||
} catch (simError) {
|
} catch (simError) {
|
||||||
console.warn('Preflight check failed, proceeding anyway:', simError);
|
console.warn('Preflight simulation failed:', simError);
|
||||||
// On mobile, we might want to be more strict about preflight failures
|
|
||||||
|
// On mobile, we might want to proceed anyway as some wallets handle this differently
|
||||||
if (isMobileDevice()) {
|
if (isMobileDevice()) {
|
||||||
|
console.log('Proceeding with transaction despite preflight failure (mobile wallet behavior)');
|
||||||
|
} else {
|
||||||
throw new Error('Transaction preflight check failed. Please try again.');
|
throw new Error('Transaction preflight check failed. Please try again.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the transaction with mobile-optimized options
|
// Send the transaction with mobile-optimized options
|
||||||
const signature = await sendTransactionWithMobileOptimization(
|
let signature: string;
|
||||||
|
|
||||||
|
try {
|
||||||
|
signature = await sendTransactionWithMobileOptimization(
|
||||||
transaction,
|
transaction,
|
||||||
connection,
|
connection,
|
||||||
wallet,
|
wallet,
|
||||||
{
|
{
|
||||||
skipPreflight: false,
|
skipPreflight: false, // Try with preflight first
|
||||||
preflightCommitment: 'confirmed',
|
preflightCommitment: 'confirmed',
|
||||||
maxRetries: 3,
|
maxRetries: 3,
|
||||||
commitment: getMobileCommitmentLevel()
|
commitment: getMobileCommitmentLevel()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Mobile-optimized transaction failed, trying with preflight disabled...');
|
||||||
|
|
||||||
|
// If mobile-optimized fails, try with preflight disabled for mobile wallets
|
||||||
|
if (isMobileDevice()) {
|
||||||
|
try {
|
||||||
|
signature = await sendTransactionWithMobileOptimization(
|
||||||
|
transaction,
|
||||||
|
connection,
|
||||||
|
wallet,
|
||||||
|
{
|
||||||
|
skipPreflight: true, // Disable preflight as fallback
|
||||||
|
preflightCommitment: 'confirmed',
|
||||||
|
maxRetries: 2,
|
||||||
|
commitment: getMobileCommitmentLevel()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (fallbackError) {
|
||||||
|
console.error('Fallback transaction also failed:', fallbackError);
|
||||||
|
throw fallbackError;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the old confirmation logic since it's handled in the utility
|
// Remove the old confirmation logic since it's handled in the utility
|
||||||
setTxHash(signature);
|
setTxHash(signature);
|
||||||
|
|
@ -340,6 +439,12 @@ export default function Home() {
|
||||||
errorMessage = 'Transaction validation failed. Please check your wallet connection and try again.';
|
errorMessage = 'Transaction validation failed. Please check your wallet connection and try again.';
|
||||||
} else if (err.message.includes('blockhash')) {
|
} else if (err.message.includes('blockhash')) {
|
||||||
errorMessage = 'Transaction expired. Please try again.';
|
errorMessage = 'Transaction expired. Please try again.';
|
||||||
|
} else if (err.message.includes('preflight')) {
|
||||||
|
errorMessage = 'Transaction preflight check failed. This usually means there\'s an issue with your wallet connection or token balance. Try the Debug Wallet button to diagnose the issue.';
|
||||||
|
} else if (err.message.includes('insufficient lamports')) {
|
||||||
|
errorMessage = 'Insufficient SOL for transaction fees. Please ensure you have some SOL in your wallet for gas fees.';
|
||||||
|
} else if (err.message.includes('invalid account')) {
|
||||||
|
errorMessage = 'Invalid account detected. Please refresh the page and reconnect your wallet.';
|
||||||
} else {
|
} else {
|
||||||
errorMessage = err.message;
|
errorMessage = err.message;
|
||||||
}
|
}
|
||||||
|
|
@ -351,6 +456,69 @@ export default function Home() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDebugWallet = async () => {
|
||||||
|
if (!publicKey) {
|
||||||
|
setError('Please connect your wallet first');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('=== WALLET DEBUG INFO ===');
|
||||||
|
console.log('Public key:', publicKey.toString());
|
||||||
|
console.log('Is mobile device:', isMobileDevice());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connection = new Connection(CLUSTER_URL, 'confirmed');
|
||||||
|
const dinoMint = new PublicKey(DINO_TOKEN_ADDRESS);
|
||||||
|
|
||||||
|
// Test basic connection
|
||||||
|
console.log('Testing Solana connection...');
|
||||||
|
const version = await connection.getVersion();
|
||||||
|
console.log('Solana version:', version);
|
||||||
|
|
||||||
|
// Test token account
|
||||||
|
console.log('Testing token account...');
|
||||||
|
const userTokenAccount = await getAssociatedTokenAddress(dinoMint, publicKey);
|
||||||
|
console.log('User token account:', userTokenAccount.toString());
|
||||||
|
|
||||||
|
const userTokenAccountInfo = await connection.getAccountInfo(userTokenAccount);
|
||||||
|
console.log('Token account exists:', !!userTokenAccountInfo);
|
||||||
|
|
||||||
|
if (userTokenAccountInfo) {
|
||||||
|
const userTokenAccounts = await connection.getParsedTokenAccountsByOwner(
|
||||||
|
publicKey,
|
||||||
|
{ mint: dinoMint }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (userTokenAccounts.value.length > 0) {
|
||||||
|
const balance = userTokenAccounts.value[0].account.data.parsed.info.tokenAmount.uiAmount;
|
||||||
|
console.log('DINO balance:', balance);
|
||||||
|
} else {
|
||||||
|
console.log('No DINO tokens found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test simple transaction simulation
|
||||||
|
console.log('Testing simple transaction simulation...');
|
||||||
|
const testTransaction = new Transaction();
|
||||||
|
testTransaction.recentBlockhash = (await connection.getLatestBlockhash('confirmed')).blockhash;
|
||||||
|
testTransaction.feePayer = publicKey;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const simResult = await connection.simulateTransaction(testTransaction);
|
||||||
|
console.log('Simple transaction simulation result:', simResult);
|
||||||
|
} catch (simError) {
|
||||||
|
console.error('Simple transaction simulation failed:', simError);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('=== END DEBUG INFO ===');
|
||||||
|
setError('Debug info logged to console. Check browser console for details.');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Debug failed:', error);
|
||||||
|
setError(`Debug failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen">
|
<div className="min-h-screen">
|
||||||
<Header ref={headerRef} />
|
<Header ref={headerRef} />
|
||||||
|
|
@ -404,6 +572,16 @@ export default function Home() {
|
||||||
}
|
}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{/* Debug Button */}
|
||||||
|
{publicKey && (
|
||||||
|
<button
|
||||||
|
onClick={handleDebugWallet}
|
||||||
|
className="px-6 py-3 text-sm font-medium bg-blue-500 hover:bg-blue-600 text-white rounded-lg transition-all duration-300 hover:scale-105"
|
||||||
|
>
|
||||||
|
Debug Wallet
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Status Messages */}
|
{/* Status Messages */}
|
||||||
{error && (
|
{error && (
|
||||||
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-lg max-w-md">
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded-lg max-w-md">
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,22 @@ export async function sendTransactionWithMobileOptimization(
|
||||||
|
|
||||||
// Preflight check for mobile wallets
|
// Preflight check for mobile wallets
|
||||||
try {
|
try {
|
||||||
const { value: { err } } = await connection.simulateTransaction(transaction);
|
console.log('Mobile wallet utility: Running preflight check...');
|
||||||
|
const { value: { err, logs } } = await connection.simulateTransaction(transaction);
|
||||||
if (err) {
|
if (err) {
|
||||||
console.warn('Preflight check failed:', err);
|
console.warn('Mobile wallet utility: Preflight check failed:', err);
|
||||||
// Don't throw here, some mobile wallets handle this differently
|
console.log('Mobile wallet utility: Preflight logs:', logs);
|
||||||
|
|
||||||
|
// For mobile wallets, we'll be more lenient with preflight failures
|
||||||
|
// as some mobile wallets handle this differently
|
||||||
|
console.log('Mobile wallet utility: Proceeding despite preflight failure (mobile wallet behavior)');
|
||||||
|
} else {
|
||||||
|
console.log('Mobile wallet utility: Preflight check passed');
|
||||||
}
|
}
|
||||||
} catch (simError) {
|
} catch (simError) {
|
||||||
console.warn('Preflight simulation failed, proceeding anyway:', simError);
|
console.warn('Mobile wallet utility: Preflight simulation failed:', simError);
|
||||||
|
// Don't throw here, some mobile wallets handle this differently
|
||||||
|
console.log('Mobile wallet utility: Proceeding despite preflight simulation failure');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send transaction with retry logic
|
// Send transaction with retry logic
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user