+ );
+}
+```
+
+```ts twoslash [signer.ts] filename="signer.ts"
+// [!include ~/shared/react-native/signer.ts]
+```
+
+:::
+
+## Batch user operation
+
+To send multiple user operations in a single call, simply pass an array of user operations to the `sendUserOperation` method.
+
+:::code-group
+
+```tsx twoslash [batch-user-operation-component.tsx]
+import React, { useState, useEffect } from "react";
+import { Alert } from "react-native";
+import { User } from "@account-kit/signer";
+import {
+ createLightAccountClient,
+ LightAccount,
+} from "@account-kit/smart-contracts";
+import { sepolia, alchemy } from "@account-kit/infra";
+import { SmartAccountClient } from "@aa-sdk/core";
+
+// import the signer
+import { signer } from "./signer";
+
+export default function MyOpSenderComponent() {
+ const [user, setUser] = useState(null);
+ const [client, setClient] = useState(null);
+ const [isSendingUserOperation, setIsSendingUserOperation] = useState(false);
+
+ useEffect(() => {
+ // get the user if they are already authenticated
+ signer.getAuthDetails().then(setUser);
+ }, []);
+
+ useEffect(() => {
+ if (user) {
+ // Create a light account client for the authenticated user
+ createLightAccountClient({
+ signer,
+ chain: sepolia,
+ transport: alchemy({ apiKey: "YOUR_API_KEY" }),
+ }).then((client) => {
+ setClient(client);
+ setAccount(client.account);
+ });
+ }
+ }, [user]);
+
+ const handleSendUserOperation = async () => {
+ if (!client) return;
+
+ try {
+ setIsSendingUserOperation(true);
+
+ const { hash } = await client.sendUserOperation({
+ uo: [
+ {
+ target: "0xTARGET_ADDRESS_1",
+ data: "0x",
+ value: 0n,
+ },
+ {
+ target: "0xTARGET_ADDRESS_2",
+ data: "0x",
+ value: 0n,
+ },
+ ],
+ account: client.account,
+ });
+
+ Alert.alert("User Operation Sent", hash);
+ } catch (error) {
+ Alert.alert("Error", "Error sending user operation");
+ } finally {
+ setIsSendingUserOperation(false);
+ }
+ };
+
+ return (
+
+
+
+ );
+}
+```
+
+```ts twoslash [signer.ts] filename="signer.ts"
+// [!include ~/shared/react-native/signer.ts]
+```
+
+:::
diff --git a/site/pages/react-native/using-smart-accounts/sponsor-gas.mdx b/site/pages/react-native/using-smart-accounts/sponsor-gas.mdx
new file mode 100644
index 0000000000..6775fa84de
--- /dev/null
+++ b/site/pages/react-native/using-smart-accounts/sponsor-gas.mdx
@@ -0,0 +1,97 @@
+---
+title: How to sponsor gas for a User Operation
+description: Follow this guide to sponsor gas for UserOperations from any
+ ERC-4337 smart account. Account Kit is a vertically integrated stack for
+ building apps that support ERC-4337.
+---
+
+import Snippet from "../../../shared/create-gas-policy.mdx";
+
+# How to sponsor gas for a User Operation
+
+Gas fees are a significant barrier to entry for new user of your app. With Account Kit you can remove this barrier by sponsoring gas fees for transactions via the [Gas Manager](https://docs.alchemy.com/docs/gas-manager-services/?a=ak-docs). This guide explains how to sponsor gas by creating a gas policy, linking it to your client, and sending sponsored `UserOperations` (UOs) from a smart account.
+
+After [setting up Account Kit](/react-native/signer/setup-guide) in your project, follow these steps to sponsor gas.
+
+## Create a Gas Manager policy
+
+
+
+## Send a sponsored User Operation with the Policy ID
+
+Now you can send a sponsored User Operation with the Policy ID.
+
+:::code-group
+
+```tsx twoslash [gas-sponsorship.tsx]
+import React, { useState, useEffect } from "react";
+import {
+ createLightAccountClient,
+ LightAccount,
+} from "@account-kit/smart-contracts";
+import { sepolia, alchemy } from "@account-kit/infra";
+import { User } from "@account-kit/signer";
+
+// import the signer
+import { signer } from "./signer.ts";
+
+export default function MyComponent() {
+ const [client, setClient] = useState(null);
+ const [user, setUser] = useState(null);
+ const [isSendingUserOperation, setIsSendingUserOperation] = useState(false);
+
+ // Assume the user is already authenticated
+ useEffect(() => {
+ signer.getAuthDetails().then(setUser);
+ }, []);
+
+ useEffect(() => {
+ if (user) {
+ // Create a smart account client for the authenticated user with the policy ID
+ createLightAccountClient({
+ signer,
+ chain: sepolia,
+ policyId: "YOUR_GAS_POLICY_ID", // [!code ++]
+ transport: alchemy({ apiKey: "API_KEY" }),
+ }).then((client) => {
+ setClient(client);
+ });
+ }
+ }, [user]);
+
+ const handleSendUserOperation = async () => {
+ if (!client) return;
+ // Send a sponsored User Operation
+ try {
+ setIsSendingUserOperation(true);
+
+ const { hash } = await client.sendUserOperation({
+ uo: {
+ target: "0xTARGET_ADDRESS",
+ data: "0x",
+ value: 0n,
+ },
+ account: client.account,
+ });
+
+ Alert.alert("User Operation Sent", hash);
+ } catch (error) {
+ Alert.alert("Error", "Error sending user operation");
+ } finally {
+ setIsSendingUserOperation(false);
+ }
+ };
+
+ return (
+
+ );
+}
+```
+
+```ts twoslash [signer.ts] filename="signer.ts"
+// [!include ~/shared/react-native/signer.ts]
+```
+
+:::
diff --git a/site/shared/infra/drop-and-replace-description.mdx b/site/shared/infra/drop-and-replace-description.mdx
new file mode 100644
index 0000000000..e0efd2fd71
--- /dev/null
+++ b/site/shared/infra/drop-and-replace-description.mdx
@@ -0,0 +1,24 @@
+In the previous guides, we learned how to send user operations with gas sponsorship, but what happens when a user operation fails to mine? In this guide,
+we'll cover how to use drop and replace to resend failing user operations and ensure they get mined.
+
+## What is drop and replace?
+
+If fees change and your user operation gets stuck in the mempool, you can use drop and replace to resend the user operation with higher fees. This is most useful
+when used in combination with [`waitForUserOperationTransaction`](/reference/aa-sdk/core/functions/waitForUserOperationTransaction) to ensure the transaction is mined
+and then resend the user operation with higher fees if waiting times out.
+
+Drop and replace works by resubmitting a user operation with the greater of:
+
+1. 10% higher fees
+2. The current minimum fees
+
+We export a `dropAndReplace` function from `@aa-sdk/core` that you can use to handle this flow for you and is automatically added to the Smart Account Client.
+
+## How to drop and replace effectively
+
+Let's run through an example that uses drop and replace if waiting for a user operation to mine times out.
+
+:::warning
+If sponsoring gas, like in the example below, each call to `sendUserOperation` and `dropAndReplace` will generate pending gas sponsorships in your dashboard. This can result in you hitting your gas manager limit.
+At the moment, pending sponsorships expire after 10 minutes of inactivity, but it is possible that retrying excessively can temporarily exhaust your sponsorship limits.
+:::
diff --git a/site/sidebar/react-native.ts b/site/sidebar/react-native.ts
index 6a60d07aef..7239b6a6a8 100644
--- a/site/sidebar/react-native.ts
+++ b/site/sidebar/react-native.ts
@@ -38,10 +38,16 @@ export const reactNativeSidebar: SidebarItem[] = [
items: [
{
text: "Send user operations",
- link: "/react-native/#TODO",
+ link: "/react-native/using-smart-accounts/send-user-operations",
+ },
+ {
+ text: "Sponsor gas",
+ link: "/react-native/using-smart-accounts/sponsor-gas",
+ },
+ {
+ text: "Retry user operations",
+ link: "/react-native/using-smart-accounts/retry-user-operations",
},
- { text: "Sponsor gas", link: "/react-native/#TODO" },
- { text: "Retry user operations", link: "/react-native/#TODO" },
],
},
];