# How to stake Toncoin using AppKit (https://docs-i0yym09dy-ton-core-docs.vercel.app/llms/ecosystem/appkit/stake/content.md)



<Callout type="note">
  [Initialize the AppKit](/llms/ecosystem/appkit/init/content.md) before using examples on this page. Staking functionality requires a configured [staking provider](#available-providers).
</Callout>

<Callout type="note">
  This page covers retail staking flows, such as letting a wallet user stake TON through a staking provider. It does not cover validator operations, institutional custody, or custom pool management. Refer to the [staking overview](/llms/ecosystem/staking/overview/content.md) page for other solutions.
</Callout>

AppKit supports on-chain liquid Toncoin staking through [pluggable staking providers](#available-providers). For most user-facing apps, the flow is:

1. Register a staking provider.
2. Show the terms and quote of the current provider.
3. Build a transaction from that quote.
4. Send the transaction from the connected wallet.
5. Display the user's staked balance.

## Available providers [#available-providers]

[Tonstakers](https://tonstakers.com) is the primary liquid staking [AppKit provider](/llms/ecosystem/appkit/init/content.md). It is configured per network, similar to API clients:

```ts
// Or @ton/appkit-react for React
import { AppKit, Network } from '@ton/appkit';
import { createTonstakersProvider } from '@ton/appkit/staking/tonstakers';

const kit = new AppKit({
  providers: [
    // Optional configuration options — omit when not known.
    createTonstakersProvider({
      [Network.mainnet().chainId]: {
        // Defaults to a known pool when available.
        contractAddress: 'EQ...POOL_ADDRESS',

        // Optional TonAPI key, get it at https://tonconsole.com/tonapi/api-keys
        // TonAPI is an alternative API client to TON Center.
        tonApiToken: '<TON_API_TOKEN>',
      }
    }),
  ],
});
```

## Set up a staking provider [#set-up-a-staking-provider]

Before requesting quotes or building transactions, register at least one staking provider:

<CodeGroup>
  <CodeBlockTabs defaultValue="React">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="React">
        React
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="TypeScript">
        TypeScript
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="React">
      ```tsx  icon="react" wrap lines
      import {
        AppKit,
        AppKitProvider,
        Network,
        createTonConnectConnector,
      } from '@ton/appkit-react';
      import { createTonstakersProvider } from '@ton/appkit/staking/tonstakers';
      import '@ton/appkit-react/styles.css';

      const kit = new AppKit({
        networks: {
          [Network.mainnet().chainId]: {
            apiClient: {
              url: 'https://toncenter.com',
              key: '<MAINNET_API_KEY>',
            },
          },
        },
        connectors: [
          createTonConnectConnector({
            tonConnectOptions: {
              manifestUrl: 'https://tonconnect-sdk-demo-dapp.vercel.app/tonconnect-manifest.json',
            },
          }),
        ],
        providers: [createTonstakersProvider()],
      });

      export function App() {
        return <AppKitProvider appKit={kit}>{/* ...app... */}</AppKitProvider>;
      }
      ```
    </CodeBlockTab>

    <CodeBlockTab value="TypeScript">
      ```ts  icon="globe" wrap lines
      import {
        AppKit,
        Network,
        createTonConnectConnector,
      } from '@ton/appkit';
      import { createTonstakersProvider } from '@ton/appkit/staking/tonstakers';

      const kit = new AppKit({
        networks: {
          [Network.mainnet().chainId]: {
            apiClient: {
              url: 'https://toncenter.com',
              key: '<MAINNET_API_KEY>',
            },
          },
        },
        connectors: [
          createTonConnectConnector({
            tonConnectOptions: {
              manifestUrl: 'https://tonconnect-sdk-demo-dapp.vercel.app/tonconnect-manifest.json',
            },
          }),
        ],
        providers: [createTonstakersProvider()],
      });
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Show provider terms and a quote [#show-provider-terms-and-a-quote]

Retail staking UIs should display the provider and an up-to-date quote before asking the user to confirm the transaction.

<Callout type="caution">
  Refresh staking quotes shortly before building the transaction. Quotes, APY, and available liquidity can change.
</Callout>

<CodeGroup>
  <CodeBlockTabs defaultValue="React">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="React">
        React
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="TypeScript">
        TypeScript
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="React">
      ```tsx  icon="react"
      import {
        useAddress,
        useStakingProviderInfo,
        useStakingProviders,
        useStakingQuote,
      } from '@ton/appkit-react';

      export const StakingQuoteCard = () => {
        const address = useAddress();
        const { data: providers } = useStakingProviders();
        const providerId = providers?.[0];

        const { data: providerInfo } = useStakingProviderInfo({ providerId });
        const { data: quote, isLoading, error } = useStakingQuote({
          providerId,

          // Quote direction: 'stake' or 'unstake'
          direction: 'stake',

          // Staking user's TON wallet address
          userAddress: address ?? '<TON_WALLET_ADDRESS>',

          // Fractional Toncoin amount string.
          // For example, '0.1' or '10' Toncoin.
          amount: '1',
        });

        if (!providerId) {
          return <p>No staking providers configured.</p>;
        }

        if (isLoading) {
          return <p>Loading quote...</p>;
        }

        if (error) {
          return <p>Error: {error.message}</p>;
        }

        return (
          <div>
            <p>Provider: {providerId}</p>
            <p>APY: {providerInfo ? providerInfo.apy / 100 : 0}%</p>
            <p>Stake amount: {quote?.amountIn} Toncoin</p>
            <p>Estimated output: {quote?.amountOut} Toncoin</p>
          </div>
        );
      };
      ```
    </CodeBlockTab>

    <CodeBlockTab value="TypeScript">
      ```ts  icon="globe"
      import {
        type AppKit,
        getSelectedWallet,
        getStakingProviderInfo,
        getStakingProviders,
        getStakingQuote,
      } from '@ton/appkit';

      async function getStakeQuote(
        /** Initialized AppKit instance */
        kit: AppKit,
        /** Fractional Toncoin amount string */
        amount: string,
      ) {
        const providerId = getStakingProviders(kit)[0];
        const userAddress = getSelectedWallet(kit)?.getAddress();
        if (!providerId || !userAddress) {
          return null;
        }

        const providerInfo = await getStakingProviderInfo(kit, { providerId });
        const quote = await getStakingQuote(kit, {
          providerId,

          // Quote direction: 'stake' or 'unstake'
          direction: 'stake',

          // Staking user's TON wallet address
          userAddress,

          // Fractional Toncoin amount string.
          // For example, '0.1' or '10' Toncoin.
          amount,
        });

        console.log('Provider:', providerId);
        console.log('APY:', providerInfo.apy / 100, '%');
        console.log('Stake amount:', quote.amountIn, 'Toncoin');
        console.log('Estimated output:', quote.amountOut, 'Toncoin');

        return quote;
      }
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Build and send the staking transaction [#build-and-send-the-staking-transaction]

Build the transaction from the quote, then send it through the connected wallet:

<CodeGroup>
  <CodeBlockTabs defaultValue="React">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="React">
        React
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="TypeScript">
        TypeScript
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="React">
      ```tsx  icon="react"
      import {
        useAddress,
        useBuildStakeTransaction,
        useSendTransaction,
        useStakingProviders,
        useStakingQuote,
      } from '@ton/appkit-react';

      export const StakeButton = () => {
        const address = useAddress();
        const { data: providers } = useStakingProviders();
        const providerId = providers?.[0];
        const { data: quote } = useStakingQuote({
          providerId,

          // Quote direction: 'stake' or 'unstake'
          direction: 'stake',

          // Staking user's TON wallet address
          userAddress: address ?? '<TON_WALLET_ADDRESS>',

          // Fractional Toncoin amount string.
          // For example, '0.1' or '10' Toncoin.
          amount: '1',
        });
        const {
          mutateAsync: buildTransaction,
          isPending: isBuilding,
        } = useBuildStakeTransaction();
        const {
          mutateAsync: sendTransaction,
          isPending: isSending,
        } = useSendTransaction();

        const handleStake = async () => {
          if (!quote || !address || !providerId) {
            return;
          }

          const transaction = await buildTransaction({
            providerId,
            quote,
            userAddress: address,
          });

          await sendTransaction(transaction);
        };

        return (
          <button
            onClick={() => void handleStake()}
            disabled={!quote || !address || isBuilding || isSending}
          >
            {isBuilding || isSending ? 'Submitting...' : 'Stake 1 TON'}
          </button>
        );
      };
      ```
    </CodeBlockTab>

    <CodeBlockTab value="TypeScript">
      ```ts  icon="globe"
      import {
        type AppKit,
        getSelectedWallet,
        getStakingProviders,
        getStakingQuote,
        buildStakeTransaction,
        sendTransaction,
      } from '@ton/appkit';

      async function stakeTon(
        /** Initialized AppKit instance */
        kit: AppKit,
        /** Fractional Toncoin amount string */
        amount: string,
      ) {
        const providerId = getStakingProviders(kit)[0];
        const userAddress = getSelectedWallet(kit)?.getAddress();
        if (!providerId || !userAddress) {
          return null;
        }
        const quote = await getStakingQuote(kit, {
          providerId,

          // Quote direction: 'stake' or 'unstake'
          direction: 'stake',

          // Staking user's TON wallet address
          userAddress,

          // Fractional Toncoin amount string.
          // For example, '0.1' or '10' Toncoin.
          amount,
        });

        const transaction = await buildStakeTransaction(kit, {
          providerId, quote, userAddress,
        });

        const result = await sendTransaction(kit, transaction);
        console.log('Transaction sent:', result.boc);
      }
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## Display the staked balance [#display-the-staked-balance]

After the transaction is sent, query the staking balance for the connected wallet:

<CodeGroup>
  <CodeBlockTabs defaultValue="React">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="React">
        React
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="TypeScript">
        TypeScript
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="React">
      ```tsx  icon="react"
      import {
        useAddress,
        useStakingProviders,
        useStakedBalance,
      } from '@ton/appkit-react';

      export const StakedBalanceCard = () => {
        const address = useAddress();
        const { data: providers } = useStakingProviders();
        const providerId = providers?.[0];
        const { data: balance, isLoading, error } = useStakedBalance({
          providerId,

          // Staking user's TON wallet address
          userAddress: address ?? '<TON_WALLET_ADDRESS>',
        });

        if (!providerId) {
          return <p>No staking providers configured.</p>;
        }

        if (isLoading) {
          return <p>Loading staked balance...</p>;
        }

        if (error) {
          return <p>Error: {error.message}</p>;
        }

        return <p>Staked balance: {balance?.stakedBalance ?? '0'}</p>;
      };
      ```
    </CodeBlockTab>

    <CodeBlockTab value="TypeScript">
      ```ts  icon="globe"
      import {
        type AppKit,
        getSelectedWallet,
        getStakingProviders,
        getStakedBalance,
      } from '@ton/appkit';

      async function getUserStakedBalance(
        /** Initialized AppKit instance */
        kit: AppKit,
      ) {
        const providerId = getStakingProviders(kit)[0];
        const userAddress = getSelectedWallet(kit)?.getAddress();
        if (!providerId || !userAddress) {
          return null;
        }

        const balance = await getStakedBalance(kit, {
          providerId,

          // Staking user's TON wallet address
          userAddress,
        });

        console.log('Staked balance:', balance.stakedBalance);
        return balance;
      }
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

## See also [#see-also]

* [Tonstakers documentation, external](https://docs.tonstakers.com)
* [Transaction fees](/llms/foundations/fees/content.md)
* [AppKit overview](/llms/ecosystem/appkit/overview/content.md)
* [TON Connect overview](/llms/ecosystem/ton-connect/overview/content.md)
