@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.
- package/README.md +97 -9
- package/dist/esm/Provider.d.ts +4 -2
- package/dist/esm/Provider.js +4 -2
- package/dist/esm/Provider.js.map +1 -1
- package/dist/esm/hooks/useAlchemySolanaTransaction.d.ts +163 -0
- package/dist/esm/hooks/useAlchemySolanaTransaction.js +233 -0
- package/dist/esm/hooks/useAlchemySolanaTransaction.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types.d.ts +5 -1
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/util/createSolanaSponsoredTransaction.d.ts +12 -0
- package/dist/esm/util/createSolanaSponsoredTransaction.js +52 -0
- package/dist/esm/util/createSolanaSponsoredTransaction.js.map +1 -0
- package/dist/esm/util/createSolanaTransaction.d.ts +11 -0
- package/dist/esm/util/createSolanaTransaction.js +21 -0
- package/dist/esm/util/createSolanaTransaction.js.map +1 -0
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/Provider.d.ts +4 -2
- package/dist/types/Provider.d.ts.map +1 -1
- package/dist/types/hooks/useAlchemySolanaTransaction.d.ts +164 -0
- package/dist/types/hooks/useAlchemySolanaTransaction.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +5 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/util/createSolanaSponsoredTransaction.d.ts +13 -0
- package/dist/types/util/createSolanaSponsoredTransaction.d.ts.map +1 -0
- package/dist/types/util/createSolanaTransaction.d.ts +12 -0
- package/dist/types/util/createSolanaTransaction.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +5 -5
- package/src/hooks/useAlchemySolanaTransaction.ts +402 -0
- package/src/index.ts +1 -0
- package/src/types.ts +7 -1
- package/src/util/createSolanaSponsoredTransaction.ts +74 -0
- package/src/util/createSolanaTransaction.ts +31 -0
- 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
|
-
| `
|
|
179
|
-
| `
|
|
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).
|
package/dist/esm/Provider.d.ts
CHANGED
|
@@ -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
|
|
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
|
*
|
package/dist/esm/Provider.js
CHANGED
|
@@ -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
|
|
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
|
*
|
package/dist/esm/Provider.js.map
CHANGED
|
@@ -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
|
|
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"]}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -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
|