Adaptador de Wallet para Constructores de Dapps
Aptos proporciona un Provider
y Context
de React para conectar wallets de Aptos a tu dapp. Este Provider
te permite especificar qué Wallets quieres permitir conexiones. Luego puedes usar el Provider
para buscar información de cuenta y firmar transacciones / mensajes.
Esto proporciona una interfaz estándar para usar todas las wallets de Aptos, y permite que nuevas wallets sean fácilmente soportadas simplemente actualizando tu versión de dependencia del Adaptador de Wallet de React.
Usando el Provider
y Context
de React
Sección titulada «Usando el Provider y Context de React»-
Instalar @aptos-labs/wallet-adapter-react.
Ventana de terminal npm install @aptos-labs/wallet-adapter-reactPara versiones anteriores a v4.0.0
(Opcional) Instalar los plugins para cualquier Wallet “Compatible con Estándar Legacy” que quieras soportar de esta lista.
Sección titulada «(Opcional) Instalar los plugins para cualquier Wallet “Compatible con Estándar Legacy” que quieras soportar de esta lista.»Para wallets que no se han actualizado para usar el estándar AIP-62, sus plugins deben ser instalados y pasados al
Provider
manualmente.Por ejemplo:
Ventana de terminal npm i @okwallet/aptos-wallet-adapterEn
Sección titulada «En App.tsx o su equivalente, importar el Adaptador de Wallet de Aptos y cualquier plugin de Wallet legacy.»App.tsx
o su equivalente, importar el Adaptador de Wallet de Aptos y cualquier plugin de Wallet legacy.import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";// Importar cualquier plugin de wallet adicional. Ej.import { OKXWallet } from "@okwallet/aptos-wallet-adapter";// ... -
Inicializar el AptosWalletAdapterProvider.
Puedes usar cualquiera de los siguientes campos opcionales.
Se recomienda:
- Establecer
autoConnect
atrue
. - Establecer el
dappConfig
con:
- La propiedad
network
establecida en la red con la que trabaja tu dapp - La propiedad
aptosApiKeys
establecida en la Api Key generada para la red especificada
Campo Descripción Ejemplo autoConnect
Una prop indica si la dapp debe auto conectarse con la wallet más recientemente conectada al recargar la página. true
dappConfig
Especificar una red alternativa para trabajar. Esta prop solo funciona para wallets que NO son extensiones de chrome. Si se establece, este objeto debe incluir el nombre de la red a la que está conectada la app. El objeto puede incluir un aptosConnectDappId. { network: 'mainnet', aptosApiKeys:{}, aptosConnectDappId: undefined }
onError
Una función de callback para ejecutar cuando el adaptador lanza un error. (error) => { console.log("error", error); }
Ejemplo Completo
Sección titulada «Ejemplo Completo»import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";import { PropsWithChildren } from "react";import { Network } from "@aptos-labs/ts-sdk";export const WalletProvider = ({ children }: PropsWithChildren) => {return (<AptosWalletAdapterProviderautoConnect={true}dappConfig={{network: Network.MAINNET,aptosApiKeys: {mainnet: process.env.APTOS_API_KEY_MAINNET,}}}onError={(error) => {console.log("error", error);}}>{children}</AptosWalletAdapterProvider>);}; - Establecer
-
Importar useWallet en archivos donde quieras acceder a datos del Provider.
import { useWallet } from "@aptos-labs/wallet-adapter-react";// Access fields / functions from the adapterconst { account, connected, wallet, changeNetwork } = useWallet();
Elegir un Paquete de UI
Sección titulada «Elegir un Paquete de UI»El Repositorio del Adaptador de Wallet proporciona varios paquetes de UI para simplificar la posibilidad de que los usuarios se conecten y seleccionen una wallet.
Para componentes de UI que funcionan de forma nativa, pero son menos personalizables, elige uno de:
- Ant Design
- MUI (Material UI)
De lo contrario, deberías usar el selector de wallet de shadcn/ui, ya que tiene las opciones de personalización más completas. Para más detalles sobre cómo personalizar este selector de wallet o construir tu propio selector de wallet, consulta esta guía.
useWallet
Campos y Funciones
Sección titulada «useWallet Campos y Funciones»Campo | Tipo | Descripción |
---|---|---|
connected | boolean | Indica si la wallet está actualmente conectada. |
isLoading | boolean | Indica si una operación de wallet está actualmente cargando. |
account | { address: string; publicKey: string | string[]; minKeysRequired?: number; ansName?: string | null; } | null | Información de la cuenta actual o null si no hay ninguna cuenta conectada. |
network | { name: Network; chainId?: string; url?: string; } | null | Información de la red actual o null si no se ha seleccionado ninguna red. |
wallet | { name: WalletName; icon: string; url: string; } | null | Información de la wallet actual o null si no se ha seleccionado ninguna wallet. Incluye el nombre de la wallet, el icono y la URL. |
wallets | ReadonlyArray<{ name: WalletName; url: string; icon: string; readyState: WalletReadyState.NotDetected; isAIP62Standard: true; }> | Lista de wallets disponibles, incluyendo las estándares soportadas, cada una con nombre, URL, icono, estado de preparación, y indicación de cumplimiento con la estándar AIP-62. |
Funciones
Sección titulada «Funciones»Ver WalletCore.ts
en wallet-adapter-core
para donde se implementan estas funciones.
Función | Firma | Descripción |
---|---|---|
connect | connect(walletName: WalletName): void | Conecta a la wallet especificada por su nombre. |
disconnect | disconnect(): void | Desconecta la wallet actualmente conectada. |
signTransaction | signTransaction(transactionOrPayload: AnyRawTransaction | Types.TransactionPayload, asFeePayer?: boolean, options?: InputGenerateTransactionOptions): Promise<AccountAuthenticator> | Firma una transacción con parámetros opcionales para el pago de tarifas. |
submitTransaction | submitTransaction(transaction: InputSubmitTransactionData): Promise<PendingTransactionResponse> | Envía una transacción con los datos de transacción proporcionados. |
signAndSubmitTransaction | signAndSubmitTransaction(transaction: InputTransactionData): Promise<any> | Firma y envía una transacción con los datos de entrada dados. |
signMessage | signMessage(message: SignMessagePayload): Promise<SignMessageResponse> | Firma un mensaje y devuelve la firma y la información de respuesta. |
signMessageAndVerify | signMessageAndVerify(message: SignMessagePayload): Promise<boolean> | Firma un mensaje y verifica el firmante. |
changeNetwork | changeNetwork(network: Network): Promise<AptosChangeNetworkOutput> | Solicita un cambio en la red conectada. Esto no es soportado por todas las wallets. |
Ejemplos de Código
Sección titulada «Ejemplos de Código»Consulta el dapp de ejemplo de next.js para ver cómo se utilizan estos componentes en la práctica:
wallets
Sección titulada «wallets»wallets
es una lista de wallets disponibles, incluyendo las estándares soportadas, cada una con nombre, URL, icono, estado de preparación, y indicación de cumplimiento con la estándar AIP-62.
import { useWallet } from '@aptos-labs/wallet-adapter-react';
const displayInstalledWalletsDemo = () => {
const { wallets } = useWallet();
return ( <div> {wallets.map(wallet => { return <p>{wallet.name}</p> })} </div> )}
Soporte para Wallets no Instalados
Sección titulada «Soporte para Wallets no Instalados»Según la estándar AIP-62, el adaptador usa un modelo de comunicación basado en eventos entre una wallet y una dapp. Esto significa que solo las wallets instaladas en el navegador del usuario son detectadas automáticamente y disponibles para su uso. Para soportar el ecosistema completo de wallets de Aptos, el adaptador mantiene un registro de wallets soportados—permitiendo que las dapps también muestren wallets no instalados. También expone una función de utilidad para gestionar fácilmente todas las wallets.
import { useWallet, groupAndSortWallets } from '@aptos-labs/wallet-adapter-react';
const displayAllWalletsDemo = () => {
const { wallets = [], notDetectedWallets = [] } = useWallet();
const { aptosConnectWallets, availableWallets, installableWallets } = groupAndSortWallets( [...wallets, ...notDetectedWallets] );
return ( <div> /** Wallets que usan el login social para crear una cuenta en la blockchain */ {aptosConnectWallets.map((aptosConnectwallet) => ( return <p>{aptosConnectwallet.name}</p> ))} /** Wallets que están actualmente instaladas o cargables. */ {availableWallets.map((availableWallet) => ( return <p>{availableWallet.name}</p> ))} /** Wallets que NO están actualmente instaladas o cargables. */ {installableWallets.map((installableWallet) => ( return <p>{installableWallet.name}</p> ))} </div> )}
connect()
y disconnect()
Sección titulada «connect() y disconnect()»connect()
establece una conexión entre la dapp y una Wallet. Luego puedes usar disconnect()
para
import React from 'react';import { WalletName, useWallet } from '@aptos-labs/wallet-adapter-react';
const WalletConnectDemo = () => { const { connect, disconnect, account, connected } = useWallet();
const handleConnect = async () => { try { // Cambia a continuación el nombre de la wallet deseado en lugar de "Petra" await connect("Petra" as WalletName<"Petra">); console.log('Conectado a la wallet:', account); } catch (error) { console.error('Error al conectar a la wallet:', error); } };
const handleDisconnect = async () => { try { await disconnect(); console.log('Desconectado de la wallet'); } catch (error) { console.error('Error al desconectar de la wallet:', error); } };
return ( <div> <h1>Conexión de Wallet de Aptos</h1> <div> {connected ? ( <div> <p>Conectado a: {account?.address}</p> <button onClick={handleDisconnect}>Desconectar</button> </div> ) : ( <button onClick={handleConnect}>Conectar Wallet</button> )} </div> </div> );};
export default WalletConnectDemo;
signAndSubmitTransaction
Sección titulada «signAndSubmitTransaction»Si quieres separar estos pasos, puedes usar signTransaction
y submitTransaction
por separado en lugar de signAndSubmitTransaction
.
import React from 'react';import { useWallet } from '@aptos-labs/wallet-adapter-react';import { Aptos, AptosConfig, Network } from '@aptos-labs/ts-sdk';
const config = new AptosConfig({ network: Network.MAINNET });const aptos = new Aptos(config);
const SignAndSubmit = () => { const { account, signAndSubmitTransaction } = useWallet();
const onSignAndSubmitTransaction = async () => { if(account == null) { throw new Error("No se pudo encontrar la cuenta para firmar la transacción") } const response = await signAndSubmitTransaction({ sender: account.address, data: { function: "0x1::aptos_account::transfer", functionArguments: [account.address, 1], }, }); // si quieres esperar a la transacción try { await aptos.waitForTransaction({ transactionHash: response.hash }); } catch (error) { console.error(error); } };
return ( <button onClick={onSignAndSubmitTransaction}> Firmar y enviar transacción </button> );};
export default SignAndSubmit;
signMessage
y verifyMessage
También puedes usar el atajo signAndVerifyMessage
para crear un mensaje que pueda ser verificable desde la wallet conectada.
import React, { useState } from 'react';import { useWallet } from '@aptos-labs/wallet-adapter-react';
const SignMessageDemo = () => { const { signMessage, signMessageAndVerify, connected, account } = useWallet(); const [message, setMessage] = useState<string>(''); const [nonce, setNonce] = useState<string>(''); const [signedMessage, setSignedMessage] = useState<any>(null); const [verificationResult, setVerificationResult] = useState<boolean | null>(null); const [error, setError] = useState<string | null>(null);
const handleSignMessage = async () => { setError(null); try { const response = await signMessage({ message, nonce }); setSignedMessage(response); } catch (err: any) { setError(`Error al firmar el mensaje: ${err.message}`); } };
const handleVerifyMessage = async () => { setError(null); try { const result = await signMessageAndVerify({ message, nonce }); setVerificationResult(result); } catch (err: any) { setError(`Error al verificar el mensaje: ${err.message}`); } };
return ( <div> <h1>Firma y Verifica Mensaje de Aptos</h1> <div> {connected ? ( <div> <p>Conectado a: {account?.address}</p> <div className="flex flex-col gap-4"> <textarea value={message} onChange={(e) => setMessage(e.target.value)} placeholder="Introduce tu mensaje aquí" className="border rounded p-2" /> <input type="text" value={nonce} onChange={(e) => setNonce(e.target.value)} placeholder="Introduce el nonce (cadena aleatoria) aquí" className="border rounded p-2 mt-2" /> <button onClick={handleSignMessage} className="bg-blue-500 text-white rounded p-2 mt-2"> Firmar Mensaje </button> {signedMessage && ( <div> <h4>Mensaje Firmado</h4> <pre>{JSON.stringify(signedMessage, null, 2)}</pre> <button onClick={handleVerifyMessage} className="bg-green-500 text-white rounded p-2 mt-2"> Verificar Mensaje </button> </div> )} {verificationResult !== null && ( <div> <h4>Resultado de Verificación</h4> <p>{verificationResult ? 'El mensaje está verificado!' : 'No se pudo verificar el mensaje.'}</p> </div> )} {error && ( <div className="text-red-600"> <p>{error}</p> </div> )} </div> </div> ) : ( <p>Por favor, conecta tu wallet para firmar y verificar mensajes.</p> )} </div> </div> );};
export default SignMessageDemo;
changeNetwork
(No soportado por todas las wallets)
Sección titulada «changeNetwork (No soportado por todas las wallets)»Algunas wallets solo soportan mainnet, por lo que no soportarán changeNetwork
. Si dependes de esta característica, asegúrate de implementar el manejo de errores para si una wallet que no soporta changeNetwork
. Nightly es un ejemplo de una wallet que sí soporta changeNetwork
.
import React from 'react';import { useWallet } from '@aptos-labs/wallet-adapter-react';import { Network } from '@aptos-labs/ts-sdk';
const ChangeNetworkDemo = () => { const { network, changeNetwork, wallet } = useWallet(); const isNetworkChangeSupported = wallet?.name === "Nightly";
const isValidNetworkName = () => { return network && Object.values<string>(Network).includes(network.name); };
return ( <div> <h4>Información de Red</h4> <div> <div><strong>Nombre de Red</strong></div> <div> <span style={{ color: isValidNetworkName() ? 'green' : 'red' }}> {network?.name ?? 'No Presente'} </span> {` (Esperado: ${Object.values<string>(Network).join(', ')})`} </div> <div><strong>URL</strong></div> <div> {network?.url ? ( <a href={network.url} target="_blank" rel="noreferrer"> {network.url} </a> ) : ( 'No Presente' )} </div> <div><strong>ID de Cadena</strong></div> <div>{network?.chainId ?? 'No Presente'}</div> </div> <div> <h4>Cambiar Red</h4> <div> <label> <input type="radio" name="network" value={Network.DEVNET} checked={network?.name === Network.DEVNET} onChange={() => changeNetwork(Network.DEVNET)} disabled={!isNetworkChangeSupported} /> Devnet </label> <label> <input type="radio" name="network" value={Network.TESTNET} checked={network?.name === Network.TESTNET} onChange={() => changeNetwork(Network.TESTNET)} disabled={!isNetworkChangeSupported} /> Testnet </label> <label> <input type="radio" name="network" value={Network.MAINNET} checked={network?.name === Network.MAINNET} onChange={() => changeNetwork(Network.MAINNET)} disabled={!isNetworkChangeSupported} /> Mainnet </label> </div> {!isNetworkChangeSupported && ( <div> * {wallet?.name ?? 'Esta wallet'} no soporta solicitudes de cambio de red </div> )} </div> </div> );};
export default ChangeNetworkDemo;
signAndSubmitBCSTransaction(payload)
(No soportado por todas las wallets)
Sección titulada «signAndSubmitBCSTransaction(payload) (No soportado por todas las wallets)»Es similar a la lógica de signAndSubmit
, pero usa un formato BCS para el data
de la transacción.
const onSignAndSubmitBCSTransaction = async () => { const response = await signAndSubmitTransaction({ sender: account.address, data: { function: "0x1::aptos_account::transfer", functionArguments: [AccountAddress.from(account.address), new U64(1)], }, }); // si quieres esperar a la transacción try { await aptos.waitForTransaction({ transactionHash: response.hash }); } catch (error) { console.error(error); }};
<button onClick={onSignAndSubmitTransaction}> Firmar y enviar transacción BCS</button>;
Soporte para móviles
Sección titulada «Soporte para móviles»Dado que las extensiones de Chrome no son soportadas por defecto en los navegadores móviles, el adaptador mantiene un registry
de wallets no detectadas, incluyendo una propiedad deeplinkProvider
para wallets que soportan enlaces profundos.
Esto permite que la dapp muestre wallets que no son detectables en una vista de navegador móvil pero que aún pueden ser conectadas redirigiendo al usuario a una vista de navegador de aplicación en el navegador.
{ name: "Petra", url: "https://chromewebstore.google.com/detail/petra-aptos-wallet/ejjladinnckdgjemekebdpeokbikhfci?hl=en", icon: "data:image/png;base64,iVBOR...QmCC", readyState: WalletReadyState.NotDetected, isAIP62Standard: true, deeplinkProvider: "https://petra.app/explore?link=",}
Para renderizar wallets con soporte para deeplinkProvider
en tu dapp—asumiendo que no estás usando el selector de wallet oficial del adaptador—sigue estos pasos:
-
Recupera todas las wallets compatibles y agrupalas por tipo de wallet
import { useWallet, groupAndSortWallets } from '@aptos-labs/wallet-adapter-react';const displayAllWalletsDemo = () => {const { wallets = [], notDetectedWallets = [] } = useWallet();const { aptosConnectWallets, availableWallets, installableWallets } =groupAndSortWallets([...wallets, ...notDetectedWallets]);return (<div>/** Wallets que usan el login social para crear una cuenta en la blockchain */{aptosConnectWallets.map((aptosConnectwallet) => (<WalletItemComponent wallet={aptosConnectwallet}/>))}/** Wallets que están actualmente instaladas o cargables. */{availableWallets.map((availableWallet) => (<WalletItemComponent wallet={availableWallets}/>))}/** Wallets que NO están actualmente instaladas o cargables. */{installableWallets.map((installableWallet) => (<WalletItemComponent wallet={installableWallets}/>))}</div>)}Este fragmento de código recupera todas las wallets en el ecosistema de Aptos que son soportadas por el adaptador de wallet.
-
Muestra las wallets no instaladas con soporte para enlaces profundos en la vista móvil.
Para asegurarnos de que solo se muestren wallets que soportan enlaces profundos en móviles, podemos verificar tanto el soporte para
deepLinkProvider
como el tipo de vista actual.En el componente que renderiza cada wallet:
import { useWallet, WalletReadyState } from '@aptos-labs/wallet-adapter-react';const WalletItemComponent = (wallet) => {const { connect } = useWallet();// En móviles, las wallets de extensión nunca tendrán un estado de `Installed`const isWalletReady = wallet.readyState === WalletReadyState.Installed;// Verifica si la wallet soporta enlaces profundos en móviles.const mobileSupport ="deeplinkProvider" in wallet && wallet.deeplinkProvider;// Si la wallet no está instalada, el usuario está en una vista redirigible (es decir, navegador móvil pero no navegador de aplicación),// y la wallet no soporta enlaces profundos—no mostrar la wallet.if (!isWalletReady && isRedirectable() && !mobileSupport) return null;// De lo contrario, mostrar la walletreturn (<Button onClick={connect(wallet)}>{wallet.name}</Button>)}Este fragmento de código asegura que el objeto
wallet
correcto se muestre en la vista apropiada.