Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tender-terms-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@gillsdk/react": minor
---

added `useSendTransaction` hook
31 changes: 31 additions & 0 deletions packages/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,37 @@ Fetch data from the Solana blockchain with the gill hooks:
- [`useTokenMint`](#get-token-mint-account) - get a decoded token's Mint account
- [`useTokenAccount`](#get-token-account) - get the token account for a given mint and owner (or ATA)

Send data to the Solana blockchain with the gill hooks:
Comment thread
jkrishnad marked this conversation as resolved.

- [`useSendTransaction`](#send-transaction) - send a serialized solana transaction (Base64 encoded) to the Solana blockchain

### Example Usage of useSendTransaction hook
```tsx
import { useSendTransaction } from "@gillsdk/react";

const { sendTransaction, isPending, data } = useSendTransaction({
config: {
encoding: "base64",
preflightCommitment: "confirmed",
skipPreflight: false,
}
});

async function handleClick() {
try {
// Create a new transaction
const transaction = createTransaction(...);
Comment thread
jkrishnad marked this conversation as resolved.

// Send the Transaction via RPC
const result = await sendTransaction(transaction);

console.log("Signature:", result);
} catch (err) {
console.error("❌ Error sending transaction:", err);
}
}
````

### Wrap your React app in a context provider

Wrap your app with the `SolanaProvider` React context provider and pass your Solana client to it:
Expand Down
30 changes: 30 additions & 0 deletions packages/react/src/__typeset__/send-transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useSendTransaction } from "../hooks";
import { Base64EncodedWireTransaction, SendTransactionApi} from "gill";

// [DESCRIBE] useSendTransaction
{
{
const { sendTransaction } = useSendTransaction({
config: {
encoding: "base64",
preflightCommitment: "confirmed",
skipPreflight: false,
},
});
sendTransaction satisfies (tx: Base64EncodedWireTransaction | string) => Promise<ReturnType<SendTransactionApi["sendTransaction"]>>;
// @ts-expect-error - Should not allow no argument
useSendTransaction();
}

// Should accept `config` input
{
const { sendTransaction } = useSendTransaction({
config: {
encoding: "base64",
preflightCommitment: "confirmed",
skipPreflight: false,
},
});
sendTransaction satisfies (tx: Base64EncodedWireTransaction | string) => Promise<ReturnType<SendTransactionApi["sendTransaction"]>>;
}
}
1 change: 1 addition & 0 deletions packages/react/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export * from "./slot.js";
export * from "./token-account.js";
export * from "./token-mint.js";
export * from "./transaction.js";
export * from "./send-transaction.js";
73 changes: 73 additions & 0 deletions packages/react/src/hooks/send-transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"use client";

import { useSolanaClient } from "./client.js";
import { GILL_HOOK_CLIENT_KEY } from "../const.js";
import { useMutation, UseMutationOptions } from "@tanstack/react-query";
import { Base64EncodedWireTransaction, SendTransactionApi, Simplify } from "gill";

type RpcConfig = Simplify<Parameters<SendTransactionApi["sendTransaction"]>[1]>;

type UseSendTransactionResponse = ReturnType<SendTransactionApi["sendTransaction"]>;

type UseSendTransactionInput<TConfig extends RpcConfig = RpcConfig> = {
/**
* Signal used to abort the RPC operation
*
* See MDN docs for {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | AbortSignal}
*/
abortSignal?: AbortSignal;
/**
* RPC configuration passed to the RPC method being called
*/
config?: TConfig;
/**
* Options passed to the {@link useMutation} hook
*/
Comment thread
jkrishnad marked this conversation as resolved.
options?: UseMutationOptions<UseSendTransactionResponse, unknown, SendTransactionArgument, unknown>;
};

type SendTransactionArgument = Base64EncodedWireTransaction | string;

/**
* Send a transaction using the Solana RPC method of
* [`sendTransaction`](https://solana.com/docs/rpc/http/sendtransaction)
*
* @param config Optional RPC configuration (e.g. `skipPreflight`, `encoding`, `preflightCommitment`s).
* @returns
* - `sendTransaction`: async function to send a transaction
* - all standard `useMutation` fields (`isLoading`, `error`, etc.)
*
* The returned signature can be viewed in Solana Explorer.
*/
export function useSendTransaction<TConfig extends RpcConfig = RpcConfig>({
options,
config,
abortSignal,
}: UseSendTransactionInput<TConfig>) {
const { rpc } = useSolanaClient();

const mutation = useMutation({
mutationFn: async (tx: SendTransactionArgument) => {
// The RPC method expects the base-64 encoded transaction as the first argument.
const response = await rpc
.sendTransaction(tx as Base64EncodedWireTransaction, {
Comment thread
jkrishnad marked this conversation as resolved.
encoding: "base64",
preflightCommitment: "confirmed",
skipPreflight: false,
...config,
})
.send({ abortSignal });
return response;
},
mutationKey: [GILL_HOOK_CLIENT_KEY, "sendTransaction"],
Comment thread
jkrishnad marked this conversation as resolved.
networkMode: "offlineFirst",
retry: false,
...options,
});

return {
...mutation,
send: mutation.mutate,
sendTransaction: mutation.mutateAsync,
};
Comment thread
jkrishnad marked this conversation as resolved.
}