@account-kit/signer 4.63.2 → 4.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/base.d.ts +0 -1
- package/dist/esm/base.js +8 -16
- package/dist/esm/base.js.map +1 -1
- package/dist/esm/client/base.d.ts +14 -0
- package/dist/esm/client/base.js +21 -1
- package/dist/esm/client/base.js.map +1 -1
- package/dist/esm/client/server.d.ts +61 -0
- package/dist/esm/client/server.js +193 -0
- package/dist/esm/client/server.js.map +1 -0
- package/dist/esm/client/types.d.ts +15 -1
- package/dist/esm/client/types.js.map +1 -1
- package/dist/esm/errors.d.ts +4 -0
- package/dist/esm/errors.js +11 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/serverSigner.d.ts +99 -0
- package/dist/esm/serverSigner.js +139 -0
- package/dist/esm/serverSigner.js.map +1 -0
- package/dist/esm/signer.d.ts +7 -1
- package/dist/esm/signer.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/base.d.ts +0 -1
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/client/base.d.ts +14 -0
- package/dist/types/client/base.d.ts.map +1 -1
- package/dist/types/client/server.d.ts +62 -0
- package/dist/types/client/server.d.ts.map +1 -0
- package/dist/types/client/types.d.ts +15 -1
- package/dist/types/client/types.d.ts.map +1 -1
- package/dist/types/errors.d.ts +4 -0
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/serverSigner.d.ts +100 -0
- package/dist/types/serverSigner.d.ts.map +1 -0
- package/dist/types/signer.d.ts +7 -1
- package/dist/types/signer.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +4 -4
- package/src/base.ts +8 -20
- package/src/client/base.ts +29 -1
- package/src/client/server.ts +149 -0
- package/src/client/types.ts +18 -1
- package/src/errors.ts +7 -0
- package/src/index.ts +6 -0
- package/src/serverSigner.ts +171 -0
- package/src/signer.ts +7 -1
- package/src/version.ts +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { ConnectionConfig } from "@aa-sdk/core";
|
|
2
|
+
import { ApiKeyStamper } from "@turnkey/api-key-stamper";
|
|
3
|
+
import type { CreateAccountParams, SignupResponse, User } from "./types";
|
|
4
|
+
import { BaseSignerClient } from "./base.js";
|
|
5
|
+
import { NotAuthenticatedError, UnsupportedFeatureError } from "../errors.js";
|
|
6
|
+
import { TurnkeyClient } from "@turnkey/http";
|
|
7
|
+
import type { AuthParams } from "../signer";
|
|
8
|
+
import { p256 } from "@noble/curves/p256";
|
|
9
|
+
import { bytesToHex } from "@noble/curves/utils";
|
|
10
|
+
|
|
11
|
+
export interface ServerSignerClientParams {
|
|
12
|
+
connection: ConnectionConfig;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const unimplementedFunction = (feature: string) => {
|
|
16
|
+
return () => {
|
|
17
|
+
throw new UnsupportedFeatureError(feature);
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const createDummyStamper = () => {
|
|
22
|
+
return {
|
|
23
|
+
stamp: () => {
|
|
24
|
+
throw new NotAuthenticatedError();
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ServerSignerClient is a client for signing messages using an access key.
|
|
31
|
+
* It extends the BaseSignerClient and uses the ApiKeyStamper for signing.
|
|
32
|
+
* Primarily intended to be used server-side.
|
|
33
|
+
*/
|
|
34
|
+
export class ServerSignerClient extends BaseSignerClient<undefined> {
|
|
35
|
+
/**
|
|
36
|
+
* Creates an instance of ServerSignerClient.
|
|
37
|
+
*
|
|
38
|
+
* @param {ServerSignerClientParams} params The parameters for the client, including the access key and connection configuration
|
|
39
|
+
* @param {ConnectionConfig} params.connection The connection configuration for the client
|
|
40
|
+
* @param {string} params.accessKey The access key to be used for authentication
|
|
41
|
+
* @param {string | undefined} params.accountId An optional ID to identify the account. Only required when using a single access key for multiple signers.
|
|
42
|
+
*/
|
|
43
|
+
constructor({ connection }: ServerSignerClientParams) {
|
|
44
|
+
// we will re-recreate the turnkey client (including the stamper) when we authenticate
|
|
45
|
+
const stamper = createDummyStamper();
|
|
46
|
+
|
|
47
|
+
super({ connection, stamper });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Unsets the user for the client
|
|
52
|
+
*/
|
|
53
|
+
public override disconnect = async (): Promise<void> => {
|
|
54
|
+
this.user = undefined;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a new user with the given parameters.
|
|
59
|
+
*
|
|
60
|
+
* @param {CreateAccountParams} params The parameters for creating the account
|
|
61
|
+
* @returns {Promise<SignupResponse>} A promise that resolves to the signup response
|
|
62
|
+
*/
|
|
63
|
+
public override createAccount = async (
|
|
64
|
+
params: CreateAccountParams,
|
|
65
|
+
): Promise<SignupResponse> => {
|
|
66
|
+
if (params.type !== "accessKey") {
|
|
67
|
+
throw new Error(
|
|
68
|
+
"ServerSignerClient only supports account creation via access key",
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return this.request("/v1/signup", {
|
|
73
|
+
accessKey: {
|
|
74
|
+
publicKey: params.publicKey,
|
|
75
|
+
accountId: params.accountId,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Authenticates the user with an access key.
|
|
82
|
+
*
|
|
83
|
+
* @param {Extract<AuthParams, { type: "accessKey" }>} params The parameters for the authentication
|
|
84
|
+
* @returns {Promise<User>} A promise that resolves to the user
|
|
85
|
+
*/
|
|
86
|
+
public authenticateWithAccessKey = async ({
|
|
87
|
+
accessKey,
|
|
88
|
+
accountId,
|
|
89
|
+
}: Extract<AuthParams, { type: "accessKey" }>): Promise<User> => {
|
|
90
|
+
const publicKey = bytesToHex(p256.getPublicKey(accessKey));
|
|
91
|
+
|
|
92
|
+
const user = await this.lookupUserByAccessKey({
|
|
93
|
+
publicKey,
|
|
94
|
+
accountId,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const orgId =
|
|
98
|
+
user?.orgId ??
|
|
99
|
+
(
|
|
100
|
+
await this.createAccount({
|
|
101
|
+
type: "accessKey",
|
|
102
|
+
publicKey,
|
|
103
|
+
accountId,
|
|
104
|
+
})
|
|
105
|
+
)?.orgId;
|
|
106
|
+
|
|
107
|
+
return this.completeAuthWithApiKey(
|
|
108
|
+
{ publicKey, privateKey: accessKey },
|
|
109
|
+
orgId,
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
private completeAuthWithApiKey = async (
|
|
114
|
+
apiKey: { publicKey: string; privateKey: string },
|
|
115
|
+
subOrgId: string,
|
|
116
|
+
) => {
|
|
117
|
+
this.turnkeyClient = new TurnkeyClient(
|
|
118
|
+
{ baseUrl: "https://api.turnkey.com" },
|
|
119
|
+
new ApiKeyStamper({
|
|
120
|
+
apiPrivateKey: apiKey.privateKey,
|
|
121
|
+
apiPublicKey: apiKey.publicKey,
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const user = await this.whoami(subOrgId);
|
|
126
|
+
this.user = user;
|
|
127
|
+
return user;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Unimplemented functions for server signer.
|
|
132
|
+
* Required to extend the BaseSignerClient class.
|
|
133
|
+
*/
|
|
134
|
+
public initSmsAuth = unimplementedFunction("Sms auth");
|
|
135
|
+
public submitJwt = unimplementedFunction("Jwt");
|
|
136
|
+
protected initSessionStamper = unimplementedFunction("Sessions");
|
|
137
|
+
protected initWebauthnStamper = unimplementedFunction("Webauthn");
|
|
138
|
+
override initEmailAuth = unimplementedFunction("Email auth");
|
|
139
|
+
public override submitOtpCode = unimplementedFunction("Otp code submission");
|
|
140
|
+
override completeAuthWithBundle = unimplementedFunction("Auth with bundle");
|
|
141
|
+
override oauthWithRedirect = unimplementedFunction("OAuth redirect");
|
|
142
|
+
override oauthWithPopup = unimplementedFunction("OAuth popup");
|
|
143
|
+
override exportWallet = unimplementedFunction("Wallet export");
|
|
144
|
+
override targetPublicKey = unimplementedFunction("Target public key");
|
|
145
|
+
override getWebAuthnAttestation = unimplementedFunction(
|
|
146
|
+
"WebAuthn attestation",
|
|
147
|
+
);
|
|
148
|
+
override getOauthConfig = unimplementedFunction("OAuth config");
|
|
149
|
+
}
|
package/src/client/types.ts
CHANGED
|
@@ -64,6 +64,11 @@ export type CreateAccountParams =
|
|
|
64
64
|
type: "passkey";
|
|
65
65
|
username: string;
|
|
66
66
|
creationOpts?: CredentialCreationOptionOverrides;
|
|
67
|
+
}
|
|
68
|
+
| {
|
|
69
|
+
type: "accessKey";
|
|
70
|
+
publicKey: string;
|
|
71
|
+
accountId?: string;
|
|
67
72
|
};
|
|
68
73
|
|
|
69
74
|
export type EmailType = "magicLink" | "otp";
|
|
@@ -83,6 +88,13 @@ export type SmsAuthParams = {
|
|
|
83
88
|
targetPublicKey: string;
|
|
84
89
|
};
|
|
85
90
|
|
|
91
|
+
export type AccessKeyAuthParamsPublicKeyOnly = {
|
|
92
|
+
accessKey: {
|
|
93
|
+
publicKey: string;
|
|
94
|
+
accountId?: string;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
86
98
|
export type OauthParams = Extract<AuthParams, { type: "oauth" }> & {
|
|
87
99
|
expirationSeconds?: number;
|
|
88
100
|
fetchIdTokenOnly?: boolean;
|
|
@@ -173,7 +185,8 @@ export type SignerEndpoints = [
|
|
|
173
185
|
challenge: string;
|
|
174
186
|
attestation: Awaited<ReturnType<typeof getWebAuthnAttestation>>;
|
|
175
187
|
};
|
|
176
|
-
}
|
|
188
|
+
}
|
|
189
|
+
| AccessKeyAuthParamsPublicKeyOnly;
|
|
177
190
|
Response: SignupResponse;
|
|
178
191
|
},
|
|
179
192
|
{
|
|
@@ -202,6 +215,10 @@ export type SignerEndpoints = [
|
|
|
202
215
|
Body: {
|
|
203
216
|
email?: string;
|
|
204
217
|
phone?: string;
|
|
218
|
+
accessKey?: {
|
|
219
|
+
publicKey: string;
|
|
220
|
+
accountId?: string;
|
|
221
|
+
};
|
|
205
222
|
};
|
|
206
223
|
Response: {
|
|
207
224
|
orgId: string | null;
|
package/src/errors.ts
CHANGED
|
@@ -33,3 +33,10 @@ export class MfaRequiredError extends BaseError {
|
|
|
33
33
|
this.multiFactors = multiFactors;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
|
|
37
|
+
export class UnsupportedFeatureError extends BaseError {
|
|
38
|
+
override name = "UnsupportedFeatureError";
|
|
39
|
+
constructor(feature: string) {
|
|
40
|
+
super(`${feature} not supported by this signer`);
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
export { BaseAlchemySigner } from "./base.js";
|
|
2
|
+
export {
|
|
3
|
+
AlchemyServerSigner,
|
|
4
|
+
createServerSigner,
|
|
5
|
+
generateAccessKey,
|
|
6
|
+
} from "./serverSigner.js";
|
|
2
7
|
export { BaseSignerClient } from "./client/base.js";
|
|
3
8
|
export {
|
|
4
9
|
AlchemySignerWebClient,
|
|
5
10
|
OauthCancelledError,
|
|
6
11
|
OauthFailedError,
|
|
7
12
|
} from "./client/index.js";
|
|
13
|
+
export { ServerSignerClient } from "./client/server.js";
|
|
8
14
|
export type * from "./client/types.js";
|
|
9
15
|
export {
|
|
10
16
|
NotAuthenticatedError,
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AuthorizationRequest,
|
|
3
|
+
type SmartAccountSigner,
|
|
4
|
+
unpackSignRawMessageBytes,
|
|
5
|
+
} from "@aa-sdk/core";
|
|
6
|
+
import {
|
|
7
|
+
ServerSignerClient,
|
|
8
|
+
type ServerSignerClientParams,
|
|
9
|
+
} from "./client/server.js";
|
|
10
|
+
import {
|
|
11
|
+
hashMessage,
|
|
12
|
+
hashTypedData,
|
|
13
|
+
type Address,
|
|
14
|
+
type Hex,
|
|
15
|
+
type SignableMessage,
|
|
16
|
+
type SignedAuthorization,
|
|
17
|
+
type TypedData,
|
|
18
|
+
type TypedDataDefinition,
|
|
19
|
+
} from "viem";
|
|
20
|
+
import { hashAuthorization } from "viem/utils";
|
|
21
|
+
import type { AccessKeyAuthParams } from "./signer.js";
|
|
22
|
+
import { SolanaSigner } from "./solanaSigner.js";
|
|
23
|
+
import { p256 } from "@noble/curves/p256";
|
|
24
|
+
import { bytesToHex } from "@noble/curves/utils";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* AlchemyServerSigner is a signer that can sign messages and typed data using an access key.
|
|
28
|
+
* It extends the SmartAccountSigner interface and uses the ServerSignerClient to sign requests.
|
|
29
|
+
* Primarily intended to be used server-side.
|
|
30
|
+
*/
|
|
31
|
+
export class AlchemyServerSigner implements SmartAccountSigner {
|
|
32
|
+
inner: ServerSignerClient;
|
|
33
|
+
signerType = "alchemy-server-signer";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates an instance of AlchemyServerSigner.
|
|
37
|
+
*
|
|
38
|
+
* @param {ServerSignerClient} client The underlying signer client
|
|
39
|
+
*/
|
|
40
|
+
constructor(client: ServerSignerClient) {
|
|
41
|
+
this.inner = client;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Gets the address of the user from the signer client.
|
|
46
|
+
*
|
|
47
|
+
* @returns {Promise<Address>} The address of the user
|
|
48
|
+
* @throws {Error} If the user cannot be retrieved from the signer client
|
|
49
|
+
*/
|
|
50
|
+
async getAddress(): Promise<Address> {
|
|
51
|
+
const { address } = await this.inner.whoami();
|
|
52
|
+
return address;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Signs a message using the inner client.
|
|
57
|
+
*
|
|
58
|
+
* @param {SignableMessage} msg The message to sign
|
|
59
|
+
* @returns {Promise<Hex>} The signed message
|
|
60
|
+
*/
|
|
61
|
+
async signMessage(msg: SignableMessage): Promise<Hex> {
|
|
62
|
+
const messageHash = hashMessage(msg);
|
|
63
|
+
return this.inner.signRawMessage(messageHash);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Signs typed data using the inner client.
|
|
68
|
+
*
|
|
69
|
+
* @param {TypedDataDefinition<TTypedData, TPrimaryType>} params The typed data to sign
|
|
70
|
+
* @returns {Promise<Hex>} The signed typed data
|
|
71
|
+
*/
|
|
72
|
+
async signTypedData<
|
|
73
|
+
const TTypedData extends TypedData | Record<string, unknown>,
|
|
74
|
+
TPrimaryType extends keyof TTypedData | "EIP712Domain" = keyof TTypedData,
|
|
75
|
+
>(params: TypedDataDefinition<TTypedData, TPrimaryType>): Promise<Hex> {
|
|
76
|
+
const messageHash = hashTypedData(params);
|
|
77
|
+
return this.inner.signRawMessage(messageHash);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Signs an authorization using the inner client.
|
|
82
|
+
*
|
|
83
|
+
* @param {Authorization<number, false>} unsignedAuthorization The unsigned authorization to sign
|
|
84
|
+
* @returns {Promise<Authorization<number, true>>} The signed authorization
|
|
85
|
+
*/
|
|
86
|
+
async signAuthorization(
|
|
87
|
+
unsignedAuthorization: AuthorizationRequest<number>,
|
|
88
|
+
): Promise<SignedAuthorization<number>> {
|
|
89
|
+
const hashedAuthorization = hashAuthorization(unsignedAuthorization);
|
|
90
|
+
const signedAuthorizationHex =
|
|
91
|
+
await this.inner.signRawMessage(hashedAuthorization);
|
|
92
|
+
const signature = unpackSignRawMessageBytes(signedAuthorizationHex);
|
|
93
|
+
const { address, contractAddress, ...unsignedAuthorizationRest } =
|
|
94
|
+
unsignedAuthorization;
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
...unsignedAuthorizationRest,
|
|
98
|
+
...signature,
|
|
99
|
+
address: address ?? contractAddress,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a new instance of `SolanaSigner` using the inner client.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* import { AlchemyServerSigner } from "@account-kit/signer";
|
|
109
|
+
*
|
|
110
|
+
* const signer = await createServerSigner({
|
|
111
|
+
* auth: { accessKey },
|
|
112
|
+
* connection: {
|
|
113
|
+
* apiKey: "alchemy-api-key",
|
|
114
|
+
* },
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* const solanaSigner = signer.toSolanaSigner();
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @returns {SolanaSigner} A new instance of `SolanaSigner`
|
|
121
|
+
*/
|
|
122
|
+
toSolanaSigner(): SolanaSigner {
|
|
123
|
+
return new SolanaSigner(this.inner);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
type CreateServerSignerParams = ServerSignerClientParams & {
|
|
128
|
+
auth: AccessKeyAuthParams;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Creates a new server signer.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* const signer = await createServerSigner({
|
|
137
|
+
* auth: { accessKey },
|
|
138
|
+
* connection: {
|
|
139
|
+
* apiKey: "alchemy-api-key",
|
|
140
|
+
* }
|
|
141
|
+
* });
|
|
142
|
+
*
|
|
143
|
+
* console.log("Signer address:", await signer.getAddress());
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @param {CreateServerSignerParams} params Parameters
|
|
147
|
+
* @param {AccessKeyAuthParams} params.auth Authentication config for the server signer
|
|
148
|
+
* @param {ConnectionConfig} params.connection Connection config for the server signer
|
|
149
|
+
* @returns {Promise<AlchemyServerSigner>} A promise that resolves to a server signer
|
|
150
|
+
*/
|
|
151
|
+
export const createServerSigner = async (
|
|
152
|
+
params: CreateServerSignerParams,
|
|
153
|
+
): Promise<AlchemyServerSigner> => {
|
|
154
|
+
const client = new ServerSignerClient(params);
|
|
155
|
+
const signer = new AlchemyServerSigner(client);
|
|
156
|
+
|
|
157
|
+
await signer.inner.authenticateWithAccessKey({
|
|
158
|
+
...params.auth,
|
|
159
|
+
type: "accessKey",
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
return signer;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Generates a new access key for use in the server signer
|
|
167
|
+
*
|
|
168
|
+
* @returns {Hex} A randomly generated access key
|
|
169
|
+
*/
|
|
170
|
+
export const generateAccessKey = () =>
|
|
171
|
+
bytesToHex(p256.utils.randomPrivateKey());
|
package/src/signer.ts
CHANGED
|
@@ -11,6 +11,11 @@ import type {
|
|
|
11
11
|
} from "./client/types.js";
|
|
12
12
|
import { SessionManagerParamsSchema } from "./session/manager.js";
|
|
13
13
|
|
|
14
|
+
export type AccessKeyAuthParams = {
|
|
15
|
+
accessKey: string;
|
|
16
|
+
accountId?: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
14
19
|
export type AuthParams =
|
|
15
20
|
| {
|
|
16
21
|
type: "email";
|
|
@@ -64,7 +69,8 @@ export type AuthParams =
|
|
|
64
69
|
type: "otp";
|
|
65
70
|
otpCode: string;
|
|
66
71
|
multiFactors?: VerifyMfaParams[];
|
|
67
|
-
}
|
|
72
|
+
}
|
|
73
|
+
| ({ type: "accessKey" } & AccessKeyAuthParams);
|
|
68
74
|
|
|
69
75
|
export type OauthProviderConfig =
|
|
70
76
|
| {
|
package/src/version.ts
CHANGED