@alchemy/wallet-apis 0.0.0-alpha.12
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/LICENSE +21 -0
- package/dist/esm/actions/formatSign.d.ts +35 -0
- package/dist/esm/actions/formatSign.js +38 -0
- package/dist/esm/actions/formatSign.js.map +1 -0
- package/dist/esm/actions/grantPermissions.d.ts +73 -0
- package/dist/esm/actions/grantPermissions.js +87 -0
- package/dist/esm/actions/grantPermissions.js.map +1 -0
- package/dist/esm/actions/listAccounts.d.ts +40 -0
- package/dist/esm/actions/listAccounts.js +43 -0
- package/dist/esm/actions/listAccounts.js.map +1 -0
- package/dist/esm/actions/prepareCalls.d.ts +44 -0
- package/dist/esm/actions/prepareCalls.js +58 -0
- package/dist/esm/actions/prepareCalls.js.map +1 -0
- package/dist/esm/actions/prepareSign.d.ts +33 -0
- package/dist/esm/actions/prepareSign.js +41 -0
- package/dist/esm/actions/prepareSign.js.map +1 -0
- package/dist/esm/actions/requestAccount.d.ts +33 -0
- package/dist/esm/actions/requestAccount.js +67 -0
- package/dist/esm/actions/requestAccount.js.map +1 -0
- package/dist/esm/actions/sendCalls.d.ts +34 -0
- package/dist/esm/actions/sendCalls.js +49 -0
- package/dist/esm/actions/sendCalls.js.map +1 -0
- package/dist/esm/actions/sendPreparedCalls.d.ts +43 -0
- package/dist/esm/actions/sendPreparedCalls.js +50 -0
- package/dist/esm/actions/sendPreparedCalls.js.map +1 -0
- package/dist/esm/actions/signMessage.d.ts +27 -0
- package/dist/esm/actions/signMessage.js +51 -0
- package/dist/esm/actions/signMessage.js.map +1 -0
- package/dist/esm/actions/signPreparedCalls.d.ts +32 -0
- package/dist/esm/actions/signPreparedCalls.js +88 -0
- package/dist/esm/actions/signPreparedCalls.js.map +1 -0
- package/dist/esm/actions/signSignatureRequest.d.ts +41 -0
- package/dist/esm/actions/signSignatureRequest.js +97 -0
- package/dist/esm/actions/signSignatureRequest.js.map +1 -0
- package/dist/esm/actions/signTypedData.d.ts +40 -0
- package/dist/esm/actions/signTypedData.js +66 -0
- package/dist/esm/actions/signTypedData.js.map +1 -0
- package/dist/esm/client.d.ts +34 -0
- package/dist/esm/client.js +62 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/decorators/smartWalletActions.d.ts +36 -0
- package/dist/esm/decorators/smartWalletActions.js +37 -0
- package/dist/esm/decorators/smartWalletActions.js.map +1 -0
- package/dist/esm/experimental/actions/requestQuoteV0.d.ts +54 -0
- package/dist/esm/experimental/actions/requestQuoteV0.js +62 -0
- package/dist/esm/experimental/actions/requestQuoteV0.js.map +1 -0
- package/dist/esm/experimental/swapActionsDecorator.d.ts +13 -0
- package/dist/esm/experimental/swapActionsDecorator.js +16 -0
- package/dist/esm/experimental/swapActionsDecorator.js.map +1 -0
- package/dist/esm/exports/experimental.d.ts +4 -0
- package/dist/esm/exports/experimental.js +3 -0
- package/dist/esm/exports/experimental.js.map +1 -0
- package/dist/esm/exports/index.d.ts +31 -0
- package/dist/esm/exports/index.js +16 -0
- package/dist/esm/exports/index.js.map +1 -0
- package/dist/esm/exports/internal.d.ts +6 -0
- package/dist/esm/exports/internal.js +4 -0
- package/dist/esm/exports/internal.js.map +1 -0
- package/dist/esm/internal.d.ts +11 -0
- package/dist/esm/internal.js +12 -0
- package/dist/esm/internal.js.map +1 -0
- package/dist/esm/logger.d.ts +2 -0
- package/dist/esm/logger.js +8 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/provider.d.ts +26 -0
- package/dist/esm/provider.js +191 -0
- package/dist/esm/provider.js.map +1 -0
- package/dist/esm/testSetup.d.ts +3 -0
- package/dist/esm/testSetup.js +18 -0
- package/dist/esm/testSetup.js.map +1 -0
- package/dist/esm/types.d.ts +34 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils/assertions.d.ts +18 -0
- package/dist/esm/utils/assertions.js +24 -0
- package/dist/esm/utils/assertions.js.map +1 -0
- package/dist/esm/utils/capabilities.d.ts +10 -0
- package/dist/esm/utils/capabilities.js +19 -0
- package/dist/esm/utils/capabilities.js.map +1 -0
- package/dist/esm/utils/format.d.ts +7 -0
- package/dist/esm/utils/format.js +37 -0
- package/dist/esm/utils/format.js.map +1 -0
- package/dist/esm/utils/viemDecode.d.ts +8 -0
- package/dist/esm/utils/viemDecode.js +231 -0
- package/dist/esm/utils/viemDecode.js.map +1 -0
- package/dist/esm/utils/viemEncode.d.ts +40 -0
- package/dist/esm/utils/viemEncode.js +216 -0
- package/dist/esm/utils/viemEncode.js.map +1 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +4 -0
- package/dist/esm/version.js.map +1 -0
- package/dist/types/actions/formatSign.d.ts +36 -0
- package/dist/types/actions/formatSign.d.ts.map +1 -0
- package/dist/types/actions/grantPermissions.d.ts +74 -0
- package/dist/types/actions/grantPermissions.d.ts.map +1 -0
- package/dist/types/actions/listAccounts.d.ts +41 -0
- package/dist/types/actions/listAccounts.d.ts.map +1 -0
- package/dist/types/actions/prepareCalls.d.ts +45 -0
- package/dist/types/actions/prepareCalls.d.ts.map +1 -0
- package/dist/types/actions/prepareSign.d.ts +34 -0
- package/dist/types/actions/prepareSign.d.ts.map +1 -0
- package/dist/types/actions/requestAccount.d.ts +34 -0
- package/dist/types/actions/requestAccount.d.ts.map +1 -0
- package/dist/types/actions/sendCalls.d.ts +35 -0
- package/dist/types/actions/sendCalls.d.ts.map +1 -0
- package/dist/types/actions/sendPreparedCalls.d.ts +44 -0
- package/dist/types/actions/sendPreparedCalls.d.ts.map +1 -0
- package/dist/types/actions/signMessage.d.ts +28 -0
- package/dist/types/actions/signMessage.d.ts.map +1 -0
- package/dist/types/actions/signPreparedCalls.d.ts +33 -0
- package/dist/types/actions/signPreparedCalls.d.ts.map +1 -0
- package/dist/types/actions/signSignatureRequest.d.ts +42 -0
- package/dist/types/actions/signSignatureRequest.d.ts.map +1 -0
- package/dist/types/actions/signTypedData.d.ts +41 -0
- package/dist/types/actions/signTypedData.d.ts.map +1 -0
- package/dist/types/client.d.ts +35 -0
- package/dist/types/client.d.ts.map +1 -0
- package/dist/types/decorators/smartWalletActions.d.ts +37 -0
- package/dist/types/decorators/smartWalletActions.d.ts.map +1 -0
- package/dist/types/experimental/actions/requestQuoteV0.d.ts +55 -0
- package/dist/types/experimental/actions/requestQuoteV0.d.ts.map +1 -0
- package/dist/types/experimental/swapActionsDecorator.d.ts +14 -0
- package/dist/types/experimental/swapActionsDecorator.d.ts.map +1 -0
- package/dist/types/exports/experimental.d.ts +5 -0
- package/dist/types/exports/experimental.d.ts.map +1 -0
- package/dist/types/exports/index.d.ts +32 -0
- package/dist/types/exports/index.d.ts.map +1 -0
- package/dist/types/exports/internal.d.ts +7 -0
- package/dist/types/exports/internal.d.ts.map +1 -0
- package/dist/types/internal.d.ts +12 -0
- package/dist/types/internal.d.ts.map +1 -0
- package/dist/types/logger.d.ts +3 -0
- package/dist/types/logger.d.ts.map +1 -0
- package/dist/types/provider.d.ts +27 -0
- package/dist/types/provider.d.ts.map +1 -0
- package/dist/types/testSetup.d.ts +4 -0
- package/dist/types/testSetup.d.ts.map +1 -0
- package/dist/types/types.d.ts +35 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils/assertions.d.ts +19 -0
- package/dist/types/utils/assertions.d.ts.map +1 -0
- package/dist/types/utils/capabilities.d.ts +11 -0
- package/dist/types/utils/capabilities.d.ts.map +1 -0
- package/dist/types/utils/format.d.ts +8 -0
- package/dist/types/utils/format.d.ts.map +1 -0
- package/dist/types/utils/viemDecode.d.ts +9 -0
- package/dist/types/utils/viemDecode.d.ts.map +1 -0
- package/dist/types/utils/viemEncode.d.ts +41 -0
- package/dist/types/utils/viemEncode.d.ts.map +1 -0
- package/dist/types/version.d.ts +2 -0
- package/dist/types/version.d.ts.map +1 -0
- package/package.json +76 -0
- package/src/actions/formatSign.ts +64 -0
- package/src/actions/grantPermissions.ts +125 -0
- package/src/actions/listAccounts.ts +66 -0
- package/src/actions/prepareCalls.ts +85 -0
- package/src/actions/prepareSign.ts +67 -0
- package/src/actions/requestAccount.ts +100 -0
- package/src/actions/sendCalls.ts +67 -0
- package/src/actions/sendPreparedCalls.ts +70 -0
- package/src/actions/signMessage.ts +74 -0
- package/src/actions/signPreparedCalls.ts +120 -0
- package/src/actions/signSignatureRequest.ts +135 -0
- package/src/actions/signTypedData.ts +90 -0
- package/src/client.ts +107 -0
- package/src/decorators/smartWalletActions.ts +123 -0
- package/src/experimental/actions/requestQuoteV0.ts +95 -0
- package/src/experimental/swapActionsDecorator.ts +34 -0
- package/src/exports/experimental.ts +7 -0
- package/src/exports/index.ts +44 -0
- package/src/exports/internal.ts +8 -0
- package/src/internal.ts +25 -0
- package/src/logger.ts +9 -0
- package/src/provider.ts +261 -0
- package/src/testSetup.ts +24 -0
- package/src/types.ts +61 -0
- package/src/utils/assertions.ts +32 -0
- package/src/utils/capabilities.ts +24 -0
- package/src/utils/format.ts +61 -0
- package/src/utils/viemDecode.ts +313 -0
- package/src/utils/viemEncode.ts +345 -0
- package/src/version.ts +3 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {
|
|
2
|
+
toHex,
|
|
3
|
+
type Address,
|
|
4
|
+
type Hex,
|
|
5
|
+
type IsUndefined,
|
|
6
|
+
type Prettify,
|
|
7
|
+
concatHex,
|
|
8
|
+
} from "viem";
|
|
9
|
+
import type { InnerWalletApiClient } from "../types.ts";
|
|
10
|
+
import type { WalletServerRpcSchemaType } from "@alchemy/wallet-api-types/rpc";
|
|
11
|
+
import { signSignatureRequest } from "./signSignatureRequest.js";
|
|
12
|
+
import { AccountNotFoundError } from "@alchemy/common";
|
|
13
|
+
import { LOGGER } from "../logger.js";
|
|
14
|
+
import type { OptionalChainId } from "../types.ts";
|
|
15
|
+
|
|
16
|
+
type RpcSchema = Extract<
|
|
17
|
+
WalletServerRpcSchemaType,
|
|
18
|
+
{
|
|
19
|
+
Request: {
|
|
20
|
+
method: "wallet_createSession";
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
>;
|
|
24
|
+
|
|
25
|
+
export type GrantPermissionsParams<
|
|
26
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
27
|
+
> = Prettify<
|
|
28
|
+
OptionalChainId<Omit<RpcSchema["Request"]["params"][0], "account">> &
|
|
29
|
+
(IsUndefined<TAccount> extends true
|
|
30
|
+
? { account: Address }
|
|
31
|
+
: { account?: never })
|
|
32
|
+
>;
|
|
33
|
+
|
|
34
|
+
export type GrantPermissionsResult = Prettify<{
|
|
35
|
+
context: Hex;
|
|
36
|
+
}>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Grants permissions to a smart account by creating a session.
|
|
40
|
+
* This allows another key to perform operations on behalf of the account.
|
|
41
|
+
*
|
|
42
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
43
|
+
* @param {GrantPermissionsParams} params - The parameters for granting permissions
|
|
44
|
+
* @param {Address} [params.account] - The account address (required if client was not initialized with an account)
|
|
45
|
+
* @param {number} params.expirySec - Unix timestamp when the permissions expire
|
|
46
|
+
* @param {sessionKeyData} params.key - The session key information
|
|
47
|
+
* @param {string} params.key.publicKey - The public key of the session key
|
|
48
|
+
* @param {string} params.key.type - The type of the key (e.g., "secp256k1")
|
|
49
|
+
* @param {Array} params.permissions - Array of permission objects defining what the session key can do
|
|
50
|
+
* @returns {Promise<GrantPermissionsResult>} A Promise that resolves to the result containing a context identifier
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* // Create a session key and grant root permissions
|
|
55
|
+
* const sessionKey = LocalAccountSigner.generatePrivateKeySigner();
|
|
56
|
+
* const account = await client.requestAccount();
|
|
57
|
+
*
|
|
58
|
+
* const permissions = await client.grantPermissions({
|
|
59
|
+
* account: account.address,
|
|
60
|
+
* expirySec: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hour from now
|
|
61
|
+
* key: {
|
|
62
|
+
* publicKey: await sessionKey.getAddress(),
|
|
63
|
+
* type: "secp256k1",
|
|
64
|
+
* },
|
|
65
|
+
* permissions: [{ type: "root" }],
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // Use the permissions to prepare a call
|
|
69
|
+
* const preparedCalls = await client.prepareCalls({
|
|
70
|
+
* calls: [{ to: zeroAddress, value: "0x0" }],
|
|
71
|
+
* from: account.address,
|
|
72
|
+
* capabilities: {
|
|
73
|
+
* paymasterService: {
|
|
74
|
+
* policyId: "your-paymaster-policy-id",
|
|
75
|
+
* },
|
|
76
|
+
* permissions,
|
|
77
|
+
* },
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* // Sign with the session key
|
|
81
|
+
* const signedCalls = await signPreparedCalls(sessionKey, preparedCalls);
|
|
82
|
+
*
|
|
83
|
+
* // Send the prepared call using the session key
|
|
84
|
+
* const result = await client.sendPreparedCalls({
|
|
85
|
+
* ...signedCalls,
|
|
86
|
+
* capabilities: {
|
|
87
|
+
* permissions,
|
|
88
|
+
* },
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export async function grantPermissions<
|
|
93
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
94
|
+
>(
|
|
95
|
+
client: InnerWalletApiClient,
|
|
96
|
+
params: GrantPermissionsParams<TAccount>,
|
|
97
|
+
): Promise<GrantPermissionsResult> {
|
|
98
|
+
const account = params.account ?? client.account?.address;
|
|
99
|
+
if (!account) {
|
|
100
|
+
LOGGER.warn("grantPermissions:no-account");
|
|
101
|
+
throw new AccountNotFoundError();
|
|
102
|
+
}
|
|
103
|
+
LOGGER.debug("grantPermissions:start", { expirySec: params.expirySec });
|
|
104
|
+
const { sessionId, signatureRequest } = await client.request({
|
|
105
|
+
method: "wallet_createSession",
|
|
106
|
+
params: [
|
|
107
|
+
{
|
|
108
|
+
...params,
|
|
109
|
+
account,
|
|
110
|
+
chainId: params.chainId ?? toHex(client.chain.id),
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const signature = await signSignatureRequest(client, signatureRequest);
|
|
116
|
+
const res = {
|
|
117
|
+
context: concatHex([
|
|
118
|
+
"0x00", // Remote mode.
|
|
119
|
+
sessionId,
|
|
120
|
+
signature.data,
|
|
121
|
+
]),
|
|
122
|
+
} as const;
|
|
123
|
+
LOGGER.debug("grantPermissions:done");
|
|
124
|
+
return res;
|
|
125
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { InnerWalletApiClient } from "../types.ts";
|
|
2
|
+
import { LOGGER } from "../logger.js";
|
|
3
|
+
import type { Address, Prettify } from "viem";
|
|
4
|
+
import type { WalletServerRpcSchemaType } from "@alchemy/wallet-api-types/rpc";
|
|
5
|
+
|
|
6
|
+
type RpcSchema = Extract<
|
|
7
|
+
WalletServerRpcSchemaType,
|
|
8
|
+
{
|
|
9
|
+
Request: {
|
|
10
|
+
method: "wallet_listAccounts";
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
export type ListAccountsParams = Prettify<
|
|
16
|
+
Omit<RpcSchema["Request"]["params"][0], "signerAddress"> & {
|
|
17
|
+
signerAddress?: Address;
|
|
18
|
+
}
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
export type ListAccountsResult = Prettify<RpcSchema["ReturnType"]>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Lists all smart accounts for a given signer using the wallet API client.
|
|
25
|
+
*
|
|
26
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
27
|
+
* @param {ListAccountsParams} params - Parameters for listing accounts
|
|
28
|
+
* @param {string} params.signerAddress - The address of the signer to list accounts for
|
|
29
|
+
* @param {number} [params.limit] - Optional maximum number of accounts to return (default: 100, max: 100)
|
|
30
|
+
* @param {string} [params.after] - Optional pagination cursor for fetching subsequent pages
|
|
31
|
+
* @returns {Promise<ListAccountsResult>} A Promise that resolves to the list of accounts and pagination metadata
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // Fetch the first page of accounts
|
|
36
|
+
* const firstPage = await client.listAccounts({
|
|
37
|
+
* signerAddress: "0x123...",
|
|
38
|
+
* limit: 10
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* // If an 'after' cursor exists, use it to fetch the next page
|
|
42
|
+
* const nextPage = await client.listAccounts({
|
|
43
|
+
* signerAddress: "0x123...",
|
|
44
|
+
* limit: 10,
|
|
45
|
+
* after: firstPage.meta.after
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export async function listAccounts(
|
|
50
|
+
client: InnerWalletApiClient,
|
|
51
|
+
params: ListAccountsParams,
|
|
52
|
+
): Promise<ListAccountsResult> {
|
|
53
|
+
const signerAddress = params.signerAddress ?? client.owner.account.address;
|
|
54
|
+
LOGGER.debug("listAccounts:start", { hasAfter: !!params.after });
|
|
55
|
+
const res = await client.request({
|
|
56
|
+
method: "wallet_listAccounts",
|
|
57
|
+
params: [
|
|
58
|
+
{
|
|
59
|
+
...params,
|
|
60
|
+
signerAddress,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
LOGGER.debug("listAccounts:done", { count: res.accounts.length });
|
|
65
|
+
return res;
|
|
66
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { toHex, type Address, type IsUndefined, type Prettify } from "viem";
|
|
2
|
+
import type { InnerWalletApiClient, OptionalChainId } from "../types.ts";
|
|
3
|
+
import { AccountNotFoundError } from "@alchemy/common";
|
|
4
|
+
import { LOGGER } from "../logger.js";
|
|
5
|
+
import { mergeClientCapabilities } from "../utils/capabilities.js";
|
|
6
|
+
import type { WalletServerRpcSchemaType } from "@alchemy/wallet-api-types/rpc";
|
|
7
|
+
|
|
8
|
+
type RpcSchema = Extract<
|
|
9
|
+
WalletServerRpcSchemaType,
|
|
10
|
+
{
|
|
11
|
+
Request: {
|
|
12
|
+
method: "wallet_prepareCalls";
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
export type PrepareCallsParams<
|
|
18
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
19
|
+
> = Prettify<
|
|
20
|
+
OptionalChainId<Omit<RpcSchema["Request"]["params"][0], "from">> &
|
|
21
|
+
(IsUndefined<TAccount> extends true ? { from: Address } : { from?: never })
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
export type PrepareCallsResult = Prettify<RpcSchema["ReturnType"]>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Prepares a set of contract calls for execution by building a user operation.
|
|
28
|
+
* Returns the built user operation and a signature request that needs to be signed
|
|
29
|
+
* before submitting to sendPreparedCalls.
|
|
30
|
+
*
|
|
31
|
+
* @param {InnerWalletApiClient<TAccount>} client - The wallet API client to use for the request
|
|
32
|
+
* @param {PrepareCallsParams<TAccount>} params - Parameters for preparing calls
|
|
33
|
+
* @param {Array<{to: Address, data?: Hex, value?: Hex}>} params.calls - Array of contract calls to execute
|
|
34
|
+
* @param {Address} [params.from] - The address to execute the calls from (required if the client wasn't initialized with an account)
|
|
35
|
+
* @param {object} [params.capabilities] - Optional capabilities to include with the request
|
|
36
|
+
* @returns {Promise<PrepareCallsResult>} A Promise that resolves to the prepared calls result containing
|
|
37
|
+
* the user operation data and signature request
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* // Prepare a sponsored user operation call
|
|
42
|
+
* const result = await client.prepareCalls({
|
|
43
|
+
* calls: [{
|
|
44
|
+
* to: "0x1234...",
|
|
45
|
+
* data: "0xabcdef...",
|
|
46
|
+
* value: "0x0"
|
|
47
|
+
* }],
|
|
48
|
+
* capabilities: {
|
|
49
|
+
* paymasterService: { policyId: "your-policy-id" }
|
|
50
|
+
* }
|
|
51
|
+
* });
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export async function prepareCalls<
|
|
55
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
56
|
+
>(
|
|
57
|
+
client: InnerWalletApiClient,
|
|
58
|
+
params: PrepareCallsParams<TAccount>,
|
|
59
|
+
): Promise<PrepareCallsResult> {
|
|
60
|
+
const from = params.from ?? client.account?.address;
|
|
61
|
+
if (!from) {
|
|
62
|
+
LOGGER.warn("prepareCalls:no-from", { hasClientAccount: !!client.account });
|
|
63
|
+
throw new AccountNotFoundError();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const capabilities = mergeClientCapabilities(client, params.capabilities);
|
|
67
|
+
|
|
68
|
+
LOGGER.debug("prepareCalls:start", {
|
|
69
|
+
callsCount: params.calls?.length,
|
|
70
|
+
hasCapabilities: !!params.capabilities,
|
|
71
|
+
});
|
|
72
|
+
const res = await client.request({
|
|
73
|
+
method: "wallet_prepareCalls",
|
|
74
|
+
params: [
|
|
75
|
+
{
|
|
76
|
+
...params,
|
|
77
|
+
chainId: params.chainId ?? toHex(client.chain.id),
|
|
78
|
+
from,
|
|
79
|
+
capabilities,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
});
|
|
83
|
+
LOGGER.debug("prepareCalls:done");
|
|
84
|
+
return res;
|
|
85
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { InnerWalletApiClient, OptionalChainId } from "../types.ts";
|
|
2
|
+
import { toHex, type Address, type IsUndefined, type Prettify } from "viem";
|
|
3
|
+
import type { WalletServerRpcSchemaType } from "@alchemy/wallet-api-types/rpc";
|
|
4
|
+
import { AccountNotFoundError } from "@alchemy/common";
|
|
5
|
+
import { LOGGER } from "../logger.js";
|
|
6
|
+
|
|
7
|
+
type RpcSchema = Extract<
|
|
8
|
+
WalletServerRpcSchemaType,
|
|
9
|
+
{
|
|
10
|
+
Request: {
|
|
11
|
+
method: "wallet_prepareSign";
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
>;
|
|
15
|
+
|
|
16
|
+
export type PrepareSignParams<
|
|
17
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
18
|
+
> = Prettify<
|
|
19
|
+
OptionalChainId<Omit<RpcSchema["Request"]["params"][0], "from">> &
|
|
20
|
+
(IsUndefined<TAccount> extends true ? { from: Address } : { from?: never })
|
|
21
|
+
>;
|
|
22
|
+
|
|
23
|
+
export type PrepareSignResult = Prettify<RpcSchema["ReturnType"]>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Prepares a signature request for signing messages or transactions.
|
|
27
|
+
*
|
|
28
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
29
|
+
* @param {PrepareSignParams} params - Parameters for preparing the signature request
|
|
30
|
+
* @returns {Promise<PrepareSignResult>} A Promise that resolves to the prepare sign result containing a signature request
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // Prepare a message to be signed
|
|
35
|
+
* const result = await client.prepareSign({
|
|
36
|
+
* from: "0x1234...",
|
|
37
|
+
* type: "personal_sign",
|
|
38
|
+
* data: "Hello, world!",
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export async function prepareSign<
|
|
43
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
44
|
+
>(
|
|
45
|
+
client: InnerWalletApiClient,
|
|
46
|
+
params: PrepareSignParams<TAccount>,
|
|
47
|
+
): Promise<PrepareSignResult> {
|
|
48
|
+
const from = params.from ?? client.account?.address;
|
|
49
|
+
if (!from) {
|
|
50
|
+
LOGGER.warn("prepareSign:no-from", { hasClientAccount: !!client.account });
|
|
51
|
+
throw new AccountNotFoundError();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
LOGGER.debug("prepareSign:start", { type: params.signatureRequest.type });
|
|
55
|
+
const res = await client.request({
|
|
56
|
+
method: "wallet_prepareSign",
|
|
57
|
+
params: [
|
|
58
|
+
{
|
|
59
|
+
...params,
|
|
60
|
+
from,
|
|
61
|
+
chainId: params.chainId ?? toHex(client.chain.id),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
LOGGER.debug("prepareSign:done");
|
|
66
|
+
return res;
|
|
67
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Address } from "abitype";
|
|
2
|
+
import type { Prettify, UnionOmit } from "viem";
|
|
3
|
+
import type { WalletServerRpcSchemaType } from "@alchemy/wallet-api-types/rpc";
|
|
4
|
+
import deepEqual from "deep-equal";
|
|
5
|
+
import type { InnerWalletApiClient, OptionalSignerAddress } from "../types";
|
|
6
|
+
import { LOGGER } from "../logger.js";
|
|
7
|
+
|
|
8
|
+
type RpcSchema = Extract<
|
|
9
|
+
WalletServerRpcSchemaType,
|
|
10
|
+
{
|
|
11
|
+
Request: {
|
|
12
|
+
method: "wallet_requestAccount";
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
export type RequestAccountParams = Prettify<
|
|
18
|
+
OptionalSignerAddress<
|
|
19
|
+
UnionOmit<RpcSchema["Request"]["params"][0], "includeCounterfactualInfo">
|
|
20
|
+
>
|
|
21
|
+
>;
|
|
22
|
+
|
|
23
|
+
export type RequestAccountResult = Prettify<{ address: Address }>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Requests an account for the provided signer using the wallet API client.
|
|
27
|
+
* If an account already exists for the signer, it will always return that account unless a new ID is specified.
|
|
28
|
+
* If an account already exists, the creationHint will be ignored.
|
|
29
|
+
*
|
|
30
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
31
|
+
* @param {RequestAccountParams} [params] - Optional parameters for requesting a specific account
|
|
32
|
+
* @param {string} [params.id] - Optional identifier for the account. If specified, a new account with this ID will be created even if one already exists for the signer
|
|
33
|
+
* @param {object} [params.creationHint] - Optional hints to guide account creation. These are ignored if an account already exists
|
|
34
|
+
* @returns {Promise<RequestAccountResult>} A Promise that resolves to an object containing a smart account address
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* // Request an account with default parameters using a local signer
|
|
39
|
+
* const signer = LocalAccountSigner.privateKeyToAccountSigner("0x...");
|
|
40
|
+
* const account = await client.requestAccount(signer);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export async function requestAccount(
|
|
44
|
+
client: InnerWalletApiClient,
|
|
45
|
+
params?: RequestAccountParams,
|
|
46
|
+
): Promise<RequestAccountResult> {
|
|
47
|
+
LOGGER.debug("requestAccount:start", {
|
|
48
|
+
hasParams: !!params,
|
|
49
|
+
hasAccountOnClient: !!client.account,
|
|
50
|
+
});
|
|
51
|
+
const args =
|
|
52
|
+
client.account && !params
|
|
53
|
+
? {
|
|
54
|
+
accountAddress: client.account.address,
|
|
55
|
+
includeCounterfactualInfo: true,
|
|
56
|
+
}
|
|
57
|
+
: params != null && "accountAddress" in params
|
|
58
|
+
? {
|
|
59
|
+
accountAddress: params.accountAddress,
|
|
60
|
+
includeCounterfactualInfo: true,
|
|
61
|
+
}
|
|
62
|
+
: {
|
|
63
|
+
...params,
|
|
64
|
+
signerAddress:
|
|
65
|
+
(params && "signerAddress" in params
|
|
66
|
+
? params.signerAddress
|
|
67
|
+
: undefined) ?? client.owner.account.address,
|
|
68
|
+
includeCounterfactualInfo: true,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const cachedAccount = client.internal?.getAccount();
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
cachedAccount &&
|
|
75
|
+
((args.accountAddress && cachedAccount.address === args.accountAddress) ||
|
|
76
|
+
deepEqual(cachedAccount.requestParams, args, { strict: true }))
|
|
77
|
+
) {
|
|
78
|
+
LOGGER.debug("requestAccount:cache-hit", {
|
|
79
|
+
address: cachedAccount.address,
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
address: cachedAccount.address,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const resp = await client.request({
|
|
87
|
+
method: "wallet_requestAccount",
|
|
88
|
+
params: [args],
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
client.internal?.setAccount({
|
|
92
|
+
address: resp.accountAddress,
|
|
93
|
+
requestParams: args,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
LOGGER.debug("requestAccount:done", { address: resp.accountAddress });
|
|
97
|
+
return {
|
|
98
|
+
address: resp.accountAddress,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Address, Prettify } from "viem";
|
|
2
|
+
import type { InnerWalletApiClient } from "../types.js";
|
|
3
|
+
import { prepareCalls, type PrepareCallsParams } from "./prepareCalls.js";
|
|
4
|
+
import { signPreparedCalls } from "./signPreparedCalls.js";
|
|
5
|
+
import {
|
|
6
|
+
sendPreparedCalls,
|
|
7
|
+
type SendPreparedCallsResult,
|
|
8
|
+
} from "./sendPreparedCalls.js";
|
|
9
|
+
import { LOGGER } from "../logger.js";
|
|
10
|
+
|
|
11
|
+
export type SendCallsParams<
|
|
12
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
13
|
+
> = Prettify<PrepareCallsParams<TAccount>>;
|
|
14
|
+
|
|
15
|
+
export type SendCallsResult = Prettify<SendPreparedCallsResult>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Prepares, signs, and submits calls. This function internally calls `prepareCalls`, `signPreparedCalls`, and `sendPreparedCalls`.
|
|
19
|
+
*
|
|
20
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
21
|
+
* @param {PrepareCallsParams<TAccount>} params - Parameters for sending calls
|
|
22
|
+
* @param {Array<{to: Address, data?: Hex, value?: Hex}>} params.calls - Array of contract calls to execute
|
|
23
|
+
* @param {Address} [params.from] - The address to execute the calls from (required if the client wasn't initialized with an account)
|
|
24
|
+
* @param {object} [params.capabilities] - Optional capabilities to include with the request.
|
|
25
|
+
* @returns {Promise<SendPreparedCallsResult>} A Promise that resolves to the result containing the prepared call IDs.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const result = await client.sendCalls({
|
|
30
|
+
* calls: [{
|
|
31
|
+
* to: "0x1234...",
|
|
32
|
+
* data: "0xabcdef...",
|
|
33
|
+
* value: "0x0"
|
|
34
|
+
* }],
|
|
35
|
+
* capabilities: {
|
|
36
|
+
* paymasterService: { policyId: "your-policy-id" }
|
|
37
|
+
* }
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // The result contains the prepared call IDs
|
|
41
|
+
* console.log(result.preparedCallIds);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export async function sendCalls<
|
|
45
|
+
TAccount extends Address | undefined = Address | undefined,
|
|
46
|
+
>(
|
|
47
|
+
client: InnerWalletApiClient,
|
|
48
|
+
params: SendCallsParams<TAccount>,
|
|
49
|
+
): Promise<SendCallsResult> {
|
|
50
|
+
LOGGER.info("sendCalls:start", {
|
|
51
|
+
calls: params.calls?.length,
|
|
52
|
+
hasCapabilities: !!params.capabilities,
|
|
53
|
+
});
|
|
54
|
+
const calls = await prepareCalls(client, params);
|
|
55
|
+
|
|
56
|
+
const signedCalls = await signPreparedCalls(client, calls);
|
|
57
|
+
|
|
58
|
+
const res = await sendPreparedCalls(client, {
|
|
59
|
+
...signedCalls,
|
|
60
|
+
// The only capability that is supported in sendPreparedCalls is permissions.
|
|
61
|
+
...(params.capabilities?.permissions != null
|
|
62
|
+
? { capabilities: { permissions: params.capabilities.permissions } }
|
|
63
|
+
: {}),
|
|
64
|
+
});
|
|
65
|
+
LOGGER.info("sendCalls:done");
|
|
66
|
+
return res;
|
|
67
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { toHex, type Prettify } from "viem";
|
|
2
|
+
import type { WalletServerRpcSchemaType } from "@alchemy/wallet-api-types/rpc";
|
|
3
|
+
import type { InnerWalletApiClient, OptionalChainId } from "../types.ts";
|
|
4
|
+
import { LOGGER } from "../logger.js";
|
|
5
|
+
|
|
6
|
+
type RpcSchema = Extract<
|
|
7
|
+
WalletServerRpcSchemaType,
|
|
8
|
+
{
|
|
9
|
+
Request: {
|
|
10
|
+
method: "wallet_sendPreparedCalls";
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
export type SendPreparedCallsParams = Prettify<
|
|
16
|
+
OptionalChainId<RpcSchema["Request"]["params"][0]>
|
|
17
|
+
>;
|
|
18
|
+
|
|
19
|
+
export type SendPreparedCallsResult = Prettify<RpcSchema["ReturnType"]>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Sends prepared calls by submitting a signed user operation.
|
|
23
|
+
* This method is used after signing the signature request returned from prepareCalls.
|
|
24
|
+
*
|
|
25
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
26
|
+
* @param {SendPreparedCallsParams} params - Parameters for sending prepared calls
|
|
27
|
+
* @returns {Promise<SendPreparedCallsResult>} A Promise that resolves to the result containing the prepared call IDs
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* // First prepare the calls
|
|
32
|
+
* const preparedCalls = await client.prepareCalls({
|
|
33
|
+
* calls: [{
|
|
34
|
+
* to: "0x1234...",
|
|
35
|
+
* data: "0xabcdef...",
|
|
36
|
+
* value: "0x0"
|
|
37
|
+
* }],
|
|
38
|
+
* capabilities: {
|
|
39
|
+
* paymasterService: { policyId: "your-policy-id" }
|
|
40
|
+
* }
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* // Then sign the calls
|
|
44
|
+
* const signedCalls = await client.signPreparedCalls(preparedCalls);
|
|
45
|
+
*
|
|
46
|
+
* // Then send the prepared calls with the signature
|
|
47
|
+
* const result = await client.sendPreparedCalls({
|
|
48
|
+
* signedCalls,
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export async function sendPreparedCalls(
|
|
53
|
+
client: InnerWalletApiClient,
|
|
54
|
+
params: SendPreparedCallsParams,
|
|
55
|
+
): Promise<SendPreparedCallsResult> {
|
|
56
|
+
LOGGER.debug("sendPreparedCalls:start", { type: params.type });
|
|
57
|
+
const res = await client.request({
|
|
58
|
+
method: "wallet_sendPreparedCalls",
|
|
59
|
+
params: [
|
|
60
|
+
params.type === "array"
|
|
61
|
+
? params
|
|
62
|
+
: {
|
|
63
|
+
...params,
|
|
64
|
+
chainId: params.chainId ?? toHex(client.chain.id),
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
LOGGER.debug("sendPreparedCalls:done");
|
|
69
|
+
return res;
|
|
70
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
type Hex,
|
|
4
|
+
type Prettify,
|
|
5
|
+
type SignableMessage,
|
|
6
|
+
} from "viem";
|
|
7
|
+
import type { InnerWalletApiClient } from "../types.js";
|
|
8
|
+
import { requestAccount } from "./requestAccount.js";
|
|
9
|
+
import { prepareSign } from "./prepareSign.js";
|
|
10
|
+
import { signSignatureRequest } from "./signSignatureRequest.js";
|
|
11
|
+
import { formatSign } from "./formatSign.js";
|
|
12
|
+
import { signableMessageToJsonSafe } from "../utils/format.js";
|
|
13
|
+
import { LOGGER } from "../logger.js";
|
|
14
|
+
|
|
15
|
+
export type SignMessageParams = Prettify<{
|
|
16
|
+
message: SignableMessage;
|
|
17
|
+
account?: Address;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
export type SignMessageResult = Prettify<Hex>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Signs a message using the smart account.
|
|
24
|
+
* This method requests the account associated with the signer and uses it to sign the message.
|
|
25
|
+
*
|
|
26
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
27
|
+
* @param {SignMessageParams} params - Parameters for signing the message
|
|
28
|
+
* @param {SignableMessage} params.message - The message to sign using EIP-191. Can be a string, or object with raw bytes.
|
|
29
|
+
* @param {Address} [params.account] - Optional account address to use for signing. If not provided, uses the client's current account.
|
|
30
|
+
* @returns {Promise<SignMessageResult>} A Promise that resolves to the signed message as a hex string
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // Sign a simple text message
|
|
35
|
+
* const signature = await client.signMessage("Hello, world!");
|
|
36
|
+
*
|
|
37
|
+
* // Sign a raw hex message
|
|
38
|
+
* const signature = await client.signMessage({ raw: "0x48656c6c6f2c20776f726c6421" });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export async function signMessage(
|
|
42
|
+
client: InnerWalletApiClient,
|
|
43
|
+
params: SignMessageParams,
|
|
44
|
+
): Promise<SignMessageResult> {
|
|
45
|
+
const accountAddress = params.account ?? client.account?.address;
|
|
46
|
+
LOGGER.debug("signMessage:start", {
|
|
47
|
+
hasExplicitAccount: params.account != null,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const account = await requestAccount(
|
|
51
|
+
client,
|
|
52
|
+
accountAddress != null ? { accountAddress } : undefined,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const prepared = await prepareSign(client, {
|
|
56
|
+
from: account.address,
|
|
57
|
+
signatureRequest: {
|
|
58
|
+
type: "personal_sign",
|
|
59
|
+
data: signableMessageToJsonSafe(params.message),
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const signed = await signSignatureRequest(client, prepared.signatureRequest);
|
|
64
|
+
|
|
65
|
+
const formatted = await formatSign(client, {
|
|
66
|
+
from: account.address,
|
|
67
|
+
signature: {
|
|
68
|
+
type: "ecdsa",
|
|
69
|
+
data: signed.data,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
LOGGER.debug("signMessage:done", { from: account.address });
|
|
73
|
+
return formatted.signature;
|
|
74
|
+
}
|