@account-kit/privy-integration 4.73.1-alpha.0 → 4.74.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 +61 -21
- package/dist/esm/Provider.d.ts +71 -4
- package/dist/esm/Provider.js +109 -4
- package/dist/esm/Provider.js.map +1 -1
- package/dist/esm/hooks/internal/useEmbeddedWallet.d.ts +4 -3
- package/dist/esm/hooks/internal/useEmbeddedWallet.js +13 -5
- package/dist/esm/hooks/internal/useEmbeddedWallet.js.map +1 -1
- package/dist/esm/hooks/useAlchemyClient.d.ts +10 -5
- package/dist/esm/hooks/useAlchemyClient.js +36 -17
- package/dist/esm/hooks/useAlchemyClient.js.map +1 -1
- package/dist/esm/hooks/useAlchemyPrepareSwap.js +3 -6
- package/dist/esm/hooks/useAlchemyPrepareSwap.js.map +1 -1
- package/dist/esm/hooks/useAlchemySendTransaction.js +11 -9
- package/dist/esm/hooks/useAlchemySendTransaction.js.map +1 -1
- package/dist/esm/hooks/useAlchemySubmitSwap.js +1 -1
- package/dist/esm/hooks/useAlchemySubmitSwap.js.map +1 -1
- package/dist/esm/types.d.ts +6 -0
- package/dist/esm/types.js.map +1 -1
- 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 +71 -4
- package/dist/types/Provider.d.ts.map +1 -1
- package/dist/types/hooks/internal/useEmbeddedWallet.d.ts +4 -3
- package/dist/types/hooks/internal/useEmbeddedWallet.d.ts.map +1 -1
- package/dist/types/hooks/useAlchemyClient.d.ts +10 -5
- package/dist/types/hooks/useAlchemyClient.d.ts.map +1 -1
- package/dist/types/hooks/useAlchemyPrepareSwap.d.ts.map +1 -1
- package/dist/types/hooks/useAlchemySendTransaction.d.ts.map +1 -1
- package/dist/types/types.d.ts +6 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/package.json +4 -17
- package/src/hooks/internal/useEmbeddedWallet.ts +20 -5
- package/src/hooks/useAlchemyClient.ts +61 -26
- package/src/hooks/useAlchemyPrepareSwap.ts +3 -6
- package/src/hooks/useAlchemySendTransaction.ts +16 -13
- package/src/hooks/useAlchemySubmitSwap.ts +1 -1
- package/src/types.ts +7 -0
- package/src/version.ts +1 -1
- package/dist/esm/adapters/react-native.d.ts +0 -6
- package/dist/esm/adapters/react-native.js +0 -46
- package/dist/esm/adapters/react-native.js.map +0 -1
- package/dist/esm/adapters/types.d.ts +0 -44
- package/dist/esm/adapters/types.js +0 -2
- package/dist/esm/adapters/types.js.map +0 -1
- package/dist/esm/adapters/web.d.ts +0 -6
- package/dist/esm/adapters/web.js +0 -50
- package/dist/esm/adapters/web.js.map +0 -1
- package/dist/esm/context/AlchemyContext.d.ts +0 -62
- package/dist/esm/context/AlchemyContext.js +0 -105
- package/dist/esm/context/AlchemyContext.js.map +0 -1
- package/dist/esm/providers/ReactNativeProvider.d.ts +0 -33
- package/dist/esm/providers/ReactNativeProvider.js +0 -37
- package/dist/esm/providers/ReactNativeProvider.js.map +0 -1
- package/dist/esm/providers/WebProvider.d.ts +0 -33
- package/dist/esm/providers/WebProvider.js +0 -37
- package/dist/esm/providers/WebProvider.js.map +0 -1
- package/dist/esm/react-native.d.ts +0 -11
- package/dist/esm/react-native.js +0 -13
- package/dist/esm/react-native.js.map +0 -1
- package/dist/types/adapters/react-native.d.ts +0 -7
- package/dist/types/adapters/react-native.d.ts.map +0 -1
- package/dist/types/adapters/types.d.ts +0 -45
- package/dist/types/adapters/types.d.ts.map +0 -1
- package/dist/types/adapters/web.d.ts +0 -7
- package/dist/types/adapters/web.d.ts.map +0 -1
- package/dist/types/context/AlchemyContext.d.ts +0 -63
- package/dist/types/context/AlchemyContext.d.ts.map +0 -1
- package/dist/types/providers/ReactNativeProvider.d.ts +0 -34
- package/dist/types/providers/ReactNativeProvider.d.ts.map +0 -1
- package/dist/types/providers/WebProvider.d.ts +0 -34
- package/dist/types/providers/WebProvider.d.ts.map +0 -1
- package/dist/types/react-native.d.ts +0 -12
- package/dist/types/react-native.d.ts.map +0 -1
- package/src/adapters/react-native.ts +0 -71
- package/src/adapters/types.ts +0 -56
- package/src/adapters/web.ts +0 -73
- package/src/react-native.ts +0 -29
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Add gas sponsorship and smart wallet features to your Privy app in under 5 minut
|
|
|
6
6
|
|
|
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
|
-
- **🔄 EIP-7702 Delegation** - Upgrade
|
|
9
|
+
- **🔄 EIP-7702 Delegation** - Upgrade your wallets to smart accounts without migration
|
|
10
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([...])`
|
|
@@ -253,15 +253,16 @@ function SolanaSendButton() {
|
|
|
253
253
|
|
|
254
254
|
### AlchemyProvider Props
|
|
255
255
|
|
|
256
|
-
| Prop | Type
|
|
257
|
-
| -------------------- |
|
|
258
|
-
| `apiKey` | `string`
|
|
259
|
-
| `jwt` | `string`
|
|
260
|
-
| `rpcUrl` | `string`
|
|
261
|
-
| `solanaRpcUrl` | `string`
|
|
262
|
-
| `policyId` | `string \| string[]`
|
|
263
|
-
| `solanaPolicyId` | `string \| string[]`
|
|
264
|
-
| `disableSponsorship` | `boolean`
|
|
256
|
+
| Prop | Type | Required | Description |
|
|
257
|
+
| -------------------- | ---------------------- | ------------- | -------------------------------------------------------------------------------------------------------- |
|
|
258
|
+
| `apiKey` | `string` | Conditional\* | Your Alchemy API key for @account-kit/infra transport |
|
|
259
|
+
| `jwt` | `string` | Conditional\* | JWT token for authentication (alternative to `apiKey`) |
|
|
260
|
+
| `rpcUrl` | `string` | Conditional\* | Custom RPC URL for EVM chains (can be used alone or with `jwt`) |
|
|
261
|
+
| `solanaRpcUrl` | `string` | No | Custom RPC URL for Solana (separate from EVM `rpcUrl`) |
|
|
262
|
+
| `policyId` | `string \| string[]` | No | Gas Manager policy ID(s) for EVM sponsorship. If array is provided, backend uses first applicable policy |
|
|
263
|
+
| `solanaPolicyId` | `string \| string[]` | No | Gas Manager policy ID(s) for Solana sponsorship |
|
|
264
|
+
| `disableSponsorship` | `boolean` | No | Set to `true` to disable gas sponsorship by default (default: `false`) |
|
|
265
|
+
| `accountAuthMode` | `'eip7702' \| 'owner'` | No | Authorization mode for EVM smart accounts (default: `'eip7702'`) |
|
|
265
266
|
|
|
266
267
|
\* **Required configuration (pick one):**
|
|
267
268
|
|
|
@@ -352,21 +353,23 @@ Send Solana transactions with optional gas sponsorship via Alchemy.
|
|
|
352
353
|
|
|
353
354
|
#### `useAlchemyClient()`
|
|
354
355
|
|
|
355
|
-
Get the underlying smart wallet client (advanced use cases).
|
|
356
|
+
Get the underlying smart wallet client and account (advanced use cases).
|
|
356
357
|
|
|
357
358
|
**Returns:**
|
|
358
359
|
|
|
359
|
-
- `getClient()` - Async function that returns `SmartWalletClient`
|
|
360
|
+
- `getClient()` - Async function that returns `{ client: SmartWalletClient, account: SmartContractAccount }`
|
|
361
|
+
- `client` - The smart wallet client instance
|
|
362
|
+
- `account` - The smart account with address and other account info
|
|
360
363
|
|
|
361
364
|
## How It Works
|
|
362
365
|
|
|
363
|
-
### EIP-7702 Delegation
|
|
366
|
+
### EIP-7702 Delegation (Default)
|
|
364
367
|
|
|
365
368
|
This package uses [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) to upgrade your users' Privy wallets into smart accounts **without requiring them to deploy new contracts or migrate funds**.
|
|
366
369
|
|
|
367
370
|
When a user sends their first transaction:
|
|
368
371
|
|
|
369
|
-
1. Their
|
|
372
|
+
1. Their wallet signs an EIP-7702 authorization
|
|
370
373
|
2. The authorization delegates to Alchemy's smart account implementation
|
|
371
374
|
3. The transaction is executed with smart account features (batching, sponsorship, etc.)
|
|
372
375
|
4. Gas is optionally sponsored by your Gas Manager policy
|
|
@@ -377,10 +380,47 @@ Under the hood, this package:
|
|
|
377
380
|
|
|
378
381
|
1. Connects to your user's Privy embedded wallet
|
|
379
382
|
2. Wraps it with `WalletClientSigner` from `@aa-sdk/core`
|
|
380
|
-
3. Creates a `SmartWalletClient` with EIP-7702 support
|
|
383
|
+
3. Creates a `SmartWalletClient` with EIP-7702 support (default) or traditional smart account support
|
|
381
384
|
4. Routes transactions through Alchemy infrastructure
|
|
382
385
|
5. Automatically handles sponsorship via Gas Manager policies
|
|
383
386
|
|
|
387
|
+
### Authorization Modes
|
|
388
|
+
|
|
389
|
+
The package supports two authorization modes via the `accountAuthMode` prop:
|
|
390
|
+
|
|
391
|
+
- **`'eip7702'` (default, recommended)**: Uses EIP-7702 to delegate the Privy wallet to a smart account. No separate deployment needed, funds stay at the wallet address. This is the recommended mode for most applications.
|
|
392
|
+
- **`'owner'`**: Uses a traditional smart account with the Privy wallet as the owner/signer. The smart account has a separate address from the owner wallet. Use this if you need compatibility with environments that don't support EIP-7702 yet.
|
|
393
|
+
|
|
394
|
+
```tsx
|
|
395
|
+
// Default behavior (EIP-7702)
|
|
396
|
+
<AlchemyProvider apiKey="...">
|
|
397
|
+
<YourApp />
|
|
398
|
+
</AlchemyProvider>
|
|
399
|
+
|
|
400
|
+
// Traditional smart account mode
|
|
401
|
+
<AlchemyProvider apiKey="..." accountAuthMode="owner">
|
|
402
|
+
<YourApp />
|
|
403
|
+
</AlchemyProvider>
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**Getting the Smart Account Address:**
|
|
407
|
+
|
|
408
|
+
When using `owner` mode, the smart account has a different address from your Privy signer. Access it via `useAlchemyClient`:
|
|
409
|
+
|
|
410
|
+
```tsx
|
|
411
|
+
import { useAlchemyClient } from "@account-kit/privy-integration";
|
|
412
|
+
|
|
413
|
+
function MyComponent() {
|
|
414
|
+
const { getClient } = useAlchemyClient();
|
|
415
|
+
|
|
416
|
+
const getSmartAccountAddress = async () => {
|
|
417
|
+
const { account } = await getClient();
|
|
418
|
+
console.log("Smart account address:", account.address);
|
|
419
|
+
// This is different from the Privy signer address in owner mode
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
384
424
|
## Get Your API Keys
|
|
385
425
|
|
|
386
426
|
### Alchemy API Key
|
|
@@ -431,7 +471,7 @@ The API is nearly identical, making migration seamless.
|
|
|
431
471
|
|
|
432
472
|
### Access the Smart Wallet Client
|
|
433
473
|
|
|
434
|
-
For advanced use cases, access the underlying client directly:
|
|
474
|
+
For advanced use cases, access the underlying client and account directly:
|
|
435
475
|
|
|
436
476
|
```tsx
|
|
437
477
|
import { useAlchemyClient } from "@account-kit/privy-integration";
|
|
@@ -440,20 +480,20 @@ function AdvancedComponent() {
|
|
|
440
480
|
const { getClient } = useAlchemyClient();
|
|
441
481
|
|
|
442
482
|
const doAdvancedOperation = async () => {
|
|
443
|
-
const client = await getClient();
|
|
483
|
+
const { client, account } = await getClient();
|
|
444
484
|
|
|
445
|
-
//
|
|
446
|
-
|
|
485
|
+
// Access the smart account address
|
|
486
|
+
console.log("Smart account address:", account.address);
|
|
447
487
|
|
|
448
488
|
// Direct access to sendCalls with full control
|
|
449
489
|
await client.sendCalls({
|
|
450
|
-
from: address,
|
|
490
|
+
from: account.address,
|
|
451
491
|
calls: [
|
|
452
492
|
{ to: "0x...", data: "0x..." },
|
|
453
493
|
{ to: "0x...", data: "0x..." },
|
|
454
494
|
],
|
|
455
495
|
capabilities: {
|
|
456
|
-
eip7702Auth: true,
|
|
496
|
+
eip7702Auth: true, // Set to true for EIP-7702 mode
|
|
457
497
|
paymasterService: { policyId: "your-policy-id" },
|
|
458
498
|
},
|
|
459
499
|
});
|
package/dist/esm/Provider.d.ts
CHANGED
|
@@ -1,6 +1,73 @@
|
|
|
1
|
+
import { type PropsWithChildren } from "react";
|
|
2
|
+
import type { SmartWalletClient } from "@account-kit/wallet-client";
|
|
3
|
+
import type { SmartContractAccount } from "@aa-sdk/core";
|
|
4
|
+
import type { AlchemyProviderConfig } from "./types.js";
|
|
1
5
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
6
|
+
* Normalized config with defaults applied
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
4
9
|
*/
|
|
5
|
-
export
|
|
6
|
-
|
|
10
|
+
export type NormalizedAlchemyConfig = AlchemyProviderConfig & Required<Pick<AlchemyProviderConfig, "accountAuthMode">>;
|
|
11
|
+
/**
|
|
12
|
+
* Client cache stored in React tree (similar to QueryClient in React Query)
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
interface ClientCache {
|
|
17
|
+
client: SmartWalletClient | null;
|
|
18
|
+
account: SmartContractAccount | null;
|
|
19
|
+
cacheKey: string | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Provider component that configures Alchemy infrastructure for transaction handling
|
|
23
|
+
* Must be nested INSIDE PrivyProvider to access authentication state
|
|
24
|
+
* Automatically manages client cache lifecycle and resets on logout
|
|
25
|
+
*
|
|
26
|
+
* @param {PropsWithChildren<AlchemyProviderConfig>} props - Component props
|
|
27
|
+
* @param {React.ReactNode} props.children - React children to wrap with Alchemy configuration
|
|
28
|
+
* @param {string} [props.apiKey] - Your Alchemy API key
|
|
29
|
+
* @param {string} [props.jwt] - JWT token for authentication
|
|
30
|
+
* @param {string} [props.rpcUrl] - Custom RPC URL for EVM chains
|
|
31
|
+
* @param {string} [props.solanaRpcUrl] - Custom RPC URL for Solana
|
|
32
|
+
* @param {string | string[]} [props.policyId] - Gas Manager policy ID(s) for EVM chains
|
|
33
|
+
* @param {string | string[]} [props.solanaPolicyId] - Gas Manager policy ID(s) for Solana
|
|
34
|
+
* @param {boolean} [props.disableSponsorship] - Set to true to disable sponsorship by default (default: false)
|
|
35
|
+
* @param {'eip7702' | 'owner'} [props.accountAuthMode] - Authorization mode for EVM smart accounts (default: 'eip7702')
|
|
36
|
+
* @returns {JSX.Element} Provider component
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <PrivyProvider appId="...">
|
|
41
|
+
* <AlchemyProvider
|
|
42
|
+
* apiKey="your-alchemy-api-key"
|
|
43
|
+
* policyId="your-gas-policy-id"
|
|
44
|
+
* >
|
|
45
|
+
* <YourApp />
|
|
46
|
+
* </AlchemyProvider>
|
|
47
|
+
* </PrivyProvider>
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function AlchemyProvider({ children, accountAuthMode, ...config }: PropsWithChildren<AlchemyProviderConfig>): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
/**
|
|
52
|
+
* Hook to access Alchemy provider configuration
|
|
53
|
+
* Must be used within an <AlchemyProvider> component
|
|
54
|
+
*
|
|
55
|
+
* @returns {NormalizedAlchemyConfig} The current Alchemy configuration with defaults applied
|
|
56
|
+
* @throws {Error} If used outside of AlchemyProvider
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* const config = useAlchemyConfig();
|
|
61
|
+
* console.log('Policy ID:', config.policyId);
|
|
62
|
+
* console.log('Auth Mode:', config.accountAuthMode); // Always defined
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function useAlchemyConfig(): NormalizedAlchemyConfig;
|
|
66
|
+
/**
|
|
67
|
+
* Hook to access the client cache (internal use only)
|
|
68
|
+
*
|
|
69
|
+
* @internal
|
|
70
|
+
* @returns {ClientCache} The client cache object
|
|
71
|
+
*/
|
|
72
|
+
export declare function useClientCache(): ClientCache;
|
|
73
|
+
export {};
|
package/dist/esm/Provider.js
CHANGED
|
@@ -1,7 +1,112 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useRef, useEffect, } from "react";
|
|
3
|
+
import { usePrivy } from "@privy-io/react-auth";
|
|
4
|
+
const AlchemyContext = createContext(null);
|
|
5
|
+
const ClientCacheContext = createContext(null);
|
|
1
6
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
7
|
+
* Provider component that configures Alchemy infrastructure for transaction handling
|
|
8
|
+
* Must be nested INSIDE PrivyProvider to access authentication state
|
|
9
|
+
* Automatically manages client cache lifecycle and resets on logout
|
|
10
|
+
*
|
|
11
|
+
* @param {PropsWithChildren<AlchemyProviderConfig>} props - Component props
|
|
12
|
+
* @param {React.ReactNode} props.children - React children to wrap with Alchemy configuration
|
|
13
|
+
* @param {string} [props.apiKey] - Your Alchemy API key
|
|
14
|
+
* @param {string} [props.jwt] - JWT token for authentication
|
|
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
|
|
19
|
+
* @param {boolean} [props.disableSponsorship] - Set to true to disable sponsorship by default (default: false)
|
|
20
|
+
* @param {'eip7702' | 'owner'} [props.accountAuthMode] - Authorization mode for EVM smart accounts (default: 'eip7702')
|
|
21
|
+
* @returns {JSX.Element} Provider component
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* <PrivyProvider appId="...">
|
|
26
|
+
* <AlchemyProvider
|
|
27
|
+
* apiKey="your-alchemy-api-key"
|
|
28
|
+
* policyId="your-gas-policy-id"
|
|
29
|
+
* >
|
|
30
|
+
* <YourApp />
|
|
31
|
+
* </AlchemyProvider>
|
|
32
|
+
* </PrivyProvider>
|
|
33
|
+
* ```
|
|
4
34
|
*/
|
|
5
|
-
export
|
|
6
|
-
|
|
35
|
+
export function AlchemyProvider({ children, accountAuthMode = "eip7702", ...config }) {
|
|
36
|
+
const { authenticated, user } = usePrivy();
|
|
37
|
+
// Normalize config with default values
|
|
38
|
+
const normalizedConfig = {
|
|
39
|
+
...config,
|
|
40
|
+
accountAuthMode,
|
|
41
|
+
};
|
|
42
|
+
// Store cache in a ref - persists across renders but scoped to this component instance
|
|
43
|
+
// This makes it SSR-safe (each request gets its own cache) and React StrictMode-safe
|
|
44
|
+
const cache = useRef({
|
|
45
|
+
client: null,
|
|
46
|
+
account: null,
|
|
47
|
+
cacheKey: null,
|
|
48
|
+
});
|
|
49
|
+
// Track previous state to detect logout and wallet changes
|
|
50
|
+
const prevAuthenticatedRef = useRef(authenticated);
|
|
51
|
+
const prevWalletAddressRef = useRef(user?.wallet?.address);
|
|
52
|
+
// Automatically reset cache when user logs out or switches wallets
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const wasAuthenticated = prevAuthenticatedRef.current;
|
|
55
|
+
const prevWalletAddress = prevWalletAddressRef.current;
|
|
56
|
+
const currentWalletAddress = user?.wallet?.address;
|
|
57
|
+
// Reset cache on logout
|
|
58
|
+
if (wasAuthenticated && !authenticated) {
|
|
59
|
+
cache.current.client = null;
|
|
60
|
+
cache.current.account = null;
|
|
61
|
+
cache.current.cacheKey = null;
|
|
62
|
+
}
|
|
63
|
+
// Reset cache on wallet address change (account switching)
|
|
64
|
+
if (authenticated &&
|
|
65
|
+
prevWalletAddress &&
|
|
66
|
+
currentWalletAddress &&
|
|
67
|
+
prevWalletAddress !== currentWalletAddress) {
|
|
68
|
+
cache.current.client = null;
|
|
69
|
+
cache.current.account = null;
|
|
70
|
+
cache.current.cacheKey = null;
|
|
71
|
+
}
|
|
72
|
+
// Update refs for next render
|
|
73
|
+
prevAuthenticatedRef.current = authenticated;
|
|
74
|
+
prevWalletAddressRef.current = currentWalletAddress;
|
|
75
|
+
}, [authenticated, user?.wallet?.address]);
|
|
76
|
+
return (_jsx(AlchemyContext.Provider, { value: normalizedConfig, children: _jsx(ClientCacheContext.Provider, { value: cache.current, children: children }) }));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Hook to access Alchemy provider configuration
|
|
80
|
+
* Must be used within an <AlchemyProvider> component
|
|
81
|
+
*
|
|
82
|
+
* @returns {NormalizedAlchemyConfig} The current Alchemy configuration with defaults applied
|
|
83
|
+
* @throws {Error} If used outside of AlchemyProvider
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* const config = useAlchemyConfig();
|
|
88
|
+
* console.log('Policy ID:', config.policyId);
|
|
89
|
+
* console.log('Auth Mode:', config.accountAuthMode); // Always defined
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export function useAlchemyConfig() {
|
|
93
|
+
const context = useContext(AlchemyContext);
|
|
94
|
+
if (!context) {
|
|
95
|
+
throw new Error("useAlchemyConfig must be used within <AlchemyProvider />");
|
|
96
|
+
}
|
|
97
|
+
return context;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Hook to access the client cache (internal use only)
|
|
101
|
+
*
|
|
102
|
+
* @internal
|
|
103
|
+
* @returns {ClientCache} The client cache object
|
|
104
|
+
*/
|
|
105
|
+
export function useClientCache() {
|
|
106
|
+
const context = useContext(ClientCacheContext);
|
|
107
|
+
if (!context) {
|
|
108
|
+
throw new Error("useClientCache must be used within <AlchemyProvider />. Make sure AlchemyProvider is nested inside PrivyProvider.");
|
|
109
|
+
}
|
|
110
|
+
return context;
|
|
111
|
+
}
|
|
7
112
|
//# sourceMappingURL=Provider.js.map
|
package/dist/esm/Provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Provider.js","sourceRoot":"","sources":["../../src/Provider.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"Provider.js","sourceRoot":"","sources":["../../src/Provider.tsx"],"names":[],"mappings":"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","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 { SmartContractAccount } from \"@aa-sdk/core\";\nimport type { AlchemyProviderConfig } from \"./types.js\";\n\n/**\n * Normalized config with defaults applied\n *\n * @internal\n */\nexport type NormalizedAlchemyConfig = AlchemyProviderConfig &\n Required<Pick<AlchemyProviderConfig, \"accountAuthMode\">>;\n\nconst AlchemyContext = createContext<NormalizedAlchemyConfig | 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 account: SmartContractAccount | 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 * @param {'eip7702' | 'owner'} [props.accountAuthMode] - Authorization mode for EVM smart accounts (default: 'eip7702')\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 accountAuthMode = \"eip7702\",\n ...config\n}: PropsWithChildren<AlchemyProviderConfig>) {\n const { authenticated, user } = usePrivy();\n\n // Normalize config with default values\n const normalizedConfig: NormalizedAlchemyConfig = {\n ...config,\n accountAuthMode,\n };\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 account: 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.account = 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.account = 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={normalizedConfig}>\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 {NormalizedAlchemyConfig} The current Alchemy configuration with defaults applied\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 * console.log('Auth Mode:', config.accountAuthMode); // Always defined\n * ```\n */\nexport function useAlchemyConfig(): NormalizedAlchemyConfig {\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,9 +1,10 @@
|
|
|
1
|
+
import { type ConnectedWallet as PrivyWallet } from "@privy-io/react-auth";
|
|
1
2
|
/**
|
|
2
3
|
* Internal hook to get the Privy embedded wallet
|
|
3
|
-
*
|
|
4
|
+
* Shared across multiple hooks to avoid duplication
|
|
4
5
|
*
|
|
5
6
|
* @internal
|
|
6
|
-
* @returns {() =>
|
|
7
|
+
* @returns {() => PrivyWallet} Function that returns the embedded wallet
|
|
7
8
|
* @throws {Error} If embedded wallet is not found
|
|
8
9
|
*/
|
|
9
|
-
export declare function useEmbeddedWallet(): () =>
|
|
10
|
+
export declare function useEmbeddedWallet(): () => PrivyWallet;
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { useWallets, } from "@privy-io/react-auth";
|
|
2
3
|
/**
|
|
3
4
|
* Internal hook to get the Privy embedded wallet
|
|
4
|
-
*
|
|
5
|
+
* Shared across multiple hooks to avoid duplication
|
|
5
6
|
*
|
|
6
7
|
* @internal
|
|
7
|
-
* @returns {() =>
|
|
8
|
+
* @returns {() => PrivyWallet} Function that returns the embedded wallet
|
|
8
9
|
* @throws {Error} If embedded wallet is not found
|
|
9
10
|
*/
|
|
10
11
|
export function useEmbeddedWallet() {
|
|
11
|
-
const
|
|
12
|
-
|
|
12
|
+
const { wallets } = useWallets();
|
|
13
|
+
const getEmbeddedWallet = useCallback(() => {
|
|
14
|
+
const embedded = wallets.find((w) => w.walletClientType === "privy");
|
|
15
|
+
if (!embedded) {
|
|
16
|
+
throw new Error("Privy embedded wallet not found. Please ensure the user is authenticated.");
|
|
17
|
+
}
|
|
18
|
+
return embedded;
|
|
19
|
+
}, [wallets]);
|
|
20
|
+
return getEmbeddedWallet;
|
|
13
21
|
}
|
|
14
22
|
//# sourceMappingURL=useEmbeddedWallet.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEmbeddedWallet.js","sourceRoot":"","sources":["../../../../src/hooks/internal/useEmbeddedWallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"useEmbeddedWallet.js","sourceRoot":"","sources":["../../../../src/hooks/internal/useEmbeddedWallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EACL,UAAU,GAEX,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,CAAC;IAEjC,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAgB,EAAE;QACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,gBAAgB,KAAK,OAAO,CAAC,CAAC;QACrE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,OAAO,iBAAiB,CAAC;AAC3B,CAAC","sourcesContent":["import { useCallback } from \"react\";\nimport {\n useWallets,\n type ConnectedWallet as PrivyWallet,\n} from \"@privy-io/react-auth\";\n\n/**\n * Internal hook to get the Privy embedded wallet\n * Shared across multiple hooks to avoid duplication\n *\n * @internal\n * @returns {() => PrivyWallet} Function that returns the embedded wallet\n * @throws {Error} If embedded wallet is not found\n */\nexport function useEmbeddedWallet() {\n const { wallets } = useWallets();\n\n const getEmbeddedWallet = useCallback((): PrivyWallet => {\n const embedded = wallets.find((w) => w.walletClientType === \"privy\");\n if (!embedded) {\n throw new Error(\n \"Privy embedded wallet not found. Please ensure the user is authenticated.\",\n );\n }\n return embedded;\n }, [wallets]);\n\n return getEmbeddedWallet;\n}\n"]}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
import { type SmartContractAccount } from "@aa-sdk/core";
|
|
1
2
|
import { type SmartWalletClient } from "@account-kit/wallet-client";
|
|
3
|
+
export type AlchemyClientResult = {
|
|
4
|
+
client: SmartWalletClient;
|
|
5
|
+
account: SmartContractAccount;
|
|
6
|
+
};
|
|
2
7
|
/**
|
|
3
|
-
* Hook to get and memoize a SmartWalletClient instance
|
|
4
|
-
* The client
|
|
8
|
+
* Hook to get and memoize a SmartWalletClient instance with its associated account
|
|
9
|
+
* The client and account are cached in the AlchemyProvider context (React tree scoped)
|
|
5
10
|
* Automatically clears cache on logout via the provider
|
|
6
11
|
*
|
|
7
|
-
* @returns {{ getClient: () => Promise<
|
|
12
|
+
* @returns {{ getClient: () => Promise<AlchemyClientResult> }} Object containing the smart wallet client and account getter
|
|
8
13
|
*
|
|
9
14
|
* @example
|
|
10
15
|
* ```tsx
|
|
11
16
|
* const { getClient } = useAlchemyClient();
|
|
12
|
-
* const
|
|
17
|
+
* const { client, account } = await getClient();
|
|
13
18
|
* ```
|
|
14
19
|
*/
|
|
15
20
|
export declare function useAlchemyClient(): {
|
|
16
|
-
getClient: () => Promise<
|
|
21
|
+
getClient: () => Promise<AlchemyClientResult>;
|
|
17
22
|
};
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
|
-
import { WalletClientSigner, ConnectionConfigSchema } from "@aa-sdk/core";
|
|
3
|
-
import { createWalletClient, custom } from "viem";
|
|
2
|
+
import { WalletClientSigner, ConnectionConfigSchema, } from "@aa-sdk/core";
|
|
3
|
+
import { createWalletClient, custom, } from "viem";
|
|
4
|
+
import { useSign7702Authorization } from "@privy-io/react-auth";
|
|
4
5
|
import { createSmartWalletClient, } from "@account-kit/wallet-client";
|
|
5
6
|
import { alchemy } from "@account-kit/infra";
|
|
6
|
-
import { useAlchemyConfig, useClientCache
|
|
7
|
+
import { useAlchemyConfig, useClientCache } from "../Provider.js";
|
|
7
8
|
import { getChain } from "../util/getChain.js";
|
|
8
9
|
import { useEmbeddedWallet } from "./internal/useEmbeddedWallet.js";
|
|
9
10
|
/**
|
|
10
|
-
* Hook to get and memoize a SmartWalletClient instance
|
|
11
|
-
* The client
|
|
11
|
+
* Hook to get and memoize a SmartWalletClient instance with its associated account
|
|
12
|
+
* The client and account are cached in the AlchemyProvider context (React tree scoped)
|
|
12
13
|
* Automatically clears cache on logout via the provider
|
|
13
14
|
*
|
|
14
|
-
* @returns {{ getClient: () => Promise<
|
|
15
|
+
* @returns {{ getClient: () => Promise<AlchemyClientResult> }} Object containing the smart wallet client and account getter
|
|
15
16
|
*
|
|
16
17
|
* @example
|
|
17
18
|
* ```tsx
|
|
18
19
|
* const { getClient } = useAlchemyClient();
|
|
19
|
-
* const
|
|
20
|
+
* const { client, account } = await getClient();
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
23
|
export function useAlchemyClient() {
|
|
23
|
-
const
|
|
24
|
-
const signAuthorizationFn = adapter.useAuthorizationSigner?.() || null;
|
|
24
|
+
const { signAuthorization } = useSign7702Authorization();
|
|
25
25
|
const config = useAlchemyConfig();
|
|
26
26
|
const cache = useClientCache();
|
|
27
27
|
const getEmbeddedWallet = useEmbeddedWallet();
|
|
@@ -52,10 +52,11 @@ export function useAlchemyClient() {
|
|
|
52
52
|
jwt: config.jwt,
|
|
53
53
|
rpcUrl: config.rpcUrl,
|
|
54
54
|
policyId: config.policyId,
|
|
55
|
+
accountAuthMode: config.accountAuthMode,
|
|
55
56
|
});
|
|
56
|
-
// Return cached client if configuration hasn't changed
|
|
57
|
-
if (cache.client && cache.cacheKey === currentCacheKey) {
|
|
58
|
-
return cache.client;
|
|
57
|
+
// Return cached client and account if configuration hasn't changed
|
|
58
|
+
if (cache.client && cache.account && cache.cacheKey === currentCacheKey) {
|
|
59
|
+
return { client: cache.client, account: cache.account };
|
|
59
60
|
}
|
|
60
61
|
// Configuration changed or no cache exists, create new client
|
|
61
62
|
const provider = await embeddedWallet.getEthereumProvider();
|
|
@@ -65,11 +66,17 @@ export function useAlchemyClient() {
|
|
|
65
66
|
chain,
|
|
66
67
|
transport: custom(provider),
|
|
67
68
|
}), "privy");
|
|
68
|
-
//
|
|
69
|
-
const signer =
|
|
69
|
+
// Optionally extend signer with EIP-7702 authorization support
|
|
70
|
+
const signer = config.accountAuthMode === "eip7702"
|
|
70
71
|
? {
|
|
71
72
|
...baseSigner,
|
|
72
|
-
signAuthorization:
|
|
73
|
+
signAuthorization: async (unsignedAuth) => {
|
|
74
|
+
const signature = await signAuthorization({
|
|
75
|
+
...unsignedAuth,
|
|
76
|
+
contractAddress: unsignedAuth.address ?? unsignedAuth.contractAddress,
|
|
77
|
+
});
|
|
78
|
+
return { ...unsignedAuth, ...signature };
|
|
79
|
+
},
|
|
73
80
|
}
|
|
74
81
|
: baseSigner;
|
|
75
82
|
// Determine transport configuration using schema validation
|
|
@@ -94,18 +101,30 @@ export function useAlchemyClient() {
|
|
|
94
101
|
: [config.policyId]
|
|
95
102
|
: undefined,
|
|
96
103
|
});
|
|
104
|
+
// Request the account to properly initialize the smart wallet
|
|
105
|
+
// Pass a creation hint based on auth mode to ensure different accounts for different modes
|
|
106
|
+
// This prevents 7702 accounts from being reused in owner mode and vice versa
|
|
107
|
+
cache.account =
|
|
108
|
+
config.accountAuthMode === "eip7702"
|
|
109
|
+
? await cache.client.requestAccount({
|
|
110
|
+
creationHint: { accountType: "7702" },
|
|
111
|
+
})
|
|
112
|
+
: await cache.client.requestAccount({
|
|
113
|
+
creationHint: { accountType: "sma-b" },
|
|
114
|
+
});
|
|
97
115
|
// Store the cache key
|
|
98
116
|
cache.cacheKey = currentCacheKey;
|
|
99
|
-
return cache.client;
|
|
117
|
+
return { client: cache.client, account: cache.account };
|
|
100
118
|
}, [
|
|
101
119
|
getEmbeddedWallet,
|
|
102
120
|
getEmbeddedWalletChain,
|
|
103
|
-
|
|
121
|
+
signAuthorization,
|
|
104
122
|
config.apiKey,
|
|
105
123
|
config.jwt,
|
|
106
124
|
config.rpcUrl,
|
|
107
125
|
config.policyId,
|
|
108
126
|
cache,
|
|
127
|
+
config.accountAuthMode,
|
|
109
128
|
]);
|
|
110
129
|
return { getClient };
|
|
111
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAlchemyClient.js","sourceRoot":"","sources":["../../../src/hooks/useAlchemyClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,
|
|
1
|
+
{"version":3,"file":"useAlchemyClient.js","sourceRoot":"","sources":["../../../src/hooks/useAlchemyClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback } from \"react\";\nimport {\n WalletClientSigner,\n type AuthorizationRequest,\n ConnectionConfigSchema,\n type SmartContractAccount,\n} from \"@aa-sdk/core\";\nimport {\n createWalletClient,\n custom,\n type Address,\n type Authorization,\n} from \"viem\";\nimport { useSign7702Authorization } from \"@privy-io/react-auth\";\nimport {\n createSmartWalletClient,\n type SmartWalletClient,\n} from \"@account-kit/wallet-client\";\nimport { alchemy } from \"@account-kit/infra\";\nimport { useAlchemyConfig, useClientCache } from \"../Provider.js\";\nimport { getChain } from \"../util/getChain.js\";\nimport { useEmbeddedWallet } from \"./internal/useEmbeddedWallet.js\";\n\nexport type AlchemyClientResult = {\n client: SmartWalletClient;\n account: SmartContractAccount;\n};\n\n/**\n * Hook to get and memoize a SmartWalletClient instance with its associated account\n * The client and account are cached in the AlchemyProvider context (React tree scoped)\n * Automatically clears cache on logout via the provider\n *\n * @returns {{ getClient: () => Promise<AlchemyClientResult> }} Object containing the smart wallet client and account getter\n *\n * @example\n * ```tsx\n * const { getClient } = useAlchemyClient();\n * const { client, account } = await getClient();\n * ```\n */\nexport function useAlchemyClient() {\n const { signAuthorization } = useSign7702Authorization();\n const config = useAlchemyConfig();\n const cache = useClientCache();\n const getEmbeddedWallet = useEmbeddedWallet();\n\n const getEmbeddedWalletChain = useCallback(() => {\n const embedded = getEmbeddedWallet();\n // Handle CAIP-2 format like \"eip155:1\"\n const chainIdStr = embedded.chainId?.toString();\n\n if (!chainIdStr) {\n throw new Error(\n \"Embedded wallet chainId is not set. Please ensure the wallet is connected to a network.\",\n );\n }\n\n const numericChainId = chainIdStr.includes(\":\")\n ? chainIdStr.split(\":\")[1]\n : chainIdStr;\n\n const parsedChainId = Number(numericChainId);\n\n if (isNaN(parsedChainId)) {\n throw new Error(\n `Failed to parse chainId from embedded wallet. Received: ${chainIdStr}`,\n );\n }\n\n return getChain(parsedChainId);\n }, [getEmbeddedWallet]);\n\n const getClient = useCallback(async (): Promise<AlchemyClientResult> => {\n const embeddedWallet = getEmbeddedWallet();\n const chain = getEmbeddedWalletChain();\n\n // Generate a cache key based on configuration and wallet address\n const currentCacheKey = JSON.stringify({\n address: embeddedWallet.address,\n chainId: chain.id,\n apiKey: config.apiKey,\n jwt: config.jwt,\n rpcUrl: config.rpcUrl,\n policyId: config.policyId,\n accountAuthMode: config.accountAuthMode,\n });\n\n // Return cached client and account if configuration hasn't changed\n if (cache.client && cache.account && cache.cacheKey === currentCacheKey) {\n return { client: cache.client, account: cache.account };\n }\n\n // Configuration changed or no cache exists, create new client\n const provider = await embeddedWallet.getEthereumProvider();\n\n // Create base signer from Privy wallet\n const baseSigner = new WalletClientSigner(\n createWalletClient({\n account: embeddedWallet.address as Address,\n chain,\n transport: custom(provider),\n }),\n \"privy\",\n );\n\n // Optionally extend signer with EIP-7702 authorization support\n const signer =\n config.accountAuthMode === \"eip7702\"\n ? {\n ...baseSigner,\n signAuthorization: async (\n unsignedAuth: AuthorizationRequest<number>,\n ): Promise<Authorization<number, true>> => {\n const signature = await signAuthorization({\n ...unsignedAuth,\n contractAddress:\n unsignedAuth.address ?? unsignedAuth.contractAddress,\n });\n return { ...unsignedAuth, ...signature };\n },\n }\n : baseSigner;\n\n // Determine transport configuration using schema validation\n // This properly handles combinations like rpcUrl + jwt together\n const transportConfig = ConnectionConfigSchema.parse({\n rpcUrl: config.rpcUrl,\n apiKey: config.apiKey,\n jwt: config.jwt,\n });\n\n const transport = alchemy(transportConfig);\n\n transport.updateHeaders({\n \"X-Alchemy-Client-Breadcrumb\": \"privyIntegrationSdk\",\n });\n\n // Create and cache the smart wallet client in provider context\n cache.client = createSmartWalletClient({\n chain,\n transport,\n signer,\n policyIds: config.policyId\n ? Array.isArray(config.policyId)\n ? config.policyId\n : [config.policyId]\n : undefined,\n });\n\n // Request the account to properly initialize the smart wallet\n // Pass a creation hint based on auth mode to ensure different accounts for different modes\n // This prevents 7702 accounts from being reused in owner mode and vice versa\n cache.account =\n config.accountAuthMode === \"eip7702\"\n ? await cache.client.requestAccount({\n creationHint: { accountType: \"7702\" },\n })\n : await cache.client.requestAccount({\n creationHint: { accountType: \"sma-b\" },\n });\n\n // Store the cache key\n cache.cacheKey = currentCacheKey;\n\n return { client: cache.client, account: cache.account };\n }, [\n getEmbeddedWallet,\n getEmbeddedWalletChain,\n signAuthorization,\n config.apiKey,\n config.jwt,\n config.rpcUrl,\n config.policyId,\n cache,\n config.accountAuthMode,\n ]);\n\n return { getClient };\n}\n"]}
|
|
@@ -2,7 +2,6 @@ import { useCallback, useState } from "react";
|
|
|
2
2
|
import {} from "viem";
|
|
3
3
|
import { swapActions } from "@account-kit/wallet-client/experimental";
|
|
4
4
|
import { useAlchemyClient } from "./useAlchemyClient.js";
|
|
5
|
-
import { useEmbeddedWallet } from "./internal/useEmbeddedWallet.js";
|
|
6
5
|
/**
|
|
7
6
|
* Hook to request swap quotes and prepare swap calls
|
|
8
7
|
* Part of the two-step swap process: prepare → submit
|
|
@@ -45,7 +44,6 @@ import { useEmbeddedWallet } from "./internal/useEmbeddedWallet.js";
|
|
|
45
44
|
*/
|
|
46
45
|
export function useAlchemyPrepareSwap() {
|
|
47
46
|
const { getClient } = useAlchemyClient();
|
|
48
|
-
const getEmbeddedWallet = useEmbeddedWallet();
|
|
49
47
|
const [isLoading, setIsLoading] = useState(false);
|
|
50
48
|
const [error, setError] = useState(null);
|
|
51
49
|
const [data, setData] = useState(null);
|
|
@@ -53,15 +51,14 @@ export function useAlchemyPrepareSwap() {
|
|
|
53
51
|
setIsLoading(true);
|
|
54
52
|
setError(null);
|
|
55
53
|
try {
|
|
56
|
-
const client = await getClient();
|
|
57
|
-
const embeddedWallet = getEmbeddedWallet();
|
|
54
|
+
const { client, account } = await getClient();
|
|
58
55
|
// Extend client with swap actions
|
|
59
56
|
const swapClient = client.extend(swapActions);
|
|
60
57
|
// Request the swap quote
|
|
61
58
|
// Note: Gas sponsorship capabilities are configured on the client itself
|
|
62
59
|
const response = await swapClient.requestQuoteV0({
|
|
63
60
|
...request,
|
|
64
|
-
from: request.from ||
|
|
61
|
+
from: request.from || account.address,
|
|
65
62
|
});
|
|
66
63
|
// Validate that we got prepared calls, not raw calls
|
|
67
64
|
if (response.rawCalls) {
|
|
@@ -78,7 +75,7 @@ export function useAlchemyPrepareSwap() {
|
|
|
78
75
|
finally {
|
|
79
76
|
setIsLoading(false);
|
|
80
77
|
}
|
|
81
|
-
}, [getClient
|
|
78
|
+
}, [getClient]);
|
|
82
79
|
const reset = useCallback(() => {
|
|
83
80
|
setError(null);
|
|
84
81
|
setData(null);
|