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>;
}
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.
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 addresschainId
: a CAIP-2 formatted chain IDlinked
: 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 userwalletClientType
: 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 signatureunlink()
: unlinks the currently connected wallet from the authenticated usersign(message: string)
: sign a message with personal_sign using the currently connected walletgetEthersProvider()
: get an ethers providergetWeb3jsProvider()
: get a Web3JS providergetEthereumProvider()
: 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
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.
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.
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
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:
- Getting an EIP1193 provider from Privy's
getEthereumProvider
method, and then - 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.
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
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
.
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 */}</>
}