@account-kit/wallet-client 0.1.0-alpha.2 → 0.1.0-alpha.4
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/dist/esm/capabilities/index.d.ts +5 -2
- package/dist/esm/capabilities/index.js +1 -1
- package/dist/esm/capabilities/index.js.map +1 -1
- package/dist/esm/capabilities/overrides.js +8 -8
- package/dist/esm/capabilities/overrides.js.map +1 -1
- package/dist/esm/capabilities/permissions/index.d.ts +10 -3
- package/dist/esm/capabilities/permissions/index.js +11 -2
- package/dist/esm/capabilities/permissions/index.js.map +1 -1
- package/dist/esm/capabilities/permissions/mav2.d.ts +2 -2
- package/dist/esm/capabilities/permissions/mav2.js +9 -1
- package/dist/esm/capabilities/permissions/mav2.js.map +1 -1
- package/dist/esm/client/actions/grantPermissions.d.ts +57 -3
- package/dist/esm/client/actions/grantPermissions.js +1 -0
- package/dist/esm/client/actions/grantPermissions.js.map +1 -1
- package/dist/esm/client/actions/requestAccount.js +2 -2
- package/dist/esm/client/actions/requestAccount.js.map +1 -1
- package/dist/esm/client/actions/signSignatureRequest.d.ts +4 -1
- package/dist/esm/client/actions/signSignatureRequest.js +22 -1
- package/dist/esm/client/actions/signSignatureRequest.js.map +1 -1
- package/dist/esm/client/client.e2e-test.js +13 -19
- package/dist/esm/client/client.e2e-test.js.map +1 -1
- package/dist/esm/client/index.d.ts +4 -3
- package/dist/esm/client/index.js +2 -2
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/exports/index.d.ts +2 -2
- package/dist/esm/exports/index.js +1 -1
- package/dist/esm/exports/index.js.map +1 -1
- package/dist/esm/isomorphic/actions/createSession.js +25 -7
- package/dist/esm/isomorphic/actions/createSession.js.map +1 -1
- package/dist/esm/isomorphic/actions/prepareCalls.js +35 -12
- package/dist/esm/isomorphic/actions/prepareCalls.js.map +1 -1
- package/dist/esm/isomorphic/actions/sendPreparedCalls.js +26 -6
- package/dist/esm/isomorphic/actions/sendPreparedCalls.js.map +1 -1
- package/dist/esm/isomorphic/client.d.ts +11 -5
- package/dist/esm/isomorphic/utils/7702.d.ts +11 -0
- package/dist/esm/isomorphic/utils/7702.js +26 -0
- package/dist/esm/isomorphic/utils/7702.js.map +1 -0
- package/dist/esm/isomorphic/utils/createAccount.d.ts +2 -1
- package/dist/esm/isomorphic/utils/createAccount.js +30 -5
- package/dist/esm/isomorphic/utils/createAccount.js.map +1 -1
- package/dist/esm/isomorphic/utils/createDummySigner.js +3 -3
- package/dist/esm/isomorphic/utils/createDummySigner.js.map +1 -1
- package/dist/esm/isomorphic/utils/parsePermissionsContext.d.ts +2 -1
- package/dist/esm/isomorphic/utils/parsePermissionsContext.js +17 -5
- package/dist/esm/isomorphic/utils/parsePermissionsContext.js.map +1 -1
- package/dist/esm/local/client.js +2 -1
- package/dist/esm/local/client.js.map +1 -1
- package/dist/esm/remote/client.js +6 -2
- package/dist/esm/remote/client.js.map +1 -1
- package/dist/esm/rpc/examples.d.ts +230 -0
- package/dist/esm/rpc/examples.js +314 -0
- package/dist/esm/rpc/examples.js.map +1 -0
- package/dist/esm/rpc/request.d.ts +48 -17
- package/dist/esm/rpc/request.js +53 -14
- package/dist/esm/rpc/request.js.map +1 -1
- package/dist/esm/rpc/schema.d.ts +42 -11
- package/dist/esm/schemas.d.ts +29 -7
- package/dist/esm/schemas.js +120 -38
- package/dist/esm/schemas.js.map +1 -1
- package/dist/types/capabilities/index.d.ts +5 -2
- package/dist/types/capabilities/index.d.ts.map +1 -1
- package/dist/types/capabilities/overrides.d.ts.map +1 -1
- package/dist/types/capabilities/permissions/index.d.ts +10 -3
- package/dist/types/capabilities/permissions/index.d.ts.map +1 -1
- package/dist/types/capabilities/permissions/mav2.d.ts +2 -2
- package/dist/types/capabilities/permissions/mav2.d.ts.map +1 -1
- package/dist/types/client/actions/grantPermissions.d.ts +57 -3
- package/dist/types/client/actions/grantPermissions.d.ts.map +1 -1
- package/dist/types/client/actions/requestAccount.d.ts.map +1 -1
- package/dist/types/client/actions/signSignatureRequest.d.ts +4 -1
- package/dist/types/client/actions/signSignatureRequest.d.ts.map +1 -1
- package/dist/types/client/index.d.ts +4 -3
- package/dist/types/client/index.d.ts.map +1 -1
- package/dist/types/exports/index.d.ts +2 -2
- package/dist/types/exports/index.d.ts.map +1 -1
- package/dist/types/isomorphic/actions/createSession.d.ts.map +1 -1
- package/dist/types/isomorphic/actions/prepareCalls.d.ts.map +1 -1
- package/dist/types/isomorphic/actions/sendPreparedCalls.d.ts.map +1 -1
- package/dist/types/isomorphic/client.d.ts +11 -5
- package/dist/types/isomorphic/client.d.ts.map +1 -1
- package/dist/types/isomorphic/utils/7702.d.ts +12 -0
- package/dist/types/isomorphic/utils/7702.d.ts.map +1 -0
- package/dist/types/isomorphic/utils/createAccount.d.ts +2 -1
- package/dist/types/isomorphic/utils/createAccount.d.ts.map +1 -1
- package/dist/types/isomorphic/utils/createDummySigner.d.ts.map +1 -1
- package/dist/types/isomorphic/utils/parsePermissionsContext.d.ts +2 -1
- package/dist/types/isomorphic/utils/parsePermissionsContext.d.ts.map +1 -1
- package/dist/types/remote/client.d.ts.map +1 -1
- package/dist/types/rpc/examples.d.ts +231 -0
- package/dist/types/rpc/examples.d.ts.map +1 -0
- package/dist/types/rpc/request.d.ts +48 -17
- package/dist/types/rpc/request.d.ts.map +1 -1
- package/dist/types/rpc/schema.d.ts +42 -11
- package/dist/types/rpc/schema.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +29 -7
- package/dist/types/schemas.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/capabilities/index.ts +5 -8
- package/src/capabilities/overrides.ts +23 -8
- package/src/capabilities/permissions/index.ts +21 -5
- package/src/capabilities/permissions/mav2.ts +12 -2
- package/src/client/actions/grantPermissions.ts +57 -3
- package/src/client/actions/requestAccount.ts +2 -3
- package/src/client/actions/signSignatureRequest.ts +31 -3
- package/src/client/client.e2e-test.ts +14 -21
- package/src/client/index.ts +12 -10
- package/src/exports/index.ts +2 -1
- package/src/isomorphic/actions/createSession.ts +28 -7
- package/src/isomorphic/actions/prepareCalls.ts +38 -11
- package/src/isomorphic/actions/sendPreparedCalls.ts +47 -20
- package/src/isomorphic/utils/7702.ts +58 -0
- package/src/isomorphic/utils/createAccount.ts +38 -6
- package/src/isomorphic/utils/createDummySigner.ts +3 -2
- package/src/isomorphic/utils/parsePermissionsContext.ts +23 -7
- package/src/local/client.ts +2 -3
- package/src/remote/client.ts +12 -2
- package/src/rpc/examples.ts +343 -0
- package/src/rpc/request.ts +75 -26
- package/src/schemas.ts +218 -87
|
@@ -122,7 +122,7 @@ describe("Client E2E Tests", () => {
|
|
|
122
122
|
|
|
123
123
|
it("should successfully send a UO with paymaster", async () => {
|
|
124
124
|
const account = await client.requestAccount();
|
|
125
|
-
const
|
|
125
|
+
const preparedCall = await client.prepareCalls({
|
|
126
126
|
calls: [{ to: zeroAddress, value: "0x0" }],
|
|
127
127
|
from: account.address,
|
|
128
128
|
capabilities: {
|
|
@@ -132,20 +132,13 @@ describe("Client E2E Tests", () => {
|
|
|
132
132
|
},
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const signature = await signer.signMessage(
|
|
140
|
-
preparedUO.signatureRequest.data,
|
|
135
|
+
const signature = await client.signSignatureRequest(
|
|
136
|
+
preparedCall.signatureRequest,
|
|
141
137
|
);
|
|
142
138
|
|
|
143
139
|
const result = await client.sendPreparedCalls({
|
|
144
|
-
...
|
|
145
|
-
signature
|
|
146
|
-
type: "ecdsa",
|
|
147
|
-
signature,
|
|
148
|
-
},
|
|
140
|
+
...preparedCall,
|
|
141
|
+
signature,
|
|
149
142
|
});
|
|
150
143
|
|
|
151
144
|
expect(result.preparedCallIds).toBeArrayOfSize(1);
|
|
@@ -166,7 +159,7 @@ describe("Client E2E Tests", () => {
|
|
|
166
159
|
permissions: [{ type: "root" }],
|
|
167
160
|
});
|
|
168
161
|
|
|
169
|
-
const
|
|
162
|
+
const preparedCall = await client.prepareCalls({
|
|
170
163
|
calls: [{ to: zeroAddress, value: "0x0" }],
|
|
171
164
|
from: account.address,
|
|
172
165
|
capabilities: {
|
|
@@ -179,11 +172,11 @@ describe("Client E2E Tests", () => {
|
|
|
179
172
|
|
|
180
173
|
const signature = await signSignatureRequest(
|
|
181
174
|
sessionKey,
|
|
182
|
-
|
|
175
|
+
preparedCall.signatureRequest,
|
|
183
176
|
);
|
|
184
177
|
|
|
185
178
|
const result = await client.sendPreparedCalls({
|
|
186
|
-
...
|
|
179
|
+
...preparedCall,
|
|
187
180
|
signature,
|
|
188
181
|
capabilities: {
|
|
189
182
|
permissions,
|
|
@@ -302,7 +295,7 @@ describe("Client E2E Tests", () => {
|
|
|
302
295
|
|
|
303
296
|
it("should successfully send a UO with paymaster", async () => {
|
|
304
297
|
const account = await client.requestAccount();
|
|
305
|
-
const
|
|
298
|
+
const preparedCall = await client.prepareCalls({
|
|
306
299
|
calls: [{ to: zeroAddress, value: "0x0" }],
|
|
307
300
|
from: account.address,
|
|
308
301
|
capabilities: {
|
|
@@ -313,11 +306,11 @@ describe("Client E2E Tests", () => {
|
|
|
313
306
|
});
|
|
314
307
|
|
|
315
308
|
const signature = await client.signSignatureRequest(
|
|
316
|
-
|
|
309
|
+
preparedCall.signatureRequest,
|
|
317
310
|
);
|
|
318
311
|
|
|
319
312
|
const result = await client.sendPreparedCalls({
|
|
320
|
-
...
|
|
313
|
+
...preparedCall,
|
|
321
314
|
signature,
|
|
322
315
|
});
|
|
323
316
|
|
|
@@ -339,7 +332,7 @@ describe("Client E2E Tests", () => {
|
|
|
339
332
|
permissions: [{ type: "root" }],
|
|
340
333
|
});
|
|
341
334
|
|
|
342
|
-
const
|
|
335
|
+
const preparedCall = await client.prepareCalls({
|
|
343
336
|
calls: [{ to: zeroAddress, value: "0x0" }],
|
|
344
337
|
from: account.address,
|
|
345
338
|
capabilities: {
|
|
@@ -352,11 +345,11 @@ describe("Client E2E Tests", () => {
|
|
|
352
345
|
|
|
353
346
|
const signature = await signSignatureRequest(
|
|
354
347
|
sessionKey,
|
|
355
|
-
|
|
348
|
+
preparedCall.signatureRequest,
|
|
356
349
|
);
|
|
357
350
|
|
|
358
351
|
const result = await client.sendPreparedCalls({
|
|
359
|
-
...
|
|
352
|
+
...preparedCall,
|
|
360
353
|
signature,
|
|
361
354
|
capabilities: {
|
|
362
355
|
permissions,
|
package/src/client/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SmartAccountSigner } from "@aa-sdk/core";
|
|
2
|
+
import type { AlchemyTransport } from "@account-kit/infra";
|
|
2
3
|
import type {
|
|
3
4
|
Address,
|
|
4
5
|
Chain,
|
|
@@ -13,7 +14,6 @@ import {
|
|
|
13
14
|
smartWalletClientActions,
|
|
14
15
|
type SmartWalletActions,
|
|
15
16
|
} from "./decorator.js";
|
|
16
|
-
import type { AlchemyTransport } from "@account-kit/infra";
|
|
17
17
|
|
|
18
18
|
export type SmartWalletClientParams<
|
|
19
19
|
TAccount extends JsonRpcAccount<Address> | undefined =
|
|
@@ -35,19 +35,21 @@ export type SmartWalletClientParams<
|
|
|
35
35
|
})
|
|
36
36
|
>;
|
|
37
37
|
|
|
38
|
+
export type SmartWalletClient<
|
|
39
|
+
TAccount extends JsonRpcAccount<Address> | undefined =
|
|
40
|
+
| JsonRpcAccount<Address>
|
|
41
|
+
| undefined,
|
|
42
|
+
> = InnerWalletApiClient<TAccount> & SmartWalletActions<TAccount>;
|
|
43
|
+
|
|
38
44
|
export function createSmartWalletClient<
|
|
39
45
|
TAccount extends JsonRpcAccount<Address> | undefined =
|
|
40
46
|
| JsonRpcAccount<Address>
|
|
41
47
|
| undefined,
|
|
42
|
-
>(
|
|
43
|
-
params: SmartWalletClientParams<TAccount>,
|
|
44
|
-
): InnerWalletApiClient<TAccount> & SmartWalletActions<TAccount>;
|
|
48
|
+
>(params: SmartWalletClientParams<TAccount>): SmartWalletClient<TAccount>;
|
|
45
49
|
|
|
46
50
|
export function createSmartWalletClient<
|
|
47
51
|
TAccount extends JsonRpcAccount<Address> = JsonRpcAccount<Address>,
|
|
48
|
-
>(
|
|
49
|
-
params: SmartWalletClientParams<TAccount>,
|
|
50
|
-
): InnerWalletApiClient<TAccount> & SmartWalletActions<TAccount>;
|
|
52
|
+
>(params: SmartWalletClientParams<TAccount>): SmartWalletClient<TAccount>;
|
|
51
53
|
|
|
52
54
|
/**
|
|
53
55
|
* Creates a smart wallet client that can be used to interact with a smart account.
|
|
@@ -59,13 +61,13 @@ export function createSmartWalletClient<
|
|
|
59
61
|
* @param {"local" | "remote"} params.mode - The client's mode (local or remote).
|
|
60
62
|
* @param {string} [params.policyId] - The policy ID for gas sponsorship (optional)
|
|
61
63
|
* @param {Address} [params.account] - The smart account address to use (optional)
|
|
62
|
-
* @returns {
|
|
64
|
+
* @returns {SmartWalletClient} - A viem-compatible client
|
|
63
65
|
*
|
|
64
66
|
* @example
|
|
65
67
|
* import { LocalAccountSigner } from "@aa-sdk/core";
|
|
66
68
|
* import { alchemy, arbitrumSepolia } from "@account-kit/infra";
|
|
67
69
|
* import { generatePrivateKey } from "viem/accounts";
|
|
68
|
-
* import { createSmartWalletClient } from "@account-kit/wallet-
|
|
70
|
+
* import { createSmartWalletClient } from "@account-kit/wallet-client";
|
|
69
71
|
*
|
|
70
72
|
* const signer = LocalAccountSigner.privateKeyToAccountSigner(generatePrivateKey());
|
|
71
73
|
* const transport = alchemy({
|
|
@@ -80,7 +82,7 @@ export function createSmartWalletClient<
|
|
|
80
82
|
*/
|
|
81
83
|
export function createSmartWalletClient(
|
|
82
84
|
params: SmartWalletClientParams,
|
|
83
|
-
):
|
|
85
|
+
): SmartWalletClient {
|
|
84
86
|
const { transport, chain, policyId, mode, account, signer } = params;
|
|
85
87
|
|
|
86
88
|
const innerClient =
|
package/src/exports/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// and we shouldn't export * for the sake of tree-shaking
|
|
3
3
|
export {
|
|
4
4
|
createSmartWalletClient,
|
|
5
|
+
type SmartWalletClient,
|
|
5
6
|
type SmartWalletClientParams,
|
|
6
7
|
} from "../client/index.js";
|
|
7
8
|
|
|
@@ -24,10 +25,10 @@ export {
|
|
|
24
25
|
// client actions
|
|
25
26
|
export { createAccount } from "../client/actions/createAccount.js";
|
|
26
27
|
export { getCallsStatus } from "../client/actions/getCallsStatus.js";
|
|
28
|
+
export { grantPermissions } from "../client/actions/grantPermissions.js";
|
|
27
29
|
export { listAccounts } from "../client/actions/listAccounts.js";
|
|
28
30
|
export { prepareCalls } from "../client/actions/prepareCalls.js";
|
|
29
31
|
export { requestAccount } from "../client/actions/requestAccount.js";
|
|
30
32
|
export { signMessage } from "../client/actions/signMessage.js";
|
|
31
33
|
export { signSignatureRequest } from "../client/actions/signSignatureRequest.js";
|
|
32
34
|
export { signTypedData } from "../client/actions/signTypedData.js";
|
|
33
|
-
export { grantPermissions } from "../client/actions/grantPermissions.js";
|
|
@@ -24,6 +24,8 @@ import type { wallet_createSession } from "../../rpc/request.js";
|
|
|
24
24
|
import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
|
|
25
25
|
import { createAccount, isModularAccountV2 } from "../utils/createAccount.js";
|
|
26
26
|
import { createDummySigner } from "../utils/createDummySigner.js";
|
|
27
|
+
import { createAuthorization } from "../utils/7702.js";
|
|
28
|
+
import { InvalidRequestError } from "ox/RpcResponse";
|
|
27
29
|
|
|
28
30
|
export type CreateSessionParams = Omit<
|
|
29
31
|
Static<
|
|
@@ -57,17 +59,20 @@ export async function createSession(
|
|
|
57
59
|
throw new ChainNotFoundError();
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
const { counterfactualInfo } = await client.request({
|
|
62
|
+
const { counterfactualInfo, delegation } = await client.request({
|
|
61
63
|
method: "wallet_requestAccount",
|
|
62
64
|
params: [
|
|
63
65
|
{
|
|
64
|
-
includeCounterfactualInfo: true,
|
|
65
66
|
accountAddress: params.account,
|
|
67
|
+
includeCounterfactualInfo: true,
|
|
66
68
|
},
|
|
67
69
|
],
|
|
68
70
|
});
|
|
69
|
-
if (!counterfactualInfo) {
|
|
70
|
-
throw new
|
|
71
|
+
if (!counterfactualInfo && !delegation) {
|
|
72
|
+
throw new InvalidRequestError({
|
|
73
|
+
message:
|
|
74
|
+
"No counterfactual info or delegated implementation address found.",
|
|
75
|
+
});
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
const account = await createAccount({
|
|
@@ -76,10 +81,13 @@ export async function createSession(
|
|
|
76
81
|
signer: createDummySigner(params.account),
|
|
77
82
|
accountAddress: params.account,
|
|
78
83
|
counterfactualInfo,
|
|
84
|
+
delegation,
|
|
79
85
|
});
|
|
80
86
|
|
|
81
87
|
if (!isModularAccountV2(account)) {
|
|
82
|
-
throw new
|
|
88
|
+
throw new InvalidRequestError({
|
|
89
|
+
message: "Sessions are currently only supported by MAv2 accounts.",
|
|
90
|
+
});
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
const _client = createSmartAccountClient({
|
|
@@ -108,12 +116,25 @@ export async function createSession(
|
|
|
108
116
|
})
|
|
109
117
|
.compileDeferred();
|
|
110
118
|
|
|
119
|
+
// If using 7702, we need an Authorization (unless it's already authorized).
|
|
120
|
+
const authorizationRequest = delegation
|
|
121
|
+
? await createAuthorization(client, {
|
|
122
|
+
address: account.address,
|
|
123
|
+
delegation,
|
|
124
|
+
})
|
|
125
|
+
: undefined;
|
|
126
|
+
|
|
127
|
+
const signatureRequest = {
|
|
128
|
+
type: "eth_signTypedData_v4" as const,
|
|
129
|
+
data: typedData,
|
|
130
|
+
};
|
|
131
|
+
|
|
111
132
|
return {
|
|
112
133
|
sessionId: null, // In remote mode, the server will set this later.
|
|
113
134
|
entityId: toHex(entityId),
|
|
114
135
|
signatureRequest: {
|
|
115
|
-
|
|
116
|
-
|
|
136
|
+
...signatureRequest,
|
|
137
|
+
...(authorizationRequest ? { authorizationRequest } : {}),
|
|
117
138
|
},
|
|
118
139
|
fullPreSignatureDeferredActionDigest,
|
|
119
140
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deepHexlify,
|
|
3
|
+
default7702GasEstimator,
|
|
3
4
|
type SmartAccountClient,
|
|
4
5
|
type SmartContractAccount,
|
|
5
6
|
} from "@aa-sdk/core";
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
custom,
|
|
10
11
|
fromHex,
|
|
11
12
|
toHex,
|
|
12
|
-
zeroAddress,
|
|
13
13
|
type Chain,
|
|
14
14
|
type Transport,
|
|
15
15
|
} from "viem";
|
|
@@ -17,6 +17,8 @@ import type { wallet_prepareCalls } from "../../rpc/request.js";
|
|
|
17
17
|
import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
|
|
18
18
|
import { createAccount } from "../utils/createAccount.js";
|
|
19
19
|
import { createDummySigner } from "../utils/createDummySigner.js";
|
|
20
|
+
import { createAuthorization } from "../utils/7702.js";
|
|
21
|
+
import { InvalidRequestError } from "ox/RpcResponse";
|
|
20
22
|
|
|
21
23
|
export type PrepareCallsParams = Omit<
|
|
22
24
|
Static<
|
|
@@ -29,7 +31,6 @@ export type PrepareCallsResult = Static<
|
|
|
29
31
|
(typeof wallet_prepareCalls)["properties"]["ReturnType"]
|
|
30
32
|
>;
|
|
31
33
|
|
|
32
|
-
// TODO: handle capabilities like permissions and paymaster here
|
|
33
34
|
export async function prepareCalls(
|
|
34
35
|
client: SmartAccountClient<
|
|
35
36
|
Transport,
|
|
@@ -45,7 +46,7 @@ export async function prepareCalls(
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
// in local mode, we probably want some kind of caching for this
|
|
48
|
-
const { counterfactualInfo } = await client.request({
|
|
49
|
+
const { counterfactualInfo, delegation } = await client.request({
|
|
49
50
|
method: "wallet_requestAccount",
|
|
50
51
|
params: [
|
|
51
52
|
{
|
|
@@ -54,19 +55,37 @@ export async function prepareCalls(
|
|
|
54
55
|
},
|
|
55
56
|
],
|
|
56
57
|
});
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
|
|
59
|
+
if (!counterfactualInfo && !delegation) {
|
|
60
|
+
throw new InvalidRequestError({
|
|
61
|
+
message:
|
|
62
|
+
"No counterfactual info or delegated implementation address found.",
|
|
63
|
+
});
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
const account = await createAccount({
|
|
62
67
|
chain: client.chain,
|
|
63
68
|
transport: custom(client.transport),
|
|
64
|
-
signer: createDummySigner(
|
|
69
|
+
signer: createDummySigner(params.from),
|
|
65
70
|
accountAddress: params.from,
|
|
66
71
|
counterfactualInfo,
|
|
67
72
|
capabilities: params.capabilities,
|
|
73
|
+
delegation,
|
|
68
74
|
});
|
|
69
75
|
|
|
76
|
+
// If using 7702, we need an Authorization (unless it's already authorized).
|
|
77
|
+
const authorizationRequest = delegation
|
|
78
|
+
? await createAuthorization(client, {
|
|
79
|
+
address: account.address,
|
|
80
|
+
delegation,
|
|
81
|
+
})
|
|
82
|
+
: undefined;
|
|
83
|
+
|
|
84
|
+
if (authorizationRequest) {
|
|
85
|
+
// @ts-expect-error - this is available but not typed as public
|
|
86
|
+
client.middleware.gasEstimator = default7702GasEstimator();
|
|
87
|
+
}
|
|
88
|
+
|
|
70
89
|
// TODO: oops we don't actually support setting the policyId as an override here
|
|
71
90
|
// if we assume that the the isomorphic client is never used directly, then we can assume that this is handled upstream correctly
|
|
72
91
|
const builtUo = await client.buildUserOperation({
|
|
@@ -79,9 +98,19 @@ export async function prepareCalls(
|
|
|
79
98
|
overrides: params.capabilities?.gasParamsOverride,
|
|
80
99
|
});
|
|
81
100
|
|
|
101
|
+
// The eip7702Auth field should never be included in the UO sig
|
|
102
|
+
// request. It's handled by the separate authorization request.
|
|
103
|
+
if ("eip7702Auth" in builtUo) {
|
|
104
|
+
builtUo.eip7702Auth = undefined;
|
|
105
|
+
}
|
|
82
106
|
const uoRequest = deepHexlify(builtUo);
|
|
83
107
|
|
|
84
|
-
const
|
|
108
|
+
const signatureRequest = {
|
|
109
|
+
type: "personal_sign" as const,
|
|
110
|
+
data: {
|
|
111
|
+
raw: account.getEntryPoint().getUserOperationHash(uoRequest),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
85
114
|
|
|
86
115
|
return {
|
|
87
116
|
type:
|
|
@@ -91,10 +120,8 @@ export async function prepareCalls(
|
|
|
91
120
|
data: uoRequest,
|
|
92
121
|
chainId: toHex(client.chain.id),
|
|
93
122
|
signatureRequest: {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
raw: hash,
|
|
97
|
-
},
|
|
123
|
+
...signatureRequest,
|
|
124
|
+
...(authorizationRequest ? { authorizationRequest } : {}),
|
|
98
125
|
},
|
|
99
126
|
};
|
|
100
127
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
import type { Static, StaticDecode } from "@sinclair/typebox";
|
|
7
7
|
import { Value } from "@sinclair/typebox/value";
|
|
8
8
|
import {
|
|
9
|
+
BaseError,
|
|
9
10
|
ChainNotFoundError,
|
|
10
11
|
concat,
|
|
11
12
|
concatHex,
|
|
@@ -18,6 +19,8 @@ import { decodePermissionsContext } from "../../capabilities/permissions/mav2.js
|
|
|
18
19
|
import type { wallet_sendPreparedCalls } from "../../rpc/request.js";
|
|
19
20
|
import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
|
|
20
21
|
import { TypeCallId } from "../../schemas.js";
|
|
22
|
+
import { isSupportedImplementationAddress7702 } from "../utils/7702.js";
|
|
23
|
+
import { InvalidRequestError } from "ox/RpcResponse";
|
|
21
24
|
|
|
22
25
|
export type SendPreparedCallsParams = Omit<
|
|
23
26
|
StaticDecode<
|
|
@@ -45,19 +48,30 @@ export async function sendPreparedCalls(
|
|
|
45
48
|
throw new ChainNotFoundError();
|
|
46
49
|
}
|
|
47
50
|
|
|
51
|
+
// One last safety check to be sure the UO wasn't modified to include an unsupported 7702 delegation address.
|
|
52
|
+
if (
|
|
53
|
+
params.signedAuthorization &&
|
|
54
|
+
!isSupportedImplementationAddress7702(params.signedAuthorization.address)
|
|
55
|
+
) {
|
|
56
|
+
throw new InvalidRequestError({
|
|
57
|
+
message: `Unsupported 7702 delegation address: ${params.signedAuthorization.address}`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
const deferredAction: Hex | undefined = (() => {
|
|
49
|
-
if (!params.capabilities?.permissions
|
|
62
|
+
if (!params.capabilities?.permissions) {
|
|
50
63
|
return;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
const decodedContext = decodePermissionsContext(
|
|
54
|
-
params.capabilities.permissions
|
|
67
|
+
params.capabilities.permissions,
|
|
55
68
|
);
|
|
56
69
|
|
|
57
70
|
if (decodedContext.contextVersion === "REMOTE_MODE_DEFERRED_ACTION") {
|
|
58
|
-
throw new
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
throw new InvalidRequestError({
|
|
72
|
+
message:
|
|
73
|
+
"Remote mode deferred action not supported in isomorphic client",
|
|
74
|
+
});
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
return decodedContext.deferredAction;
|
|
@@ -68,21 +82,34 @@ export async function sendPreparedCalls(
|
|
|
68
82
|
? getEntryPoint(client.chain, { version: "0.6.0" })
|
|
69
83
|
: getEntryPoint(client.chain, { version: "0.7.0" });
|
|
70
84
|
|
|
71
|
-
const hash = await client
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
const hash = await client
|
|
86
|
+
.sendRawUserOperation(
|
|
87
|
+
{
|
|
88
|
+
...params.data,
|
|
89
|
+
signature:
|
|
90
|
+
deferredAction != null
|
|
91
|
+
? concatHex([
|
|
92
|
+
`0x${deferredAction.slice(68)}`, // Cuts off stuff preprended to the digest (nonce, etc. that we had previously).
|
|
93
|
+
"0xff",
|
|
94
|
+
"0x00",
|
|
95
|
+
params.signature.signature,
|
|
96
|
+
])
|
|
97
|
+
: concat(["0xFF", "0x00", params.signature.signature]),
|
|
98
|
+
eip7702Auth: params.signedAuthorization,
|
|
99
|
+
},
|
|
100
|
+
entryPoint.address,
|
|
101
|
+
)
|
|
102
|
+
.catch((err) => {
|
|
103
|
+
if (
|
|
104
|
+
err instanceof BaseError &&
|
|
105
|
+
err.details.endsWith("is not a contract and initCode is empty")
|
|
106
|
+
) {
|
|
107
|
+
throw new BaseError(
|
|
108
|
+
`${err.details} (If using 7702, be sure you include the 'signedAuthorization' field in the request parameters)`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
throw err;
|
|
112
|
+
});
|
|
86
113
|
|
|
87
114
|
const callId = Value.Encode(TypeCallId, {
|
|
88
115
|
chainId: toHex(client.chain.id),
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SmartAccountClient, SmartContractAccount } from "@aa-sdk/core";
|
|
2
|
+
import {
|
|
3
|
+
concatHex,
|
|
4
|
+
type Authorization,
|
|
5
|
+
type Address,
|
|
6
|
+
type Chain,
|
|
7
|
+
type Transport,
|
|
8
|
+
} from "viem";
|
|
9
|
+
import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
|
|
10
|
+
|
|
11
|
+
export const createAuthorization = async (
|
|
12
|
+
client: SmartAccountClient<
|
|
13
|
+
Transport,
|
|
14
|
+
Chain,
|
|
15
|
+
SmartContractAccount | undefined,
|
|
16
|
+
Record<string, unknown>,
|
|
17
|
+
WalletServerViemRpcSchema
|
|
18
|
+
>,
|
|
19
|
+
params: { address: Address; delegation: Address },
|
|
20
|
+
): Promise<Authorization<number, false> | undefined> => {
|
|
21
|
+
const expectedCode = concatHex(["0xef0100", params.delegation]);
|
|
22
|
+
const code = (await client.getCode({ address: params.address })) ?? "0x";
|
|
23
|
+
if (code.toLowerCase() === expectedCode.toLowerCase()) {
|
|
24
|
+
return undefined; // Already authorized.
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
chainId: client.chain.id,
|
|
28
|
+
address: params.delegation,
|
|
29
|
+
nonce: await client.getTransactionCount({
|
|
30
|
+
address: params.address,
|
|
31
|
+
}),
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type Supported7702AccountType = "ModularAccountV2";
|
|
36
|
+
|
|
37
|
+
const IMPLEMENTATION_ADDRESS_TO_ACCOUNT_TYPE: Record<
|
|
38
|
+
Address,
|
|
39
|
+
Supported7702AccountType
|
|
40
|
+
> = {
|
|
41
|
+
"0x69007702764179f14F51cdce752f4f775d74E139": "ModularAccountV2",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const getAccountTypeForImplementationAddress7702 = (
|
|
45
|
+
address: Address,
|
|
46
|
+
): Supported7702AccountType | undefined => {
|
|
47
|
+
return IMPLEMENTATION_ADDRESS_TO_ACCOUNT_TYPE[address];
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const SUPPORTED_IMPLEMENTATION_ADDRESSES = Object.keys(
|
|
51
|
+
IMPLEMENTATION_ADDRESS_TO_ACCOUNT_TYPE,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export const isSupportedImplementationAddress7702 = (
|
|
55
|
+
address: string,
|
|
56
|
+
): boolean => {
|
|
57
|
+
return SUPPORTED_IMPLEMENTATION_ADDRESSES.includes(address);
|
|
58
|
+
};
|
|
@@ -9,13 +9,17 @@ import { concatHex, hexToNumber } from "viem";
|
|
|
9
9
|
import type { Capabilities } from "../../capabilities/index.js";
|
|
10
10
|
import type { TypeSerializedInitcode } from "../../schemas.js";
|
|
11
11
|
import { parsePermissionsContext } from "./parsePermissionsContext.js";
|
|
12
|
+
import { assertNever } from "../../utils.js";
|
|
13
|
+
import { getAccountTypeForImplementationAddress7702 } from "./7702.js";
|
|
14
|
+
import { InternalError } from "ox/RpcResponse";
|
|
12
15
|
|
|
13
16
|
type CreateAccountParams = {
|
|
14
17
|
chain: Chain;
|
|
15
18
|
transport: Transport;
|
|
16
19
|
signer: SmartAccountSigner;
|
|
17
20
|
accountAddress: Address;
|
|
18
|
-
counterfactualInfo
|
|
21
|
+
counterfactualInfo?: StaticDecode<typeof TypeSerializedInitcode>; // undefined for 7702 accounts
|
|
22
|
+
delegation?: Address;
|
|
19
23
|
capabilities?: StaticDecode<typeof Capabilities>;
|
|
20
24
|
};
|
|
21
25
|
|
|
@@ -28,12 +32,38 @@ export async function createAccount(
|
|
|
28
32
|
params: CreateAccountParams,
|
|
29
33
|
): Promise<SmartContractAccount> {
|
|
30
34
|
const { counterfactualInfo: ci, ...accountParams } = params;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
|
|
36
|
+
const mode = params.delegation ? "7702" : "default";
|
|
37
|
+
|
|
38
|
+
if (mode === "default") {
|
|
39
|
+
if (!ci) {
|
|
40
|
+
throw new InternalError({
|
|
41
|
+
message: "Counterfactual info not found",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (ci.factoryType !== "MAv2.0.0-sma-b") {
|
|
45
|
+
throw new InternalError({
|
|
46
|
+
message: `Factory type ${ci.factoryType} is not currently supported.`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
} else if (mode === "7702") {
|
|
50
|
+
const accountType = getAccountTypeForImplementationAddress7702(
|
|
51
|
+
params.delegation!,
|
|
52
|
+
);
|
|
53
|
+
if (accountType !== "ModularAccountV2") {
|
|
54
|
+
throw new InternalError({
|
|
55
|
+
message: "7702 mode currently only supports ModularAccountV2",
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
assertNever(mode, "Unexpected mode in createAccount");
|
|
34
60
|
}
|
|
35
61
|
|
|
36
|
-
const parsedContext = parsePermissionsContext(
|
|
62
|
+
const parsedContext = parsePermissionsContext(
|
|
63
|
+
params.capabilities,
|
|
64
|
+
ci,
|
|
65
|
+
params.delegation,
|
|
66
|
+
);
|
|
37
67
|
|
|
38
68
|
const signerEntity =
|
|
39
69
|
parsedContext?.contextVersion === "NON_DEFERRED_ACTION"
|
|
@@ -43,11 +73,13 @@ export async function createAccount(
|
|
|
43
73
|
}
|
|
44
74
|
: undefined;
|
|
45
75
|
|
|
76
|
+
// TODO: clean this up to support different account types.
|
|
46
77
|
return createModularAccountV2({
|
|
47
78
|
...accountParams,
|
|
48
79
|
signerEntity,
|
|
49
80
|
deferredAction: parsedContext?.deferredAction,
|
|
50
|
-
initCode: concatHex([ci.factoryAddress, ci.factoryData]),
|
|
81
|
+
initCode: ci ? concatHex([ci.factoryAddress, ci.factoryData]) : undefined,
|
|
82
|
+
mode,
|
|
51
83
|
});
|
|
52
84
|
}
|
|
53
85
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type SmartAccountSigner } from "@aa-sdk/core";
|
|
2
2
|
import type { TypedData } from "abitype";
|
|
3
3
|
import {
|
|
4
|
+
BaseError,
|
|
4
5
|
type Address,
|
|
5
6
|
type Hex,
|
|
6
7
|
type SignableMessage,
|
|
@@ -15,12 +16,12 @@ export const createDummySigner = (address: Address): SmartAccountSigner => ({
|
|
|
15
16
|
},
|
|
16
17
|
// Not supported on the server
|
|
17
18
|
signMessage: function (_message: SignableMessage): Promise<Hex> {
|
|
18
|
-
throw new
|
|
19
|
+
throw new BaseError("signMessage not implemented by dummy signer.");
|
|
19
20
|
},
|
|
20
21
|
signTypedData: function <
|
|
21
22
|
const TTypedData extends TypedData | Record<string, unknown>,
|
|
22
23
|
TPrimaryType extends keyof TTypedData | "EIP712Domain" = keyof TTypedData,
|
|
23
24
|
>(_params: TypedDataDefinition<TTypedData, TPrimaryType>): Promise<Hex> {
|
|
24
|
-
throw new
|
|
25
|
+
throw new BaseError("signTypedData not implemented by dummy signer.");
|
|
25
26
|
},
|
|
26
27
|
});
|