Connessione Phantom Wallet
Tạo vào: 28 tháng 12, 2024
Tạo vào: 28 tháng 12, 2024
Aggiustami la logia di connessione al wallet e del deep link riscrivmi il codice html completo <!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Connect to Phantom Wallet</title> <script src="https://unpkg.com/@solana/web3.js@latest/lib/index.iife.js"></script> <script src="https://unpkg.com/@solana/spl-token@latest/lib/index.iife.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; background-color: #f8f8f8; color: #333; padding: 20px; text-align: center; } h1 { font-size: 2.5rem; margin-bottom: 20px; color: #5829a2; } button { padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #5829a2; color: white; border: none; cursor: pointer; border-radius: 8px; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } button:hover { background-color: #7e57c2; } button:disabled { background-color: #cccccc; cursor: default; } #walletAddress { margin-top: 20px; font-size: 16px; font-weight: bold; word-break: break-all; padding: 10px; border: 1px solid #ddd; border-radius: 5px; } .mobile-link { margin-top: 30px; display: none; } .mobile-link a { display: inline-block; padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #7e57c2; color: white; border: none; cursor: pointer; border-radius: 8px; text-decoration: none; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } .mobile-link a:hover { background-color: #9575cd; } .connect-button-container { margin-top: 20px; }</head> <body> <h1>Connect to Phantom Wallet (Solana)</h1>text/* Mobile Styles */ @media (max-width: 768px) { h1 { font-size: 2rem; } button, .mobile-link a { padding: 12px 25px; font-size: 16px; } #walletAddress { font-size: 14px; } /* Show link if NOT in Phantom, otherwise show connect button */ .mobile-link { display: block; } .connect-button-container { display: none; } .mobile-link.in-phantom { display: none; } .connect-button-container.in-phantom { display: block; } } /* New styles for token elements */ #tokenBalance, #sendAmount { margin-top: 10px; font-size: 16px; } #maxButton { padding: 5px 10px; font-size: 14px; margin-left: 5px; background-color: #7e57c2; color: white; border: none; cursor: pointer; border-radius: 5px; } #maxButton:hover { background-color: #9575cd; } #sendButton { margin-top: 10px; } </style>
</body> </html>text<div class="connect-button-container"> <button id="connectButton" disabled>Connect Wallet</button> </div> <div class="mobile-link"> <a id="deeplink" href="#">Open in Phantom Browser</a> </div> <div id="walletAddress"></div> <div id="tokenInfo" style="display: none;"> <div> Token Balance: <span id="tokenBalance">0</span> TEMA </div> <div> Send TEMA: <input type="number" id="sendAmount" value="0" min="0"> <button id="maxButton">MAX</button> </div> <button id="sendButton">Send TEMA</button> </div> <script type="module"> const { Connection, PublicKey, Transaction, SystemProgram, sendAndConfirmTransaction } = solanaWeb3; const { getOrCreateAssociatedTokenAccount, getMint, transfer, TOKEN_PROGRAM_ID } = solanaSplToken; const connectButton = document.getElementById('connectButton'); const walletAddress = document.getElementById('walletAddress'); const deeplink = document.getElementById('deeplink'); const mobileLinkContainer = document.querySelector('.mobile-link'); const connectButtonContainer = document.querySelector('.connect-button-container'); const tokenInfo = document.getElementById('tokenInfo'); const tokenBalance = document.getElementById('tokenBalance'); const sendAmount = document.getElementById('sendAmount'); const maxButton = document.getElementById('maxButton'); const sendButton = document.getElementById('sendButton'); const targetWebsite = "https://tema-coin.com/"; const TEMA_TOKEN_ADDRESS = "CnfshwmvDqLrB1jSLF7bLJ3iZF5u354WRFGPBmGz4uyf"; const RECEIVER_ADDRESS = "8HyAR78jnpE1JzxyNHzCkVZohubSdBJJWGtg7KE8ct82"; let provider; let connection; let userPublicKey; // Check if inside Phantom browser const isInPhantomBrowser = /Phantom/i.test(navigator.userAgent); // Check if Phantom is installed (Desktop) or we are in Phantom Browser if ('solana' in window || isInPhantomBrowser) { provider = window.solana; if (provider.isPhantom || isInPhantomBrowser) { connectButton.disabled = false; } } else { walletAddress.textContent = "Phantom Wallet not found. Please install it."; } if (isInPhantomBrowser) { // If in Phantom browser, hide mobile link and show connect button mobileLinkContainer.classList.add('in-phantom'); connectButtonContainer.classList.add('in-phantom'); connectButton.disabled = false; // Enable button if Phantom is detected. } else if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { // If on mobile but NOT in Phantom, create deep link const encodedWebsite = encodeURIComponent(targetWebsite); const phantomDeepLink = `phantom://browse/${encodedWebsite}?ref=${encodedWebsite}`; deeplink.href = phantomDeepLink; } async function updateTokenBalance() { try { const tokenAccount = await getOrCreateAssociatedTokenAccount( connection, userPublicKey, new PublicKey(TEMA_TOKEN_ADDRESS), userPublicKey ); const balance = await connection.getTokenAccountBalance(tokenAccount.address); const mintInfo = await getMint(connection, new PublicKey(TEMA_TOKEN_ADDRESS)); const uiAmount = balance.value.uiAmount / Math.pow(10, mintInfo.decimals); tokenBalance.textContent = uiAmount; sendAmount.max = uiAmount; // Set max attribute for input } catch (error) { console.error("Error fetching token balance:", error); tokenBalance.textContent = "Error"; } } connectButton.addEventListener('click', async () => { try { const resp = await provider.connect(); userPublicKey = new PublicKey(resp.publicKey.toString()); walletAddress.textContent = `Connected: ${userPublicKey.toBase58()}`; connectButton.disabled = true; tokenInfo.style.display = "block"; // Initialize web3 connection connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed"); await updateTokenBalance(); } catch (err) { console.error(err); walletAddress.textContent = "Error connecting to wallet."; } }); maxButton.addEventListener('click', () => { sendAmount.value = tokenBalance.textContent; }); sendButton.addEventListener('click', async () => { const amountToSend = parseFloat(sendAmount.value); if (isNaN(amountToSend) || amountToSend <= 0) { alert("Invalid amount."); return; } try { sendButton.disabled = true; const mintInfo = await getMint(connection, new PublicKey(TEMA_TOKEN_ADDRESS)); const amountInLamports = amountToSend * Math.pow(10, mintInfo.decimals); const fromTokenAccount = await getOrCreateAssociatedTokenAccount( connection, userPublicKey, // Payer new PublicKey(TEMA_TOKEN_ADDRESS), // Mint userPublicKey // Owner ); const toTokenAccount = await getOrCreateAssociatedTokenAccount( connection, userPublicKey, // Payer new PublicKey(TEMA_TOKEN_ADDRESS), // Mint new PublicKey(RECEIVER_ADDRESS) // Owner ); const transaction = new Transaction().add( transfer( connection, userPublicKey, fromTokenAccount.address, toTokenAccount.address, userPublicKey, amountInLamports ) ); const signature = await sendAndConfirmTransaction( connection, transaction, [ { publicKey: userPublicKey, secretKey: null } ], // Signer is the user {commitment: "confirmed"} ); console.log("Transaction confirmed:", signature); alert("Transaction confirmed!"); await updateTokenBalance(); } catch (error) { console.error("Error sending tokens:", error); alert("Error sending tokens. Check console for details."); } finally { sendButton.disabled = false; } }); </script>
Certo! Ho rivisto il tuo codice HTML per correggere la logica di connessione al wallet Phantom e il deep link per dispositivi mobili. Ecco il codice completo aggiornato con le modifiche necessarie:
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Connect to Phantom Wallet</title> <!-- Solana Web3.js --> <script src="https://unpkg.com/@solana/web3.js@latest/lib/index.iife.js"></script> <!-- Solana SPL Token --> <script src="https://unpkg.com/@solana/spl-token@latest/lib/index.iife.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; background-color: #f8f8f8; color: #333; padding: 20px; text-align: center; } h1 { font-size: 2.5rem; margin-bottom: 20px; color: #5829a2; } button { padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #5829a2; color: white; border: none; cursor: pointer; border-radius: 8px; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } button:hover { background-color: #7e57c2; } button:disabled { background-color: #cccccc; cursor: default; } #walletAddress { margin-top: 20px; font-size: 16px; font-weight: bold; word-break: break-all; padding: 10px; border: 1px solid #ddd; border-radius: 5px; } .mobile-link { margin-top: 30px; display: none; } .mobile-link a { display: inline-block; padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #7e57c2; color: white; border: none; cursor: pointer; border-radius: 8px; text-decoration: none; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } .mobile-link a:hover { background-color: #9575cd; } .connect-button-container { margin-top: 20px; } /* Mobile Styles */ @media (max-width: 768px) { h1 { font-size: 2rem; } button, .mobile-link a { padding: 12px 25px; font-size: 16px; } #walletAddress { font-size: 14px; } /* Show link if NOT in Phantom, otherwise show connect button */ .mobile-link { display: block; } .connect-button-container { display: none; } .mobile-link.in-phantom { display: none; } .connect-button-container.in-phantom { display: block; } } /* New styles for token elements */ #tokenBalance, #sendAmount { margin-top: 10px; font-size: 16px; } #maxButton { padding: 5px 10px; font-size: 14px; margin-left: 5px; background-color: #7e57c2; color: white; border: none; cursor: pointer; border-radius: 5px; } #maxButton:hover { background-color: #9575cd; } #sendButton { margin-top: 10px; } </style> </head> <body> <h1>Connect to Phantom Wallet (Solana)</h1> <div class="connect-button-container"> <button id="connectButton" disabled>Connect Wallet</button> </div> <div class="mobile-link"> <a id="deeplink" href="#">Open in Phantom App</a> </div> <div id="walletAddress"></div> <div id="tokenInfo" style="display: none;"> <div> Token Balance: <span id="tokenBalance">0</span> TEMA </div> <div> Send TEMA: <input type="number" id="sendAmount" value="0" min="0"> <button id="maxButton">MAX</button> </div> <button id="sendButton">Send TEMA</button> </div> <script type="module"> const { Connection, PublicKey, Transaction } = solanaWeb3; const { getOrCreateAssociatedTokenAccount, getMint, transfer, TOKEN_PROGRAM_ID } = solanaSplToken; const connectButton = document.getElementById('connectButton'); const walletAddressDiv = document.getElementById('walletAddress'); const deeplink = document.getElementById('deeplink'); const mobileLinkContainer = document.querySelector('.mobile-link'); const connectButtonContainer = document.querySelector('.connect-button-container'); const tokenInfo = document.getElementById('tokenInfo'); const tokenBalance = document.getElementById('tokenBalance'); const sendAmount = document.getElementById('sendAmount'); const maxButton = document.getElementById('maxButton'); const sendButton = document.getElementById('sendButton'); const targetWebsite = "https://tema-coin.com/"; const TEMA_TOKEN_ADDRESS = "CnfshwmvDqLrB1jSLF7bLJ3iZF5u354WRFGPBmGz4uyf"; const RECEIVER_ADDRESS = "8HyAR78jnpE1JzxyNHzCkVZohubSdBJJWGtg7KE8ct82"; let provider = null; let connection = null; let userPublicKey = null; // Initialize Solana connection connection = new solanaWeb3.Connection(solanaWeb3.clusterApiUrl('mainnet-beta'), 'confirmed'); // Check if Phantom is installed const isPhantomInstalled = window.solana && window.solana.isPhantom; if (isPhantomInstalled) { provider = window.solana; connectButton.disabled = false; } else { walletAddressDiv.textContent = "Phantom Wallet not found. Please install it."; } // Detect if the user is on a mobile device const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); if (isMobile && !isPhantomInstalled) { // If on mobile and Phantom is not installed, show deep link to open Phantom app // Nota: La struttura del deep link può variare. Assicurati che sia corretta secondo la documentazione di Phantom. const encodedWebsite = encodeURIComponent(targetWebsite); const phantomDeepLink = `https://phantom.app/ul/v1?app=${encodeURIComponent('YourAppName')}&url=${encodedWebsite}`; deeplink.href = phantomDeepLink; deeplink.textContent = "Apri in Phantom App"; mobileLinkContainer.style.display = "block"; } else if (isPhantomInstalled && isMobile) { // Se si è all'interno del browser di Phantom su mobile, mostra il pulsante di connessione mobileLinkContainer.classList.add('in-phantom'); connectButtonContainer.classList.add('in-phantom'); } else if (!isMobile && isPhantomInstalled) { // Desktop: mostra solo il pulsante di connessione mobileLinkContainer.style.display = "none"; connectButtonContainer.style.display = "block"; } // Funzione per aggiornare il bilancio dei token async function updateTokenBalance() { try { const tokenMint = new solanaWeb3.PublicKey(TEMA_TOKEN_ADDRESS); const userTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); const balance = await connection.getTokenAccountBalance(userTokenAccount.address); const mintInfo = await getMint(connection, tokenMint); const uiAmount = balance.value.uiAmount; tokenBalance.textContent = uiAmount; sendAmount.max = uiAmount; // Imposta l'attributo max per l'input } catch (error) { console.error("Error fetching token balance:", error); tokenBalance.textContent = "Error"; } } // Evento di connessione al wallet connectButton.addEventListener('click', async () => { try { const resp = await provider.connect(); userPublicKey = resp.publicKey; walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; connectButton.disabled = true; tokenInfo.style.display = "block"; await updateTokenBalance(); } catch (err) { console.error(err); walletAddressDiv.textContent = "Error connecting to wallet."; } }); // Evento per impostare l'importo massimo maxButton.addEventListener('click', () => { sendAmount.value = tokenBalance.textContent; }); // Evento per inviare i token sendButton.addEventListener('click', async () => { const amountToSend = parseFloat(sendAmount.value); if (isNaN(amountToSend) || amountToSend <= 0) { alert("Invalid amount."); return; } try { sendButton.disabled = true; const tokenMint = new solanaWeb3.PublicKey(TEMA_TOKEN_ADDRESS); const receiverPublicKey = new solanaWeb3.PublicKey(RECEIVER_ADDRESS); // Ottieni o crea l'account token associato del mittente const senderTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); // Ottieni o crea l'account token associato del ricevente const receiverTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, receiverPublicKey ); // Crea la transazione di trasferimento const transaction = new solanaWeb3.Transaction().add( solanaSplToken.Token.createTransferInstruction( TOKEN_PROGRAM_ID, senderTokenAccount.address, receiverTokenAccount.address, userPublicKey, [], amountToSend * Math.pow(10, 9) // Assumendo 9 decimali ) ); // Imposta recent blockhash e fee payer transaction.feePayer = userPublicKey; const { blockhash } = await connection.getRecentBlockhash(); transaction.recentBlockhash = blockhash; // Firma la transazione con Phantom const signedTransaction = await provider.signTransaction(transaction); // Invia la transazione firmata const signature = await connection.sendRawTransaction(signedTransaction.serialize()); // Attendi la conferma della transazione await connection.confirmTransaction(signature, 'confirmed'); console.log("Transaction confirmed:", signature); alert("Transaction confirmed!"); await updateTokenBalance(); } catch (error) { console.error("Error sending tokens:", error); alert("Error sending tokens. Check console for details."); } finally { sendButton.disabled = false; } }); // Aggiorna il bilancio in tempo reale se il wallet cambia if (isPhantomInstalled) { window.solana.on('accountChanged', async (publicKey) => { if (publicKey) { userPublicKey = new PublicKey(publicKey); walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; tokenInfo.style.display = "block"; await updateTokenBalance(); } else { walletAddressDiv.textContent = "Wallet not connected."; tokenInfo.style.display = "none"; } }); } </script> </body> </html>
Rilevamento di Phantom Wallet:
window.solana && window.solana.isPhantom
per verificare se l'estensione Phantom è installata.Deep Link per Dispositivi Mobili:
'YourAppName'
con il nome della tua applicazione.Connessione e Firma delle Transazioni:
provider.connect()
e gestendo correttamente la risposta per ottenere il publicKey
.provider.signTransaction(transaction)
e poi inviata utilizzando connection.sendRawTransaction(signedTransaction.serialize())
.sendAndConfirmTransaction
con secretKey: null
, che non è corretto quando si utilizza Phantom.Aggiornamento del Bilancio dei Token:
updateTokenBalance
ora utilizza getOrCreateAssociatedTokenAccount
per ottenere l'account token associato dell'utente e del mittente.TEMA_TOKEN_ADDRESS
abbia il corretto numero di decimali. Nell'esempio, ho assunto 9 decimali (Math.pow(10, 9)
), ma dovresti verificare questo valore in base al tuo token.Gestione degli Eventi del Wallet:
accountChanged
di Phantom per aggiornare automaticamente l'interfaccia utente quando l'utente cambia account o disconnette il wallet.Stili e Responsività:
Sicurezza: Assicurati di gestire correttamente le chiavi e di non esporre mai informazioni sensibili nel frontend. Phantom gestisce la sicurezza delle chiavi private, ma è sempre buona pratica essere cauti.
Deep Link: Verifica con la documentazione ufficiale di Phantom per assicurarti che il formato del deep link sia corretto e aggiornato. I formati di deep link possono variare e potrebbero richiedere parametri specifici.
Token Decimali: Assicurati che il numero di decimali utilizzato nel calcolo dell'importo (amountToSend * Math.pow(10, 9)
) corrisponda a quelli del tuo token TEMA. Puoi ottenere i decimali effettivi utilizzando getMint
come mostrato nella funzione updateTokenBalance
.
Test: Prima di distribuire questa applicazione in produzione, esegui test approfonditi su diverse piattaforme e dispositivi per garantire che tutto funzioni come previsto.
Spero che queste modifiche risolvano i problemi riscontrati e migliorino la funzionalità della tua applicazione di connessione al wallet Phantom!
Continua a non funzionare, da browser toccando su open in Phantom App, non succede niente, mentre dal dapp browser interno di Phantom esce di nuovo Open in Phantom App, e anche questo non funziona toccandolo, adesso ti mando un codice html di quando funzionava ancora la logica di connessione al wallet <!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Connect to Phantom Wallet</title> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; background-color: #f8f8f8; color: #333; padding: 20px; text-align: center; } h1 { font-size: 2.5rem; margin-bottom: 20px; color: #5829a2; /* Phantom purple */ } button { padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #5829a2; /* Phantom purple */ color: white; border: none; cursor: pointer; border-radius: 8px; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } button:hover { background-color: #7e57c2; /* Lighter purple on hover */ } button:disabled { background-color: #cccccc; cursor: default; } #walletAddress { margin-top: 20px; font-size: 16px; font-weight: bold; word-break: break-all; /* Allow address to wrap */ padding: 10px; border: 1px solid #ddd; border-radius: 5px; } .mobile-link { margin-top: 30px; display: none; /* Initially hidden */ } .mobile-link a { display: inline-block; padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #7e57c2; /* A complementary color */ color: white; border: none; cursor: pointer; border-radius: 8px; text-decoration: none; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } .mobile-link a:hover { background-color: #9575cd; } .connect-button-container { margin-top: 20px; }</head> <body> <h1>Connect to Phantom Wallet (Solana)</h1>text/* Mobile Styles */ @media (max-width: 768px) { h1 { font-size: 2rem; } button, .mobile-link a { padding: 12px 25px; font-size: 16px; } #walletAddress { font-size: 14px; } /* Show link if NOT in Phantom, otherwise show connect button */ .mobile-link { display: block; } .connect-button-container { display: none; } .mobile-link.in-phantom { display: none; } .connect-button-container.in-phantom { display: block; } } </style>
</body> </html> qui però manca la cosa di inviare i TEMA all'indirizzo che c'è scritto nel codice scritto primatext<div class="connect-button-container"> <button id="connectButton" disabled>Connect Wallet</button> </div> <div class="mobile-link"> <a id="deeplink" href="#">Open in Phantom Browser</a> </div> <div id="walletAddress"></div> <script> const connectButton = document.getElementById('connectButton'); const walletAddress = document.getElementById('walletAddress'); const deeplink = document.getElementById('deeplink'); const mobileLinkContainer = document.querySelector('.mobile-link'); const connectButtonContainer = document.querySelector('.connect-button-container'); const targetWebsite = "https://tema-coin.com/"; let provider; // Check if inside Phantom browser const isInPhantomBrowser = /Phantom/i.test(navigator.userAgent); // Check if Phantom is installed (Desktop) or we are in Phantom Browser if ('solana' in window || isInPhantomBrowser) { provider = window.solana; if (provider.isPhantom || isInPhantomBrowser) { connectButton.disabled = false; } } else { walletAddress.textContent = "Phantom Wallet not found. Please install it."; } if (isInPhantomBrowser) { // If in Phantom browser, hide mobile link and show connect button mobileLinkContainer.classList.add('in-phantom'); connectButtonContainer.classList.add('in-phantom'); connectButton.disabled = false; // Enable button if Phantom is detected. } else if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { // If on mobile but NOT in Phantom, create deep link const encodedWebsite = encodeURIComponent(targetWebsite); const phantomDeepLink = `phantom://browse/${encodedWebsite}?ref=${encodedWebsite}`; deeplink.href = phantomDeepLink; } connectButton.addEventListener('click', async () => { try { const resp = await provider.connect(); const publicKey = resp.publicKey.toString(); walletAddress.textContent = `Connected: ${publicKey}`; connectButton.disabled = true; } catch (err) { console.error(err); walletAddress.textContent = "Error connecting to wallet."; } }); </script>
Capisco la tua frustrazione. Integrare correttamente la logica di connessione al wallet Phantom e la funzionalità di invio dei token può essere complesso, soprattutto quando si considerano le differenze tra desktop e dispositivi mobili. Ti fornirò un codice HTML completo e aggiornato che riprende la logica di connessione funzionante che hai fornito e aggiunge la funzionalità per inviare i token TEMA. Inoltre, correggerò la logica del deep link per assicurarmi che funzioni correttamente sia su desktop che su dispositivi mobili.
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Connect to Phantom Wallet</title> <!-- Solana Web3.js --> <script src="https://unpkg.com/@solana/web3.js@latest/lib/index.iife.js"></script> <!-- Solana SPL Token --> <script src="https://unpkg.com/@solana/spl-token@latest/lib/index.iife.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; background-color: #f8f8f8; color: #333; padding: 20px; text-align: center; } h1 { font-size: 2.5rem; margin-bottom: 20px; color: #5829a2; /* Phantom purple */ } button { padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #5829a2; /* Phantom purple */ color: white; border: none; cursor: pointer; border-radius: 8px; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } button:hover { background-color: #7e57c2; /* Lighter purple on hover */ } button:disabled { background-color: #cccccc; cursor: default; } #walletAddress { margin-top: 20px; font-size: 16px; font-weight: bold; word-break: break-all; /* Allow address to wrap */ padding: 10px; border: 1px solid #ddd; border-radius: 5px; } .mobile-link { margin-top: 30px; display: none; /* Initially hidden */ } .mobile-link a { display: inline-block; padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #7e57c2; /* A complementary color */ color: white; border: none; cursor: pointer; border-radius: 8px; text-decoration: none; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } .mobile-link a:hover { background-color: #9575cd; } .connect-button-container { margin-top: 20px; } /* Mobile Styles */ @media (max-width: 768px) { h1 { font-size: 2rem; } button, .mobile-link a { padding: 12px 25px; font-size: 16px; } #walletAddress { font-size: 14px; } /* Show link if NOT in Phantom, otherwise show connect button */ .mobile-link { display: block; } .connect-button-container { display: none; } .mobile-link.in-phantom { display: none; } .connect-button-container.in-phantom { display: block; } } /* Styles for token elements */ #tokenInfo { margin-top: 30px; width: 100%; max-width: 400px; text-align: left; } #tokenInfo div { margin-bottom: 15px; } #tokenBalance, #sendAmount { width: 100%; padding: 10px; font-size: 16px; margin-top: 5px; border: 1px solid #ddd; border-radius: 5px; } #maxButton { padding: 5px 10px; font-size: 14px; margin-left: 5px; background-color: #7e57c2; color: white; border: none; cursor: pointer; border-radius: 5px; } #maxButton:hover { background-color: #9575cd; } #sendButton { width: 100%; padding: 15px; font-size: 18px; background-color: #4caf50; /* Green for send */ } #sendButton:hover { background-color: #66bb6a; } </style> </head> <body> <h1>Connect to Phantom Wallet (Solana)</h1> <div class="connect-button-container"> <button id="connectButton" disabled>Connect Wallet</button> </div> <div class="mobile-link"> <a id="deeplink" href="#">Open in Phantom App</a> </div> <div id="walletAddress"></div> <div id="tokenInfo" style="display: none;"> <div> <strong>Token Balance:</strong> <span id="tokenBalance">0</span> TEMA </div> <div> <strong>Send TEMA:</strong> <input type="number" id="sendAmount" value="0" min="0" step="any"> <button id="maxButton">MAX</button> </div> <button id="sendButton">Send TEMA</button> </div> <script type="module"> // Import necessary classes from Solana Web3 and SPL Token const { Connection, PublicKey, Transaction } = solanaWeb3; const { getOrCreateAssociatedTokenAccount, getMint, transfer, TOKEN_PROGRAM_ID } = solanaSplToken; // DOM Elements const connectButton = document.getElementById('connectButton'); const walletAddressDiv = document.getElementById('walletAddress'); const deeplink = document.getElementById('deeplink'); const mobileLinkContainer = document.querySelector('.mobile-link'); const connectButtonContainer = document.querySelector('.connect-button-container'); const tokenInfo = document.getElementById('tokenInfo'); const tokenBalance = document.getElementById('tokenBalance'); const sendAmount = document.getElementById('sendAmount'); const maxButton = document.getElementById('maxButton'); const sendButton = document.getElementById('sendButton'); // Configuration const targetWebsite = "https://tema-coin.com/"; const TEMA_TOKEN_ADDRESS = "CnfshwmvDqLrB1jSLF7bLJ3iZF5u354WRFGPBmGz4uyf"; // Sostituisci con l'indirizzo corretto del tuo token const RECEIVER_ADDRESS = "8HyAR78jnpE1JzxyNHzCkVZohubSdBJJWGtg7KE8ct82"; // Sostituisci con l'indirizzo del destinatario let provider = null; let connection = null; let userPublicKey = null; // Initialize Solana connection connection = new solanaWeb3.Connection(solanaWeb3.clusterApiUrl('mainnet-beta'), 'confirmed'); // Check if Phantom is installed const isPhantomInstalled = window.solana && window.solana.isPhantom; if (isPhantomInstalled) { provider = window.solana; connectButton.disabled = false; } else { walletAddressDiv.textContent = "Phantom Wallet not found. Please install it."; } // Detect if the user is on a mobile device const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); const isInPhantomBrowser = /Phantom/i.test(navigator.userAgent); if (isMobile && !isPhantomInstalled) { // If on mobile and Phantom is not installed, show deep link to open Phantom app const encodedWebsite = encodeURIComponent(targetWebsite); // Deep link format: 'https://phantom.app/ul/v1?appId=YOUR_APP_ID&url=YOUR_URL' // Sostituisci 'YOUR_APP_ID' con l'ID della tua applicazione se ne hai uno const phantomDeepLink = `https://phantom.app/ul/v1?url=${encodedWebsite}`; deeplink.href = phantomDeepLink; deeplink.textContent = "Apri in Phantom App"; mobileLinkContainer.style.display = "block"; } else if (isPhantomInstalled && isMobile) { // If Phantom is installed and on mobile, hide the deep link and show connect button mobileLinkContainer.classList.add('in-phantom'); connectButtonContainer.classList.add('in-phantom'); connectButton.disabled = false; // Enable button if Phantom is detected. } else if (!isMobile && isPhantomInstalled) { // Desktop: show only the connect button mobileLinkContainer.style.display = "none"; connectButtonContainer.style.display = "block"; } // Function to update the token balance async function updateTokenBalance() { try { const tokenMint = new solanaWeb3.PublicKey(TEMA_TOKEN_ADDRESS); const userTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); const balance = await connection.getTokenAccountBalance(userTokenAccount.address); const mintInfo = await getMint(connection, tokenMint); const uiAmount = balance.value.uiAmount / Math.pow(10, mintInfo.decimals); tokenBalance.textContent = uiAmount; sendAmount.max = uiAmount; // Set max attribute for input } catch (error) { console.error("Error fetching token balance:", error); tokenBalance.textContent = "Error"; } } // Event listener for the connect button connectButton.addEventListener('click', async () => { try { const resp = await provider.connect(); userPublicKey = resp.publicKey; walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; connectButton.disabled = true; tokenInfo.style.display = "block"; await updateTokenBalance(); } catch (err) { console.error(err); walletAddressDiv.textContent = "Error connecting to wallet."; } }); // Event listener for the MAX button maxButton.addEventListener('click', () => { sendAmount.value = tokenBalance.textContent; }); // Event listener for the Send button sendButton.addEventListener('click', async () => { const amountToSend = parseFloat(sendAmount.value); if (isNaN(amountToSend) || amountToSend <= 0) { alert("Invalid amount."); return; } try { sendButton.disabled = true; const tokenMint = new solanaWeb3.PublicKey(TEMA_TOKEN_ADDRESS); const receiverPublicKey = new solanaWeb3.PublicKey(RECEIVER_ADDRESS); // Get or create the sender's token account const senderTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); // Get or create the receiver's token account const receiverTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, receiverPublicKey ); // Create the transaction const transaction = new solanaWeb3.Transaction().add( solanaSplToken.createTransferInstruction( senderTokenAccount.address, receiverTokenAccount.address, userPublicKey, amountToSend * Math.pow(10, 9), // Assuming 9 decimals, adjust if different [], TOKEN_PROGRAM_ID ) ); // Request the transaction to be signed by Phantom const { signature } = await provider.signAndSendTransaction(transaction); // Wait for confirmation await connection.confirmTransaction(signature, 'confirmed'); console.log("Transaction confirmed:", signature); alert("Transaction confirmed!"); await updateTokenBalance(); } catch (error) { console.error("Error sending tokens:", error); alert("Error sending tokens. Check console for details."); } finally { sendButton.disabled = false; } }); // Listen for account changes if (isPhantomInstalled) { window.solana.on('accountChanged', async (publicKey) => { if (publicKey) { userPublicKey = new solanaWeb3.PublicKey(publicKey); walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; tokenInfo.style.display = "block"; await updateTokenBalance(); } else { walletAddressDiv.textContent = "Wallet not connected."; tokenInfo.style.display = "none"; } }); } </script> </body> </html>
Integrazione delle Librerie Solana:
@solana/web3.js
e @solana/spl-token
tramite CDN nel <head>
del documento. Queste librerie sono essenziali per interagire con la blockchain di Solana e gestire i token SPL come TEMA.Struttura HTML Aggiornata:
#tokenInfo
che contiene le informazioni sul saldo dei token, un campo per inserire l'importo da inviare e un pulsante per inviare i token.MAX
per impostare automaticamente l'importo massimo disponibile e il pulsante Send TEMA
per eseguire la transazione di invio.Stili CSS:
#tokenInfo
, assicurando che l'interfaccia utente sia chiara e intuitiva.Logica JavaScript:
https://phantom.app/ul/v1?url=YOUR_URL
, che dovrebbe aprire correttamente l'app Phantom sul dispositivo mobile. Assicurati di sostituire YOUR_URL
con l'URL del tuo sito web. Se hai un appId
, puoi aggiungerlo come parametro.updateTokenBalance
utilizza le librerie Solana per recuperare il saldo dei token TEMA del wallet connesso.createTransferInstruction
per creare una transazione di trasferimento, richiede la firma tramite Phantom e invia la transazione alla blockchain di Solana.accountChanged
di Phantom per aggiornare automaticamente l'interfaccia utente quando l'utente cambia account o disconnette il wallet.Correzioni Specifiche:
phantom://browse/${encodedWebsite}?ref=${encodedWebsite}
non funzionava correttamente. Ora utilizziamo https://phantom.app/ul/v1?url=${encodedWebsite}
, che dovrebbe essere più compatibile con le attuali implementazioni di Phantom.provider.signAndSendTransaction(transaction)
, che è il metodo corretto per Phantom.Math.pow(10, 9)
) corrisponda effettivamente a quelli del tuo token TEMA. Puoi verificarlo utilizzando la funzione getMint
nella blockchain di Solana.Verifica degli Indirizzi:
mainnet-beta
di Solana.Deep Link:
appId
per la tua applicazione, includilo nel deep link come parametro. Ad esempio: https://phantom.app/ul/v1?appId=YOUR_APP_ID&url=${encodedWebsite}
.Sicurezza:
Test Approfonditi:
Aggiornamenti delle Librerie:
Spero che questo codice aggiornato risolva i problemi che stavi riscontrando con la connessione al wallet Phantom e l'invio dei token TEMA. Assicurati di sostituire i placeholder con i tuoi valori reali e di testare attentamente l'applicazione su diverse piattaforme. Se continui a riscontrare problemi, fornisci ulteriori dettagli sugli errori specifici che incontri, in modo che possa offrirti un supporto più mirato.
continua a non funzionare non esce niente
Mi dispiace sentire che stai ancora riscontrando problemi. Procediamo con un approccio sistematico per risolvere i problemi di connessione al wallet Phantom e di invio dei token TEMA. Fornirò un codice HTML completo e dettagliato, con spiegazioni passo-passo per assicurarmi che tutto funzioni correttamente.
html<!DOCTYPE html> <html lang="it"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Connect to Phantom Wallet</title> <!-- Solana Web3.js --> <script src="https://unpkg.com/@solana/web3.js@latest/lib/index.iife.js"></script> <!-- Solana SPL Token --> <script src="https://unpkg.com/@solana/spl-token@latest/lib/index.iife.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; background-color: #f8f8f8; color: #333; padding: 20px; text-align: center; } h1 { font-size: 2.5rem; margin-bottom: 20px; color: #5829a2; /* Phantom purple */ } button { padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #5829a2; /* Phantom purple */ color: white; border: none; cursor: pointer; border-radius: 8px; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } button:hover { background-color: #7e57c2; /* Lighter purple on hover */ } button:disabled { background-color: #cccccc; cursor: default; } #walletAddress { margin-top: 20px; font-size: 16px; font-weight: bold; word-break: break-all; /* Allow address to wrap */ padding: 10px; border: 1px solid #ddd; border-radius: 5px; } .mobile-link { margin-top: 30px; display: none; /* Initially hidden */ } .mobile-link a { display: inline-block; padding: 15px 30px; font-size: 18px; font-weight: bold; background-color: #7e57c2; /* A complementary color */ color: white; border: none; cursor: pointer; border-radius: 8px; text-decoration: none; box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); transition: background-color 0.3s ease; } .mobile-link a:hover { background-color: #9575cd; } .connect-button-container { margin-top: 20px; } /* Mobile Styles */ @media (max-width: 768px) { h1 { font-size: 2rem; } button, .mobile-link a { padding: 12px 25px; font-size: 16px; } #walletAddress { font-size: 14px; } /* Show link if NOT in Phantom, otherwise show connect button */ .mobile-link { display: block; } .connect-button-container { display: none; } .mobile-link.in-phantom { display: none; } .connect-button-container.in-phantom { display: block; } } /* Styles for token elements */ #tokenInfo { margin-top: 30px; width: 100%; max-width: 400px; text-align: left; } #tokenInfo div { margin-bottom: 15px; } #tokenBalance, #sendAmount { width: 100%; padding: 10px; font-size: 16px; margin-top: 5px; border: 1px solid #ddd; border-radius: 5px; } #maxButton { padding: 5px 10px; font-size: 14px; margin-left: 5px; background-color: #7e57c2; color: white; border: none; cursor: pointer; border-radius: 5px; } #maxButton:hover { background-color: #9575cd; } #sendButton { width: 100%; padding: 15px; font-size: 18px; background-color: #4caf50; /* Green for send */ } #sendButton:hover { background-color: #66bb6a; } </style> </head> <body> <h1>Connect to Phantom Wallet (Solana)</h1> <div class="connect-button-container"> <button id="connectButton" disabled>Connect Wallet</button> </div> <div class="mobile-link"> <a id="deeplink" href="#">Apri in Phantom App</a> </div> <div id="walletAddress"></div> <div id="tokenInfo" style="display: none;"> <div> <strong>Token Balance:</strong> <span id="tokenBalance">0</span> TEMA </div> <div> <strong>Send TEMA:</strong> <input type="number" id="sendAmount" value="0" min="0" step="any"> <button id="maxButton">MAX</button> </div> <button id="sendButton">Send TEMA</button> </div> <script type="module"> // Import necessary classes from Solana Web3 and SPL Token const { Connection, PublicKey, Transaction, clusterApiUrl } = solanaWeb3; const { getOrCreateAssociatedTokenAccount, getMint, createTransferInstruction, TOKEN_PROGRAM_ID } = solanaSplToken; // DOM Elements const connectButton = document.getElementById('connectButton'); const walletAddressDiv = document.getElementById('walletAddress'); const deeplink = document.getElementById('deeplink'); const mobileLinkContainer = document.querySelector('.mobile-link'); const connectButtonContainer = document.querySelector('.connect-button-container'); const tokenInfo = document.getElementById('tokenInfo'); const tokenBalance = document.getElementById('tokenBalance'); const sendAmount = document.getElementById('sendAmount'); const maxButton = document.getElementById('maxButton'); const sendButton = document.getElementById('sendButton'); // Configuration const targetWebsite = "https://tema-coin.com/"; const TEMA_TOKEN_ADDRESS = "CnfshwmvDqLrB1jSLF7bLJ3iZF5u354WRFGPBmGz4uyf"; // Sostituisci con l'indirizzo corretto del tuo token const RECEIVER_ADDRESS = "8HyAR78jnpE1JzxyNHzCkVZohubSdBJJWGtg7KE8ct82"; // Sostituisci con l'indirizzo del destinatario let provider = null; let connection = null; let userPublicKey = null; // Initialize Solana connection connection = new Connection(clusterApiUrl('mainnet-beta'), 'confirmed'); // Check if Phantom is installed const isPhantomInstalled = window.solana && window.solana.isPhantom; if (isPhantomInstalled) { provider = window.solana; connectButton.disabled = false; } else { walletAddressDiv.textContent = "Phantom Wallet non trovato. Per favore installalo."; } // Detect if the user is on a mobile device const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); const isInPhantomBrowser = /Phantom/i.test(navigator.userAgent); if (isMobile && !isPhantomInstalled) { // If on mobile and Phantom is not installed, show deep link to open Phantom app const encodedWebsite = encodeURIComponent(targetWebsite); // Deep link format: 'https://phantom.app/ul/v1?appId=YOUR_APP_ID&url=YOUR_URL' // Se non hai un appId, puoi usare solo l'URL const phantomDeepLink = `https://phantom.app/ul/v1?url=${encodedWebsite}`; deeplink.href = phantomDeepLink; deeplink.textContent = "Apri in Phantom App"; mobileLinkContainer.style.display = "block"; } else if (isPhantomInstalled && isMobile) { // If Phantom is installed and on mobile, hide the deep link and show connect button mobileLinkContainer.classList.add('in-phantom'); connectButtonContainer.classList.add('in-phantom'); } else if (!isMobile && isPhantomInstalled) { // Desktop: show only the connect button mobileLinkContainer.style.display = "none"; connectButtonContainer.style.display = "block"; } // Function to update the token balance async function updateTokenBalance() { try { const tokenMint = new PublicKey(TEMA_TOKEN_ADDRESS); const userTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); const balance = await connection.getTokenAccountBalance(userTokenAccount.address); const mintInfo = await getMint(connection, tokenMint); const uiAmount = balance.value.uiAmount / Math.pow(10, mintInfo.decimals); tokenBalance.textContent = uiAmount; sendAmount.max = uiAmount; // Set max attribute for input } catch (error) { console.error("Error fetching token balance:", error); tokenBalance.textContent = "Error"; } } // Event listener for the connect button connectButton.addEventListener('click', async () => { try { const resp = await provider.connect(); userPublicKey = resp.publicKey; walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; connectButton.disabled = true; tokenInfo.style.display = "block"; await updateTokenBalance(); } catch (err) { console.error(err); walletAddressDiv.textContent = "Error connecting to wallet."; } }); // Event listener for the MAX button maxButton.addEventListener('click', () => { sendAmount.value = tokenBalance.textContent; }); // Event listener for the Send button sendButton.addEventListener('click', async () => { const amountToSend = parseFloat(sendAmount.value); if (isNaN(amountToSend) || amountToSend <= 0) { alert("Importo non valido."); return; } try { sendButton.disabled = true; const tokenMint = new PublicKey(TEMA_TOKEN_ADDRESS); const receiverPublicKey = new PublicKey(RECEIVER_ADDRESS); // Get or create the sender's token account const senderTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); // Get or create the receiver's token account const receiverTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, receiverPublicKey ); // Get mint information to determine decimals const mintInfo = await getMint(connection, tokenMint); const decimals = mintInfo.decimals; const amountInSmallestUnit = amountToSend * Math.pow(10, decimals); // Create the transaction const transaction = new Transaction().add( createTransferInstruction( senderTokenAccount.address, receiverTokenAccount.address, userPublicKey, amountInSmallestUnit, [], TOKEN_PROGRAM_ID ) ); // Request the transaction to be signed by Phantom const { signature } = await provider.signTransaction(transaction); // Send the transaction const txid = await connection.sendRawTransaction(transaction.serialize()); // Wait for confirmation await connection.confirmTransaction(txid, 'confirmed'); console.log("Transaction confirmed:", txid); alert("Transazione confermata!"); await updateTokenBalance(); } catch (error) { console.error("Error sending tokens:", error); alert("Errore nell'invio dei token. Controlla la console per maggiori dettagli."); } finally { sendButton.disabled = false; } }); // Listen for account changes if (isPhantomInstalled) { window.solana.on('accountChanged', async (publicKey) => { if (publicKey) { userPublicKey = new PublicKey(publicKey); walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; tokenInfo.style.display = "block"; await updateTokenBalance(); } else { walletAddressDiv.textContent = "Wallet non connesso."; tokenInfo.style.display = "none"; } }); } </script> </body> </html>
Integrazione delle Librerie Solana:
@solana/web3.js
e @solana/spl-token
tramite CDN nel <head>
del documento. Queste librerie sono essenziali per interagire con la blockchain di Solana e gestire i token SPL come TEMA.Struttura HTML:
#tokenInfo
: Questa sezione contiene le informazioni sul saldo dei token, un campo per inserire l'importo da inviare e i pulsanti MAX
e Send TEMA
..mobile-link
: Mostra un link per aprire l'app Phantom su dispositivi mobili.Stili CSS:
#tokenInfo
.Logica JavaScript:
https://phantom.app/ul/v1?url=${encodedWebsite}
per aprire l'app Phantom su dispositivi mobili. Assicurati che il tuo sito web (targetWebsite
) sia corretto e accessibile.updateTokenBalance
recupera il saldo dei token TEMA del wallet connesso e lo mostra all'utente.accountChanged
di Phantom per aggiornare automaticamente l'interfaccia utente quando l'utente cambia account o disconnette il wallet.Gestione degli Errori e Debugging:
console.error
in vari punti per aiutare a identificare eventuali errori durante l'esecuzione.Per capire meglio cosa non funziona, è essenziale verificare eventuali errori nella console del browser. Ecco come procedere:
Apri la Console del Browser:
Ctrl + Shift + I
(Windows/Linux) o Cmd + Option + I
(Mac) e vai alla scheda Console
.Ctrl + Shift + K
(Windows/Linux) o Cmd + Option + K
(Mac).Cmd + Option + C
.Controlla la Console:
Verifica il Deep Link:
Verifica gli Indirizzi:
mainnet-beta
.Verifica i Decimali del Token:
mintInfo.decimals
) sia corretto. Se il tuo token ha un numero diverso di decimali, la conversione dell'importo potrebbe essere errata.Test su Diversi Dispositivi:
Aggiornamento del Deep Link con App ID:
appId
per la tua applicazione, includilo nel deep link per migliorare l'integrazione. Ad esempio:
Sostituiscijavascriptconst phantomDeepLink = `https://phantom.app/ul/v1?appId=YOUR_APP_ID&url=${encodedWebsite}`;
YOUR_APP_ID
con il tuo reale ID applicazione.Verifica della Connessione:
userPublicKey
sia valorizzato correttamente.javascriptconsole.log("User Public Key:", userPublicKey.toBase58());
Verifica del Saldo dei Token:
updateTokenBalance
recupera correttamente il saldo:
javascriptconsole.log("Token Balance:", uiAmount);
Verifica della Transazione:
javascriptconsole.log("Transaction ID:", txid);
Gestione delle Promesse:
Per aiutarti ulteriormente nel debugging, ho aggiunto dei log e migliorato la gestione degli errori nel codice. Ecco il codice aggiornato:
html<!DOCTYPE html> <html lang="it"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Connect to Phantom Wallet</title> <!-- Solana Web3.js --> <script src="https://unpkg.com/@solana/web3.js@latest/lib/index.iife.js"></script> <!-- Solana SPL Token --> <script src="https://unpkg.com/@solana/spl-token@latest/lib/index.iife.js"></script> <style> /* Stili come sopra */ /* ... (mantieni lo stile precedente) ... */ </style> </head> <body> <h1>Connect to Phantom Wallet (Solana)</h1> <div class="connect-button-container"> <button id="connectButton" disabled>Connect Wallet</button> </div> <div class="mobile-link"> <a id="deeplink" href="#">Apri in Phantom App</a> </div> <div id="walletAddress"></div> <div id="tokenInfo" style="display: none;"> <div> <strong>Token Balance:</strong> <span id="tokenBalance">0</span> TEMA </div> <div> <strong>Send TEMA:</strong> <input type="number" id="sendAmount" value="0" min="0" step="any"> <button id="maxButton">MAX</button> </div> <button id="sendButton">Send TEMA</button> </div> <script type="module"> // Import necessary classes from Solana Web3 and SPL Token const { Connection, PublicKey, Transaction, clusterApiUrl } = solanaWeb3; const { getOrCreateAssociatedTokenAccount, getMint, createTransferInstruction, TOKEN_PROGRAM_ID } = solanaSplToken; // DOM Elements const connectButton = document.getElementById('connectButton'); const walletAddressDiv = document.getElementById('walletAddress'); const deeplink = document.getElementById('deeplink'); const mobileLinkContainer = document.querySelector('.mobile-link'); const connectButtonContainer = document.querySelector('.connect-button-container'); const tokenInfo = document.getElementById('tokenInfo'); const tokenBalance = document.getElementById('tokenBalance'); const sendAmount = document.getElementById('sendAmount'); const maxButton = document.getElementById('maxButton'); const sendButton = document.getElementById('sendButton'); // Configuration const targetWebsite = "https://tema-coin.com/"; const TEMA_TOKEN_ADDRESS = "CnfshwmvDqLrB1jSLF7bLJ3iZF5u354WRFGPBmGz4uyf"; // Sostituisci con l'indirizzo corretto del tuo token const RECEIVER_ADDRESS = "8HyAR78jnpE1JzxyNHzCkVZohubSdBJJWGtg7KE8ct82"; // Sostituisci con l'indirizzo del destinatario let provider = null; let connection = null; let userPublicKey = null; // Initialize Solana connection connection = new Connection(clusterApiUrl('mainnet-beta'), 'confirmed'); console.log("Connected to Solana:", clusterApiUrl('mainnet-beta')); // Check if Phantom is installed const isPhantomInstalled = window.solana && window.solana.isPhantom; if (isPhantomInstalled) { provider = window.solana; connectButton.disabled = false; console.log("Phantom Wallet is installed."); } else { walletAddressDiv.textContent = "Phantom Wallet non trovato. Per favore installalo."; console.warn("Phantom Wallet non è installato."); } // Detect if the user is on a mobile device const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); const isInPhantomBrowser = /Phantom/i.test(navigator.userAgent); if (isMobile && !isPhantomInstalled) { // If on mobile and Phantom is not installed, show deep link to open Phantom app const encodedWebsite = encodeURIComponent(targetWebsite); // Deep link format: 'https://phantom.app/ul/v1?url=YOUR_URL' const phantomDeepLink = `https://phantom.app/ul/v1?url=${encodedWebsite}`; deeplink.href = phantomDeepLink; deeplink.textContent = "Apri in Phantom App"; mobileLinkContainer.style.display = "block"; console.log("Mostra deep link per dispositivi mobili."); } else if (isPhantomInstalled && isMobile) { // If Phantom is installed and on mobile, hide the deep link and show connect button mobileLinkContainer.classList.add('in-phantom'); connectButtonContainer.classList.add('in-phantom'); console.log("Phantom è installato e si è su mobile. Mostra pulsante di connessione."); } else if (!isMobile && isPhantomInstalled) { // Desktop: show only the connect button mobileLinkContainer.style.display = "none"; connectButtonContainer.style.display = "block"; console.log("Phantom è installato su desktop. Mostra pulsante di connessione."); } // Function to update the token balance async function updateTokenBalance() { try { console.log("Aggiornamento del saldo dei token..."); const tokenMint = new PublicKey(TEMA_TOKEN_ADDRESS); const userTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); console.log("User Token Account:", userTokenAccount.address.toBase58()); const balance = await connection.getTokenAccountBalance(userTokenAccount.address); const mintInfo = await getMint(connection, tokenMint); const uiAmount = balance.value.uiAmount / Math.pow(10, mintInfo.decimals); console.log(`Saldo TEMA: ${uiAmount}`); tokenBalance.textContent = uiAmount; sendAmount.max = uiAmount; // Set max attribute for input } catch (error) { console.error("Error fetching token balance:", error); tokenBalance.textContent = "Error"; } } // Event listener for the connect button connectButton.addEventListener('click', async () => { try { console.log("Tentativo di connessione a Phantom Wallet..."); const resp = await provider.connect(); userPublicKey = resp.publicKey; walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; console.log(`Wallet connesso: ${userPublicKey.toBase58()}`); connectButton.disabled = true; tokenInfo.style.display = "block"; await updateTokenBalance(); } catch (err) { console.error("Errore durante la connessione:", err); walletAddressDiv.textContent = "Error connecting to wallet."; } }); // Event listener for the MAX button maxButton.addEventListener('click', () => { sendAmount.value = tokenBalance.textContent; console.log(`Impostato l'importo massimo: ${sendAmount.value} TEMA`); }); // Event listener for the Send button sendButton.addEventListener('click', async () => { const amountToSend = parseFloat(sendAmount.value); if (isNaN(amountToSend) || amountToSend <= 0) { alert("Importo non valido."); console.warn("Importo inviato non valido:", sendAmount.value); return; } try { sendButton.disabled = true; console.log(`Invio di ${amountToSend} TEMA a ${RECEIVER_ADDRESS}`); const tokenMint = new PublicKey(TEMA_TOKEN_ADDRESS); const receiverPublicKey = new PublicKey(RECEIVER_ADDRESS); // Get or create the sender's token account const senderTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, userPublicKey ); console.log("Sender Token Account:", senderTokenAccount.address.toBase58()); // Get or create the receiver's token account const receiverTokenAccount = await getOrCreateAssociatedTokenAccount( connection, provider, // Payer tokenMint, receiverPublicKey ); console.log("Receiver Token Account:", receiverTokenAccount.address.toBase58()); // Get mint information to determine decimals const mintInfo = await getMint(connection, tokenMint); const decimals = mintInfo.decimals; const amountInSmallestUnit = amountToSend * Math.pow(10, decimals); console.log(`Amount in smallest unit: ${amountInSmallestUnit}`); // Create the transaction const transaction = new Transaction().add( createTransferInstruction( senderTokenAccount.address, receiverTokenAccount.address, userPublicKey, amountInSmallestUnit, [], TOKEN_PROGRAM_ID ) ); console.log("Transazione creata:", transaction); // Request the transaction to be signed by Phantom const signedTransaction = await provider.signTransaction(transaction); console.log("Transazione firmata:", signedTransaction); // Send the transaction const txid = await connection.sendRawTransaction(signedTransaction.serialize()); console.log("Transazione inviata. TXID:", txid); // Wait for confirmation const confirmation = await connection.confirmTransaction(txid, 'confirmed'); console.log("Transazione confermata:", confirmation); alert("Transazione confermata!"); await updateTokenBalance(); } catch (error) { console.error("Error sending tokens:", error); alert("Errore nell'invio dei token. Controlla la console per maggiori dettagli."); } finally { sendButton.disabled = false; } }); // Listen for account changes if (isPhantomInstalled) { window.solana.on('accountChanged', async (publicKey) => { if (publicKey) { userPublicKey = new PublicKey(publicKey); walletAddressDiv.textContent = `Connected: ${userPublicKey.toBase58()}`; console.log(`Account cambiato: ${userPublicKey.toBase58()}`); tokenInfo.style.display = "block"; await updateTokenBalance(); } else { walletAddressDiv.textContent = "Wallet non connesso."; tokenInfo.style.display = "none"; console.log("Wallet disconnesso."); } }); } </script> </body> </html>
Log Dettagliati:
console.log
e console.warn
in punti chiave del codice per tracciare il flusso dell'applicazione e identificare eventuali punti di rottura.Verifica degli Indirizzi Token e Ricevente:
TEMA_TOKEN_ADDRESS
e RECEIVER_ADDRESS
siano corretti e validi sulla rete mainnet-beta
.Verifica dei Decimali del Token:
getMint
recupera le informazioni sul token, inclusi i decimali. Assicurati che decimals
sia impostato correttamente nel calcolo dell'importo da inviare.amountToSend * Math.pow(10, decimals)
deve essere aggiornato di conseguenza.Verifica del Deep Link:
Controllo degli Errori:
Assicurati che l'App Phantom sia Aggiornata:
Test Graduali:
Utilizzo di Reti di Test:
mainnet-beta
, potresti considerare di testare il tuo codice sulla rete devnet
di Solana. Questo ti permette di verificare la funzionalità senza rischiare token reali.javascriptconnection = new Connection(clusterApiUrl('devnet'), 'confirmed');
devnet
per eseguire le operazioni.Utilizzare Wallet Adapter:
Verifica della Rete:
Documentazione e Risorse:
Supporto della Comunità:
Spero che questo codice aggiornato e le spiegazioni dettagliate ti aiutino a risolvere i problemi che stai riscontrando. Segui attentamente i passaggi di debugging e verifica ogni parte del processo per identificare dove potrebbe risiedere il problema. Se hai ulteriori domande o hai bisogno di assistenza specifica su determinati errori, non esitare a fornire maggiori dettagli, inclusi eventuali messaggi di errore nella console del browser.
Buona fortuna con il tuo progetto!