Skip to content

Latest commit

 

History

History
474 lines (349 loc) · 12.9 KB

File metadata and controls

474 lines (349 loc) · 12.9 KB

@gillsdk/react

React hooks library for the Solana blockchain

Overview

Welcome to @gillsdk/react, a React hooks library for easily interacting with the Solana blockchain.

Notice: @gillsdk/react is in active development. All APIs are subject to change until reaching the first major version (v1.0.0).

This React hooks library is built on top of two core libraries:

  1. gill - modern JavaScript/TypeScript library for interacting with the Solana blockchain.
  2. @tanstack/react-query - popular and powerful asynchronous state management for React.

Installation

Install @gillsdk/react with your package manager of choice:

npm install gill @gillsdk/react @tanstack/react-query
pnpm add gill @gillsdk/react @tanstack/react-query
yarn add gill @gillsdk/react @tanstack/react-query

Note: gill and @tanstack/react-query are peer dependencies of @gillsdk/react so you need to explicitly install them. This allows you have more/easier control over managing dependencies yourself.

Quick start

Setup and configure your SolanaProvider to use the gill hooks:

Manage and use your Solana client's connections:

  • useSolanaClient - get the current Solana client (including rpc and rpcSubscriptions)
  • useUpdateSolanaClient - update the current Solana client (including rpc and rpcSubscriptions)

Fetch data from the Solana blockchain with the gill hooks:

Send data to the Solana blockchain with the gill hooks:

  • useSendTransaction - send a serialized solana transaction (Base64 encoded) to the Solana blockchain

Example Usage of useSendTransaction hook

const { send, signature, isPending, isError } = useSendTransaction({
  transaction: base64EncodedTransaction,
  config: {
    skipPreflight: true,
    preflightCommitment: 'finalized'
  }
});
// Send the transaction
send();

Wrap your React app in a context provider

Wrap your app with the SolanaProvider React context provider and pass your Solana client to it:

import { createSolanaClient } from "gill";
import { SolanaProvider } from "@gillsdk/react";

const client = createSolanaClient({
  urlOrMoniker: "devnet",
});

function App() {
  return <SolanaProvider client={client}>{/* ... */}</SolanaProvider>;
}

Create a client-only provider for NextJs and React server components

For application that use React server components, like NextJS, you will need to create a "client only" wrapper for the SolanaProvider exported from @gillsdk/react:

"use client"; // <--- this "use client" directive is required!

import { createSolanaClient } from "gill";
import { SolanaProvider } from "@gillsdk/react";

const client = createSolanaClient({
  urlOrMoniker: "devnet",
});

export function SolanaProviderClient({ children }: { children: React.ReactNode }) {
  return <SolanaProvider client={client}>{children}</SolanaProvider>;
}

Wrap your app in the client-only provider for NextJs

After creating your client-only provider, you can wrap your app with this SolanaProviderClient (normally inside the root layout.tsx):

import { SolanaProviderClient } from "@/providers/solana-provider";

export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
  return (
    <html>
      <body>
        <SolanaProviderClient>{children}</SolanaProviderClient>
      </body>
    </html>
  );
}

Using React hooks in React server component applications

After you have setup your client-only provider, you must set the use client directive in any component that uses the @gillsdk/react library. Signifying this component is required to be "client only".

See React's use client directive docs.

Note: NextJs uses React server components by default. Read their docs here on the use client directive.

"use client"; // <--- directive required anywhere you use `@gillsdk/react`

import { useBalance, ... } from "@gillsdk/react";
// ... other imports

export function PageClient() {
  const { balance } = useBalance({
    address: "nicktrLHhYzLmoVbuZQzHUTicd2sfP571orwo9jfc8c",
  });

  return (
    {/* ... */}
  );
}

Get your Solana client

Get the current Solana client configured in the SolanaProvider, including the rpc and rpcSubscriptions connections:

"use client";

import { useSolanaClient } from "@gillsdk/react";

export function PageClient() {
  const { rpc, rpcSubscriptions } = useSolanaClient();

  // you can now use `rpc` to access any of the Solana JSON RPC methods

  return { ... }
}

Get account balance (in lamports)

Get an account's balance (in lamports) using the Solana RPC method of getBalance:

"use client";

import { lamportsToSol } from "gill";
import { useBalance } from "@gillsdk/react";

export function PageClient() {
  const { balance, isLoading, isError, error } = useBalance({
    address: "nicktrLHhYzLmoVbuZQzHUTicd2sfP571orwo9jfc8c",
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <p>Balance: {lamportsToSol(balance) + " SOL"}</p>
    </div>
  );
}

Get latest blockhash

Get the latest blockhash using the Solana RPC method of getLatestBlockhash

"use client";

import { useLatestBlockhash } from "@gillsdk/react";

export function PageClient() {
  const { latestBlockhash, isLoading, isError, error } = useLatestBlockhash();

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>latestBlockhash: {JSON.stringify(latestBlockhash, null, "\t")}</pre>
    </div>
  );
}

Get account info (and data)

Get the account info for an address using the Solana RPC method of getAccountInfo:

See also: useTokenMint and useTokenAccount

"use client";

import { useAccount } from "@gillsdk/react";

export function PageClient() {
  const { account, isLoading, isError, error } = useAccount({
    address: "nicktrLHhYzLmoVbuZQzHUTicd2sfP571orwo9jfc8c",
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>account: {JSON.stringify(account, null, "\t")}</pre>
    </div>
  );
}

You can also provide a Decoder for known account data structure in order to decode the data byte array into a typed object:

![NOTE] Some popular account types may have their own dedicated hook, like Token Mints (useTokenMint) and and useTokenAccount. If a dedicated hook exists for an account type, it is highly recommended to use those hooks as opposed to manually providing a decoder to useAccount().

"use client";

import { useAccount } from "@gillsdk/react";
import { getMintDecoder } from "gill/programs";

export function PageClient() {
  const { account, isLoading, isError, error } = useAccount({
    // USDC mint account (on Solana mainnet)
    address: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    decoder: getMintDecoder(),
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>account: {JSON.stringify(account, null, "\t")}</pre>
    </div>
  );
}

Get signature statuses

Get the statuses of signatures using the Solana RPC method of getSignatureStatuses:

"use client";

import { useSignatureStatuses } from "@gillsdk/react";

export function PageClient() {
  const { statuses, isLoading, isError, error } = useSignatureStatuses({
    signatures: ["5ewJmppABUbsWcDQEvThJj4GH4pRVK8NDjUtMVJXjvEndkhdy23mHjHpDmHVNNGoKsjPAsCwD4vzTQY4V2GEmvKu"],
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>statuses: {JSON.stringify(statuses, null, "\t")}</pre>
    </div>
  );
}

Get program accounts (GPA)

Get all the accounts owned by a program using the Solana RPC method of getProgramAccounts:

"use client";

import { useProgramAccounts } from "@gillsdk/react";

export function PageClient() {
  const { accounts, isLoading, isError, error } = useProgramAccounts({
    program: "4Nd1mBQtrMJVYVfKf2PJy9NZUZdTAsp7D4xWLs4gDB4T",
    config: {
      encoding: "base64",
      filters: [
        { dataSize: 17n },
        {
          memcmp: {
            offset: 4n,
            bytes: "3Mc6vR",
            encoding: "base64",
          },
        },
      ],
    },
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>accounts: {JSON.stringify(accounts, null, "\t")}</pre>
    </div>
  );
}

Get token Mint account

Get a decoded Mint account for a given token's Mint address.

Note: the Mint's information can be accessed via the returned account.data field.

"use client";

import { useTokenMint } from "@gillsdk/react";

export function PageClient() {
  const { account, isLoading, isError, error } = useTokenMint({
    // USDC mint account (on Solana mainnet)
    mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>account: {JSON.stringify(account, null, "\t")}</pre>
    </div>
  );
}

Get token account

Get the token account for a given mint and owner:

"use client";

import { useTokenAccount } from "@gillsdk/react";

export function PageClient() {
  const { account, isLoading, isError, error } = useTokenAccount({
    // token on devnet
    mint: "HwxZNMkZbZMeiu9Xnmc6Rg8jYgNsJB47jwabHGUebW4F",
    owner: "nick6zJc6HpW3kfBm4xS2dmbuVRyb5F3AnUvj5ymzR5",
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>account: {JSON.stringify(account, null, "\t")}</pre>
    </div>
  );
}

If you already know the specific Associated Token Account's address (ATA), then you can get that specific token account by providing the ata address:

Note: This is most commonly used for multi-sig protocols like Squads.

"use client";

import { useTokenAccount } from "@gillsdk/react";

export function PageClient() {
  const { account, isLoading, isError, error } = useTokenAccount({
    ata: "CCMCWh4FudPEmY6Q1AVi5o8mQMXkHYkJUmZfzRGdcJ9P",
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>account: {JSON.stringify(account, null, "\t")}</pre>
    </div>
  );
}

Get Signatures for address

Get the signatures for confirmed transactions using the RPC method of getSignaturesForAddress

"use client";

import { useSignaturesForAddress } from "@gillsdk/react";

export function PageClient() {
  const { signatures, isLoading, isError, error } = useSignaturesForAddress({
    address: "nicktrLHhYzLmoVbuZQzHUTicd2sfP571orwo9jfc8c",
    config: {
      limit: 10,
    },
  });

  // if (isLoading) { return ... }
  // if (isError) { return ... }

  return (
    <div className="">
      <pre>signatures: {JSON.stringify(signatures, null, "\t")}</pre>
    </div>
  );
}