Skip to content

v1.x.x to v2.0.0 migration guide for react-auth

This guide will help you migrate your Privy React SDK from v1.x.x to v2.0.0.

To install the latest version, install the package from the latest tag:

bash
npm i @privy-io/react-auth@latest

New features and improvements 🎉

  • Removed ethers v5 dependency, allowing developers to more easily use ethers v6
  • Added support for submitting transactions without waiting for confirmation
  • Added UIs for Ethereum signTransaction

For the full set of changes check out our changelog

Breaking changes

Authentication

  • Guaranteed that user.wallet is the first linked wallet on the user object. To maintain state of the latest connected wallet, interact with the wallets array directly.

  • Removed the forkSession method. This feature was experimental and has been removed.

  • Removed the PrivyProvider's deprecated onSuccess prop - use the onSuccess callback registered via the useLogin hook instead.

Embedded wallets

  • Apps using custom auth providers must now explicitly configure wallet UIs in the dashboard, or use the updated showWalletUIs option.

  • Removed the PrivyProvider's deprecated createPrivyWalletOnLogin prop. Use config.embeddedWallets.createOnLogin instead.

tsx
<PrivyProvider
  createPrivyWalletOnLogin={true} 
  config={{
    embeddedWallets: {createOnLogin: 'users-without-wallets'}, 
  }}
>
  ...
</PrivyProvider>
  • Removed the deprecated additionalChains and rpcConfig props from PrivyProvider config, please configure these via the supportedChains
tsx
<PrivyProvider
  config={{
    additionalChains: [], 
    rpcConfig: {}, 
    supportedChains: [], 
  }}
>
  ...
</PrivyProvider>
  • Removed the deprecated noPromptOnSignature configuration option. Configure wallet UIs in the dashboard, or use the updated showWalletUIs option.
tsx
<PrivyProvider
  config={{
    embeddedWallets: {
      noPromptOnSignature: true, 
      showWalletUIs: false, 
    },
  }}
>
  ...
</PrivyProvider>

EVM

  • Removed the deprecated getEthersProvider and getWeb3jsProvider from the ConnectedWallet class. Use getEthereumProvider instead.
ts
const provider = await wallet.getEthersProvider(); 
const privyProvider = await wallet.getEthereumProvider(); 
const provider = new ethers.providers.Web3Provider(privyProvider); 

const provider = await wallet.getWeb3jsProvider(); 
const privyProvider = await wallet.getEthereumProvider(); 
const provider = new Web3(privyProvider); 
  • Ethereum sendTransaction method now returns a Promise<{hash: string}> instead of a Promise<TransactionReceipt>. To get the full details of the submitted transaction, use a library like viem.
tsx
const receipt = await sendTransaction({...}); 
const {hash} = await sendTransaction({...}); 
const receipt = await publicClient.waitForTransactionReceipt({hash}); 
  • Removed the experimental waitForTransactionConfirmation config option as it is the default behavior.
tsx
<PrivyProvider
  config={{
    embeddedWallets: {
      waitForTransactionConfirmation: false, 
    },
  }}
>
  ...
</PrivyProvider>
  • Updated signMessage, signTypedData, sendTransaction, and signTransaction methods:
tsx
const {signMessage} = usePrivy();
// `uiOptions` and `address` are optional
const signature = await signMessage(message, uiOptions, address); 
// the first argument should be formatted `{message: string}`
const {signature} = await signMessage({message}, {uiOptions, address}); 

Smart Wallets

  • Updated signMessage, signTypedData, and sendTransaction methods of the smart wallet client:
tsx
import {useSmartWallets} from '@privy-io/react-auth/smart-wallets';

const {client} = useSmartWallets();
// `uiOptions` and `address` are optional
const signature = await client.signMessage({message}, uiOptions, address); 
const signature = await client.signMessage({message}, {uiOptions, address}); 

Solana

  • Migrated useSendSolanaTransaction from @privy-io/react-auth to useSendTransaction from @privy-io/react-auth/solana (Solana-specific export path)
tsx
import {useSendSolanaTransaction} from '@privy-io/react-auth'; 
import {useSendTransaction} from '@privy-io/react-auth/solana'; 

...

const {sendSolanaTransaction} = useSendSolanaTransaction(); 
const {sendTransaction} = useSendTransaction(); 
  • Removed sendSolanaTransaction from usePrivy in favor of exporting sendTransaction from useSendTransaction from @privy-io/react-auth/solana
tsx
import {usePrivy} from '@privy-io/react-auth'; 
import {useSendTransaction} from '@privy-io/react-auth/solana'; 

...

const {sendSolanaTransaction} = usePrivy(); 
const {sendTransaction} = useSendTransaction(); 
  • Removed delegateWalletAction from useSolanaWallets. Use delegateWallet from useDelegatedActions instead.
tsx
import {useSolanaWallets} from '@privy-io/react-auth/solana'; 
import {useDelegatedActions} from '@privy-io/react-auth'; 

...

const {delegateWalletAction} = useSolanaWallets(); 
delegateWalletAction(); 

const {delegateWallet} = useDelegatedActions(); 
await delegateWallet({  
  address: '<wallet to delegate>', 
  chainType: 'solana', 
}); 
  • Removed rpcUrl from fundWallet from useSolanaWallets. Set rpcUrl in config.solanaClusters prop of the PrivyProvider instead
tsx
import {useSolanaWallets} from '@privy-io/react-auth/solana';

const {fundWallet} = useSolanaWallets();
fundWallet({
  address: '<wallet to fund>',
  cluster: {name: 'mainnet-beta', rpcUrl: 'https://api.mainnet-beta.solana.com'}, 
  cluster: {name: 'mainnet-beta'}, 
});

<PrivyProvider
  appId="your-privy-app-id"
  config={{
    ...theRestOfYourConfig,
    // Replace this with your required clusters and custom RPC URLs
    solanaClusters: [{name: 'mainnet-beta', rpcUrl: 'https://api.mainnet-beta.solana.com'}], 
  }}
>
  {/* your app's content */}
</PrivyProvider>;

Connectors

  • Removed the setActiveWallet method - use the wallets array directly to interact with wallets.

Callbacks

  • Updated all non-error callbacks to use named arguments instead of positional arguments.
tsx
const {login} = useLogin({
  onComplete: (user, isNewUser, wasAlreadyAuthenticated, loginMethod, linkedAccount) => { 
  onComplete: ({user, isNewUser, wasAlreadyAuthenticated, loginMethod, linkedAccount}) => { 

    console.log(user, isNewUser, wasAlreadyAuthenticated, loginMethod, linkedAccount);
    // Any logic you'd like to execute if the user is/becomes authenticated while this
    // component is mounted
  },
  ...
  onError: (error) => { // onError will continue to stay as a singular error argument
    console.log(error)
  }})

...
 const {reauthorize} = useOAuthTokens({
  onOAuthTokenGrant: (tokens: OAuthTokens, {user}: {user: User}) => {  
  onOAuthTokenGrant: ({tokens, user}) => {  
    const oAuthToken = tokens.accessToken

  ...
  }})