npm package: @loranza/react
Description: React hooks for building Solana apps
Author: Solana Labs Maintainers
Latest version: 6.1.1

[![npm][npm-image]][npm-url]
[![npm-downloads][npm-downloads-image]][npm-url]
<br />
[![code-style-prettier][code-style-prettier-image]][code-style-prettier-url]

[code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
[code-style-prettier-url]: https://github.com/prettier/prettier
[npm-downloads-image]: https://img.shields.io/npm/dm/@solana/react?style=flat
[npm-image]: https://img.shields.io/npm/v/@solana/react?style=flat
[npm-url]: https://www.npmjs.com/package/@solana/react

# @solana/react

This package contains React hooks for building Solana apps.

## Hooks

### `useSignIn(uiWalletAccount, chain)`

Given a `UiWallet` or `UiWalletAccount` this hook returns a function that you can call to trigger a wallet's [&lsquo;Sign In With Solana&rsquo;](https://phantom.app/learn/developers/sign-in-with-solana) feature.

#### Example

```tsx
import { useSignIn } from '@solana/react';

function SignInButton({ wallet }) {
    const csrfToken = useCsrfToken();
    const signIn = useSignIn(wallet);
    return (
        <button
            onClick={async () => {
                try {
                    const { account, signedMessage, signature } = await signIn({
                        requestId: csrfToken,
                    });
                    // Authenticate the user, typically on the server, by verifying that
                    // `signedMessage` was signed by the person who holds the private key for
                    // `account.publicKey`.
                    //
                    // Authorize the user, also on the server, by decoding `signedMessage` as the
                    // text of a Sign In With Solana message, verifying that it was not modified
                    // from the values your application expects, and that its content is sufficient
                    // to grant them access.
                    window.alert(`You are now signed in with the address ${account.address}`);
                } catch (e) {
                    console.error('Failed to sign in', e);
                }
            }}
        >
            Sign In
        </button>
    );
}
```

### `useWalletAccountMessageSigner(uiWalletAccount)`

Given a `UiWalletAccount`, this hook returns an object that conforms to the `MessageModifyingSigner` interface of `@solana/signers`.

#### Example

```tsx
import { useWalletAccountMessageSigner } from '@solana/react';
import { createSignableMessage } from '@solana/signers';

function SignMessageButton({ account, text }) {
    const messageSigner = useWalletAccountMessageSigner(account);
    return (
        <button
            onClick={async () => {
                try {
                    const signableMessage = createSignableMessage(text);
                    const [signedMessage] = await messageSigner.modifyAndSignMessages([signableMessage]);
                    const messageWasModified = signableMessage.content !== signedMessage.content;
                    const signatureBytes = signedMessage.signatures[messageSigner.address];
                    window.alert(
                        `Signature bytes: ${signatureBytes.toString()}${
                            messageWasModified ? ' (message was modified)' : ''
                        }`,
                    );
                } catch (e) {
                    console.error('Failed to sign message', e);
                }
            }}
        >
            Sign Message: {text}
        </button>
    );
}
```

> [!NOTE]
> The type `MessageModifyingSigner` is returned from this hook instead of `MessageSigner` or `MessagePartialSigner`. This is a conservative assumption based on the fact that your application can not control whether or not the wallet will modify the message before signing it.

### `useWalletAccountTransactionSigner(uiWalletAccount, chain)`

Given a `UiWalletAccount` and a chain that begins with `solana:`, this hook returns an object that conforms to the `TransactionModifyingSigner` interface of `@solana/signers`.

#### Example

```tsx
import { useWalletAccountTransactionSigner } from '@solana/react';

function SignTransactionButton({ account, transaction }) {
    const transactionSigner = useWalletAccountTransactionSigner(account, 'solana:devnet');
    return (
        <button
            onClick={async () => {
                try {
                    const [{ signatures }] = await transactionSigner.modifyAndSignTransactions([transaction]);
                    const signatureBytes = signatures[transactionSigner.address];
                    window.alert(`Signature bytes: ${signatureBytes.toString()}`);
                } catch (e) {
                    console.error('Failed to sign transaction', e);
                }
            }}
        >
            Sign Transaction
        </button>
    );
}
```

> [!NOTE]
> The type `TransactionModifyingSigner` is returned from this hook instead of `TransactionSigner` or `TransactionPartialSigner`. This is a conservative assumption based on the fact that your application can not control whether or not the wallet will modify the transaction before signing it (eg. to add guard instructions, or a priority fee budget).

### `useWalletAccountTransactionSendingSigner(uiWalletAccount, chain)`

Given a `UiWalletAccount` and a chain that begins with `solana:`, this hook returns an object that conforms to the `TransactionSendingSigner` interface of `@solana/signers`.

#### Example

```tsx
import { useWalletAccountTransactionSendingSigner } from '@solana/react';
import {
    appendTransactionMessageInstruction,
    createSolanaRpc,
    getBase58Decoder,
    pipe,
    setTransactionMessageFeePayerSigner,
    setTransactionMessageLifetimeUsingBlockhash,
    signAndSendTransactionMessageWithSigners,
} from '@solana/kit';

function RecordMemoButton({ account, rpc, text }) {
    const signer = useWalletAccountTransactionSendingSigner(account, 'solana:devnet');
    return (
        <button
            onClick={async () => {
                try {
                    const { value: latestBlockhash } = await createSolanaRpc('https://api.devnet.solana.com')
                        .getLatestBlockhash()
                        .send();
                    const message = pipe(
                        createTransactionMessage({ version: 'legacy' }),
                        m => setTransactionMessageFeePayerSigner(signer, m),
                        m => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m),
                        m => appendTransactionMessageInstruction(getAddMemoInstruction({ memo: text }), m),
                    );
                    const signatureBytes = await signAndSendTransactionMessageWithSigners(message);
                    const base58Signature = getBase58Decoder().decode(signature);
                    window.alert(`View transaction: https://explorer.solana.com/tx/${base58Signature}?cluster=devnet`);
                } catch (e) {
                    console.error('Failed to record memo', e);
                }
            }}
        >
            Record Memo
        </button>
    );
}
```

### `useSignMessage(uiWalletAccount)`

Given a `UiWalletAccount`, this hook returns a function you can call to sign a byte array.

#### Arguments

A config object with the following properties:

- `message`: A `Uint8Array` of bytes to sign

#### Returns

An object with the following properties:

- `signature`: The 64-byte Ed25519 signature as a `Uint8Array`
- `signedMessage`: The `Uint8Array` of bytes signed by the wallet. These bytes might differ from the input bytes if the wallet modified the message

#### Example

```tsx
import { useSignMessage } from '@solana/react';

function SignMessageButton({ account, messageBytes }) {
    const signMessage = useSignMessage(account);
    return (
        <button
            onClick={async () => {
                try {
                    const { signature } = await signMessage({
                        message: messageBytes,
                    });
                    window.alert(`Signature bytes: ${signature.toString()}`);
                } catch (e) {
                    console.error('Failed to sign message', e);
                }
            }}
        >
            Sign Message
        </button>
    );
}
```

### `useSignTransaction(uiWalletAccount, chain)`

Given a `UiWalletAccount` and a chain that begins with `solana:`, this hook returns a function you can call to sign a serialized transaction.

#### Arguments

A config object with the following properties:

- `options`: An object with the following properties:
    - `minContextSlot`: A slot at which any blockhash/nonce in the transaction is known to exist. This may be used by the signer and/or RPC to determine the validity of the blockhashes/nonces it has observed.
- `transaction`: A `Uint8Array` of bytes that conforms to the [Solana transaction schema](https://solana.com/docs/core/transactions#transaction)

#### Returns

An object with the following properties:

- `signedTransaction`: A `Uint8Array` of bytes that conforms to the [Solana transaction schema](https://solana.com/docs/core/transactions#transaction)

#### Example

```tsx
import { useSignTransaction } from '@solana/react';

function SignTransactionButton({ account, transactionBytes }) {
    const signTransaction = useSignTransaction(account, 'solana:devnet');
    return (
        <button
            onClick={async () => {
                try {
                    const { signedTransaction } = await signTransaction({
                        transaction: transactionBytes,
                    });
                    window.alert(`Signed transaction bytes: ${signedTransaction.toString()}`);
                } catch (e) {
                    console.error('Failed to sign transaction', e);
                }
            }}
        >
            Sign Transaction
        </button>
    );
}
```

### `useSignAndSendTransaction(uiWalletAccount, chain)`

Given a `UiWalletAccount` and a chain that begins with `solana:`, this hook returns a function you can call to sign and send a serialized transaction.

#### Arguments

A config object with the following properties:

- `options`: An object with the following properties:
    - `minContextSlot`: A slot at which any blockhash/nonce in the transaction is known to exist. This may be used by the signer and/or RPC to determine the validity of the blockhashes/nonces it has observed.
- `transaction`: A `Uint8Array` of bytes that conforms to the [Solana transaction schema](https://solana.com/docs/core/transactions#transaction)

#### Returns

That function returns an object with the following properties:

- `signature`: A `Uint8Array` of bytes representing the signature of the sent transaction.

#### Example

```tsx
import { getBase58Decoder } from '@solana/codecs-strings';
import { useSignAndSendTransaction } from '@solana/react';

function SignAndSendTransactionButton({ account, transactionBytes }) {
    const signAndSendTransaction = useSignAndSendTransaction(account, 'solana:devnet');
    return (
        <button
            onClick={async () => {
                try {
                    const { signature } = await signAndSendTransaction({
                        transaction: transactionBytes,
                    });
                    const base58TransactionSignature = getBase58Decoder().decode(signature);
                    window.alert(
                        `View transaction: https://explorer.solana.com/tx/${base58TransactionSignature}?cluster=devnet`,
                    );
                } catch (e) {
                    console.error('Failed to send transaction', e);
                }
            }}
        >
            Sign and Send Transaction
        </button>
    );
}
```

### `useSignTransactions(uiWalletAccount, chain)`

Given a `UiWalletAccount` and a chain that begins with `solana:`, this hook returns a function you can call to sign one or more serialized transactions in a single request.

#### Arguments

One or more config objects with the following properties:

- `options`: An object with the following properties:
    - `minContextSlot`: A slot at which any blockhash/nonce in the transaction is known to exist. This may be used by the signer and/or RPC to determine the validity of the blockhashes/nonces it has observed.
- `transaction`: A `Uint8Array` of bytes that conforms to the [Solana transaction schema](https://solana.com/docs/core/transactions#transaction)

#### Returns

An array of objects with the following properties:

- `signedTransaction`: A `Uint8Array` of bytes that conforms to the [Solana transaction schema](https://solana.com/docs/core/transactions#transaction)

#### Example

```tsx
import { useSignTransactions } from '@solana/react';

function SignTransactionsButton({ account, transactionBytes1, transactionBytes2 }) {
    const signTransactions = useSignTransactions(account, 'solana:devnet');
    return (
        <button
            onClick={async () => {
                try {
                    const [{ signedTransaction: first }, { signedTransaction: second }] = await signTransactions(
                        { transaction: transactionBytes1 },
                        { transaction: transactionBytes2 },
                    );
                    window.alert(`Signed transaction bytes: ${first.toString()} and ${second.toString()}`);
                } catch (e) {
                    console.error('Failed to sign transactions', e);
                }
            }}
        >
            Sign Transactions
        </button>
    );
}
```

### `useSignAndSendTransactions(uiWalletAccount, chain)`

Given a `UiWalletAccount` and a chain that begins with `solana:`, this hook returns a function you can call to sign and send one or more serialized transactions in a single request.

#### Arguments

One or more config objects with the following properties:

- `options`: An object with the following properties:
    - `minContextSlot`: A slot at which any blockhash/nonce in the transaction is known to exist. This may be used by the signer and/or RPC to determine the validity of the blockhashes/nonces it has observed.
- `transaction`: A `Uint8Array` of bytes that conforms to the [Solana transaction schema](https://solana.com/docs/core/transactions#transaction)

#### Returns

An array of objects with the following properties:

- `signature`: A `Uint8Array` of bytes representing the signature of each sent transaction.

#### Example

```tsx
import { getBase58Decoder } from '@solana/codecs-strings';
import { useSignAndSendTransactions } from '@solana/react';

function SignAndSendTransactionsButton({ account, transactionBytes1, transactionBytes2 }) {
    const signAndSendTransactions = useSignAndSendTransactions(account, 'solana:devnet');
    return (
        <button
            onClick={async () => {
                try {
                    const [first, second] = await signAndSendTransactions(
                        { transaction: transactionBytes1 },
                        { transaction: transactionBytes2 },
                    );
                    const [firstSignature, secondSignature] = [first.signature, second.signature].map(signature =>
                        getBase58Decoder().decode(signature),
                    );
                    window.alert(
                        `View transactions: https://explorer.solana.com/tx/${firstSignature}?cluster=devnet and https://explorer.solana.com/tx/${secondSignature}?cluster=devnet`,
                    );
                } catch (e) {
                    console.error('Error returned by signAndSendTransactions', e);
                }
            }}
        >
            Sign and Send Transactions
        </button>
    );
}
```

### `useSelectedWalletAccount()`

This hook returns the wallet account that is selected, a function to change the selection, and a list of wallets which pass a filter condition you have provided. This hook must be used in a React Component inside `SelectedWalletAccountContextProvider`.

#### Arguments

This hook doesn't take any arguments.

#### Returns

The function returns an array consisting of the following elements in the order given:

- `SelectedWalletAccount`: This element could be a `UiWalletAccount` or `undefined`, and represents the selected wallet account.
- `SetSelectedWalletAccount`: A setter function to set the SelectedWalletAccount state. It takes an argument which could be a callback function `(prevState)=>newState` or `newState`.
- `filteredWallets`: List of filtered wallets using the function provided as `filterWallet` function in `SelectedWalletAccountContextProvider`

#### Example

```tsx
import React from 'react';
import { useSelectedWalletAccount } from '@solana/react';

function WalletInfo() {
    const [selectedAccount, setSelectedAccount, filteredWallets] = useSelectedWalletAccount();

    if (!selectedAccount) {
        return <div>No wallet selected</div>;
    }

    return (
        <div>
            <p>Address: {selectedAccount.address}</p>

            <button onClick={() => setSelectedAccount(undefined)}>Clear selection</button>

            <p>Available wallets: {filteredWallets.length}</p>
        </div>
    );
}
```

### `SelectedWalletAccountContextProvider`

This is a react context provider for `SelectedWalletAccountContext`. It provides its children access to the context by using either `useSelectedWalletAccount()` or `useContext(SelectedWalletAccountContext)`.

#### Props

The provider takes the following props:

- `filterWallet`: a function used to filter supported wallets. For example you might use this to restrict your app to wallets that support `solana:mainnet`.
- `stateSync`: an object to store the selected wallet, with these properties:
    - `storeSelectedWallet`: a function used to store a selected wallet account identifier (as a string) into persistent storage. For example this might write to local storage in the browser. The string stored is `${walletName}:${accountAddress}`.
    - `getSelectedWallet`: a function used to retrieve the persisted wallet account identifier from the persistent storage.
    - `deleteSelectedWallet`: clears any persisted wallet account identifier from the persistent storage.

#### Example

```tsx
import React from 'react';
import { SelectedWalletAccountContextProvider } from '@solana/react';
import type { UiWallet } from '@wallet-standard/react';

const STORAGE_KEY = 'solana-wallet-account-id';

export function App() {
    return (
        <SelectedWalletAccountContextProvider
            filterWallet={(wallet: UiWallet) => wallet.accounts.length > 0}
            stateSync={{
                getSelectedWallet: () => localStorage.getItem(STORAGE_KEY),
                storeSelectedWallet: accountKey => localStorage.setItem(STORAGE_KEY, accountKey),
                deleteSelectedWallet: () => localStorage.removeItem(STORAGE_KEY),
            }}
        >
            <WalletInfo />
        </SelectedWalletAccountContextProvider>
    );
}
```