A Solana é uma rede blockchain que vem crescendo muito em popularidade nos últimos anos e apesar de ainda estar muito atrás de Bitcoin e Ethereum, é muito promissora no novo mundo descentralizado da web3. A interação com tais aplicações se dá através de carteiras de criptomoedas, logo, criar aplicações web que sejam capazes de se integrar a essas carteiras é uam habilidade cada vez mais importante para os devs.
Neste tutorial de hoje em que te ensinarei como integrar-se à uma carteira Solana para obter o saldo da mesma e também para enviar fundos dela para outras carteiras na blockchain de mesmo nome.
Vamos lá!
#1 – Setup da Carteira
Tem diversas carteiras cripto compatíveis com a rede Solana no mercado, sendo que as mais comuns são as browser wallets. Neste tutorial eu vou utilizar a carteira Brave Wallet, nativa do Brave Browser. No vídeo abaixo eu ensino como instalar e configurar a dita-cuja, ou se preferir, tem o passo a passo neste artigo também.
Certifique-se de estar com a rede Solana DevNet habilitada e selecionada na sua carteira, pois é ela que usaremos a fim de não gastarmos fundos com os testes. Basta deixar ela aparecendo no topo da sua carteira e em seguida copie o endereço da sua carteira de testes.
Agora, antes de sairmos desenvolvendo, nosso próximo passo é adicionarmos fundos para os testes. Você pode fazê-lo usando o faucet oficial. Isso vai te fornecer 0.5 SOL a cada 8h o que é mais do que o suficiente. Precisaremos sempre ter SOL já que é a moeda oficial da rede e é com ela que pagamos as taxas das transações (este artigo sobre taxas é para Ethereum, mas segue lógica parecida para Solana). Note que você só pode fazer isso uma vez a cada 8h e que esse saldo é completamente fake, só funciona na DevNet, não pode ser transacionado nas exchanges e não pode ser sacado mas pode ser transferido entre carteiras de teste, que é o que faremos aqui.
Agora com saldo na carteira e ela apontada para a Solana DevNet, podemos avançar para o setup da aplicação em si.
Vamos criar uma aplicação ReactJS para fazer nosso exemplo. Você pode criar uma aplicação facilmente com o comando abaixo, que crie uma com o nome de react-solana-wallet.
1 2 3 |
yarn create react-app react-solana-wallet |
Agora que temos uma aplicação React criada, vamos instalar as dependências para integração da mesma com a carteira cripto. Existe a possibilidade de usar templates prontos de projetos React com suporte a Solana, mas eles tiram todo o aprendizado importante e sem esse aprendizado você inclusive não conseguiria customizar os templates depois.
1 2 3 |
npm install @solana/wallet-adapter-base @solana/wallet-adapter-react @solana/wallet-adapter-react-ui |
O pacote @solana/wallet-adapter-react provê hooks e contexts para facilitar a integração e gestão de estado das carteiras de browser compatíveis com Solana, como a Brave. No entanto, para que isso funcione, você deve envolver toda sua aplicação com os context providers fornecidos por ela: ConnectionProvider e WalletProvider, como abaixo (arquivo App.js).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import { useMemo } from "react"; import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react"; import { clusterApiUrl } from "@solana/web3.js"; import "@solana/wallet-adapter-react-ui/styles.css"; function App() { const endpoint = clusterApiUrl("devnet"); const wallets = useMemo(() => [], []); return ( <ConnectionProvider endpoint={endpoint}> <WalletProvider wallets={wallets}> <p>Put the rest of your app here</p> </WalletProvider> </ConnectionProvider> ); } export default App; |
Note que o ConnectionProvider requer um endpoint, para que ele saiba onde se conectar. Usaremos aqui a Solana DevNet cuja URL do cluster pegamos através da função clusterApiUrl. Lembre-se que você deve fazer os testes no mesmo browser onde está a sua carteira Solana, também configurada para DevNet. No entanto, se testar agora, não verá nada funcionando ainda, pois só fizemos um setup inicial.
#2 – Se conectando à carteira Solana
Nosso exemplo vai ser bem simples mas igualmente interessante. Vamos começar adicionando um botão que, quando clicado, solicita a permissão para conexão com a carteira do navegador. Para isso usaremos dois componentes da biblioteca wallet-adapter-react-ui, o WalletModalProvider, responsável pela modal de solicitação de permissão, e o WalletMultiButton, responsável pelo botão de “login” que já tem embutido o comportamento de exibir a carteira conectada depois que o usuário autorizar a mesma.
Abra o App.js e altere o seu conteúdo para que inclua as dependências novas e os componentes novos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import { WalletModalProvider, WalletMultiButton } from "@solana/wallet-adapter-react-ui"; function App() { const endpoint = clusterApiUrl("devnet"); const wallets = useMemo(() => [], []); return ( <ConnectionProvider endpoint={endpoint}> <WalletProvider wallets={wallets}> <WalletModalProvider> <WalletMultiButton /> <p>Put the rest of your app here</p> </WalletModalProvider> </WalletProvider> </ConnectionProvider> ); } export default App; |
Agora sim, se abrir no seu navegador com uma carteira Solana verá que o botão sugere ao usuário que se conecte na sua carteira e, uma vez que ele clique e autorize a mesma (no meu exemplo a Brave Wallet), o botão exibe a carteira conectada, como na imagem abaixo.
Agora que temos a funcionalidade de conexão da carteira, podemos fazer coisas mais legais em nosso projeto.
#3 – Consultando o saldo da carteira Solana
Agora vamos criar um componente que vai exibir o saldo da sua carteira Solana em tempo real. Para isso, crie um novo arquivo no projeto com o nome de BalanceDisplay.js com os seguintes imports.
1 2 3 4 5 |
import { useConnection, useWallet } from "@solana/wallet-adapter-react"; import { LAMPORTS_PER_SOL } from "@solana/web3.js"; import { useEffect, useState } from "react"; |
O useConnection e o useWallet são hooks que servem, para respectivamente acessar a conexão com a blockchain e com a carteira. Já o LAMPORTS_PER_SOL é apenas uma constante usada em conversões de valores e os hooks useEffect e useState são velhos conhecidos dos programadores React.
A seguir, vamos criar a estrutura do function component e declarar algumas variáveis dentro dele, obtidas através da criação de um state para o balance e das chamadas dos dois hooks que importamos anteriormente. Repare que já deixei também o JSX do componente preparado para exibir o balance em SOL.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function BalanceDisplay() { const [balance, setBalance] = useState(0); const { connection } = useConnection(); const { publicKey } = useWallet(); return ( <div> <p>{publicKey ? `Balance: ${balance} SOL` : ""}</p> </div> ); } export default BalanceDisplay; |
Para o comportamento de obtenção em tempo real do balance em si, vamos criar um effect que vai monitorar a conexão com a blockchain e a chave pública da carteira conectada. Caso qualquer um desses valores mude, o effect agirá carregando novamente o saldo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
useEffect(() => { const updateBalance = async () => { if (!connection || !publicKey) { console.error("Wallet not connected or connection unavailable"); } try { connection.onAccountChange( publicKey, (updatedAccountInfo) => { setBalance(updatedAccountInfo.lamports / LAMPORTS_PER_SOL); }, "confirmed", ); const accountInfo = await connection.getAccountInfo(publicKey); if (accountInfo) { setBalance(accountInfo.lamports / LAMPORTS_PER_SOL); } else { throw new Error("Account info not found"); } } catch (error) { console.error("Failed to retrieve account info:", error); } }; updateBalance(); }, [connection, publicKey]); |
Para obtenção do saldo em si usamos a função nativa getAccountInfo, disponível a partir do objeto connection. Ela espera uma public key e retorna, dentre outras informações, o saldo da conta em lamports, a menor unidade de medida da SOL. Essa informação a gente converte para a escala de SOL, mais fácil do usuário acompanhar, e coloca no state balance que será renderizado automaticamente no espaço apropriado do componente.
Agora importe e posicione esse componente no JSX da tela principal da aplicação.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import BalanceDisplay from "./BalanceDisplay"; function App() { const endpoint = clusterApiUrl("devnet"); const wallets = useMemo(() => [], []); return ( <ConnectionProvider endpoint={endpoint}> <WalletProvider wallets={wallets}> <WalletModalProvider> <WalletMultiButton /> <BalanceDisplay /> </WalletModalProvider> </WalletProvider> </ConnectionProvider> ); } |
E com isso, teste no seu navegador, que deve apresentar algo como abaixo.
E com isso finalizamos a terceira etapa do nosso tutorial!
#4 – Transferindo fundos da Solana
Agora para finalizar nosso tutorial vamos fazer algo ainda mais legal que é transferir fundos de uma carteira para outra usando JS. Para fazer isso você vai precisar ter outra carteira de destino, podendo ser inclusive outra Brave Wallet que você crie ou um software de carteira criado por você.
Crie um novo arquivo no seu projeto com o nome de SendForm.js e dentro dele adicione os seguintes imports. O último só é necessário caso esteja usando create-react-app assim como eu, pois ele resolve um bug comum no ambiente do webpack.
1 2 3 4 5 6 7 8 9 10 11 |
import { useState } from "react"; import { useConnection, useWallet } from "@solana/wallet-adapter-react"; import { PublicKey, Transaction, LAMPORTS_PER_SOL, SystemProgram } from "@solana/web3.js"; import * as buffer from "buffer"; function SendForm() { } export default SendForm; |
Agora dentro do function componente SendForm, declare as seguintes variáveis, que eu explico na sequêcia.
1 2 3 4 5 6 7 |
window.Buffer = buffer.Buffer; const { publicKey, sendTransaction } = useWallet(); const { connection } = useConnection(); const [value, setValue] = useState("0.05"); const [wallet, setWallet] = useState("d9zy8p3VL5Q3yQ9Zt8xCtbuwivcVx9EcjN1G9izP88Z"); |
A primeira tem a ver com o mesmo bug do webpack que citei antes, ignore caso esteja usando Next, Vite ou outro ambiente mais moderno de React. As duas atribuições seguintes são usando hooks do wallet-adapter-react, que servem para pegar a carteira logada (publicKey), a função de envio de transação (sendTransaction) e a conexão com a rede da Solana (connection). Para que estes dois hooks funcionem (useWallet e useConnection), o seu componente deve estar dentro de um WalletContext, coisa que colocaremos ele depois, quando usarmos o SendForm no App.js.
Já as duas declarações seguintes são states React simples, um para o valor a ser transferido (em SOL) e outro para a carteira de destino. Os valores default são opcionais. Com as declarações todas realizadas, vamos escrever o código JSX da página, como abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
return ( <> { publicKey ? ( <> <p>Wallet:</p> <div> <input type="text" style={{ lineHeight: "40px", width: 260 }} value={wallet} onChange={(evt) => setWallet(evt.target.value)}></input> </div> <div style={{ display: "flex", marginTop: 10 }}> <input type="number" style={{ lineHeight: "40px" }} value={value} onChange={(evt) => setValue(evt.target.value)} /> <button className="wallet-adapter-button-trigger wallet-adapter-button" onClick={sendSol}>Send SOL</button> </div> </> ) : <></> } </> ) |
Aqui eu optei por apenas exibir o form de envio quando a publicKey está definida, já que no caso de usuários deslogados não tem como fazer transferências. Nosso formulário é bem simples: são dois campos, um para o valor e outro para o destinatário e um botão, que dispara uma função que criaremos a seguir. Preste atenção especial no value e onChange dos dois inputs, já que eles devem gerenciar os seus respectivos states. Já as classes de estilo que coloquei no botão eu peguei emprestado do pacote de UI que importamos no App.js, mas não são realmente necessários, é apenas estilo.
Para usarmos este componente, importe o SendForm no topo do App.js e inclua ele no código da página como abaixo.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
return ( <ConnectionProvider endpoint={endpoint}> <WalletProvider wallets={wallets}> <WalletModalProvider> <WalletMultiButton /> <BalanceDisplay /> <SendForm /> </WalletModalProvider> </WalletProvider> </ConnectionProvider> ); |
A aparência resultante abaixo.
Agora vamos para a função que envia os fundos de fato, pegando os states e montando a transação.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
async function sendSol() { if (!publicKey) { console.error("Wallet not connected"); return; } try { const recipientPubKey = new PublicKey(wallet); const transaction = new Transaction(); const sendSolInstruction = SystemProgram.transfer({ fromPubkey: publicKey, toPubkey: recipientPubKey, lamports: parseFloat(value) * LAMPORTS_PER_SOL }); transaction.add(sendSolInstruction); const txHash = await sendTransaction(transaction, connection); console.log(`Transaction signature: ${txHash}`); alert("Transaction sent successfully! Tx Hash: " + txHash); } catch (error) { console.error("Transaction failed", error); } }; |
Aqui, fizemos um teste rápido se o usuário está logado e depois vamos para a construção das variáveis necessárias que são o objeto da conta do destinatário, a instrução de envio de fundos e a transação em si, até chegar na chamada da função que envia a mesma. Esse envio irá fazer com que a sua carteira do browser alerte o usuário que uma transação aguarda aprovação, o que ele pode concordar ou rejeitar.
Caso o usuário concorde com a transação, o resultado será o hash da mesma concluída com sucesso (havendo fundos). Esse hash você pode usar para verificar se deu tudo certo no block explorer da Solana, a exemplo dessa transação.
E com isso concluímos este tutorial, agora você já sabe como conectar, ver saldo e transferir fundos da sua carteira Solana usando JavaScript (e React) para outras carteiras na mesma rede.
Mas Luiz, e os outros tokens, pelo que entendi isso tudo que você fez funciona só com SOL, certo?
Esse é um assunto para uma parte 2, sobre como interagir com outras moedas/tokens.


Como criar seu primeiro programa para Solana com Anchor

Como configurar ambiente para desenvolvimento Solana

Como criar sua própria carteira de criptomoedas com JS (Solana) - Parte 2

Como configurar a Brave Wallet para desenvolvimento blockchain
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.