Skip to main content

Interfacing with external wallets

With Privy, your users can connect external wallets like MetaMask, Coinbase Wallet, Rainbow Wallet, and more to your app. You can use popular web3 libraries like ethers.js, web3.js, wagmi, and others to request signatures and transactions from external wallets that have been connected through Privy.

Connecting a wallet

Apps can connect any number of wallets by calling the connectWallet method from the usePrivy hook. You may then access the recently connected wallet via the wallets array from the useWallets hook.

import { usePrivy } from '@privy-io/react-auth';

export default function ConnectWalletButton() {
const { connectWallet } = usePrivy();

// Prompt user to connect a wallet with Privy modal
return <button onClick={connectWallet}>Connect Wallet</button>;
}
tip

You can easily attach callbacks to connectWallet using the new useConnectWallet interface! Read more here.

Handling wallets with the useWallets hook

When a user connects their wallet to your app using connectWallet, linkWallet, or login, Privy adds a new ConnectedWallet object to the wallets array from the useWallets hook. This list includes external wallets and embedded wallets.

This powerful wallets array can be used for more complex flows. For example, while we recommend using our built-in login for standard use cases, you can split the connect and login calls, allowing for more customization of the flow.

Login with a connected wallet
import { usePrivy, useWallets } from '@privy-io/react-auth';

export default function ConnectAndLogin() {
const { connectWallet, ready, authenticated } = usePrivy();
const { wallets } = useWallets();

// Prompt user to sign a message
return <div>
<button onClick={() => connectWallet()}>Connect Wallet</button>
<p>Most recent wallet: {wallets[0] ? wallets[0].address : "none"}</p>
<button onClick={() => wallets[0]?.loginOrLink()} disabled={!ready || !wallets[0] || !authenticated}>Login</button>
</div>;
}

The wallets array is always sorted by most-recently-connected. Therefore, wallets[0] will always be the most recently connected wallet.

The ConnectedWallet object has several properties and methods that you can use to interact with the user's wallet.

Properties

The ConnectedWallet object has the following properties:

  • address: checksum formatted Ethereum address
  • chainId: a CAIP-2 formatted chain ID
  • linked: is set to false if the user is not authenticated or the user is authenticated and this wallet has not yet been linked to the current user
  • walletClientType: the type of wallet provider (metamask, trust, rainbow, etc)
  • connectorType: the method by which the wallet is connected (injected, wallet_connect, coinbase_wallet, etc)
  • connectedAt: time this wallet was last connected

Methods

The Wallet object has the following methods:

  • loginOrLink(): logs in or links using the currently connected wallet by prompting the user for a signature
  • unlink(): unlinks the currently connected wallet from the authenticated user
  • sign(message: string): sign a message with personal_sign using the currently connected wallet
  • getEthersProvider(): get an ethers provider
  • getWeb3jsProvider(): get a Web3JS provider
  • getEthereumProvider(): get an EIP1193 provider

Requesting a signature

Signatures can be requested with any third party integration or on the wallet object directly.

import { useWallets } from '@privy-io/react-auth';

export default function SignMessageButton() {
const { wallets } = useWallets();

// Prompt user to sign a message
return <button onClick={() => wallets[0]?.sign("Hello World.")} disabled={!wallets[0]}>Sign Message</button>;
}

Sending a transaction

Signatures can be requested with any third party integration. As an example, we will request a signature with the Ethers.js integration.

import { useWallets } from '@privy-io/react-auth';

export default function SendTransactionButton() {
const { wallets } = useWallets();

async function sendTransaction() {
// Get an ethers provider and signer from the most recently connected wallet
const provider = await wallets[0]?.getEthersProvider();
const signer = await provider?.getSigner();

const txn = {
from: ...,
to: ...,
value: ...,
nonce: ...,
gasLimit: ...,
gasPrice: ...,
}

// Send transaction
signer.sendTransaction(txn).then((completedTxn) => {
console.log(completedTxn);
});
}

// Prompt user to sign a message
return <button onClick={() => sendTransaction()} disabled={!wallets[0]}>Sign Message</button>;
}

Integrations

Privy provides a number of integrations to allow developers to continue to use their favorite web3 libraries.

Ethers.js

info

If you need the user's wallet to take action on a given network, you should switch the user's wallet to the desired network before initializing the wallet's ethers provider. Otherwise, the provider may be configured for an out-of-date network.

You can get an ethers-compatible provider from a user's wallet by calling the getEthersProvider method from a wallet in the wallets array. You may then use this as an ethers provider to read blockchain data and send requests to a user’s wallet.

Example Ethers.js Integration
import { useWallets } from '@privy-io/react-auth';

export default function MyComponent() {
const { wallets } = useWallets();

const getEthersSigner = async () => {
// Switch the wallet to your target chain before getting the ethers provider
await wallets[0]?.switchChain('your-target-chain-id');
// Get an ethers provider and signer from the user's recently connected wallet
const provider = await wallets[0]?.getEthersProvider();
return await provider?.getSigner();
}

return <>{/* your code here */}</>
}

Ethereum Javascript API

You can get a generic EIP-1193 (Ethereum Javascript API) provider that you may use to communicate with a user’s wallet (via JSON-RPC). You can access this provider using the getEthereumProvider method from a wallet in the wallets array.

Example Usage of EIP-1193 Provider
import { useWallets } from '@privy-io/react-auth';

export default function MyComponent() {
const { wallets } = useWallets();

// You can now use the ethereum.request({method: ...})
// syntax as documented in the EIP.
const getEthereumProvider = async () => {
// Initialize your Web3.js client with the provider
return await wallets[0]?.getEthereumProvider();
}

return <>{/* your code here */}</>
}

Wagmi

Privy offers a Wagmi Connector package that you can use to integrate wagmi alongside Privy in your app. Please see our guide for more.

Viem

info

If you need the user's wallet to take action on a given network, you should switch the user's wallet to the desired network before initializing the wallet's viem WalletClient. Otherwise, the WalletClient may be configured for an out-of-date network.

You can get a Viem-compatible wallet client for a user's wallet by:

  1. Getting an EIP1193 provider from Privy's getEthereumProvider method, and then
  2. Passing this provider and the chain you need to Viem's createWalletClient method

You may then use this wallet client to read blockchain data and send requests to a user’s wallet.

Example Viem Integration
import { useWallets } from '@privy-io/react-auth';
import { createWalletClient, custom } from 'viem';
// Replace 'mainnet' below with the chain your application needs
// See https://viem.sh/docs/clients/chains.html
import { mainnet } from 'viem/chains';

export default function MyComponent() {
const { wallets } = useWallets();

const getViemWalletClient = async () => {
// Switch your wallet to your target chain before getting the viem WalletClient
await wallets[0]?.switchChain('your-target-chain-id');
// Get an EIP1193 provider from the user's wallet
const ethereumProvider = await wallets[0]?.getEthereumProvider();
// Create a Viem wallet client from the EIP1193 provider
const walletClient = await createWalletClient({
account: embeddedWallet?.address,
chain: mainnet,
transport: custom(ethereumProvider)
});
return walletClient;
}

return <>{/* your code here */}</>
}

Web3.js

info

If you need the user's wallet to take action on a given network, you should switch the user's wallet to the desired network before initializing the wallet's web3.js provider. Otherwise, the provider may be configured for an out-of-date network.

You can get a web3.js-compatible provider from a user's wallet by calling the getWeb3jsProvider method from a wallet in the wallets array. You can then initialize your web3 client with this provider.

Example Web3.js Integration
import { useWallets } from '@privy-io/react-auth';
import Web3 from 'web3';

export default function MyComponent() {
const { wallets } = useWallets();

const getWeb3Provider = async () => {
// Initialize your Web3.js client with the provider
const provider = await wallets[0]?.getWeb3jsProvider();
return new Web3(provider);
}

return <>{/* your code here */}</>
}