@account-kit/privy-integration 4.71.0 → 4.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +97 -9
  2. package/dist/esm/Provider.d.ts +4 -2
  3. package/dist/esm/Provider.js +4 -2
  4. package/dist/esm/Provider.js.map +1 -1
  5. package/dist/esm/hooks/useAlchemySolanaTransaction.d.ts +163 -0
  6. package/dist/esm/hooks/useAlchemySolanaTransaction.js +233 -0
  7. package/dist/esm/hooks/useAlchemySolanaTransaction.js.map +1 -0
  8. package/dist/esm/index.d.ts +1 -0
  9. package/dist/esm/index.js +1 -0
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/types.d.ts +5 -1
  12. package/dist/esm/types.js.map +1 -1
  13. package/dist/esm/util/createSolanaSponsoredTransaction.d.ts +12 -0
  14. package/dist/esm/util/createSolanaSponsoredTransaction.js +52 -0
  15. package/dist/esm/util/createSolanaSponsoredTransaction.js.map +1 -0
  16. package/dist/esm/util/createSolanaTransaction.d.ts +11 -0
  17. package/dist/esm/util/createSolanaTransaction.js +21 -0
  18. package/dist/esm/util/createSolanaTransaction.js.map +1 -0
  19. package/dist/esm/version.d.ts +1 -1
  20. package/dist/esm/version.js +1 -1
  21. package/dist/esm/version.js.map +1 -1
  22. package/dist/types/Provider.d.ts +4 -2
  23. package/dist/types/Provider.d.ts.map +1 -1
  24. package/dist/types/hooks/useAlchemySolanaTransaction.d.ts +164 -0
  25. package/dist/types/hooks/useAlchemySolanaTransaction.d.ts.map +1 -0
  26. package/dist/types/index.d.ts +1 -0
  27. package/dist/types/index.d.ts.map +1 -1
  28. package/dist/types/types.d.ts +5 -1
  29. package/dist/types/types.d.ts.map +1 -1
  30. package/dist/types/util/createSolanaSponsoredTransaction.d.ts +13 -0
  31. package/dist/types/util/createSolanaSponsoredTransaction.d.ts.map +1 -0
  32. package/dist/types/util/createSolanaTransaction.d.ts +12 -0
  33. package/dist/types/util/createSolanaTransaction.d.ts.map +1 -0
  34. package/dist/types/version.d.ts +1 -1
  35. package/package.json +5 -5
  36. package/src/hooks/useAlchemySolanaTransaction.ts +402 -0
  37. package/src/index.ts +1 -0
  38. package/src/types.ts +7 -1
  39. package/src/util/createSolanaSponsoredTransaction.ts +74 -0
  40. package/src/util/createSolanaTransaction.ts +31 -0
  41. package/src/version.ts +1 -1
package/README.md CHANGED
@@ -7,9 +7,10 @@ Add gas sponsorship and smart wallet features to your Privy app in under 5 minut
7
7
  If you're already using [Privy](https://privy.io) for authentication, this package lets you upgrade your users' wallets with:
8
8
 
9
9
  - **🔄 EIP-7702 Delegation** - Upgrade EOAs to smart accounts without migration
10
- - **⛽ Gas Sponsorship** - Pay gas fees for your users via Alchemy Gas Manager
10
+ - **⛽ Gas Sponsorship** - Pay gas fees for your users via Alchemy Gas Manager (EVM & Solana)
11
11
  - **💱 Token Swaps** - Execute swaps through Alchemy's swap infrastructure
12
12
  - **🚀 Batched Transactions** - Send multiple operations in a single transaction using `sendTransaction([...])`
13
+ - **☀️ Solana Support** - Send sponsored Solana transactions with Privy's embedded Solana wallets
13
14
 
14
15
  All while keeping Privy as your authentication provider. No need to change your auth flow or migrate user accounts.
15
16
 
@@ -166,17 +167,81 @@ function SwapButton() {
166
167
  }
167
168
  ```
168
169
 
170
+ ### 4. Send Solana Transactions
171
+
172
+ ```tsx
173
+ import { useAlchemySolanaTransaction } from "@account-kit/privy-integration";
174
+
175
+ function SolanaSendButton() {
176
+ const { sendTransactionAsync, isPending, error, data } =
177
+ useAlchemySolanaTransaction({
178
+ rpcUrl: "https://solana-mainnet.g.alchemy.com/v2/your-api-key",
179
+ policyId: "your-solana-policy-id", // optional, for gas sponsorship
180
+ });
181
+
182
+ const handleTransfer = async () => {
183
+ try {
184
+ // Simple SOL transfer
185
+ const result = await sendTransactionAsync({
186
+ transfer: {
187
+ amount: 1_000_000_000, // 1 SOL in lamports
188
+ toAddress: "recipient-base58-address",
189
+ },
190
+ });
191
+
192
+ console.log("Transaction hash:", result.hash);
193
+ } catch (err) {
194
+ console.error("Transaction failed:", err);
195
+ }
196
+ };
197
+
198
+ const handleCustomInstructions = async () => {
199
+ try {
200
+ // Custom instructions
201
+ import { SystemProgram, PublicKey } from "@solana/web3.js";
202
+
203
+ const instruction = SystemProgram.transfer({
204
+ fromPubkey: new PublicKey(walletAddress),
205
+ toPubkey: new PublicKey(recipientAddress),
206
+ lamports: 1_000_000,
207
+ });
208
+
209
+ const result = await sendTransactionAsync({
210
+ instructions: [instruction],
211
+ });
212
+
213
+ console.log("Transaction hash:", result.hash);
214
+ } catch (err) {
215
+ console.error("Transaction failed:", err);
216
+ }
217
+ };
218
+
219
+ return (
220
+ <>
221
+ <button onClick={handleTransfer} disabled={isPending}>
222
+ {isPending ? "Sending..." : "Send SOL"}
223
+ </button>
224
+ <button onClick={handleCustomInstructions} disabled={isPending}>
225
+ {isPending ? "Sending..." : "Custom Instructions"}
226
+ </button>
227
+ </>
228
+ );
229
+ }
230
+ ```
231
+
169
232
  ## Configuration
170
233
 
171
234
  ### AlchemyProvider Props
172
235
 
173
- | Prop | Type | Required | Description |
174
- | -------------------- | -------------------- | ------------- | ---------------------------------------------------------------------------------------------------- |
175
- | `apiKey` | `string` | Conditional\* | Your Alchemy API key for @account-kit/infra transport |
176
- | `jwt` | `string` | Conditional\* | JWT token for authentication (alternative to `apiKey`) |
177
- | `rpcUrl` | `string` | Conditional\* | Custom RPC URL (can be used alone or with `jwt`) |
178
- | `policyId` | `string \| string[]` | No | Gas Manager policy ID(s) for sponsorship. If array is provided, backend uses first applicable policy |
179
- | `disableSponsorship` | `boolean` | No | Set to `true` to disable gas sponsorship by default (default: `false`) |
236
+ | Prop | Type | Required | Description |
237
+ | -------------------- | -------------------- | ------------- | -------------------------------------------------------------------------------------------------------- |
238
+ | `apiKey` | `string` | Conditional\* | Your Alchemy API key for @account-kit/infra transport |
239
+ | `jwt` | `string` | Conditional\* | JWT token for authentication (alternative to `apiKey`) |
240
+ | `rpcUrl` | `string` | Conditional\* | Custom RPC URL for EVM chains (can be used alone or with `jwt`) |
241
+ | `solanaRpcUrl` | `string` | No | Custom RPC URL for Solana (separate from EVM `rpcUrl`) |
242
+ | `policyId` | `string \| string[]` | No | Gas Manager policy ID(s) for EVM sponsorship. If array is provided, backend uses first applicable policy |
243
+ | `solanaPolicyId` | `string \| string[]` | No | Gas Manager policy ID(s) for Solana sponsorship |
244
+ | `disableSponsorship` | `boolean` | No | Set to `true` to disable gas sponsorship by default (default: `false`) |
180
245
 
181
246
  \* **Required configuration (pick one):**
182
247
 
@@ -206,7 +271,7 @@ await sendTransaction(
206
271
 
207
272
  #### `useAlchemySendTransaction()`
208
273
 
209
- Send single or batch transactions with optional gas sponsorship.
274
+ Send single or batch EVM transactions with optional gas sponsorship.
210
275
 
211
276
  **Returns:**
212
277
 
@@ -242,6 +307,29 @@ Sign and submit prepared swap calls.
242
307
  - `data` - Swap result with `txnHash`
243
308
  - `reset()` - Reset hook state
244
309
 
310
+ #### `useAlchemySolanaTransaction(options?)`
311
+
312
+ Send Solana transactions with optional gas sponsorship via Alchemy.
313
+
314
+ **Parameters:**
315
+
316
+ - `options.rpcUrl` - Solana RPC URL (overrides provider config)
317
+ - `options.policyId` - Gas sponsorship policy ID (overrides provider config)
318
+ - `options.walletAddress` - Specific wallet address to use (defaults to first wallet)
319
+ - `options.confirmationOptions` - Transaction confirmation options
320
+
321
+ **Returns:**
322
+
323
+ - `sendTransactionAsync(params)` - Send transaction and await result (throws on error)
324
+ - `params.transfer` - Simple SOL transfer with `amount` (lamports) and `toAddress`
325
+ - `params.instructions` - Custom Solana transaction instructions array
326
+ - `sendTransaction(params)` - Send transaction (fire-and-forget, errors caught internally)
327
+ - `connection` - Active Solana connection instance
328
+ - `isPending` - Whether a transaction is currently being sent
329
+ - `error` - Error object if failed
330
+ - `data` - Transaction result with `hash` (base58 signature)
331
+ - `reset()` - Reset hook state
332
+
245
333
  #### `useAlchemyClient()`
246
334
 
247
335
  Get the underlying smart wallet client (advanced use cases).
@@ -19,8 +19,10 @@ interface ClientCache {
19
19
  * @param {React.ReactNode} props.children - React children to wrap with Alchemy configuration
20
20
  * @param {string} [props.apiKey] - Your Alchemy API key
21
21
  * @param {string} [props.jwt] - JWT token for authentication
22
- * @param {string} [props.rpcUrl] - Custom RPC URL
23
- * @param {string | string[]} [props.policyId] - Gas Manager policy ID(s)
22
+ * @param {string} [props.rpcUrl] - Custom RPC URL for EVM chains
23
+ * @param {string} [props.solanaRpcUrl] - Custom RPC URL for Solana
24
+ * @param {string | string[]} [props.policyId] - Gas Manager policy ID(s) for EVM chains
25
+ * @param {string | string[]} [props.solanaPolicyId] - Gas Manager policy ID(s) for Solana
24
26
  * @param {boolean} [props.disableSponsorship] - Set to true to disable sponsorship by default (default: false)
25
27
  * @returns {JSX.Element} Provider component
26
28
  *
@@ -12,8 +12,10 @@ const ClientCacheContext = createContext(null);
12
12
  * @param {React.ReactNode} props.children - React children to wrap with Alchemy configuration
13
13
  * @param {string} [props.apiKey] - Your Alchemy API key
14
14
  * @param {string} [props.jwt] - JWT token for authentication
15
- * @param {string} [props.rpcUrl] - Custom RPC URL
16
- * @param {string | string[]} [props.policyId] - Gas Manager policy ID(s)
15
+ * @param {string} [props.rpcUrl] - Custom RPC URL for EVM chains
16
+ * @param {string} [props.solanaRpcUrl] - Custom RPC URL for Solana
17
+ * @param {string | string[]} [props.policyId] - Gas Manager policy ID(s) for EVM chains
18
+ * @param {string | string[]} [props.solanaPolicyId] - Gas Manager policy ID(s) for Solana
17
19
  * @param {boolean} [props.disableSponsorship] - Set to true to disable sponsorship by default (default: false)
18
20
  * @returns {JSX.Element} Provider component
19
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Provider.js","sourceRoot":"","sources":["../../src/Provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAEL,aAAa,EACb,UAAU,EACV,MAAM,EACN,SAAS,GACV,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIhD,MAAM,cAAc,GAAG,aAAa,CAA+B,IAAI,CAAC,CAAC;AAYzE,MAAM,kBAAkB,GAAG,aAAa,CAAqB,IAAI,CAAC,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,GAAG,MAAM,EACgC;IACzC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,CAAC;IAE3C,uFAAuF;IACvF,qFAAqF;IACrF,MAAM,KAAK,GAAG,MAAM,CAAc;QAChC,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,2DAA2D;IAC3D,MAAM,oBAAoB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IACnD,MAAM,oBAAoB,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3D,mEAAmE;IACnE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,OAAO,CAAC;QACtD,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,OAAO,CAAC;QACvD,MAAM,oBAAoB,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC;QAEnD,wBAAwB;QACxB,IAAI,gBAAgB,IAAI,CAAC,aAAa,EAAE,CAAC;YACvC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChC,CAAC;QAED,2DAA2D;QAC3D,IACE,aAAa;YACb,iBAAiB;YACjB,oBAAoB;YACpB,iBAAiB,KAAK,oBAAoB,EAC1C,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChC,CAAC;QAED,8BAA8B;QAC9B,oBAAoB,CAAC,OAAO,GAAG,aAAa,CAAC;QAC7C,oBAAoB,CAAC,OAAO,GAAG,oBAAoB,CAAC;IACtD,CAAC,EAAE,CAAC,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAE3C,OAAO,CACL,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,YACpC,KAAC,kBAAkB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,YAC9C,QAAQ,GACmB,GACN,CAC3B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,mHAAmH,CACpH,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import {\n type PropsWithChildren,\n createContext,\n useContext,\n useRef,\n useEffect,\n} from \"react\";\nimport { usePrivy } from \"@privy-io/react-auth\";\nimport type { SmartWalletClient } from \"@account-kit/wallet-client\";\nimport type { AlchemyProviderConfig } from \"./types.js\";\n\nconst AlchemyContext = createContext<AlchemyProviderConfig | null>(null);\n\n/**\n * Client cache stored in React tree (similar to QueryClient in React Query)\n *\n * @internal\n */\ninterface ClientCache {\n client: SmartWalletClient | null;\n cacheKey: string | null;\n}\n\nconst ClientCacheContext = createContext<ClientCache | null>(null);\n\n/**\n * Provider component that configures Alchemy infrastructure for transaction handling\n * Must be nested INSIDE PrivyProvider to access authentication state\n * Automatically manages client cache lifecycle and resets on logout\n *\n * @param {PropsWithChildren<AlchemyProviderConfig>} props - Component props\n * @param {React.ReactNode} props.children - React children to wrap with Alchemy configuration\n * @param {string} [props.apiKey] - Your Alchemy API key\n * @param {string} [props.jwt] - JWT token for authentication\n * @param {string} [props.rpcUrl] - Custom RPC URL\n * @param {string | string[]} [props.policyId] - Gas Manager policy ID(s)\n * @param {boolean} [props.disableSponsorship] - Set to true to disable sponsorship by default (default: false)\n * @returns {JSX.Element} Provider component\n *\n * @example\n * ```tsx\n * <PrivyProvider appId=\"...\">\n * <AlchemyProvider\n * apiKey=\"your-alchemy-api-key\"\n * policyId=\"your-gas-policy-id\"\n * >\n * <YourApp />\n * </AlchemyProvider>\n * </PrivyProvider>\n * ```\n */\nexport function AlchemyProvider({\n children,\n ...config\n}: PropsWithChildren<AlchemyProviderConfig>) {\n const { authenticated, user } = usePrivy();\n\n // Store cache in a ref - persists across renders but scoped to this component instance\n // This makes it SSR-safe (each request gets its own cache) and React StrictMode-safe\n const cache = useRef<ClientCache>({\n client: null,\n cacheKey: null,\n });\n\n // Track previous state to detect logout and wallet changes\n const prevAuthenticatedRef = useRef(authenticated);\n const prevWalletAddressRef = useRef(user?.wallet?.address);\n\n // Automatically reset cache when user logs out or switches wallets\n useEffect(() => {\n const wasAuthenticated = prevAuthenticatedRef.current;\n const prevWalletAddress = prevWalletAddressRef.current;\n const currentWalletAddress = user?.wallet?.address;\n\n // Reset cache on logout\n if (wasAuthenticated && !authenticated) {\n cache.current.client = null;\n cache.current.cacheKey = null;\n }\n\n // Reset cache on wallet address change (account switching)\n if (\n authenticated &&\n prevWalletAddress &&\n currentWalletAddress &&\n prevWalletAddress !== currentWalletAddress\n ) {\n cache.current.client = null;\n cache.current.cacheKey = null;\n }\n\n // Update refs for next render\n prevAuthenticatedRef.current = authenticated;\n prevWalletAddressRef.current = currentWalletAddress;\n }, [authenticated, user?.wallet?.address]);\n\n return (\n <AlchemyContext.Provider value={config}>\n <ClientCacheContext.Provider value={cache.current}>\n {children}\n </ClientCacheContext.Provider>\n </AlchemyContext.Provider>\n );\n}\n\n/**\n * Hook to access Alchemy provider configuration\n * Must be used within an <AlchemyProvider> component\n *\n * @returns {AlchemyProviderConfig} The current Alchemy configuration\n * @throws {Error} If used outside of AlchemyProvider\n *\n * @example\n * ```tsx\n * const config = useAlchemyConfig();\n * console.log('Policy ID:', config.policyId);\n * ```\n */\nexport function useAlchemyConfig(): AlchemyProviderConfig {\n const context = useContext(AlchemyContext);\n if (!context) {\n throw new Error(\"useAlchemyConfig must be used within <AlchemyProvider />\");\n }\n return context;\n}\n\n/**\n * Hook to access the client cache (internal use only)\n *\n * @internal\n * @returns {ClientCache} The client cache object\n */\nexport function useClientCache(): ClientCache {\n const context = useContext(ClientCacheContext);\n if (!context) {\n throw new Error(\n \"useClientCache must be used within <AlchemyProvider />. Make sure AlchemyProvider is nested inside PrivyProvider.\",\n );\n }\n return context;\n}\n"]}
1
+ {"version":3,"file":"Provider.js","sourceRoot":"","sources":["../../src/Provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAEL,aAAa,EACb,UAAU,EACV,MAAM,EACN,SAAS,GACV,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIhD,MAAM,cAAc,GAAG,aAAa,CAA+B,IAAI,CAAC,CAAC;AAYzE,MAAM,kBAAkB,GAAG,aAAa,CAAqB,IAAI,CAAC,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,GAAG,MAAM,EACgC;IACzC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,CAAC;IAE3C,uFAAuF;IACvF,qFAAqF;IACrF,MAAM,KAAK,GAAG,MAAM,CAAc;QAChC,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,2DAA2D;IAC3D,MAAM,oBAAoB,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IACnD,MAAM,oBAAoB,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE3D,mEAAmE;IACnE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,OAAO,CAAC;QACtD,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,OAAO,CAAC;QACvD,MAAM,oBAAoB,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC;QAEnD,wBAAwB;QACxB,IAAI,gBAAgB,IAAI,CAAC,aAAa,EAAE,CAAC;YACvC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChC,CAAC;QAED,2DAA2D;QAC3D,IACE,aAAa;YACb,iBAAiB;YACjB,oBAAoB;YACpB,iBAAiB,KAAK,oBAAoB,EAC1C,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAC5B,KAAK,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChC,CAAC;QAED,8BAA8B;QAC9B,oBAAoB,CAAC,OAAO,GAAG,aAAa,CAAC;QAC7C,oBAAoB,CAAC,OAAO,GAAG,oBAAoB,CAAC;IACtD,CAAC,EAAE,CAAC,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAE3C,OAAO,CACL,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,YACpC,KAAC,kBAAkB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,YAC9C,QAAQ,GACmB,GACN,CAC3B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,mHAAmH,CACpH,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["import {\n type PropsWithChildren,\n createContext,\n useContext,\n useRef,\n useEffect,\n} from \"react\";\nimport { usePrivy } from \"@privy-io/react-auth\";\nimport type { SmartWalletClient } from \"@account-kit/wallet-client\";\nimport type { AlchemyProviderConfig } from \"./types.js\";\n\nconst AlchemyContext = createContext<AlchemyProviderConfig | null>(null);\n\n/**\n * Client cache stored in React tree (similar to QueryClient in React Query)\n *\n * @internal\n */\ninterface ClientCache {\n client: SmartWalletClient | null;\n cacheKey: string | null;\n}\n\nconst ClientCacheContext = createContext<ClientCache | null>(null);\n\n/**\n * Provider component that configures Alchemy infrastructure for transaction handling\n * Must be nested INSIDE PrivyProvider to access authentication state\n * Automatically manages client cache lifecycle and resets on logout\n *\n * @param {PropsWithChildren<AlchemyProviderConfig>} props - Component props\n * @param {React.ReactNode} props.children - React children to wrap with Alchemy configuration\n * @param {string} [props.apiKey] - Your Alchemy API key\n * @param {string} [props.jwt] - JWT token for authentication\n * @param {string} [props.rpcUrl] - Custom RPC URL for EVM chains\n * @param {string} [props.solanaRpcUrl] - Custom RPC URL for Solana\n * @param {string | string[]} [props.policyId] - Gas Manager policy ID(s) for EVM chains\n * @param {string | string[]} [props.solanaPolicyId] - Gas Manager policy ID(s) for Solana\n * @param {boolean} [props.disableSponsorship] - Set to true to disable sponsorship by default (default: false)\n * @returns {JSX.Element} Provider component\n *\n * @example\n * ```tsx\n * <PrivyProvider appId=\"...\">\n * <AlchemyProvider\n * apiKey=\"your-alchemy-api-key\"\n * policyId=\"your-gas-policy-id\"\n * >\n * <YourApp />\n * </AlchemyProvider>\n * </PrivyProvider>\n * ```\n */\nexport function AlchemyProvider({\n children,\n ...config\n}: PropsWithChildren<AlchemyProviderConfig>) {\n const { authenticated, user } = usePrivy();\n\n // Store cache in a ref - persists across renders but scoped to this component instance\n // This makes it SSR-safe (each request gets its own cache) and React StrictMode-safe\n const cache = useRef<ClientCache>({\n client: null,\n cacheKey: null,\n });\n\n // Track previous state to detect logout and wallet changes\n const prevAuthenticatedRef = useRef(authenticated);\n const prevWalletAddressRef = useRef(user?.wallet?.address);\n\n // Automatically reset cache when user logs out or switches wallets\n useEffect(() => {\n const wasAuthenticated = prevAuthenticatedRef.current;\n const prevWalletAddress = prevWalletAddressRef.current;\n const currentWalletAddress = user?.wallet?.address;\n\n // Reset cache on logout\n if (wasAuthenticated && !authenticated) {\n cache.current.client = null;\n cache.current.cacheKey = null;\n }\n\n // Reset cache on wallet address change (account switching)\n if (\n authenticated &&\n prevWalletAddress &&\n currentWalletAddress &&\n prevWalletAddress !== currentWalletAddress\n ) {\n cache.current.client = null;\n cache.current.cacheKey = null;\n }\n\n // Update refs for next render\n prevAuthenticatedRef.current = authenticated;\n prevWalletAddressRef.current = currentWalletAddress;\n }, [authenticated, user?.wallet?.address]);\n\n return (\n <AlchemyContext.Provider value={config}>\n <ClientCacheContext.Provider value={cache.current}>\n {children}\n </ClientCacheContext.Provider>\n </AlchemyContext.Provider>\n );\n}\n\n/**\n * Hook to access Alchemy provider configuration\n * Must be used within an <AlchemyProvider> component\n *\n * @returns {AlchemyProviderConfig} The current Alchemy configuration\n * @throws {Error} If used outside of AlchemyProvider\n *\n * @example\n * ```tsx\n * const config = useAlchemyConfig();\n * console.log('Policy ID:', config.policyId);\n * ```\n */\nexport function useAlchemyConfig(): AlchemyProviderConfig {\n const context = useContext(AlchemyContext);\n if (!context) {\n throw new Error(\"useAlchemyConfig must be used within <AlchemyProvider />\");\n }\n return context;\n}\n\n/**\n * Hook to access the client cache (internal use only)\n *\n * @internal\n * @returns {ClientCache} The client cache object\n */\nexport function useClientCache(): ClientCache {\n const context = useContext(ClientCacheContext);\n if (!context) {\n throw new Error(\n \"useClientCache must be used within <AlchemyProvider />. Make sure AlchemyProvider is nested inside PrivyProvider.\",\n );\n }\n return context;\n}\n"]}
@@ -0,0 +1,163 @@
1
+ import { Connection, Transaction, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
2
+ /**
3
+ * Type helper for values that can be synchronous or asynchronous
4
+ *
5
+ * @template T - The value type
6
+ */
7
+ export type PromiseOrValue<T> = T | Promise<T>;
8
+ /**
9
+ * Callback to modify a transaction before it's signed
10
+ * Useful for adding additional signatures or metadata
11
+ *
12
+ * @param transaction - The unsigned transaction to modify
13
+ * @returns The modified transaction
14
+ */
15
+ export type PreSend = (this: void, transaction: VersionedTransaction | Transaction) => PromiseOrValue<VersionedTransaction | Transaction>;
16
+ /**
17
+ * Callback to transform instructions into a custom transaction
18
+ * Useful for advanced transaction construction (e.g., multi-sig, custom versioning)
19
+ *
20
+ * @param instructions - Array of Solana transaction instructions
21
+ * @returns Constructed transaction (legacy or versioned)
22
+ */
23
+ export type TransformInstruction = (this: void, instructions: TransactionInstruction[]) => PromiseOrValue<Transaction | VersionedTransaction>;
24
+ /**
25
+ * Optional transaction lifecycle hooks for advanced use cases
26
+ */
27
+ export type SolanaTransactionParamOptions = {
28
+ /** Hook called before signing the transaction */
29
+ preSend?: PreSend;
30
+ /** Custom transaction builder from instructions */
31
+ transformInstruction?: TransformInstruction;
32
+ };
33
+ /**
34
+ * Parameters for sending a Solana transaction
35
+ * Supports either a simple transfer or custom instructions
36
+ */
37
+ export type SolanaTransactionParams = {
38
+ /** Simple SOL transfer parameters */
39
+ transfer: {
40
+ /** Amount in lamports (accepts number or bigint) */
41
+ amount: number | bigint;
42
+ /** Recipient's base58-encoded address */
43
+ toAddress: string;
44
+ };
45
+ /** Optional transaction lifecycle hooks */
46
+ transactionComponents?: SolanaTransactionParamOptions;
47
+ /** Options for confirming the transaction on-chain */
48
+ confirmationOptions?: Parameters<Connection["confirmTransaction"]>[1];
49
+ } | {
50
+ /** Custom Solana transaction instructions */
51
+ instructions: TransactionInstruction[];
52
+ /** Optional transaction lifecycle hooks */
53
+ transactionComponents?: SolanaTransactionParamOptions;
54
+ /** Options for confirming the transaction on-chain */
55
+ confirmationOptions?: Parameters<Connection["confirmTransaction"]>[1];
56
+ };
57
+ /**
58
+ * Result of a successful Solana transaction
59
+ */
60
+ export interface SolanaTransactionResult {
61
+ /** Base58-encoded transaction signature (hash) */
62
+ hash: string;
63
+ }
64
+ /**
65
+ * Configuration options for useAlchemySolanaTransaction hook
66
+ */
67
+ export interface UseAlchemySolanaTransactionOptions {
68
+ /** Solana RPC URL (overrides provider config) */
69
+ rpcUrl?: string;
70
+ /** Gas sponsorship policy ID (overrides provider config) */
71
+ policyId?: string | void;
72
+ /** Transaction confirmation options */
73
+ confirmationOptions?: Parameters<Connection["confirmTransaction"]>[1];
74
+ /** Specific wallet address to use (defaults to first available wallet) */
75
+ walletAddress?: string;
76
+ }
77
+ /**
78
+ * Return type of useAlchemySolanaTransaction hook
79
+ */
80
+ export interface UseAlchemySolanaTransactionResult {
81
+ /** Active Solana connection instance */
82
+ readonly connection: Connection | null;
83
+ /** Transaction result if successful */
84
+ readonly data: void | SolanaTransactionResult;
85
+ /** Whether a transaction is currently being sent */
86
+ readonly isPending: boolean;
87
+ /** Error if transaction failed */
88
+ readonly error: Error | null;
89
+ /** Reset hook state (clears error, data, isPending) */
90
+ reset(): void;
91
+ /** Send transaction (fire-and-forget, errors caught internally) */
92
+ sendTransaction(params: SolanaTransactionParams): void;
93
+ /** Send transaction and await result (throws on error) */
94
+ sendTransactionAsync(params: SolanaTransactionParams): Promise<SolanaTransactionResult>;
95
+ }
96
+ /**
97
+ * Hook to send Solana transactions with optional gas sponsorship via Alchemy
98
+ * Works with Privy's Solana wallet integration for signing transactions
99
+ * Supports both simple transfers and custom instruction sets
100
+ *
101
+ * @param {UseAlchemySolanaTransactionOptions} [opts] - Configuration options
102
+ * @param {string} [opts.rpcUrl] - Solana RPC URL (overrides provider config)
103
+ * @param {string} [opts.policyId] - Gas sponsorship policy ID (overrides provider config)
104
+ * @param {string} [opts.walletAddress] - Specific wallet address to use (defaults to first wallet)
105
+ * @param {Parameters<Connection["confirmTransaction"]>[1]} [opts.confirmationOptions] - Transaction confirmation options
106
+ * @returns {UseAlchemySolanaTransactionResult} Hook result with transaction functions and state
107
+ *
108
+ * @example Simple SOL transfer
109
+ * ```tsx
110
+ * const { sendTransactionAsync, isPending, error, data } = useAlchemySolanaTransaction({
111
+ * rpcUrl: 'https://solana-mainnet.g.alchemy.com/v2/your-api-key',
112
+ * policyId: 'your-policy-id', // Optional: for gas sponsorship
113
+ * });
114
+ *
115
+ * const handleTransfer = async () => {
116
+ * try {
117
+ * const result = await sendTransactionAsync({
118
+ * transfer: {
119
+ * amount: 1_000_000_000, // 1 SOL in lamports
120
+ * toAddress: 'recipient-address',
121
+ * },
122
+ * });
123
+ * console.log('Transaction hash:', result.hash);
124
+ * } catch (err) {
125
+ * console.error('Transaction failed:', err);
126
+ * }
127
+ * };
128
+ * ```
129
+ *
130
+ * @example Custom instructions
131
+ * ```tsx
132
+ * import { SystemProgram, PublicKey } from '@solana/web3.js';
133
+ *
134
+ * const { sendTransactionAsync } = useAlchemySolanaTransaction();
135
+ *
136
+ * // Build your custom instructions
137
+ * const transferIx = SystemProgram.transfer({
138
+ * fromPubkey: new PublicKey(walletAddress),
139
+ * toPubkey: new PublicKey(recipientAddress),
140
+ * lamports: 1_000_000,
141
+ * });
142
+ *
143
+ * // Pass instructions array to the hook
144
+ * const result = await sendTransactionAsync({
145
+ * instructions: [transferIx],
146
+ * });
147
+ * ```
148
+ *
149
+ * @example With provider configuration
150
+ * ```tsx
151
+ * // In your provider setup
152
+ * <AlchemyProvider
153
+ * solanaRpcUrl="https://solana-mainnet.g.alchemy.com/v2/..."
154
+ * solanaPolicyId="your-solana-policy-id"
155
+ * >
156
+ * <YourApp />
157
+ * </AlchemyProvider>
158
+ *
159
+ * // In your component - uses provider config automatically
160
+ * const { sendTransactionAsync } = useAlchemySolanaTransaction();
161
+ * ```
162
+ */
163
+ export declare function useAlchemySolanaTransaction(opts?: UseAlchemySolanaTransactionOptions): UseAlchemySolanaTransactionResult;
@@ -0,0 +1,233 @@
1
+ import { useCallback, useMemo, useState } from "react";
2
+ import { Connection, PublicKey, SystemProgram, Transaction, TransactionInstruction, VersionedTransaction, } from "@solana/web3.js";
3
+ import { useAlchemyConfig } from "../Provider.js";
4
+ import { createSolanaSponsoredTransaction } from "../util/createSolanaSponsoredTransaction.js";
5
+ import { useSignTransaction, useWallets } from "@privy-io/react-auth/solana";
6
+ import { createSolanaTransaction } from "../util/createSolanaTransaction.js";
7
+ /**
8
+ * Hook to send Solana transactions with optional gas sponsorship via Alchemy
9
+ * Works with Privy's Solana wallet integration for signing transactions
10
+ * Supports both simple transfers and custom instruction sets
11
+ *
12
+ * @param {UseAlchemySolanaTransactionOptions} [opts] - Configuration options
13
+ * @param {string} [opts.rpcUrl] - Solana RPC URL (overrides provider config)
14
+ * @param {string} [opts.policyId] - Gas sponsorship policy ID (overrides provider config)
15
+ * @param {string} [opts.walletAddress] - Specific wallet address to use (defaults to first wallet)
16
+ * @param {Parameters<Connection["confirmTransaction"]>[1]} [opts.confirmationOptions] - Transaction confirmation options
17
+ * @returns {UseAlchemySolanaTransactionResult} Hook result with transaction functions and state
18
+ *
19
+ * @example Simple SOL transfer
20
+ * ```tsx
21
+ * const { sendTransactionAsync, isPending, error, data } = useAlchemySolanaTransaction({
22
+ * rpcUrl: 'https://solana-mainnet.g.alchemy.com/v2/your-api-key',
23
+ * policyId: 'your-policy-id', // Optional: for gas sponsorship
24
+ * });
25
+ *
26
+ * const handleTransfer = async () => {
27
+ * try {
28
+ * const result = await sendTransactionAsync({
29
+ * transfer: {
30
+ * amount: 1_000_000_000, // 1 SOL in lamports
31
+ * toAddress: 'recipient-address',
32
+ * },
33
+ * });
34
+ * console.log('Transaction hash:', result.hash);
35
+ * } catch (err) {
36
+ * console.error('Transaction failed:', err);
37
+ * }
38
+ * };
39
+ * ```
40
+ *
41
+ * @example Custom instructions
42
+ * ```tsx
43
+ * import { SystemProgram, PublicKey } from '@solana/web3.js';
44
+ *
45
+ * const { sendTransactionAsync } = useAlchemySolanaTransaction();
46
+ *
47
+ * // Build your custom instructions
48
+ * const transferIx = SystemProgram.transfer({
49
+ * fromPubkey: new PublicKey(walletAddress),
50
+ * toPubkey: new PublicKey(recipientAddress),
51
+ * lamports: 1_000_000,
52
+ * });
53
+ *
54
+ * // Pass instructions array to the hook
55
+ * const result = await sendTransactionAsync({
56
+ * instructions: [transferIx],
57
+ * });
58
+ * ```
59
+ *
60
+ * @example With provider configuration
61
+ * ```tsx
62
+ * // In your provider setup
63
+ * <AlchemyProvider
64
+ * solanaRpcUrl="https://solana-mainnet.g.alchemy.com/v2/..."
65
+ * solanaPolicyId="your-solana-policy-id"
66
+ * >
67
+ * <YourApp />
68
+ * </AlchemyProvider>
69
+ *
70
+ * // In your component - uses provider config automatically
71
+ * const { sendTransactionAsync } = useAlchemySolanaTransaction();
72
+ * ```
73
+ */
74
+ export function useAlchemySolanaTransaction(opts = {}) {
75
+ const config = useAlchemyConfig();
76
+ const { wallets } = useWallets();
77
+ const { signTransaction } = useSignTransaction();
78
+ // Resolve the Privy Solana wallet to use
79
+ const embeddedWallet = useMemo(() => {
80
+ if (opts.walletAddress) {
81
+ const w = wallets.find((w) => w.address === opts.walletAddress);
82
+ if (!w)
83
+ throw new Error("Specified Solana wallet not found");
84
+ return w;
85
+ }
86
+ return wallets[0];
87
+ }, [wallets, opts.walletAddress]);
88
+ // Build Solana connection from rpcUrl (hook override or provider default)
89
+ const connection = useMemo(() => {
90
+ const url = opts.rpcUrl || config.solanaRpcUrl;
91
+ return url ? new Connection(url) : null;
92
+ }, [opts.rpcUrl, config.solanaRpcUrl]);
93
+ const [isPending, setIsPending] = useState(false);
94
+ const [error, setError] = useState(null);
95
+ const [data, setData] = useState(undefined);
96
+ const resolvedPolicyId = useMemo(() => {
97
+ if (opts.policyId != null)
98
+ return opts.policyId || undefined;
99
+ // Use solanaPolicyId from config, fallback to policyId for backwards compat
100
+ const configPolicy = config.solanaPolicyId || config.policyId;
101
+ return Array.isArray(configPolicy) ? configPolicy[0] : configPolicy;
102
+ }, [opts.policyId, config.solanaPolicyId, config.policyId]);
103
+ const mapTransformInstructions = useMemo(() => {
104
+ const addSponsorship = async (instructions) => {
105
+ const policyId = resolvedPolicyId;
106
+ if (!policyId)
107
+ throw new Error("Gas sponsorship requires a policyId (see provider or hook options).");
108
+ const localConnection = connection || missing("connection");
109
+ const fromAddress = embeddedWallet?.address;
110
+ if (!fromAddress)
111
+ throw new Error("No embedded Solana wallet connected");
112
+ return createSolanaSponsoredTransaction(instructions, localConnection, policyId, fromAddress);
113
+ };
114
+ const createTx = async (instructions) => {
115
+ const localConnection = connection || missing("connection");
116
+ const fromAddress = embeddedWallet?.address;
117
+ if (!fromAddress)
118
+ throw new Error("No embedded Solana wallet connected");
119
+ return createSolanaTransaction(instructions, localConnection, fromAddress);
120
+ };
121
+ const defaultTransform = !!resolvedPolicyId && !config.disableSponsorship
122
+ ? addSponsorship
123
+ : createTx;
124
+ return {
125
+ addSponsorship,
126
+ createTransaction: createTx,
127
+ default: defaultTransform,
128
+ };
129
+ }, [
130
+ resolvedPolicyId,
131
+ config.disableSponsorship,
132
+ connection,
133
+ embeddedWallet?.address,
134
+ ]);
135
+ const buildInstructions = useCallback((params, fromAddress) => {
136
+ if ("instructions" in params)
137
+ return params.instructions;
138
+ return [
139
+ SystemProgram.transfer({
140
+ fromPubkey: new PublicKey(fromAddress),
141
+ toPubkey: new PublicKey(params.transfer.toAddress),
142
+ lamports: typeof params.transfer.amount === "bigint"
143
+ ? Number(params.transfer.amount) // web3.js currently expects number; callers can pass bigint safely
144
+ : params.transfer.amount,
145
+ }),
146
+ ];
147
+ }, []);
148
+ function toUnsignedBytes(tx) {
149
+ // Serialize the full transaction structure (with placeholder signatures)
150
+ // Privy expects the complete transaction format, not just the message
151
+ if (tx instanceof VersionedTransaction) {
152
+ // VersionedTransaction.serialize() includes signature slots
153
+ return tx.serialize();
154
+ }
155
+ // Legacy Transaction: serialize without requiring all signatures
156
+ const buf = tx.serialize({
157
+ requireAllSignatures: false,
158
+ verifySignatures: false,
159
+ });
160
+ return buf instanceof Uint8Array ? buf : new Uint8Array(buf);
161
+ }
162
+ const sendTransactionAsync = useCallback(async (params) => {
163
+ setIsPending(true);
164
+ setError(null);
165
+ try {
166
+ const localConnection = connection || missing("connection");
167
+ if (!embeddedWallet?.address) {
168
+ throw new Error("No Solana wallet connected via Privy");
169
+ }
170
+ const fromAddress = embeddedWallet.address;
171
+ const { transactionComponents: { preSend, transformInstruction } = {}, confirmationOptions, } = params;
172
+ const instructions = buildInstructions(params, fromAddress);
173
+ let transaction;
174
+ if (transformInstruction) {
175
+ transaction = await transformInstruction(instructions);
176
+ }
177
+ else {
178
+ transaction = await mapTransformInstructions.default(instructions);
179
+ }
180
+ transaction = (await preSend?.(transaction)) || transaction;
181
+ // Sign the transaction using Privy's useSignTransaction hook
182
+ const unsignedBytes = toUnsignedBytes(transaction);
183
+ const { signedTransaction } = await signTransaction({
184
+ transaction: unsignedBytes,
185
+ wallet: embeddedWallet,
186
+ });
187
+ // Broadcast the signed transaction
188
+ const hash = await localConnection.sendRawTransaction(signedTransaction, { skipPreflight: false });
189
+ if (confirmationOptions || opts.confirmationOptions) {
190
+ await localConnection.confirmTransaction(hash, confirmationOptions || opts.confirmationOptions);
191
+ }
192
+ setData({ hash });
193
+ return { hash };
194
+ }
195
+ catch (err) {
196
+ const e = err instanceof Error ? err : new Error(String(err));
197
+ setError(e);
198
+ throw e;
199
+ }
200
+ finally {
201
+ setIsPending(false);
202
+ }
203
+ }, [
204
+ embeddedWallet,
205
+ connection,
206
+ buildInstructions,
207
+ mapTransformInstructions,
208
+ opts.confirmationOptions,
209
+ signTransaction,
210
+ ]);
211
+ const sendTransaction = useCallback((params) => {
212
+ // Prevent unhandled rejection warnings; error state is already set in sendTransactionAsync
213
+ sendTransactionAsync(params).catch(() => { });
214
+ }, [sendTransactionAsync]);
215
+ const reset = useCallback(() => {
216
+ setIsPending(false);
217
+ setError(null);
218
+ setData(undefined);
219
+ }, []);
220
+ return {
221
+ connection,
222
+ data,
223
+ isPending,
224
+ error,
225
+ reset,
226
+ sendTransaction,
227
+ sendTransactionAsync,
228
+ };
229
+ }
230
+ function missing(message) {
231
+ throw new Error(message);
232
+ }
233
+ //# sourceMappingURL=useAlchemySolanaTransaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAlchemySolanaTransaction.js","sourceRoot":"","sources":["../../../src/hooks/useAlchemySolanaTransaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useMemo, useState } from \"react\";\nimport {\n Connection,\n PublicKey,\n SystemProgram,\n Transaction,\n TransactionInstruction,\n VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { useAlchemyConfig } from \"../Provider.js\";\nimport { createSolanaSponsoredTransaction } from \"../util/createSolanaSponsoredTransaction.js\";\nimport { useSignTransaction, useWallets } from \"@privy-io/react-auth/solana\";\nimport { createSolanaTransaction } from \"../util/createSolanaTransaction.js\";\n\n/**\n * Type helper for values that can be synchronous or asynchronous\n *\n * @template T - The value type\n */\nexport type PromiseOrValue<T> = T | Promise<T>;\n\n/**\n * Callback to modify a transaction before it's signed\n * Useful for adding additional signatures or metadata\n *\n * @param transaction - The unsigned transaction to modify\n * @returns The modified transaction\n */\nexport type PreSend = (\n this: void,\n transaction: VersionedTransaction | Transaction,\n) => PromiseOrValue<VersionedTransaction | Transaction>;\n\n/**\n * Callback to transform instructions into a custom transaction\n * Useful for advanced transaction construction (e.g., multi-sig, custom versioning)\n *\n * @param instructions - Array of Solana transaction instructions\n * @returns Constructed transaction (legacy or versioned)\n */\nexport type TransformInstruction = (\n this: void,\n instructions: TransactionInstruction[],\n) => PromiseOrValue<Transaction | VersionedTransaction>;\n\n/**\n * Optional transaction lifecycle hooks for advanced use cases\n */\nexport type SolanaTransactionParamOptions = {\n /** Hook called before signing the transaction */\n preSend?: PreSend;\n /** Custom transaction builder from instructions */\n transformInstruction?: TransformInstruction;\n};\n\n/**\n * Parameters for sending a Solana transaction\n * Supports either a simple transfer or custom instructions\n */\nexport type SolanaTransactionParams =\n | {\n /** Simple SOL transfer parameters */\n transfer: {\n /** Amount in lamports (accepts number or bigint) */\n amount: number | bigint;\n /** Recipient's base58-encoded address */\n toAddress: string;\n };\n /** Optional transaction lifecycle hooks */\n transactionComponents?: SolanaTransactionParamOptions;\n /** Options for confirming the transaction on-chain */\n confirmationOptions?: Parameters<Connection[\"confirmTransaction\"]>[1];\n }\n | {\n /** Custom Solana transaction instructions */\n instructions: TransactionInstruction[];\n /** Optional transaction lifecycle hooks */\n transactionComponents?: SolanaTransactionParamOptions;\n /** Options for confirming the transaction on-chain */\n confirmationOptions?: Parameters<Connection[\"confirmTransaction\"]>[1];\n };\n\n/**\n * Result of a successful Solana transaction\n */\nexport interface SolanaTransactionResult {\n /** Base58-encoded transaction signature (hash) */\n hash: string;\n}\n\n/**\n * Configuration options for useAlchemySolanaTransaction hook\n */\nexport interface UseAlchemySolanaTransactionOptions {\n /** Solana RPC URL (overrides provider config) */\n rpcUrl?: string;\n /** Gas sponsorship policy ID (overrides provider config) */\n policyId?: string | void;\n /** Transaction confirmation options */\n confirmationOptions?: Parameters<Connection[\"confirmTransaction\"]>[1];\n /** Specific wallet address to use (defaults to first available wallet) */\n walletAddress?: string;\n}\n\n/**\n * Return type of useAlchemySolanaTransaction hook\n */\nexport interface UseAlchemySolanaTransactionResult {\n /** Active Solana connection instance */\n readonly connection: Connection | null;\n /** Transaction result if successful */\n readonly data: void | SolanaTransactionResult;\n /** Whether a transaction is currently being sent */\n readonly isPending: boolean;\n /** Error if transaction failed */\n readonly error: Error | null;\n /** Reset hook state (clears error, data, isPending) */\n reset(): void;\n /** Send transaction (fire-and-forget, errors caught internally) */\n sendTransaction(params: SolanaTransactionParams): void;\n /** Send transaction and await result (throws on error) */\n sendTransactionAsync(\n params: SolanaTransactionParams,\n ): Promise<SolanaTransactionResult>;\n}\n\n/**\n * Hook to send Solana transactions with optional gas sponsorship via Alchemy\n * Works with Privy's Solana wallet integration for signing transactions\n * Supports both simple transfers and custom instruction sets\n *\n * @param {UseAlchemySolanaTransactionOptions} [opts] - Configuration options\n * @param {string} [opts.rpcUrl] - Solana RPC URL (overrides provider config)\n * @param {string} [opts.policyId] - Gas sponsorship policy ID (overrides provider config)\n * @param {string} [opts.walletAddress] - Specific wallet address to use (defaults to first wallet)\n * @param {Parameters<Connection[\"confirmTransaction\"]>[1]} [opts.confirmationOptions] - Transaction confirmation options\n * @returns {UseAlchemySolanaTransactionResult} Hook result with transaction functions and state\n *\n * @example Simple SOL transfer\n * ```tsx\n * const { sendTransactionAsync, isPending, error, data } = useAlchemySolanaTransaction({\n * rpcUrl: 'https://solana-mainnet.g.alchemy.com/v2/your-api-key',\n * policyId: 'your-policy-id', // Optional: for gas sponsorship\n * });\n *\n * const handleTransfer = async () => {\n * try {\n * const result = await sendTransactionAsync({\n * transfer: {\n * amount: 1_000_000_000, // 1 SOL in lamports\n * toAddress: 'recipient-address',\n * },\n * });\n * console.log('Transaction hash:', result.hash);\n * } catch (err) {\n * console.error('Transaction failed:', err);\n * }\n * };\n * ```\n *\n * @example Custom instructions\n * ```tsx\n * import { SystemProgram, PublicKey } from '@solana/web3.js';\n *\n * const { sendTransactionAsync } = useAlchemySolanaTransaction();\n *\n * // Build your custom instructions\n * const transferIx = SystemProgram.transfer({\n * fromPubkey: new PublicKey(walletAddress),\n * toPubkey: new PublicKey(recipientAddress),\n * lamports: 1_000_000,\n * });\n *\n * // Pass instructions array to the hook\n * const result = await sendTransactionAsync({\n * instructions: [transferIx],\n * });\n * ```\n *\n * @example With provider configuration\n * ```tsx\n * // In your provider setup\n * <AlchemyProvider\n * solanaRpcUrl=\"https://solana-mainnet.g.alchemy.com/v2/...\"\n * solanaPolicyId=\"your-solana-policy-id\"\n * >\n * <YourApp />\n * </AlchemyProvider>\n *\n * // In your component - uses provider config automatically\n * const { sendTransactionAsync } = useAlchemySolanaTransaction();\n * ```\n */\nexport function useAlchemySolanaTransaction(\n opts: UseAlchemySolanaTransactionOptions = {},\n): UseAlchemySolanaTransactionResult {\n const config = useAlchemyConfig();\n const { wallets } = useWallets();\n const { signTransaction } = useSignTransaction();\n\n // Resolve the Privy Solana wallet to use\n const embeddedWallet = useMemo(() => {\n if (opts.walletAddress) {\n const w = wallets.find((w) => w.address === opts.walletAddress);\n if (!w) throw new Error(\"Specified Solana wallet not found\");\n return w;\n }\n return wallets[0];\n }, [wallets, opts.walletAddress]);\n\n // Build Solana connection from rpcUrl (hook override or provider default)\n const connection = useMemo(() => {\n const url = opts.rpcUrl || config.solanaRpcUrl;\n return url ? new Connection(url) : null;\n }, [opts.rpcUrl, config.solanaRpcUrl]);\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<void | SolanaTransactionResult>(undefined);\n\n const resolvedPolicyId = useMemo(() => {\n if (opts.policyId != null) return opts.policyId || undefined;\n // Use solanaPolicyId from config, fallback to policyId for backwards compat\n const configPolicy = config.solanaPolicyId || config.policyId;\n return Array.isArray(configPolicy) ? configPolicy[0] : configPolicy;\n }, [opts.policyId, config.solanaPolicyId, config.policyId]);\n\n const mapTransformInstructions = useMemo(() => {\n const addSponsorship: TransformInstruction = async (instructions) => {\n const policyId = resolvedPolicyId;\n if (!policyId)\n throw new Error(\n \"Gas sponsorship requires a policyId (see provider or hook options).\",\n );\n const localConnection = connection || missing(\"connection\");\n const fromAddress = embeddedWallet?.address;\n if (!fromAddress) throw new Error(\"No embedded Solana wallet connected\");\n return createSolanaSponsoredTransaction(\n instructions,\n localConnection,\n policyId,\n fromAddress,\n );\n };\n const createTx: TransformInstruction = async (instructions) => {\n const localConnection = connection || missing(\"connection\");\n const fromAddress = embeddedWallet?.address;\n if (!fromAddress) throw new Error(\"No embedded Solana wallet connected\");\n return createSolanaTransaction(\n instructions,\n localConnection,\n fromAddress,\n );\n };\n const defaultTransform =\n !!resolvedPolicyId && !config.disableSponsorship\n ? addSponsorship\n : createTx;\n return {\n addSponsorship,\n createTransaction: createTx,\n default: defaultTransform,\n } as const;\n }, [\n resolvedPolicyId,\n config.disableSponsorship,\n connection,\n embeddedWallet?.address,\n ]);\n\n const buildInstructions = useCallback(\n (\n params: SolanaTransactionParams,\n fromAddress: string,\n ): TransactionInstruction[] => {\n if (\"instructions\" in params) return params.instructions;\n return [\n SystemProgram.transfer({\n fromPubkey: new PublicKey(fromAddress),\n toPubkey: new PublicKey(params.transfer.toAddress),\n lamports:\n typeof params.transfer.amount === \"bigint\"\n ? Number(params.transfer.amount) // web3.js currently expects number; callers can pass bigint safely\n : params.transfer.amount,\n }),\n ];\n },\n [],\n );\n\n function toUnsignedBytes(tx: VersionedTransaction | Transaction): Uint8Array {\n // Serialize the full transaction structure (with placeholder signatures)\n // Privy expects the complete transaction format, not just the message\n if (tx instanceof VersionedTransaction) {\n // VersionedTransaction.serialize() includes signature slots\n return tx.serialize();\n }\n // Legacy Transaction: serialize without requiring all signatures\n const buf = tx.serialize({\n requireAllSignatures: false,\n verifySignatures: false,\n });\n return buf instanceof Uint8Array ? buf : new Uint8Array(buf);\n }\n\n const sendTransactionAsync = useCallback(\n async (\n params: SolanaTransactionParams,\n ): Promise<SolanaTransactionResult> => {\n setIsPending(true);\n setError(null);\n try {\n const localConnection = connection || missing(\"connection\");\n if (!embeddedWallet?.address) {\n throw new Error(\"No Solana wallet connected via Privy\");\n }\n\n const fromAddress = embeddedWallet.address;\n const {\n transactionComponents: { preSend, transformInstruction } = {},\n confirmationOptions,\n } = params;\n\n const instructions = buildInstructions(params, fromAddress);\n\n let transaction: VersionedTransaction | Transaction;\n if (transformInstruction) {\n transaction = await transformInstruction(instructions);\n } else {\n transaction = await mapTransformInstructions.default(instructions);\n }\n\n transaction = (await preSend?.(transaction)) || transaction;\n\n // Sign the transaction using Privy's useSignTransaction hook\n const unsignedBytes = toUnsignedBytes(transaction);\n const { signedTransaction } = await signTransaction({\n transaction: unsignedBytes,\n wallet: embeddedWallet,\n });\n\n // Broadcast the signed transaction\n const hash = await localConnection.sendRawTransaction(\n signedTransaction,\n { skipPreflight: false },\n );\n\n if (confirmationOptions || opts.confirmationOptions) {\n await localConnection.confirmTransaction(\n hash,\n confirmationOptions || opts.confirmationOptions,\n );\n }\n\n setData({ hash });\n return { hash };\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n throw e;\n } finally {\n setIsPending(false);\n }\n },\n [\n embeddedWallet,\n connection,\n buildInstructions,\n mapTransformInstructions,\n opts.confirmationOptions,\n signTransaction,\n ],\n );\n\n const sendTransaction = useCallback(\n (params: SolanaTransactionParams) => {\n // Prevent unhandled rejection warnings; error state is already set in sendTransactionAsync\n sendTransactionAsync(params).catch(() => {});\n },\n [sendTransactionAsync],\n );\n\n const reset = useCallback(() => {\n setIsPending(false);\n setError(null);\n setData(undefined);\n }, []);\n\n return {\n connection,\n data,\n isPending,\n error,\n reset,\n sendTransaction,\n sendTransactionAsync,\n };\n}\n\nfunction missing(message: string): never {\n throw new Error(message);\n}\n"]}
@@ -3,4 +3,5 @@ export { useAlchemyClient } from "./hooks/useAlchemyClient.js";
3
3
  export { useAlchemySendTransaction } from "./hooks/useAlchemySendTransaction.js";
4
4
  export { useAlchemyPrepareSwap } from "./hooks/useAlchemyPrepareSwap.js";
5
5
  export { useAlchemySubmitSwap } from "./hooks/useAlchemySubmitSwap.js";
6
+ export { useAlchemySolanaTransaction } from "./hooks/useAlchemySolanaTransaction.js";
6
7
  export type { AlchemyProviderConfig, UnsignedTransactionRequest, SendTransactionOptions, SendTransactionResult, UseSendTransactionResult, PrepareSwapRequest, PrepareSwapResult, UsePrepareSwapResult, SubmitSwapResult, UseSubmitSwapResult, SwapQuote, } from "./types.js";
package/dist/esm/index.js CHANGED
@@ -5,4 +5,5 @@ export { useAlchemyClient } from "./hooks/useAlchemyClient.js";
5
5
  export { useAlchemySendTransaction } from "./hooks/useAlchemySendTransaction.js";
6
6
  export { useAlchemyPrepareSwap } from "./hooks/useAlchemyPrepareSwap.js";
7
7
  export { useAlchemySubmitSwap } from "./hooks/useAlchemySubmitSwap.js";
8
+ export { useAlchemySolanaTransaction } from "./hooks/useAlchemySolanaTransaction.js";
8
9
  //# sourceMappingURL=index.js.map