UNPKG

@avalabs/avacloud-waas-react

Version:
447 lines (347 loc) 11.6 kB
# @avalabs/avacloud-waas-react Official React SDK for AvaCloud Wallet-as-a-Service (WaaS) integration. This library provides a seamless way to integrate AvaCloud wallet functionality into your React applications. [![npm version](https://img.shields.io/npm/v/@avalabs/avacloud-waas-react.svg)](https://www.npmjs.com/package/@avalabs/avacloud-waas-react) [![License](https://img.shields.io/npm/l/@avalabs/avacloud-waas-react.svg)](https://github.com/ava-labs/avacloud-waas-react/blob/main/LICENSE) ## Installation ```bash # npm npm install @avalabs/avacloud-waas-react # yarn yarn add @avalabs/avacloud-waas-react # pnpm pnpm add @avalabs/avacloud-waas-react ``` ## Quick Start Wrap your application with the `AvaCloudWalletProvider`: ```tsx import { AvaCloudWalletProvider } from '@avalabs/avacloud-waas-react'; function App() { return ( <AvaCloudWalletProvider orgId="your-avacloud-org-id" // Required chainId={43113} // Avalanche Fuji Testnet > <YourApp /> </AvaCloudWalletProvider> ); } ``` Use the wallet hooks and components in your application: ```tsx import { useAvaCloudWallet, LoginButton, WalletDisplay } from '@avalabs/avacloud-waas-react'; function YourComponent() { const { isAuthenticated, isLoading, user, wallet } = useAvaCloudWallet(); if (isLoading) { return <div>Loading...</div>; } return ( <div> {isAuthenticated ? ( <> <p>Welcome, {user?.email || 'User'}!</p> <WalletDisplay /> </> ) : ( <LoginButton /> )} </div> ); } ``` ## Core Components ### AvaCloudWalletProvider The main provider component that wraps your application and provides wallet context. ```tsx <AvaCloudWalletProvider orgId="your-avacloud-org-id" // Required - your AvaCloud organization ID chainId={43113} // Optional - defaults to Avalanche Fuji Testnet darkMode={false} // Optional - theme mode for UI components onAuthSuccess={(user) => console.log('Auth success', user)} onAuthError={(error) => console.error('Auth error', error)} onWalletUpdate={(wallet) => console.log('Wallet updated', wallet)} > {children} </AvaCloudWalletProvider> ``` #### Props | Prop | Type | Description | |------|------|-------------| | `orgId` | `string` | **Required** - Your AvaCloud organization ID used to fetch wallet configuration | | `env` | `'local' \| 'development' \| 'prod'` | Environment to use (default: `'prod'`) | | `chainId` | `number` | EVM chain ID (default: `43113` - Avalanche Fuji Testnet) | | `darkMode` | `boolean` | Enable dark mode for UI components (default: `false`) | | `onAuthSuccess` | `(user: Auth0User) => void` | Callback on successful authentication | | `onAuthError` | `(error: Error) => void` | Callback on authentication error | | `onWalletUpdate` | `(wallet: WalletInfo) => void` | Callback when wallet information updates | ### UI Components - `LoginButton`: Button component for initiating the login flow - `WalletButton`: Button component for displaying wallet information and actions - `WalletDisplay`: Component for displaying wallet address and balance - `UserProfile`: Component for displaying user profile information - `WalletCard`: Card component for displaying wallet information - `TokensView`: Component for displaying token balances - `SendView`: Component for sending tokens - `ReceiveView`: Component for receiving tokens (displays QR code) - `ExportView`: Component for exporting wallet information ## Hooks ### useAvaCloudWallet The main hook for accessing wallet state and methods. ```tsx const { isAuthenticated, isLoading, user, wallet, login, logout, addAccount, } = useAvaCloudWallet(); ``` ### useAuth Simplified hook for basic authentication state. ```tsx const { isAuthenticated, login, logout } = useAuth(); ``` ### useSignMessage Hook for signing messages with the connected wallet. ```tsx const { signMessage, isLoading, error } = useSignMessage(); const handleSign = async () => { try { const signature = await signMessage('Hello, AvaCloud!'); console.log('Signature:', signature); } catch (error) { console.error('Error signing message:', error); } }; ``` ### useSignTransaction Hook for signing transactions with the connected wallet. ```tsx const { signTransaction, isLoading, error } = useSignTransaction(); const handleSignTx = async () => { try { const signedTx = await signTransaction({ to: '0x...', value: '0.1', data: '0x...', }); console.log('Signed transaction:', signedTx); } catch (error) { console.error('Error signing transaction:', error); } }; ``` ### useTransferTokens Hook for transferring tokens. ```tsx const { transfer, isLoading, error } = useTransferTokens(); const handleTransfer = async () => { try { const txHash = await transfer({ to: '0x...', amount: '0.1', tokenAddress: '0x...', // Optional, use null for native token }); console.log('Transaction hash:', txHash); } catch (error) { console.error('Error transferring tokens:', error); } }; ``` ### useUserWallets Hook for accessing and managing user wallets. ```tsx const { wallets, isLoading, error } = useUserWallets(); ``` ### useChainId Hook for accessing and setting the current chain ID. ```tsx const { chainId, setChainId } = useChainId(); ``` ### useGaslessTransaction Hook for sending gasless (meta-)transactions through AvaCloud's gas relayer. ```tsx import { useGaslessTransaction, useGlacier } from '@avalabs/avacloud-waas-react'; function CounterExample() { // Retrieve the current subnet RPC URL from Glacier const { blockchain } = useGlacier(); const gaslessConfig = { relayerUrl: 'https://gas-relayer.avax-test.network/printedapr/testnet/rpc', // AvaCloud relayer RPC subnetRpcUrl: blockchain?.rpcUrl || '', // Target subnet RPC forwarderAddress: '0x52ec85e43d09889b2bf9e431935356e06f023680', // AvaCloud forwarder domainName: 'Counter', domainVersion: '1', requestType: 'Message', suffixType: 'bytes32', // Optional – request suffix type suffixName: 'XMKUCJONOFSUSFCYHTYHCLX', // Optional – request suffix name } as const; // Counter contract information const COUNTER_CONTRACT_ADDRESS = '0xe4bB5F15dc278197FcE9B21e5aC0442a95e25b5f'; const COUNTER_INCREMENT_ABI = [ { inputs: [], name: 'increment', outputs: [], stateMutability: 'nonpayable', type: 'function', }, ] as const; const { sendGaslessTransaction, isLoading, error, txHash, reset, } = useGaslessTransaction({ gaslessConfig, contractAddress: COUNTER_CONTRACT_ADDRESS, abi: COUNTER_INCREMENT_ABI, }); const handleIncrement = () => sendGaslessTransaction({ functionName: 'increment' }); return ( <div> <button onClick={handleIncrement} disabled={isLoading}> Increment counter (no gas) </button> {isLoading && <p>Sending transaction…</p>} {txHash && <p>Transaction hash: {txHash}</p>} {error && <p style={{ color: 'red' }}>{error}</p>} <button onClick={reset}>Reset</button> </div> ); } ``` **Parameters returned by the hook** | Property | Type | Description | |----------|------|-------------| | `sendGaslessTransaction` | `(params: { functionName: string; args?: unknown[]; abi?: unknown; contractAddress?: string }) => Promise<void>` | Sends the meta-transaction | | `isLoading` | `boolean` | `true` while the transaction is being prepared or broadcast | | `error` | `string \| null` | Error message, if any | | `txHash` | `string \| null` | Transaction hash once broadcast | | `reset` | `() => void` | Resets the hook state | ## WAGMI Integration This SDK includes a WAGMI connector that allows you to use AvaCloud wallets with WAGMI (React Ethereum Library). ### Prerequisites Install the required WAGMI dependencies: ```bash npm install wagmi viem@2.x @tanstack/react-query ``` ### Setting up WAGMI with AvaCloud ```tsx import { WagmiProvider, createConfig } from 'wagmi'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { avaCloudWallet } from '@avalabs/avacloud-waas-react'; import { avalancheFuji } from 'wagmi/chains'; import { http } from 'wagmi'; const queryClient = new QueryClient(); const config = createConfig({ chains: [avalancheFuji], connectors: [ avaCloudWallet(), ], transports: { [avalancheFuji.id]: http(), }, }); function App() { return ( <QueryClientProvider client={queryClient}> <WagmiProvider config={config}> <AvaCloudWalletProvider orgId="your-avacloud-org-id"> <YourApp /> </AvaCloudWalletProvider> </WagmiProvider> </QueryClientProvider> ); } ``` ### Using WAGMI Hooks Once configured, use standard WAGMI hooks with your AvaCloud wallet: ```tsx import { useAccount, useConnect, useDisconnect, useSignMessage } from 'wagmi'; function WagmiExample() { const { address, isConnected } = useAccount(); const { connect, connectors } = useConnect(); const { disconnect } = useDisconnect(); const { signMessage } = useSignMessage(); const handleConnect = () => { const avaCloudConnector = connectors.find(c => c.id === 'avaCloudWallet'); if (avaCloudConnector) { connect({ connector: avaCloudConnector }); } }; const handleSign = async () => { const signature = await signMessage({ message: 'Hello from WAGMI!' }); console.log('Signature:', signature); }; return ( <div> {isConnected ? ( <> <p>Connected: {address}</p> <button onClick={() => disconnect()}>Disconnect</button> <button onClick={handleSign}>Sign Message</button> </> ) : ( <button onClick={handleConnect}>Connect AvaCloud Wallet</button> )} </div> ); } ``` ### Important Notes - The AvaCloud WAGMI connector requires the `AvaCloudWalletProvider` to be present in your component tree - Authentication is still managed through the AvaCloud SDK's authentication flow - The connector automatically syncs with the wallet state from `AvaCloudWalletProvider` - All standard WAGMI hooks and functionality are supported ## Advanced Usage ### Theme Customization Use the `ThemeProvider` to customize the appearance of UI components: ```tsx import { ThemeProvider } from '@avalabs/avacloud-waas-react'; function App() { return ( <ThemeProvider darkMode={true}> <YourApp /> </ThemeProvider> ); } ``` ### Custom Authentication Flow You can implement a custom authentication flow using the lower-level hooks: ```tsx import { usePostMessage } from '@avalabs/avacloud-waas-react'; function CustomAuth() { const { sendMessage, lastMessage } = usePostMessage(); const handleCustomLogin = () => { sendMessage({ type: 'login', payload: { // Custom payload } }); }; // Handle response in useEffect useEffect(() => { if (lastMessage?.type === 'login_success') { // Handle successful login } }, [lastMessage]); return ( <button onClick={handleCustomLogin}> Custom Login </button> ); } ``` ## Browser Support - Chrome (latest) - Firefox (latest) - Safari (latest) - Edge (latest) ## Contributing We welcome contributions! Please see [CONTRIBUTING.md](https://github.com/ava-labs/avacloud-waas-react/blob/main/CONTRIBUTING.md) for details. ## License MIT © [Ava Labs, Inc.](https://github.com/ava-labs)