@alchemy/wallet-apis 0.0.0-alpha.14 → 0.0.0-alpha.16
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/actions/grantPermissions.js +9 -2
- package/dist/esm/actions/grantPermissions.js.map +1 -1
- package/dist/esm/actions/listAccounts.d.ts +10 -2
- package/dist/esm/actions/listAccounts.js +23 -2
- package/dist/esm/actions/listAccounts.js.map +1 -1
- package/dist/esm/actions/requestAccount.d.ts +10 -3
- package/dist/esm/actions/requestAccount.js +43 -15
- package/dist/esm/actions/requestAccount.js.map +1 -1
- package/dist/esm/actions/sendCalls.d.ts +4 -0
- package/dist/esm/actions/sendCalls.js +26 -4
- package/dist/esm/actions/sendCalls.js.map +1 -1
- package/dist/esm/actions/sendPreparedCalls.js +2 -0
- package/dist/esm/actions/sendPreparedCalls.js.map +1 -1
- package/dist/esm/actions/signMessage.js +5 -1
- package/dist/esm/actions/signMessage.js.map +1 -1
- package/dist/esm/actions/signPreparedCalls.js +6 -1
- package/dist/esm/actions/signPreparedCalls.js.map +1 -1
- package/dist/esm/actions/signSignatureRequest.d.ts +10 -3
- package/dist/esm/actions/signSignatureRequest.js +93 -42
- package/dist/esm/actions/signSignatureRequest.js.map +1 -1
- package/dist/esm/actions/signTypedData.js +5 -1
- package/dist/esm/actions/signTypedData.js.map +1 -1
- package/dist/esm/client.d.ts +4 -4
- package/dist/esm/client.js +3 -13
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/types.d.ts +4 -7
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/assertions.d.ts +6 -2
- package/dist/esm/utils/assertions.js +9 -0
- package/dist/esm/utils/assertions.js.map +1 -1
- package/dist/esm/utils/capabilities.d.ts +13 -4
- package/dist/esm/utils/capabilities.js +37 -11
- package/dist/esm/utils/capabilities.js.map +1 -1
- package/dist/esm/utils/format.d.ts +3 -1
- package/dist/esm/utils/format.js +11 -1
- package/dist/esm/utils/format.js.map +1 -1
- package/dist/esm/utils/signer.d.ts +10 -0
- package/dist/esm/utils/signer.js +28 -0
- package/dist/esm/utils/signer.js.map +1 -0
- package/dist/esm/utils/viemDecode.d.ts +1 -1
- package/dist/esm/utils/viemDecode.js.map +1 -1
- package/dist/esm/utils/viemEncode.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/actions/grantPermissions.d.ts.map +1 -1
- package/dist/types/actions/listAccounts.d.ts +10 -2
- package/dist/types/actions/listAccounts.d.ts.map +1 -1
- package/dist/types/actions/requestAccount.d.ts +10 -3
- package/dist/types/actions/requestAccount.d.ts.map +1 -1
- package/dist/types/actions/sendCalls.d.ts +4 -0
- package/dist/types/actions/sendCalls.d.ts.map +1 -1
- package/dist/types/actions/sendPreparedCalls.d.ts.map +1 -1
- package/dist/types/actions/signMessage.d.ts.map +1 -1
- package/dist/types/actions/signPreparedCalls.d.ts.map +1 -1
- package/dist/types/actions/signSignatureRequest.d.ts +10 -3
- package/dist/types/actions/signSignatureRequest.d.ts.map +1 -1
- package/dist/types/actions/signTypedData.d.ts.map +1 -1
- package/dist/types/client.d.ts +4 -4
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/types.d.ts +4 -7
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/assertions.d.ts +6 -2
- package/dist/types/utils/assertions.d.ts.map +1 -1
- package/dist/types/utils/capabilities.d.ts +13 -4
- package/dist/types/utils/capabilities.d.ts.map +1 -1
- package/dist/types/utils/format.d.ts +3 -1
- package/dist/types/utils/format.d.ts.map +1 -1
- package/dist/types/utils/signer.d.ts +11 -0
- package/dist/types/utils/signer.d.ts.map +1 -0
- package/dist/types/utils/viemDecode.d.ts +1 -1
- package/dist/types/utils/viemDecode.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +7 -6
- package/src/actions/grantPermissions.ts +13 -2
- package/src/actions/listAccounts.ts +39 -5
- package/src/actions/requestAccount.ts +67 -22
- package/src/actions/sendCalls.ts +40 -4
- package/src/actions/sendPreparedCalls.ts +3 -0
- package/src/actions/signMessage.ts +8 -0
- package/src/actions/signPreparedCalls.ts +14 -1
- package/src/actions/signSignatureRequest.ts +165 -54
- package/src/actions/signTypedData.ts +8 -0
- package/src/client.ts +5 -23
- package/src/types.ts +5 -5
- package/src/utils/assertions.ts +21 -2
- package/src/utils/capabilities.ts +56 -15
- package/src/utils/format.ts +20 -1
- package/src/utils/signer.ts +36 -0
- package/src/utils/viemDecode.ts +1 -1
- package/src/utils/viemEncode.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -6,11 +6,21 @@ import type {
|
|
|
6
6
|
Eip7702UnsignedAuth,
|
|
7
7
|
} from "@alchemy/wallet-api-types";
|
|
8
8
|
import { vToYParity } from "ox/Signature";
|
|
9
|
-
import type {
|
|
10
|
-
|
|
9
|
+
import type {
|
|
10
|
+
InnerWalletApiClient,
|
|
11
|
+
SignerClient,
|
|
12
|
+
WithoutRawPayload,
|
|
13
|
+
} from "../types";
|
|
14
|
+
import { assertNever, BaseError } from "@alchemy/common";
|
|
15
|
+
import { LOGGER } from "../logger.js";
|
|
16
|
+
import { isLocalAccount, isWebAuthnAccount } from "../utils/assertions.js";
|
|
11
17
|
import { getAction } from "viem/utils";
|
|
12
18
|
import { signAuthorization, signMessage, signTypedData } from "viem/actions";
|
|
13
|
-
import {
|
|
19
|
+
import type {
|
|
20
|
+
WebAuthnSignReturnType,
|
|
21
|
+
WebAuthnAccount,
|
|
22
|
+
} from "viem/account-abstraction";
|
|
23
|
+
import type { LocalAccount } from "viem";
|
|
14
24
|
|
|
15
25
|
export type SignSignatureRequestParams = Prettify<
|
|
16
26
|
WithoutRawPayload<
|
|
@@ -22,16 +32,27 @@ export type SignSignatureRequestParams = Prettify<
|
|
|
22
32
|
>
|
|
23
33
|
>;
|
|
24
34
|
|
|
25
|
-
export type SignSignatureRequestResult =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
35
|
+
export type SignSignatureRequestResult =
|
|
36
|
+
| {
|
|
37
|
+
type: "secp256k1";
|
|
38
|
+
data: Hex;
|
|
39
|
+
}
|
|
40
|
+
| {
|
|
41
|
+
type: "webauthn-p256";
|
|
42
|
+
data: {
|
|
43
|
+
signature: Hex;
|
|
44
|
+
metadata: Pick<
|
|
45
|
+
WebAuthnSignReturnType["webauthn"],
|
|
46
|
+
"clientDataJSON" | "authenticatorData"
|
|
47
|
+
>;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
29
50
|
|
|
30
51
|
/**
|
|
31
52
|
* Signs a signature request using the provided signer.
|
|
32
53
|
* This method handles different types of signature requests including personal_sign, eth_signTypedData_v4, and authorization.
|
|
33
54
|
*
|
|
34
|
-
* @param {
|
|
55
|
+
* @param {InnerWalletApiClient} client - The wallet client to use for signing
|
|
35
56
|
* @param {SignSignatureRequestParams} params - The signature request parameters
|
|
36
57
|
* @param {string} params.type - The type of signature request ('personal_sign', 'eth_signTypedData_v4', or 'signature_with_authorization')
|
|
37
58
|
* @param {SignSignatureRequestParams["data"]} params.data - The data to sign, format depends on the signature type
|
|
@@ -63,73 +84,163 @@ export async function signSignatureRequest(
|
|
|
63
84
|
params: SignSignatureRequestParams,
|
|
64
85
|
): Promise<SignSignatureRequestResult> {
|
|
65
86
|
LOGGER.debug("signSignatureRequest:start", { type: params.type });
|
|
66
|
-
const actions = {
|
|
67
|
-
signMessage: getAction(client.owner, signMessage, "signMessage"),
|
|
68
|
-
signTypedData: getAction(client.owner, signTypedData, "signTypedData"),
|
|
69
|
-
signAuthorization: getAction(
|
|
70
|
-
client.owner,
|
|
71
|
-
signAuthorization,
|
|
72
|
-
"signAuthorization",
|
|
73
|
-
),
|
|
74
|
-
};
|
|
75
87
|
|
|
88
|
+
if (isWebAuthnAccount(client.owner)) {
|
|
89
|
+
return signWithWebAuthn(client.owner, params);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (isLocalAccount(client.owner)) {
|
|
93
|
+
return signWithLocalAccount(client.owner, params);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return signWithSignerClient(client.owner, params);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
100
|
+
// WebAuthn signer
|
|
101
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
type WebAuthnResult = Extract<
|
|
104
|
+
SignSignatureRequestResult,
|
|
105
|
+
{ type: "webauthn-p256" }
|
|
106
|
+
>;
|
|
107
|
+
|
|
108
|
+
async function signWithWebAuthn(
|
|
109
|
+
signer: WebAuthnAccount,
|
|
110
|
+
params: SignSignatureRequestParams,
|
|
111
|
+
): Promise<WebAuthnResult> {
|
|
76
112
|
switch (params.type) {
|
|
77
113
|
case "personal_sign": {
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}),
|
|
84
|
-
} as const;
|
|
85
|
-
LOGGER.debug("signSignatureRequest:personal_sign:ok");
|
|
86
|
-
return res;
|
|
114
|
+
const { signature, webauthn: metadata } = await signer.signMessage({
|
|
115
|
+
message: params.data,
|
|
116
|
+
});
|
|
117
|
+
LOGGER.debug("signSignatureRequest:webauthn:personal_sign:ok");
|
|
118
|
+
return { type: "webauthn-p256", data: { signature, metadata } };
|
|
87
119
|
}
|
|
88
120
|
case "eth_signTypedData_v4": {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
121
|
+
const { signature, webauthn: metadata } = await signer.signTypedData(
|
|
122
|
+
params.data,
|
|
123
|
+
);
|
|
124
|
+
LOGGER.debug("signSignatureRequest:webauthn:eth_signTypedData_v4:ok");
|
|
125
|
+
return { type: "webauthn-p256", data: { signature, metadata } };
|
|
126
|
+
}
|
|
127
|
+
case "eip7702Auth":
|
|
128
|
+
throw new BaseError(
|
|
129
|
+
"WebAuthn account cannot sign EIP-7702 authorization requests",
|
|
130
|
+
);
|
|
131
|
+
default:
|
|
132
|
+
LOGGER.warn("signSignatureRequest:unknown-type", {
|
|
133
|
+
type: (params as { type?: unknown }).type,
|
|
134
|
+
});
|
|
135
|
+
return assertNever(params, "Unexpected signature request type.");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
140
|
+
// LocalAccount signer
|
|
141
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
type Secp256k1Result = Extract<
|
|
144
|
+
SignSignatureRequestResult,
|
|
145
|
+
{ type: "secp256k1" }
|
|
146
|
+
>;
|
|
147
|
+
|
|
148
|
+
async function signWithLocalAccount(
|
|
149
|
+
signer: LocalAccount,
|
|
150
|
+
params: SignSignatureRequestParams,
|
|
151
|
+
): Promise<Secp256k1Result> {
|
|
152
|
+
switch (params.type) {
|
|
153
|
+
case "personal_sign": {
|
|
154
|
+
const data = await signer.signMessage({ message: params.data });
|
|
155
|
+
LOGGER.debug("signSignatureRequest:localAccount:personal_sign:ok");
|
|
156
|
+
return { type: "secp256k1", data };
|
|
157
|
+
}
|
|
158
|
+
case "eth_signTypedData_v4": {
|
|
159
|
+
const data = await signer.signTypedData(params.data);
|
|
160
|
+
LOGGER.debug("signSignatureRequest:localAccount:eth_signTypedData_v4:ok");
|
|
161
|
+
return { type: "secp256k1", data };
|
|
98
162
|
}
|
|
99
163
|
case "eip7702Auth": {
|
|
164
|
+
if (!signer.signAuthorization) {
|
|
165
|
+
throw new BaseError(
|
|
166
|
+
"Current signer does not support signing authorization requests",
|
|
167
|
+
);
|
|
168
|
+
}
|
|
100
169
|
const {
|
|
101
170
|
r,
|
|
102
171
|
s,
|
|
103
172
|
v,
|
|
104
173
|
yParity: _yParity,
|
|
105
|
-
} = await
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
nonce: hexToNumber(params.data.nonce),
|
|
110
|
-
},
|
|
111
|
-
account: client.owner.account,
|
|
174
|
+
} = await signer.signAuthorization({
|
|
175
|
+
address: params.data.address,
|
|
176
|
+
chainId: hexToNumber(params.data.chainId),
|
|
177
|
+
nonce: hexToNumber(params.data.nonce),
|
|
112
178
|
});
|
|
113
|
-
// yParity *should* already be a number, but some 3rd
|
|
114
|
-
// party signers may mistakenly return it as a bigint.
|
|
115
179
|
const yParity =
|
|
116
180
|
_yParity != null ? Number(_yParity) : vToYParity(Number(v));
|
|
181
|
+
LOGGER.debug("signSignatureRequest:localAccount:eip7702Auth:ok");
|
|
182
|
+
return {
|
|
183
|
+
type: "secp256k1",
|
|
184
|
+
data: serializeSignature({ r, s, yParity }),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
default:
|
|
188
|
+
LOGGER.warn("signSignatureRequest:unknown-type", {
|
|
189
|
+
type: (params as { type?: unknown }).type,
|
|
190
|
+
});
|
|
191
|
+
return assertNever(params, "Unexpected signature request type.");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
117
194
|
|
|
118
|
-
|
|
195
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
196
|
+
// SignerClient (WalletClient)
|
|
197
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
198
|
+
|
|
199
|
+
async function signWithSignerClient(
|
|
200
|
+
signer: SignerClient,
|
|
201
|
+
params: SignSignatureRequestParams,
|
|
202
|
+
): Promise<Secp256k1Result> {
|
|
203
|
+
switch (params.type) {
|
|
204
|
+
case "personal_sign": {
|
|
205
|
+
const action = getAction(signer, signMessage, "signMessage");
|
|
206
|
+
const data = await action({
|
|
207
|
+
message: params.data,
|
|
208
|
+
account: signer.account,
|
|
209
|
+
});
|
|
210
|
+
LOGGER.debug("signSignatureRequest:signerClient:personal_sign:ok");
|
|
211
|
+
return { type: "secp256k1", data };
|
|
212
|
+
}
|
|
213
|
+
case "eth_signTypedData_v4": {
|
|
214
|
+
const action = getAction(signer, signTypedData, "signTypedData");
|
|
215
|
+
const data = await action({ ...params.data, account: signer.account });
|
|
216
|
+
LOGGER.debug("signSignatureRequest:signerClient:eth_signTypedData_v4:ok");
|
|
217
|
+
return { type: "secp256k1", data };
|
|
218
|
+
}
|
|
219
|
+
case "eip7702Auth": {
|
|
220
|
+
const action = getAction(signer, signAuthorization, "signAuthorization");
|
|
221
|
+
const {
|
|
222
|
+
r,
|
|
223
|
+
s,
|
|
224
|
+
v,
|
|
225
|
+
yParity: _yParity,
|
|
226
|
+
} = await action({
|
|
227
|
+
address: params.data.address,
|
|
228
|
+
chainId: hexToNumber(params.data.chainId),
|
|
229
|
+
nonce: hexToNumber(params.data.nonce),
|
|
230
|
+
account: signer.account,
|
|
231
|
+
});
|
|
232
|
+
const yParity =
|
|
233
|
+
_yParity != null ? Number(_yParity) : vToYParity(Number(v));
|
|
234
|
+
LOGGER.debug("signSignatureRequest:signerClient:eip7702Auth:ok");
|
|
235
|
+
return {
|
|
119
236
|
type: "secp256k1",
|
|
120
|
-
data: serializeSignature({
|
|
121
|
-
|
|
122
|
-
s,
|
|
123
|
-
yParity,
|
|
124
|
-
}),
|
|
125
|
-
} as const;
|
|
126
|
-
LOGGER.debug("signSignatureRequest:eip7702Auth:ok");
|
|
127
|
-
return res;
|
|
237
|
+
data: serializeSignature({ r, s, yParity }),
|
|
238
|
+
};
|
|
128
239
|
}
|
|
129
240
|
default:
|
|
130
241
|
LOGGER.warn("signSignatureRequest:unknown-type", {
|
|
131
242
|
type: (params as { type?: unknown }).type,
|
|
132
243
|
});
|
|
133
|
-
return assertNever(params,
|
|
244
|
+
return assertNever(params, "Unexpected signature request type.");
|
|
134
245
|
}
|
|
135
246
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BaseError,
|
|
2
3
|
type Address,
|
|
3
4
|
type Hex,
|
|
4
5
|
type Prettify,
|
|
@@ -78,6 +79,13 @@ export async function signTypedData(
|
|
|
78
79
|
|
|
79
80
|
const signed = await signSignatureRequest(client, prepared.signatureRequest);
|
|
80
81
|
|
|
82
|
+
// TODO: Wallet server needs to be updated to support webauthn here.
|
|
83
|
+
if (signed.type === "webauthn-p256") {
|
|
84
|
+
throw new BaseError(
|
|
85
|
+
"WebAuthn account is currently unsupported by wallet_formatSign",
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
81
89
|
const formatted = await formatSign(client, {
|
|
82
90
|
from: account.address,
|
|
83
91
|
signature: {
|
package/src/client.ts
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createClient,
|
|
3
|
-
type Address,
|
|
4
|
-
type Chain,
|
|
5
|
-
type LocalAccount,
|
|
6
|
-
createWalletClient,
|
|
7
|
-
} from "viem";
|
|
1
|
+
import { createClient, type Address, type Chain } from "viem";
|
|
8
2
|
import { smartWalletActions } from "./decorators/smartWalletActions.js";
|
|
9
3
|
import { type AlchemyTransport } from "@alchemy/common";
|
|
10
|
-
import type {
|
|
4
|
+
import type { SmartWalletClient, SmartWalletSigner } from "./types.js";
|
|
11
5
|
import { createInternalState } from "./internal.js";
|
|
12
6
|
import type { CreationOptionsBySignerAddress } from "@alchemy/wallet-api-types";
|
|
13
7
|
|
|
14
8
|
export type CreateSmartWalletClientParams<
|
|
15
9
|
TAccount extends Address | undefined = Address | undefined,
|
|
16
10
|
> = {
|
|
17
|
-
signer:
|
|
11
|
+
signer: SmartWalletSigner;
|
|
18
12
|
transport: AlchemyTransport;
|
|
19
13
|
chain: Chain;
|
|
20
14
|
account?: TAccount;
|
|
@@ -30,7 +24,7 @@ export type CreateSmartWalletClientParams<
|
|
|
30
24
|
* Creates a smart wallet client with wallet API actions.
|
|
31
25
|
*
|
|
32
26
|
* @param {CreateSmartWalletClientParams} params - Parameters for creating the smart wallet client.
|
|
33
|
-
* @param {
|
|
27
|
+
* @param {SmartWalletSigner} params.account - The account to use for signing.
|
|
34
28
|
* @param {AlchemyTransport} params.transport - The transport to use for RPC calls.
|
|
35
29
|
* @param {Chain} params.chain - The blockchain network to connect to.
|
|
36
30
|
* @param {string[]} params.policyIds - Optional policy IDs for paymaster service.
|
|
@@ -48,18 +42,6 @@ export const createSmartWalletClient = <
|
|
|
48
42
|
}: CreateSmartWalletClientParams<TAccount>): SmartWalletClient<TAccount> => {
|
|
49
43
|
const _policyIds = [...(policyId ? [policyId] : []), ...(policyIds ?? [])];
|
|
50
44
|
|
|
51
|
-
// If the signer is a `LocalAccount` wrap it inside of a client now so
|
|
52
|
-
// downstream actions can just use `getAction` to get signing actions
|
|
53
|
-
// and `signerClient.account.address` to access the address.
|
|
54
|
-
const signerClient =
|
|
55
|
-
"request" in signer
|
|
56
|
-
? signer
|
|
57
|
-
: createWalletClient({
|
|
58
|
-
account: signer,
|
|
59
|
-
transport,
|
|
60
|
-
chain,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
45
|
return createClient({
|
|
64
46
|
account,
|
|
65
47
|
transport,
|
|
@@ -69,7 +51,7 @@ export const createSmartWalletClient = <
|
|
|
69
51
|
.extend(() => ({
|
|
70
52
|
policyIds: _policyIds,
|
|
71
53
|
internal: createInternalState(),
|
|
72
|
-
owner:
|
|
54
|
+
owner: signer,
|
|
73
55
|
}))
|
|
74
56
|
.extend(smartWalletActions<TAccount>);
|
|
75
57
|
};
|
package/src/types.ts
CHANGED
|
@@ -11,10 +11,12 @@ import type {
|
|
|
11
11
|
Prettify,
|
|
12
12
|
Transport,
|
|
13
13
|
WalletClient,
|
|
14
|
+
LocalAccount,
|
|
14
15
|
} from "viem";
|
|
15
16
|
import type { InternalState } from "./internal";
|
|
16
17
|
import type { SmartWalletClient1193Methods } from "./provider";
|
|
17
18
|
import type { SmartWalletActions } from "./decorators/smartWalletActions";
|
|
19
|
+
import type { WebAuthnAccount } from "viem/account-abstraction";
|
|
18
20
|
|
|
19
21
|
export type BaseWalletClient<
|
|
20
22
|
TExtend extends { [key: string]: unknown } | undefined =
|
|
@@ -30,12 +32,14 @@ export type BaseWalletClient<
|
|
|
30
32
|
|
|
31
33
|
export type InnerWalletApiClient = BaseWalletClient<{
|
|
32
34
|
internal: InternalState | undefined; // undefined if you want to skip using an internal cache
|
|
33
|
-
owner:
|
|
35
|
+
owner: SmartWalletSigner;
|
|
34
36
|
policyIds?: string[];
|
|
35
37
|
}>;
|
|
36
38
|
|
|
37
39
|
export type SignerClient = WalletClient<Transport, Chain | undefined, Account>;
|
|
38
40
|
|
|
41
|
+
export type SmartWalletSigner = LocalAccount | WebAuthnAccount | SignerClient;
|
|
42
|
+
|
|
39
43
|
export type SmartWalletClientEip1193Provider = Prettify<
|
|
40
44
|
EIP1193Events & {
|
|
41
45
|
request: EIP1193RequestFn<SmartWalletClient1193Methods>;
|
|
@@ -50,10 +54,6 @@ export type OptionalChainId<T> = T extends { chainId: Hex }
|
|
|
50
54
|
? Omit<T, "chainId"> & { chainId?: Hex | undefined }
|
|
51
55
|
: T;
|
|
52
56
|
|
|
53
|
-
export type OptionalSignerAddress<T> = T extends { signerAddress: Address }
|
|
54
|
-
? Omit<T, "signerAddress"> & { signerAddress?: Address | undefined }
|
|
55
|
-
: T;
|
|
56
|
-
|
|
57
57
|
export type WithoutRawPayload<T> = T extends { rawPayload: Hex }
|
|
58
58
|
? Omit<T, "rawPayload">
|
|
59
59
|
: T;
|
package/src/utils/assertions.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { Client } from "viem";
|
|
2
|
-
import type { InnerWalletApiClient } from "../types.js";
|
|
1
|
+
import type { Client, LocalAccount } from "viem";
|
|
2
|
+
import type { InnerWalletApiClient, SignerClient } from "../types.js";
|
|
3
3
|
import { BaseError } from "@alchemy/common";
|
|
4
|
+
import type { WebAuthnAccount } from "viem/account-abstraction";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Type guard function to check if a client is an Alchemy Smart Wallet Client.
|
|
@@ -30,3 +31,21 @@ export function assertSmartWalletClient(
|
|
|
30
31
|
throw new BaseError(message);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
34
|
+
|
|
35
|
+
export function isLocalAccount(
|
|
36
|
+
signer: LocalAccount | WebAuthnAccount | SignerClient,
|
|
37
|
+
): signer is LocalAccount {
|
|
38
|
+
return signer.type === "local";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isWebAuthnAccount(
|
|
42
|
+
signer: LocalAccount | WebAuthnAccount | SignerClient,
|
|
43
|
+
): signer is WebAuthnAccount {
|
|
44
|
+
return signer.type === "webAuthn";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isSignerClient(
|
|
48
|
+
signer: LocalAccount | WebAuthnAccount | SignerClient,
|
|
49
|
+
): signer is SignerClient {
|
|
50
|
+
return "request" in signer;
|
|
51
|
+
}
|
|
@@ -1,24 +1,65 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
PrepareCallsCapabilities,
|
|
3
|
+
SendPreparedCallsCapabilities,
|
|
4
|
+
} from "@alchemy/wallet-api-types/capabilities";
|
|
2
5
|
import type { InnerWalletApiClient } from "../types.js";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Merges client capabilities with capabilities from the request.
|
|
9
|
+
* Uses policyId (singular) when there's one policy, policyIds (array) when multiple.
|
|
6
10
|
*
|
|
7
11
|
* @param {InnerWalletApiClient} client - The inner wallet API client (potentially including global capabilities like policy IDs)
|
|
8
|
-
* @param {
|
|
9
|
-
* @returns {
|
|
12
|
+
* @param {T | undefined} capabilities - Request capabilities to merge with, if any
|
|
13
|
+
* @returns {T | undefined} The merged capabilities object, or original capabilities if no capability configuration exists on the client
|
|
10
14
|
*/
|
|
11
|
-
export const mergeClientCapabilities =
|
|
15
|
+
export const mergeClientCapabilities = <
|
|
16
|
+
T extends PrepareCallsCapabilities | SendPreparedCallsCapabilities,
|
|
17
|
+
>(
|
|
12
18
|
client: InnerWalletApiClient,
|
|
13
|
-
capabilities:
|
|
14
|
-
):
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
capabilities: T | undefined,
|
|
20
|
+
): T | undefined => {
|
|
21
|
+
if (!client.policyIds?.length || capabilities?.paymasterService) {
|
|
22
|
+
return capabilities;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
...capabilities,
|
|
27
|
+
paymasterService:
|
|
28
|
+
client.policyIds.length === 1
|
|
29
|
+
? { policyId: client.policyIds[0] }
|
|
30
|
+
: { policyIds: client.policyIds },
|
|
31
|
+
} as T;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Extracts capabilities from prepareCalls that are usable for sendPreparedCalls.
|
|
36
|
+
* Only permissions and paymasterService (policyId/policyIds & webhookData) are supported.
|
|
37
|
+
*
|
|
38
|
+
* @param {PrepareCallsCapabilities | undefined} capabilities - The prepareCalls capabilities
|
|
39
|
+
* @returns {SendPreparedCallsCapabilities | undefined} The sendPreparedCalls capabilities, or undefined if no relevant capabilities exist
|
|
40
|
+
*/
|
|
41
|
+
export const extractCapabilitiesForSending = (
|
|
42
|
+
capabilities: PrepareCallsCapabilities | undefined,
|
|
43
|
+
): SendPreparedCallsCapabilities | undefined => {
|
|
44
|
+
if (
|
|
45
|
+
capabilities?.permissions == null &&
|
|
46
|
+
capabilities?.paymasterService == null
|
|
47
|
+
) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const paymasterService = capabilities.paymasterService;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
permissions: capabilities.permissions,
|
|
55
|
+
paymasterService:
|
|
56
|
+
paymasterService != null
|
|
57
|
+
? {
|
|
58
|
+
...("policyId" in paymasterService
|
|
59
|
+
? { policyId: paymasterService.policyId }
|
|
60
|
+
: { policyIds: paymasterService.policyIds }),
|
|
61
|
+
webhookData: paymasterService.webhookData,
|
|
62
|
+
}
|
|
63
|
+
: undefined,
|
|
64
|
+
};
|
|
24
65
|
};
|
package/src/utils/format.ts
CHANGED
|
@@ -6,8 +6,13 @@ import {
|
|
|
6
6
|
bytesToHex,
|
|
7
7
|
type TypedDataDefinition,
|
|
8
8
|
getTypesForEIP712Domain,
|
|
9
|
+
sliceHex,
|
|
9
10
|
} from "viem";
|
|
10
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
TypedDataDefinition as WalletServerTypedDataDefinition,
|
|
13
|
+
WebAuthnPublicKey,
|
|
14
|
+
} from "@alchemy/wallet-api-types";
|
|
15
|
+
import type { ToWebAuthnAccountParameters } from "viem/account-abstraction";
|
|
11
16
|
|
|
12
17
|
export const castToHex = (val: string | number | bigint | Hex): Hex => {
|
|
13
18
|
if (isHex(val)) {
|
|
@@ -59,3 +64,17 @@ export const typedDataToJsonSafe = ({
|
|
|
59
64
|
),
|
|
60
65
|
};
|
|
61
66
|
};
|
|
67
|
+
|
|
68
|
+
export function credentialToWebAuthnPublicKey(
|
|
69
|
+
credential: ToWebAuthnAccountParameters["credential"],
|
|
70
|
+
): WebAuthnPublicKey {
|
|
71
|
+
const { x, y } = {
|
|
72
|
+
x: sliceHex(credential.publicKey, 0, 32, { strict: true }),
|
|
73
|
+
y: sliceHex(credential.publicKey, 32, 64, { strict: true }),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
x,
|
|
78
|
+
y,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { toHex, type Address } from "viem";
|
|
2
|
+
import type { SmartWalletSigner } from "../types";
|
|
3
|
+
import type { WebAuthnPublicKey } from "@alchemy/wallet-api-types";
|
|
4
|
+
import { parsePublicKey } from "webauthn-p256";
|
|
5
|
+
|
|
6
|
+
export function getSignerAddressOrPublicKey(
|
|
7
|
+
signer: SmartWalletSigner,
|
|
8
|
+
):
|
|
9
|
+
| { type: "secp256k1"; address: Address }
|
|
10
|
+
| { type: "webauthn-p256"; publicKey: WebAuthnPublicKey } {
|
|
11
|
+
// SignerClient.
|
|
12
|
+
if ("request" in signer) {
|
|
13
|
+
return {
|
|
14
|
+
type: "secp256k1",
|
|
15
|
+
address: signer.account.address,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// LocalAccount.
|
|
20
|
+
if (signer.type === "local") {
|
|
21
|
+
return {
|
|
22
|
+
type: "secp256k1",
|
|
23
|
+
address: signer.address,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// WebAuthnAccount.
|
|
28
|
+
const key = parsePublicKey(signer.publicKey);
|
|
29
|
+
return {
|
|
30
|
+
type: "webauthn-p256",
|
|
31
|
+
publicKey: {
|
|
32
|
+
x: toHex(key.x),
|
|
33
|
+
y: toHex(key.y),
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
package/src/utils/viemDecode.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
PreparedCall_UserOpV060,
|
|
16
16
|
PreparedCall_UserOpV070,
|
|
17
17
|
} from "@alchemy/wallet-api-types";
|
|
18
|
-
import type {
|
|
18
|
+
import type { PrepareCallsCapabilities as WalletApiCapabilities } from "@alchemy/wallet-api-types/capabilities";
|
|
19
19
|
import type {
|
|
20
20
|
ViemEncodedAuthorizationCall,
|
|
21
21
|
ViemEncodedPaymasterPermitCall,
|
package/src/utils/viemEncode.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
PreparedCall_UserOpV060,
|
|
20
20
|
PreparedCall_UserOpV070,
|
|
21
21
|
} from "@alchemy/wallet-api-types";
|
|
22
|
-
import type {
|
|
22
|
+
import type { PrepareCallsCapabilities as WalletApiCapabilities } from "@alchemy/wallet-api-types/capabilities";
|
|
23
23
|
|
|
24
24
|
export type ViemEncodedPreparedCalls =
|
|
25
25
|
| (ViemEncodedUserOperationCall | ViemEncodedPaymasterPermitCall)
|
package/src/version.ts
CHANGED