@account-kit/wallet-client 0.1.0-alpha.7 → 0.1.0-alpha.9
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 +3 -0
- package/dist/esm/capabilities/index.js +2 -0
- package/dist/esm/capabilities/index.js.map +1 -1
- package/dist/esm/capabilities/multiDimensionalNonce.d.ts +3 -0
- package/dist/esm/capabilities/multiDimensionalNonce.js +7 -0
- package/dist/esm/capabilities/multiDimensionalNonce.js.map +1 -0
- package/dist/esm/client/actions/prepareCalls.d.ts +1 -1
- package/dist/esm/client/actions/prepareCalls.js +1 -1
- package/dist/esm/client/actions/prepareCalls.js.map +1 -1
- package/dist/esm/client/actions/signPreparedCalls.js +26 -37
- package/dist/esm/client/actions/signPreparedCalls.js.map +1 -1
- package/dist/esm/client/actions/signSignatureRequest.d.ts +3 -2
- package/dist/esm/client/actions/signSignatureRequest.js.map +1 -1
- package/dist/esm/exports/internal.d.ts +1 -0
- package/dist/esm/exports/internal.js +1 -0
- package/dist/esm/exports/internal.js.map +1 -1
- package/dist/esm/isomorphic/actions/createSession.js +20 -5
- package/dist/esm/isomorphic/actions/createSession.js.map +1 -1
- package/dist/esm/isomorphic/actions/prepareCalls.js +39 -17
- package/dist/esm/isomorphic/actions/prepareCalls.js.map +1 -1
- package/dist/esm/isomorphic/actions/sendPreparedCalls.js +62 -8
- package/dist/esm/isomorphic/actions/sendPreparedCalls.js.map +1 -1
- package/dist/esm/isomorphic/client.d.ts +9 -0
- package/dist/esm/isomorphic/utils/7702.d.ts +6 -1
- package/dist/esm/isomorphic/utils/7702.js +26 -12
- package/dist/esm/isomorphic/utils/7702.js.map +1 -1
- package/dist/esm/isomorphic/utils/createAccount.d.ts +1 -0
- package/dist/esm/isomorphic/utils/createAccount.js +96 -34
- package/dist/esm/isomorphic/utils/createAccount.js.map +1 -1
- package/dist/esm/isomorphic/utils/supportsFeature.d.ts +4 -0
- package/dist/esm/isomorphic/utils/supportsFeature.js +21 -0
- package/dist/esm/isomorphic/utils/supportsFeature.js.map +1 -0
- package/dist/esm/rpc/request.d.ts +54 -0
- package/dist/esm/rpc/request.js +1 -0
- package/dist/esm/rpc/request.js.map +1 -1
- package/dist/esm/rpc/schema.d.ts +54 -0
- package/dist/esm/schemas.d.ts +35 -1
- package/dist/esm/schemas.js +56 -1
- package/dist/esm/schemas.js.map +1 -1
- package/dist/esm/types.d.ts +3 -0
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils.d.ts +1 -0
- package/dist/esm/utils.js.map +1 -1
- package/dist/types/capabilities/index.d.ts +3 -0
- package/dist/types/capabilities/index.d.ts.map +1 -1
- package/dist/types/capabilities/multiDimensionalNonce.d.ts +4 -0
- package/dist/types/capabilities/multiDimensionalNonce.d.ts.map +1 -0
- package/dist/types/client/actions/prepareCalls.d.ts +1 -1
- package/dist/types/client/actions/signPreparedCalls.d.ts.map +1 -1
- package/dist/types/client/actions/signSignatureRequest.d.ts +3 -2
- package/dist/types/client/actions/signSignatureRequest.d.ts.map +1 -1
- package/dist/types/exports/internal.d.ts +1 -0
- package/dist/types/exports/internal.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 +9 -0
- package/dist/types/isomorphic/client.d.ts.map +1 -1
- package/dist/types/isomorphic/utils/7702.d.ts +6 -1
- package/dist/types/isomorphic/utils/7702.d.ts.map +1 -1
- package/dist/types/isomorphic/utils/createAccount.d.ts +1 -0
- package/dist/types/isomorphic/utils/createAccount.d.ts.map +1 -1
- package/dist/types/isomorphic/utils/supportsFeature.d.ts +5 -0
- package/dist/types/isomorphic/utils/supportsFeature.d.ts.map +1 -0
- package/dist/types/rpc/request.d.ts +54 -0
- package/dist/types/rpc/request.d.ts.map +1 -1
- package/dist/types/rpc/schema.d.ts +54 -0
- package/dist/types/rpc/schema.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +35 -1
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/types.d.ts +3 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils.d.ts +1 -0
- package/dist/types/utils.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/capabilities/index.ts +2 -0
- package/src/capabilities/multiDimensionalNonce.ts +7 -0
- package/src/client/actions/prepareCalls.ts +1 -1
- package/src/client/actions/signPreparedCalls.ts +42 -43
- package/src/client/actions/signSignatureRequest.ts +4 -2
- package/src/exports/internal.ts +1 -0
- package/src/isomorphic/actions/createSession.ts +25 -4
- package/src/isomorphic/actions/prepareCalls.ts +48 -21
- package/src/isomorphic/actions/sendPreparedCalls.ts +69 -9
- package/src/isomorphic/utils/7702.ts +41 -14
- package/src/isomorphic/utils/createAccount.ts +115 -35
- package/src/isomorphic/utils/supportsFeature.ts +34 -0
- package/src/rpc/request.ts +1 -0
- package/src/schemas.ts +94 -3
- package/src/types.ts +4 -0
- package/src/utils.ts +2 -0
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
ChainNotFoundError,
|
|
10
10
|
custom,
|
|
11
11
|
fromHex,
|
|
12
|
+
hashMessage,
|
|
12
13
|
toHex,
|
|
13
14
|
type Chain,
|
|
14
15
|
type Transport,
|
|
@@ -17,7 +18,7 @@ import type { wallet_prepareCalls } from "../../rpc/request.js";
|
|
|
17
18
|
import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
|
|
18
19
|
import { createAccount } from "../utils/createAccount.js";
|
|
19
20
|
import { createDummySigner } from "../utils/createDummySigner.js";
|
|
20
|
-
import { createAuthorizationRequest,
|
|
21
|
+
import { createAuthorizationRequest, isDelegated } from "../utils/7702.js";
|
|
21
22
|
import { InvalidRequestError } from "ox/RpcResponse";
|
|
22
23
|
import { assertNever } from "../../utils.js";
|
|
23
24
|
import { assertValid7702AccountAddress } from "../utils/7702.js";
|
|
@@ -50,20 +51,23 @@ export async function prepareCalls(
|
|
|
50
51
|
assertValid7702AccountAddress(params.from, params.capabilities?.eip7702Auth);
|
|
51
52
|
|
|
52
53
|
// in local mode, we probably want some kind of caching for this
|
|
53
|
-
const { counterfactualInfo, delegation } =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
const { counterfactualInfo, delegation } = await client.request({
|
|
55
|
+
method: "wallet_requestAccount",
|
|
56
|
+
params: [
|
|
57
|
+
params.capabilities?.eip7702Auth
|
|
58
|
+
? {
|
|
59
|
+
signerAddress: params.from,
|
|
60
|
+
creationHint: {
|
|
61
|
+
accountType: "7702",
|
|
62
|
+
},
|
|
63
|
+
includeCounterfactualInfo: true,
|
|
64
|
+
}
|
|
65
|
+
: {
|
|
62
66
|
accountAddress: params.from,
|
|
63
67
|
includeCounterfactualInfo: true,
|
|
64
68
|
},
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
],
|
|
70
|
+
});
|
|
67
71
|
|
|
68
72
|
if (!counterfactualInfo && !delegation) {
|
|
69
73
|
throw new InvalidRequestError({
|
|
@@ -82,13 +86,26 @@ export async function prepareCalls(
|
|
|
82
86
|
delegation,
|
|
83
87
|
});
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
const authorizationRequest =
|
|
90
|
+
delegation &&
|
|
91
|
+
!(await isDelegated(client, {
|
|
92
|
+
address: account.address,
|
|
93
|
+
delegation,
|
|
94
|
+
}))
|
|
95
|
+
? await createAuthorizationRequest(client, {
|
|
96
|
+
address: account.address,
|
|
97
|
+
delegation,
|
|
98
|
+
})
|
|
99
|
+
: undefined;
|
|
100
|
+
|
|
101
|
+
if (params.capabilities?.permissions && authorizationRequest) {
|
|
102
|
+
// The user shouldn't see this in most cases since we require
|
|
103
|
+
// the account to be delegated before creating the session.
|
|
104
|
+
throw new InvalidRequestError({
|
|
105
|
+
message:
|
|
106
|
+
"When using a 7702 account with a session key, the account must be delegated before preparing calls.",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
92
109
|
|
|
93
110
|
if (authorizationRequest) {
|
|
94
111
|
// @ts-expect-error - this is available but not typed as public
|
|
@@ -104,7 +121,12 @@ export async function prepareCalls(
|
|
|
104
121
|
value: x.value ? fromHex(x.value, "bigint") : undefined,
|
|
105
122
|
})),
|
|
106
123
|
account,
|
|
107
|
-
overrides:
|
|
124
|
+
overrides: {
|
|
125
|
+
...params.capabilities?.gasParamsOverride,
|
|
126
|
+
nonceKey: params.capabilities?.nonceOverride?.nonceKey
|
|
127
|
+
? fromHex(params.capabilities.nonceOverride.nonceKey, "bigint")
|
|
128
|
+
: undefined,
|
|
129
|
+
},
|
|
108
130
|
});
|
|
109
131
|
|
|
110
132
|
// The eip7702Auth field should never be included in the UO sig
|
|
@@ -117,6 +139,8 @@ export async function prepareCalls(
|
|
|
117
139
|
|
|
118
140
|
const ep = account.getEntryPoint();
|
|
119
141
|
|
|
142
|
+
const uoHash = ep.getUserOperationHash(hexlifiedUo);
|
|
143
|
+
|
|
120
144
|
const uoRequest = {
|
|
121
145
|
type:
|
|
122
146
|
ep.version === "0.7.0"
|
|
@@ -129,8 +153,11 @@ export async function prepareCalls(
|
|
|
129
153
|
signatureRequest: {
|
|
130
154
|
type: "personal_sign" as const,
|
|
131
155
|
data: {
|
|
132
|
-
raw:
|
|
156
|
+
raw: uoHash,
|
|
133
157
|
},
|
|
158
|
+
rawPayload: hashMessage({
|
|
159
|
+
raw: uoHash,
|
|
160
|
+
}),
|
|
134
161
|
},
|
|
135
162
|
};
|
|
136
163
|
|
|
@@ -85,6 +85,12 @@ export async function sendPreparedCalls(
|
|
|
85
85
|
})
|
|
86
86
|
: [params];
|
|
87
87
|
|
|
88
|
+
if (!userOps.length) {
|
|
89
|
+
throw new InvalidRequestError({
|
|
90
|
+
message: "Calls must include at least one user operation",
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
88
94
|
const authorizations =
|
|
89
95
|
params.type === "array"
|
|
90
96
|
? params.data.filter((it) => it.type === "authorization")
|
|
@@ -120,19 +126,73 @@ export async function sendPreparedCalls(
|
|
|
120
126
|
? parseSignature(decodeSignature(authorization.signature).data)
|
|
121
127
|
: undefined;
|
|
122
128
|
const uoSigHex = decodeSignature(userOp.signature).data;
|
|
129
|
+
|
|
130
|
+
const { counterfactualInfo, delegation } = await client.request({
|
|
131
|
+
method: "wallet_requestAccount",
|
|
132
|
+
params: [
|
|
133
|
+
{
|
|
134
|
+
accountAddress: userOp.data.sender,
|
|
135
|
+
includeCounterfactualInfo: true,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (!counterfactualInfo && !delegation) {
|
|
141
|
+
throw new InvalidRequestError({
|
|
142
|
+
message:
|
|
143
|
+
"No counterfactual info or delegated implementation address found.",
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const factoryType = counterfactualInfo?.factoryType;
|
|
148
|
+
|
|
149
|
+
// build signature based on account type
|
|
150
|
+
const signature = (() => {
|
|
151
|
+
switch (factoryType) {
|
|
152
|
+
// light accounts
|
|
153
|
+
case "LightAccountV1.0.1":
|
|
154
|
+
case "LightAccountV1.0.2":
|
|
155
|
+
case "LightAccountV1.1.0":
|
|
156
|
+
case "MAv1.0.0-MultiOwner":
|
|
157
|
+
// For LAv1 and MAv1-MultiOwner, we always just pass the signature.
|
|
158
|
+
return uoSigHex;
|
|
159
|
+
case "LightAccountV2.0.0":
|
|
160
|
+
// for LAv2, we need to prepend the "SignatureType.EOA" byte.
|
|
161
|
+
// TODO: Once we support nested smart accounts, switch this byte depending on the signature type.
|
|
162
|
+
return concat(["0x00", uoSigHex]);
|
|
163
|
+
case undefined: // undefined defaults to sma-b
|
|
164
|
+
case "MAv2.0.0-sma-b":
|
|
165
|
+
// For sma-b, we need to handle deferred actions if needed and prepend the "Reserved
|
|
166
|
+
// Signature Segment" and "SignatureType.EOA" bytes
|
|
167
|
+
return deferredAction != null
|
|
168
|
+
? concatHex([
|
|
169
|
+
`0x${deferredAction.slice(68)}`, // Cuts off stuff prepended to the digest (nonce, etc.).
|
|
170
|
+
"0xFF",
|
|
171
|
+
"0x00",
|
|
172
|
+
uoSigHex,
|
|
173
|
+
])
|
|
174
|
+
: concat(["0xFF", "0x00", uoSigHex]);
|
|
175
|
+
case "LightAccountV2.0.0-MultiOwner":
|
|
176
|
+
// for LAv2-MultiOwner, we need to prepend the "SignatureType.EOA" byte
|
|
177
|
+
// TODO: Once we support nested smart accounts, switch this byte depending on the signature type, and add the smart account signer's address.
|
|
178
|
+
return concat(["0x00", uoSigHex]);
|
|
179
|
+
case "MAv2.0.0-ma-ssv":
|
|
180
|
+
case "MAv2.0.0-ma-webauthn":
|
|
181
|
+
case "MAv1.0.0-MultiSig":
|
|
182
|
+
case "unknown":
|
|
183
|
+
throw new InvalidRequestError({
|
|
184
|
+
message: `Unsupported factory type: ${factoryType}`,
|
|
185
|
+
});
|
|
186
|
+
default:
|
|
187
|
+
return assertNever(factoryType, "Unsupported factory type");
|
|
188
|
+
}
|
|
189
|
+
})();
|
|
190
|
+
|
|
123
191
|
return client
|
|
124
192
|
.sendRawUserOperation(
|
|
125
193
|
{
|
|
126
194
|
...userOp.data,
|
|
127
|
-
signature
|
|
128
|
-
deferredAction != null
|
|
129
|
-
? concatHex([
|
|
130
|
-
`0x${deferredAction.slice(68)}`, // Cuts off stuff prepended to the digest (nonce, etc. that we had previously).
|
|
131
|
-
"0xff",
|
|
132
|
-
"0x00",
|
|
133
|
-
uoSigHex,
|
|
134
|
-
])
|
|
135
|
-
: concat(["0xFF", "0x00", uoSigHex]),
|
|
195
|
+
signature,
|
|
136
196
|
eip7702Auth:
|
|
137
197
|
idx === 0 && authorization && authSig
|
|
138
198
|
? {
|
|
@@ -6,14 +6,17 @@ import {
|
|
|
6
6
|
type Chain,
|
|
7
7
|
type Transport,
|
|
8
8
|
isAddress,
|
|
9
|
+
hexToNumber,
|
|
9
10
|
} from "viem";
|
|
10
11
|
import type { WalletServerViemRpcSchema } from "../../rpc/schema.js";
|
|
11
12
|
import { PreparedCall_Authorization } from "../../schemas.js";
|
|
12
13
|
import type { Eip7702AuthCapability } from "../../capabilities/eip7702Auth.ts";
|
|
13
14
|
import type { Static } from "@sinclair/typebox";
|
|
14
15
|
import { InvalidRequestError } from "ox/RpcResponse";
|
|
16
|
+
import { hashAuthorization } from "viem/utils";
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
/** Checks if an address is actively delegated on-chain. */
|
|
19
|
+
export const isDelegated = async (
|
|
17
20
|
client: SmartAccountClient<
|
|
18
21
|
Transport,
|
|
19
22
|
Chain,
|
|
@@ -22,12 +25,22 @@ export const createAuthorizationRequest = async (
|
|
|
22
25
|
WalletServerViemRpcSchema
|
|
23
26
|
>,
|
|
24
27
|
params: { address: Address; delegation: Address },
|
|
25
|
-
): Promise<
|
|
28
|
+
): Promise<boolean> => {
|
|
26
29
|
const expectedCode = concatHex(["0xef0100", params.delegation]);
|
|
27
30
|
const code = (await client.getCode({ address: params.address })) ?? "0x";
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
return code.toLowerCase() === expectedCode.toLowerCase();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const createAuthorizationRequest = async (
|
|
35
|
+
client: SmartAccountClient<
|
|
36
|
+
Transport,
|
|
37
|
+
Chain,
|
|
38
|
+
SmartContractAccount | undefined,
|
|
39
|
+
Record<string, unknown>,
|
|
40
|
+
WalletServerViemRpcSchema
|
|
41
|
+
>,
|
|
42
|
+
params: { address: Address; delegation: Address },
|
|
43
|
+
): Promise<Static<typeof PreparedCall_Authorization>> => {
|
|
31
44
|
const data = {
|
|
32
45
|
address: params.delegation,
|
|
33
46
|
nonce: numberToHex(
|
|
@@ -42,6 +55,11 @@ export const createAuthorizationRequest = async (
|
|
|
42
55
|
chainId: numberToHex(client.chain.id),
|
|
43
56
|
signatureRequest: {
|
|
44
57
|
type: "eip7702Auth" as const,
|
|
58
|
+
rawPayload: hashAuthorization({
|
|
59
|
+
chainId: client.chain.id,
|
|
60
|
+
nonce: hexToNumber(data.nonce),
|
|
61
|
+
address: params.delegation,
|
|
62
|
+
}),
|
|
45
63
|
},
|
|
46
64
|
};
|
|
47
65
|
};
|
|
@@ -103,14 +121,23 @@ export const assertValid7702AccountAddress = (
|
|
|
103
121
|
fromAddress: Address,
|
|
104
122
|
eip7702AuthCapability: Static<typeof Eip7702AuthCapability> | undefined,
|
|
105
123
|
) => {
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
if (eip7702AuthCapability) {
|
|
125
|
+
if (
|
|
126
|
+
typeof eip7702AuthCapability === "object" &&
|
|
127
|
+
"account" in eip7702AuthCapability &&
|
|
128
|
+
eip7702AuthCapability?.account !== fromAddress
|
|
129
|
+
) {
|
|
130
|
+
throw new InvalidRequestError({
|
|
131
|
+
message: `EIP-7702 delegation account ${eip7702AuthCapability.account} must match 'from' address ${fromAddress}.`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const delegation = parseDelegation(eip7702AuthCapability);
|
|
136
|
+
|
|
137
|
+
if (!isSupportedDelegationAddress7702(delegation)) {
|
|
138
|
+
throw new InvalidRequestError({
|
|
139
|
+
message: `Unsupported 7702 delegation address: ${delegation}`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
115
142
|
}
|
|
116
143
|
};
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import type { SmartAccountSigner, SmartContractAccount } from "@aa-sdk/core";
|
|
2
2
|
import {
|
|
3
|
+
createLightAccount,
|
|
3
4
|
createModularAccountV2,
|
|
5
|
+
createMultiOwnerLightAccount,
|
|
6
|
+
createMultiOwnerModularAccount,
|
|
4
7
|
type ModularAccountV2,
|
|
5
8
|
} from "@account-kit/smart-contracts";
|
|
6
9
|
import type { StaticDecode } from "@sinclair/typebox";
|
|
7
10
|
import type { Address, Chain, Transport } from "viem";
|
|
8
|
-
import { concatHex, hexToNumber } from "viem";
|
|
11
|
+
import { concatHex, hexToBigInt, hexToNumber, zeroAddress } from "viem";
|
|
9
12
|
import type { TypeSerializedInitcode } from "../../schemas.js";
|
|
10
13
|
import { parsePermissionsContext } from "./parsePermissionsContext.js";
|
|
11
14
|
import { assertNever } from "../../utils.js";
|
|
12
15
|
import { getAccountTypeForDelegationAddress7702 } from "./7702.js";
|
|
13
|
-
import { InternalError } from "ox/RpcResponse";
|
|
14
16
|
import { PermissionsCapability } from "../../capabilities/permissions/index.js";
|
|
17
|
+
import { InternalError, InvalidRequestError } from "ox/RpcResponse";
|
|
15
18
|
|
|
16
19
|
type CreateAccountParams = {
|
|
17
20
|
chain: Chain;
|
|
@@ -33,32 +36,8 @@ export async function createAccount(
|
|
|
33
36
|
): Promise<SmartContractAccount> {
|
|
34
37
|
const { counterfactualInfo: ci, ...accountParams } = params;
|
|
35
38
|
|
|
36
|
-
|
|
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 = getAccountTypeForDelegationAddress7702(
|
|
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");
|
|
60
|
-
}
|
|
61
|
-
|
|
39
|
+
// This throws if we pass a permission context and the account is not MA-v2
|
|
40
|
+
// TODO: test that this edge case is handled correctly
|
|
62
41
|
const parsedContext = parsePermissionsContext(
|
|
63
42
|
params.permissions,
|
|
64
43
|
ci,
|
|
@@ -73,14 +52,91 @@ export async function createAccount(
|
|
|
73
52
|
}
|
|
74
53
|
: undefined;
|
|
75
54
|
|
|
76
|
-
|
|
77
|
-
|
|
55
|
+
const mode = params.delegation ? "7702" : "default";
|
|
56
|
+
|
|
57
|
+
if (mode === "7702") {
|
|
58
|
+
const accountType = getAccountTypeForDelegationAddress7702(
|
|
59
|
+
params.delegation!,
|
|
60
|
+
);
|
|
61
|
+
if (accountType !== "ModularAccountV2") {
|
|
62
|
+
throw new Error("7702 mode currently only supports ModularAccountV2");
|
|
63
|
+
}
|
|
64
|
+
return createModularAccountV2({
|
|
65
|
+
...accountParams,
|
|
66
|
+
signerEntity,
|
|
67
|
+
deferredAction: parsedContext?.deferredAction,
|
|
68
|
+
mode,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (mode !== "default") {
|
|
73
|
+
return assertNever(mode, "Unexpected mode in createAccount");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// At this point, we are guaranteed to be in default mode, where ci
|
|
77
|
+
// (counterfactualInfo) must be defined
|
|
78
|
+
|
|
79
|
+
if (!ci) {
|
|
80
|
+
throw new InternalError({
|
|
81
|
+
message: "Counterfactual info not found",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const factoryType = ci.factoryType;
|
|
86
|
+
const commonParams = {
|
|
78
87
|
...accountParams,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
88
|
+
initCode: concatHex([ci.factoryAddress, ci.factoryData]),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Return the account created based on the factory type
|
|
92
|
+
switch (factoryType) {
|
|
93
|
+
case "MAv2.0.0-sma-b":
|
|
94
|
+
return createModularAccountV2({
|
|
95
|
+
...commonParams,
|
|
96
|
+
signerEntity,
|
|
97
|
+
deferredAction: parsedContext?.deferredAction,
|
|
98
|
+
mode,
|
|
99
|
+
});
|
|
100
|
+
case "LightAccountV2.0.0":
|
|
101
|
+
return createLightAccount({
|
|
102
|
+
...commonParams,
|
|
103
|
+
version: "v2.0.0",
|
|
104
|
+
});
|
|
105
|
+
case "LightAccountV1.0.1":
|
|
106
|
+
return createLightAccount({
|
|
107
|
+
...commonParams,
|
|
108
|
+
version: "v1.0.1",
|
|
109
|
+
});
|
|
110
|
+
case "LightAccountV1.0.2":
|
|
111
|
+
return createLightAccount({
|
|
112
|
+
...commonParams,
|
|
113
|
+
version: "v1.0.2",
|
|
114
|
+
});
|
|
115
|
+
case "LightAccountV1.1.0":
|
|
116
|
+
return createLightAccount({
|
|
117
|
+
...commonParams,
|
|
118
|
+
version: "v1.1.0",
|
|
119
|
+
});
|
|
120
|
+
case "MAv1.0.0-MultiOwner":
|
|
121
|
+
return createMultiOwnerModularAccount({
|
|
122
|
+
...commonParams,
|
|
123
|
+
});
|
|
124
|
+
case "LightAccountV2.0.0-MultiOwner":
|
|
125
|
+
return createMultiOwnerLightAccount({
|
|
126
|
+
...commonParams,
|
|
127
|
+
version: "v2.0.0",
|
|
128
|
+
});
|
|
129
|
+
case "MAv1.0.0-MultiSig":
|
|
130
|
+
case "MAv2.0.0-ma-ssv":
|
|
131
|
+
case "MAv2.0.0-ma-webauthn":
|
|
132
|
+
case "unknown":
|
|
133
|
+
case undefined:
|
|
134
|
+
throw new InvalidRequestError({
|
|
135
|
+
message: `Account type currently unsupported: ${factoryType}`,
|
|
136
|
+
});
|
|
137
|
+
default:
|
|
138
|
+
return assertNever(factoryType, "Unsupported factory type");
|
|
139
|
+
}
|
|
84
140
|
}
|
|
85
141
|
|
|
86
142
|
export function isModularAccountV2(
|
|
@@ -88,3 +144,27 @@ export function isModularAccountV2(
|
|
|
88
144
|
): account is ModularAccountV2 {
|
|
89
145
|
return account.source === "ModularAccountV2";
|
|
90
146
|
}
|
|
147
|
+
|
|
148
|
+
// Performs basic checks on the initialOwners array and returns a new array with the signer address added if not present.
|
|
149
|
+
// Pulled from MAv1 support in Account Kit.
|
|
150
|
+
export function prepareInitialOwners(
|
|
151
|
+
initialOwners: Address[],
|
|
152
|
+
signerAddress: Address,
|
|
153
|
+
): Address[] {
|
|
154
|
+
const preparedOwners = Array.from(
|
|
155
|
+
new Set([...initialOwners, signerAddress]),
|
|
156
|
+
).sort((a, b) => {
|
|
157
|
+
const bigintA = hexToBigInt(a);
|
|
158
|
+
const bigintB = hexToBigInt(b);
|
|
159
|
+
|
|
160
|
+
return bigintA < bigintB ? -1 : bigintA > bigintB ? 1 : 0;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (preparedOwners.some((x) => x === zeroAddress)) {
|
|
164
|
+
throw new InvalidRequestError({
|
|
165
|
+
message: "Initial owners cannot contain the zero address",
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return preparedOwners;
|
|
170
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StaticDecode } from "@sinclair/typebox";
|
|
2
|
+
import type { TypeSerializedInitcode } from "../../schemas.ts";
|
|
3
|
+
|
|
4
|
+
export type Feature = "permissions";
|
|
5
|
+
|
|
6
|
+
type FactoryType = StaticDecode<typeof TypeSerializedInitcode>["factoryType"];
|
|
7
|
+
|
|
8
|
+
const supportedFeatures: Record<FactoryType, Feature[]> = {
|
|
9
|
+
"LightAccountV1.0.1": [],
|
|
10
|
+
"LightAccountV1.0.2": [],
|
|
11
|
+
"LightAccountV1.1.0": [],
|
|
12
|
+
"LightAccountV2.0.0": [],
|
|
13
|
+
"LightAccountV2.0.0-MultiOwner": [],
|
|
14
|
+
"MAv1.0.0-MultiOwner": [],
|
|
15
|
+
"MAv1.0.0-MultiSig": [],
|
|
16
|
+
"MAv2.0.0-sma-b": ["permissions"],
|
|
17
|
+
"MAv2.0.0-ma-ssv": ["permissions"],
|
|
18
|
+
"MAv2.0.0-ma-webauthn": [],
|
|
19
|
+
unknown: [],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function supportsFeature(
|
|
23
|
+
counterfactualInfo: StaticDecode<typeof TypeSerializedInitcode>,
|
|
24
|
+
feature: Feature,
|
|
25
|
+
): boolean {
|
|
26
|
+
const factorySupportedFeatures =
|
|
27
|
+
supportedFeatures[counterfactualInfo.factoryType];
|
|
28
|
+
if (factorySupportedFeatures === undefined) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"Unsupported FactoryType: " + counterfactualInfo.factoryType,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return factorySupportedFeatures.includes(feature);
|
|
34
|
+
}
|
package/src/rpc/request.ts
CHANGED
package/src/schemas.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
parseSignature,
|
|
17
17
|
numberToHex,
|
|
18
18
|
} from "viem";
|
|
19
|
+
import type { Expect } from "./utils.ts";
|
|
19
20
|
|
|
20
21
|
const UUID_V4_REGEX =
|
|
21
22
|
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
@@ -24,6 +25,22 @@ FormatRegistry.Set("uuid", (value) => UUID_V4_REGEX.test(value));
|
|
|
24
25
|
const BASE_64_URL_REGEX = /^[A-Za-z0-9_-]+$/; // Matches base64url encoded strings (without padding)
|
|
25
26
|
FormatRegistry.Set("base64url", (value) => BASE_64_URL_REGEX.test(value));
|
|
26
27
|
|
|
28
|
+
export const baseAccountTypes = [
|
|
29
|
+
"sma-b",
|
|
30
|
+
"la-v2",
|
|
31
|
+
"la-v2-multi-owner",
|
|
32
|
+
"la-v1.0.1",
|
|
33
|
+
"la-v1.0.2",
|
|
34
|
+
"la-v1.1.0",
|
|
35
|
+
"ma-v1-multi-owner",
|
|
36
|
+
] as const;
|
|
37
|
+
|
|
38
|
+
export type BaseAccountType = (typeof baseAccountTypes)[number];
|
|
39
|
+
|
|
40
|
+
export const accountTypes = [...baseAccountTypes, "7702"] as const;
|
|
41
|
+
|
|
42
|
+
export type AccountType = (typeof accountTypes)[number];
|
|
43
|
+
|
|
27
44
|
export const TypeHex = (options?: SchemaOptions) =>
|
|
28
45
|
Type.TemplateLiteral("0x${string}", {
|
|
29
46
|
...options,
|
|
@@ -275,7 +292,73 @@ export const TypeCreationOptions = Type.Optional(
|
|
|
275
292
|
salt: Type.Optional(TypeHex()),
|
|
276
293
|
},
|
|
277
294
|
{
|
|
278
|
-
description: "SMA-B account type",
|
|
295
|
+
description: "Modular Account V2 SMA-B account type",
|
|
296
|
+
},
|
|
297
|
+
),
|
|
298
|
+
Type.Object(
|
|
299
|
+
{
|
|
300
|
+
accountType: Type.Literal("la-v2"),
|
|
301
|
+
salt: Type.Optional(TypeHex()),
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
description: "Light Account V2 account type",
|
|
305
|
+
},
|
|
306
|
+
),
|
|
307
|
+
Type.Object(
|
|
308
|
+
{
|
|
309
|
+
accountType: Type.Literal("la-v2-multi-owner"),
|
|
310
|
+
salt: Type.Optional(TypeHex()),
|
|
311
|
+
initialOwners: Type.Optional(
|
|
312
|
+
Type.Array(TypeAddress, {
|
|
313
|
+
description:
|
|
314
|
+
"The initial owners of the account. The signer address will be implicitly added if not specified in this list.",
|
|
315
|
+
}),
|
|
316
|
+
),
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
description: "Light Account V2 Multi-Owner account type",
|
|
320
|
+
},
|
|
321
|
+
),
|
|
322
|
+
Type.Object(
|
|
323
|
+
{
|
|
324
|
+
accountType: Type.Literal("la-v1.0.1"),
|
|
325
|
+
salt: Type.Optional(TypeHex()),
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
description: "Light Account V1.0.1 account type",
|
|
329
|
+
},
|
|
330
|
+
),
|
|
331
|
+
Type.Object(
|
|
332
|
+
{
|
|
333
|
+
accountType: Type.Literal("la-v1.0.2"),
|
|
334
|
+
salt: Type.Optional(TypeHex()),
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
description: "Light Account V1.0.2 account type",
|
|
338
|
+
},
|
|
339
|
+
),
|
|
340
|
+
Type.Object(
|
|
341
|
+
{
|
|
342
|
+
accountType: Type.Literal("la-v1.1.0"),
|
|
343
|
+
salt: Type.Optional(TypeHex()),
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
description: "Light Account V1.1.0 account type",
|
|
347
|
+
},
|
|
348
|
+
),
|
|
349
|
+
Type.Object(
|
|
350
|
+
{
|
|
351
|
+
accountType: Type.Literal("ma-v1-multi-owner"),
|
|
352
|
+
salt: Type.Optional(TypeHex()),
|
|
353
|
+
initialOwners: Type.Optional(
|
|
354
|
+
Type.Array(TypeAddress, {
|
|
355
|
+
description:
|
|
356
|
+
"The initial owners of the account. The signer address will be implicitly added if not specified in this list.",
|
|
357
|
+
}),
|
|
358
|
+
),
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
description: "Modular Account V1 Multi-Owner account type",
|
|
279
362
|
},
|
|
280
363
|
),
|
|
281
364
|
Type.Object(
|
|
@@ -295,10 +378,15 @@ export const TypeCreationOptions = Type.Optional(
|
|
|
295
378
|
);
|
|
296
379
|
export type TypeCreationOptions = Static<typeof TypeCreationOptions>;
|
|
297
380
|
|
|
298
|
-
|
|
381
|
+
type BaseAccountTypeExhaustive = BaseAccountType extends Exclude<
|
|
299
382
|
Static<typeof TypeCreationOptions>,
|
|
300
383
|
undefined
|
|
301
|
-
>["accountType"]
|
|
384
|
+
>["accountType"]
|
|
385
|
+
? true
|
|
386
|
+
: "BaseAccountType values not fully covered in TypeCreationOptions";
|
|
387
|
+
|
|
388
|
+
// Compile-time assertion that TypeCreationOptions covers all BaseAccountType values.
|
|
389
|
+
type _AssertBaseAccountTypeExhaustive = Expect<BaseAccountTypeExhaustive>;
|
|
302
390
|
|
|
303
391
|
export const TypeSignatureType = Type.Union([
|
|
304
392
|
Type.Literal("secp256k1", { description: "Secp256k1" }),
|
|
@@ -371,6 +459,7 @@ export const TypePersonalSignSignatureRequest = Type.Object(
|
|
|
371
459
|
{ description: "Raw message" },
|
|
372
460
|
),
|
|
373
461
|
]),
|
|
462
|
+
rawPayload: TypeHex(),
|
|
374
463
|
},
|
|
375
464
|
{ description: "Personal sign" },
|
|
376
465
|
);
|
|
@@ -379,6 +468,7 @@ export const TypeTypedDataSignatureRequest = Type.Object(
|
|
|
379
468
|
{
|
|
380
469
|
type: Type.Literal("eth_signTypedData_v4"),
|
|
381
470
|
data: TTypedDataDefinition,
|
|
471
|
+
rawPayload: TypeHex(),
|
|
382
472
|
},
|
|
383
473
|
{
|
|
384
474
|
description: "Typed data",
|
|
@@ -387,6 +477,7 @@ export const TypeTypedDataSignatureRequest = Type.Object(
|
|
|
387
477
|
|
|
388
478
|
export const TypeAuthorizationSignatureRequest = Type.Object({
|
|
389
479
|
type: Type.Literal("eip7702Auth"),
|
|
480
|
+
rawPayload: TypeHex(),
|
|
390
481
|
});
|
|
391
482
|
|
|
392
483
|
export const TypeSignatureRequest = Type.Union([
|
package/src/types.ts
CHANGED