@account-kit/signer 4.52.4 → 4.53.1-alpha.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.
Files changed (62) hide show
  1. package/dist/esm/base.d.ts +41 -1
  2. package/dist/esm/base.js +116 -39
  3. package/dist/esm/base.js.map +1 -1
  4. package/dist/esm/client/base.d.ts +14 -1
  5. package/dist/esm/client/base.js +24 -0
  6. package/dist/esm/client/base.js.map +1 -1
  7. package/dist/esm/client/index.d.ts +29 -1
  8. package/dist/esm/client/index.js +37 -0
  9. package/dist/esm/client/index.js.map +1 -1
  10. package/dist/esm/client/types.d.ts +13 -5
  11. package/dist/esm/client/types.js.map +1 -1
  12. package/dist/esm/index.d.ts +1 -0
  13. package/dist/esm/index.js +1 -0
  14. package/dist/esm/index.js.map +1 -1
  15. package/dist/esm/metrics.d.ts +1 -1
  16. package/dist/esm/metrics.js.map +1 -1
  17. package/dist/esm/signer.d.ts +3 -0
  18. package/dist/esm/signer.js.map +1 -1
  19. package/dist/esm/solanaSigner.js +2 -40
  20. package/dist/esm/solanaSigner.js.map +1 -1
  21. package/dist/esm/types.d.ts +1 -0
  22. package/dist/esm/types.js +1 -0
  23. package/dist/esm/types.js.map +1 -1
  24. package/dist/esm/utils/solana.d.ts +21 -0
  25. package/dist/esm/utils/solana.js +72 -0
  26. package/dist/esm/utils/solana.js.map +1 -0
  27. package/dist/esm/version.d.ts +1 -1
  28. package/dist/esm/version.js +1 -1
  29. package/dist/esm/version.js.map +1 -1
  30. package/dist/types/base.d.ts +41 -1
  31. package/dist/types/base.d.ts.map +1 -1
  32. package/dist/types/client/base.d.ts +14 -1
  33. package/dist/types/client/base.d.ts.map +1 -1
  34. package/dist/types/client/index.d.ts +29 -1
  35. package/dist/types/client/index.d.ts.map +1 -1
  36. package/dist/types/client/types.d.ts +13 -5
  37. package/dist/types/client/types.d.ts.map +1 -1
  38. package/dist/types/index.d.ts +1 -0
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/dist/types/metrics.d.ts +1 -1
  41. package/dist/types/metrics.d.ts.map +1 -1
  42. package/dist/types/signer.d.ts +3 -0
  43. package/dist/types/signer.d.ts.map +1 -1
  44. package/dist/types/solanaSigner.d.ts.map +1 -1
  45. package/dist/types/types.d.ts +1 -0
  46. package/dist/types/types.d.ts.map +1 -1
  47. package/dist/types/utils/solana.d.ts +22 -0
  48. package/dist/types/utils/solana.d.ts.map +1 -0
  49. package/dist/types/version.d.ts +1 -1
  50. package/dist/types/version.d.ts.map +1 -1
  51. package/package.json +4 -4
  52. package/src/base.ts +175 -12
  53. package/src/client/base.ts +27 -0
  54. package/src/client/index.ts +37 -0
  55. package/src/client/types.ts +19 -6
  56. package/src/index.ts +4 -0
  57. package/src/metrics.ts +1 -0
  58. package/src/signer.ts +4 -0
  59. package/src/solanaSigner.ts +5 -49
  60. package/src/types.ts +1 -0
  61. package/src/utils/solana.ts +100 -0
  62. package/src/version.ts +1 -1
@@ -47,6 +47,7 @@ import type {
47
47
  OauthProviderInfo,
48
48
  IdTokenOnly,
49
49
  AuthMethods,
50
+ SmsAuthParams,
50
51
  } from "./types.js";
51
52
  import { VERSION } from "../version.js";
52
53
  import { secp256k1 } from "@noble/curves/secp256k1";
@@ -182,6 +183,18 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
182
183
  return response;
183
184
  }
184
185
 
186
+ if (params.type === "sms") {
187
+ this.eventEmitter.emit("authenticating", { type: "otp" });
188
+ const { phone } = params;
189
+ const publicKey = await this.initSessionStamper();
190
+
191
+ const response = await this.request("/v1/signup", {
192
+ phone,
193
+ targetPublicKey: publicKey,
194
+ });
195
+ return response;
196
+ }
197
+
185
198
  this.eventEmitter.emit("authenticating", { type: "passkey" });
186
199
  // Passkey account creation flow
187
200
  const { attestation, challenge } = await this.getWebAuthnAttestation(
@@ -218,6 +231,10 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
218
231
  params: Omit<EmailAuthParams, "targetPublicKey">,
219
232
  ): Promise<{ orgId: string; otpId?: string; multiFactors?: MfaFactor[] }>;
220
233
 
234
+ public abstract initSmsAuth(
235
+ params: Omit<SmsAuthParams, "targetPublicKey">,
236
+ ): Promise<{ orgId: string; otpId?: string }>;
237
+
221
238
  public abstract completeAuthWithBundle(params: {
222
239
  bundle: string;
223
240
  orgId: string;
@@ -645,6 +662,16 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
645
662
  return this.request("/v1/lookup", { email });
646
663
  };
647
664
 
665
+ /**
666
+ * Looks up information based on a phone number.
667
+ *
668
+ * @param {string} phone the phone number to look up
669
+ * @returns {Promise<any>} the result of the lookup request
670
+ */
671
+ public lookupUserByPhone = async (phone: string) => {
672
+ return this.request("/v1/lookup", { phone });
673
+ };
674
+
648
675
  /**
649
676
  * This will sign a message with the user's private key, without doing any transformations on the message.
650
677
  * For SignMessage or SignTypedData, the caller should hash the message before calling this method and pass
@@ -19,6 +19,7 @@ import type {
19
19
  AuthLinkingPrompt,
20
20
  GetWebAuthnAttestationResult,
21
21
  IdTokenOnly,
22
+ SmsAuthParams,
22
23
  } from "./types.js";
23
24
  import { MfaRequiredError } from "../errors.js";
24
25
  import { parseMfaError } from "../utils/parseMfaError.js";
@@ -160,6 +161,42 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
160
161
  }
161
162
  };
162
163
 
164
+ /**
165
+ * Begin authenticating a user through sms. Initializes the iframe stamper to get the target public key.
166
+ * This method sends a text message to the user to complete their login
167
+ *
168
+ * @example
169
+ * ```ts
170
+ * import { AlchemySignerWebClient } from "@account-kit/signer";
171
+ *
172
+ * const client = new AlchemySignerWebClient({
173
+ * connection: {
174
+ * apiKey: "your-api-key",
175
+ * },
176
+ * iframeConfig: {
177
+ * iframeContainerId: "signer-iframe-container",
178
+ * },
179
+ * });
180
+ *
181
+ * const account = await client.initSmsAuth({ phone: "+1234567890" });
182
+ * ```
183
+ *
184
+ * @param {Omit<SmsAuthParams, "targetPublicKey">} params The parameters for sms authentication, excluding the target public key
185
+ * @returns {Promise<any>} The response from the authentication request
186
+ */
187
+ public override initSmsAuth = async (
188
+ params: Omit<SmsAuthParams, "targetPublicKey">,
189
+ ) => {
190
+ this.eventEmitter.emit("authenticating", { type: "otp" });
191
+ const { phone } = params;
192
+ const publicKey = await this.initSessionStamper();
193
+
194
+ return this.request("/v1/auth", {
195
+ phone,
196
+ targetPublicKey: publicKey,
197
+ });
198
+ };
199
+
163
200
  /**
164
201
  * Authenticates using an OTP code which was previously received via email.
165
202
  *
@@ -38,6 +38,10 @@ export type CreateAccountParams =
38
38
  expirationSeconds?: number;
39
39
  redirectParams?: URLSearchParams;
40
40
  }
41
+ | {
42
+ type: "sms";
43
+ phone: string;
44
+ }
41
45
  | {
42
46
  type: "passkey";
43
47
  email: string;
@@ -61,6 +65,11 @@ export type EmailAuthParams = {
61
65
  multiFactors?: VerifyMfaParams[];
62
66
  };
63
67
 
68
+ export type SmsAuthParams = {
69
+ phone: string;
70
+ targetPublicKey: string;
71
+ };
72
+
64
73
  export type OauthParams = Extract<AuthParams, { type: "oauth" }> & {
65
74
  expirationSeconds?: number;
66
75
  fetchIdTokenOnly?: boolean;
@@ -131,6 +140,7 @@ export type SignerEndpoints = [
131
140
  | (Omit<EmailAuthParams, "redirectParams"> & {
132
141
  redirectParams?: string;
133
142
  })
143
+ | SmsAuthParams
134
144
  | {
135
145
  passkey: {
136
146
  challenge: string;
@@ -148,10 +158,12 @@ export type SignerEndpoints = [
148
158
  },
149
159
  {
150
160
  Route: "/v1/auth";
151
- Body: Omit<EmailAuthParams, "redirectParams"> & {
152
- redirectParams?: string;
153
- multiFactors?: VerifyMfaParams[];
154
- };
161
+ Body:
162
+ | (Omit<EmailAuthParams, "redirectParams"> & {
163
+ redirectParams?: string;
164
+ multiFactors?: VerifyMfaParams[];
165
+ })
166
+ | SmsAuthParams;
155
167
  Response: {
156
168
  orgId: string;
157
169
  otpId?: string;
@@ -161,7 +173,8 @@ export type SignerEndpoints = [
161
173
  {
162
174
  Route: "/v1/lookup";
163
175
  Body: {
164
- email: string;
176
+ email?: string;
177
+ phone?: string;
165
178
  };
166
179
  Response: {
167
180
  orgId: string | null;
@@ -334,7 +347,7 @@ export type SignerEndpoints = [
334
347
  ];
335
348
 
336
349
  export type AuthenticatingEventMetadata = {
337
- type: "email" | "passkey" | "oauth" | "otp" | "otpVerify";
350
+ type: "email" | "passkey" | "oauth" | "otp" | "otpVerify" | "sms";
338
351
  };
339
352
 
340
353
  export type AlchemySignerClientEvents = {
package/src/index.ts CHANGED
@@ -21,3 +21,7 @@ export type * from "./solanaSigner.js";
21
21
  export type * from "./types.js";
22
22
  export { AlchemySignerStatus } from "./types.js";
23
23
  export { SolanaSigner } from "./solanaSigner.js";
24
+ export {
25
+ createSolanaSponsoredTransaction,
26
+ createSolanaTransaction,
27
+ } from "./utils/solana.js";
package/src/metrics.ts CHANGED
@@ -8,6 +8,7 @@ export type SignerEventsSchema = [
8
8
  | {
9
9
  authType:
10
10
  | "email"
11
+ | "sms"
11
12
  | "passkey_anon"
12
13
  | "passkey_email"
13
14
  | "otp"
package/src/signer.ts CHANGED
@@ -21,6 +21,10 @@ export type AuthParams =
21
21
  multiFactors?: VerifyMfaParams[];
22
22
  }
23
23
  | { type: "email"; bundle: string; orgId?: string; isNewUser?: boolean }
24
+ | {
25
+ type: "sms";
26
+ phone: string;
27
+ }
24
28
  | {
25
29
  type: "passkey";
26
30
  email: string;
@@ -9,6 +9,7 @@ import {
9
9
  import { size, slice, toBytes, toHex, type ByteArray, type Hex } from "viem";
10
10
  import type { BaseSignerClient } from "./client/base";
11
11
  import { NotAuthenticatedError } from "./errors.js";
12
+ import { createSolanaSponsoredTransaction } from "./utils/solana.js";
12
13
 
13
14
  /**
14
15
  * The SolanaSigner class is used to sign transactions and messages for the Solana blockchain.
@@ -159,53 +160,11 @@ export class SolanaSigner {
159
160
  connection: Connection,
160
161
  policyId: string,
161
162
  ): Promise<VersionedTransaction> {
162
- const { blockhash } = await connection.getLatestBlockhash({
163
- commitment: "finalized",
164
- });
165
- const message = new TransactionMessage({
166
- // Right now the backend will rewrite this payer Key to the server's address
167
- payerKey: new PublicKey(this.address),
168
- recentBlockhash: blockhash,
163
+ return createSolanaSponsoredTransaction(
169
164
  instructions,
170
- }).compileToV0Message();
171
- const versionedTransaction = new VersionedTransaction(message);
172
- const serializedTransaction = Buffer.from(
173
- versionedTransaction.serialize(),
174
- ).toString("base64");
175
- const body = JSON.stringify({
176
- id: crypto?.randomUUID() ?? Math.floor(Math.random() * 1000000),
177
- jsonrpc: "2.0",
178
- method: "alchemy_requestFeePayer",
179
- params: [
180
- {
181
- policyId,
182
- serializedTransaction,
183
- },
184
- ],
185
- });
186
- const options = {
187
- method: "POST",
188
- headers: {
189
- accept: "application/json",
190
- "content-type": "application/json",
191
- },
192
- body,
193
- };
194
-
195
- const response = await fetch(
196
- // TODO: Use the connection??
197
- connection.rpcEndpoint,
198
- options,
199
- );
200
- const jsonResponse = await response.json();
201
- if (!jsonResponse?.result?.serializedTransaction)
202
- throw new Error(
203
- `Response doesn't include the serializedTransaction ${JSON.stringify(
204
- jsonResponse,
205
- )}`,
206
- );
207
- return VersionedTransaction.deserialize(
208
- decodeBase64(jsonResponse.result.serializedTransaction),
165
+ connection,
166
+ policyId,
167
+ this.address,
209
168
  );
210
169
  }
211
170
 
@@ -225,6 +184,3 @@ export class SolanaSigner {
225
184
  return toHex(messageToSign);
226
185
  }
227
186
  }
228
- function decodeBase64(serializedTransaction: string): Uint8Array {
229
- return Buffer.from(serializedTransaction, "base64");
230
- }
package/src/types.ts CHANGED
@@ -24,6 +24,7 @@ export enum AlchemySignerStatus {
24
24
  AUTHENTICATING_EMAIL = "AUTHENTICATING_EMAIL",
25
25
  AUTHENTICATING_OAUTH = "AUTHENTICATING_OAUTH",
26
26
  AWAITING_EMAIL_AUTH = "AWAITING_EMAIL_AUTH",
27
+ AWAITING_SMS_AUTH = "AWAITING_SMS_AUTH",
27
28
  AWAITING_OTP_AUTH = "AWAITING_OTP_AUTH",
28
29
  AWAITING_MFA_AUTH = "AWAITING_MFA_AUTH",
29
30
  }
@@ -0,0 +1,100 @@
1
+ import type { TransactionInstruction } from "@solana/web3.js";
2
+ import {
3
+ Connection,
4
+ PublicKey,
5
+ TransactionMessage,
6
+ VersionedTransaction,
7
+ } from "@solana/web3.js";
8
+
9
+ /**
10
+ * This function wraps instructions in a sponsored transaction using Alchemy's fee payer service
11
+ *
12
+ * @param {TransactionInstruction[]} instructions - The instructions to add sponsorship to
13
+ * @param {Connection} connection - The connection to use
14
+ * @param {string} policyId - The policy id to use
15
+ * @param {string} address - The address to use
16
+ * @returns {Promise<VersionedTransaction>} - The sponsored transaction
17
+ */
18
+ export async function createSolanaSponsoredTransaction(
19
+ instructions: TransactionInstruction[],
20
+ connection: Connection,
21
+ policyId: string,
22
+ address: string,
23
+ ): Promise<VersionedTransaction> {
24
+ const { blockhash } = await connection.getLatestBlockhash({
25
+ commitment: "finalized",
26
+ });
27
+ const message = new TransactionMessage({
28
+ // Right now the backend will rewrite this payer Key to the server's address
29
+ payerKey: new PublicKey(address),
30
+ recentBlockhash: blockhash,
31
+ instructions,
32
+ }).compileToV0Message();
33
+ const versionedTransaction = new VersionedTransaction(message);
34
+ const serializedTransaction = Buffer.from(
35
+ versionedTransaction.serialize(),
36
+ ).toString("base64");
37
+ const body = JSON.stringify({
38
+ id: crypto?.randomUUID() ?? Math.floor(Math.random() * 1000000),
39
+ jsonrpc: "2.0",
40
+ method: "alchemy_requestFeePayer",
41
+ params: [
42
+ {
43
+ policyId,
44
+ serializedTransaction,
45
+ },
46
+ ],
47
+ });
48
+ const options = {
49
+ method: "POST",
50
+ headers: {
51
+ accept: "application/json",
52
+ "content-type": "application/json",
53
+ },
54
+ body,
55
+ };
56
+
57
+ const response = await fetch(
58
+ // TODO: Use the connection??
59
+ connection.rpcEndpoint,
60
+ options,
61
+ );
62
+ const jsonResponse = await response.json();
63
+ if (!jsonResponse?.result?.serializedTransaction)
64
+ throw new Error(
65
+ `Response doesn't include the serializedTransaction ${JSON.stringify(
66
+ jsonResponse,
67
+ )}`,
68
+ );
69
+ return VersionedTransaction.deserialize(
70
+ decodeBase64(jsonResponse.result.serializedTransaction),
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Creates a regular (non-sponsored) Solana transaction from instructions
76
+ *
77
+ * @param {TransactionInstruction[]} instructions - The instructions to create transaction from
78
+ * @param {Connection} connection - The connection to use
79
+ * @param {string} address - The payer address
80
+ * @returns {Promise<VersionedTransaction>} - The transaction
81
+ */
82
+ export async function createSolanaTransaction(
83
+ instructions: TransactionInstruction[],
84
+ connection: Connection,
85
+ address: string,
86
+ ): Promise<VersionedTransaction> {
87
+ const { blockhash } = await connection.getLatestBlockhash({
88
+ commitment: "finalized",
89
+ });
90
+ const message = new TransactionMessage({
91
+ payerKey: new PublicKey(address),
92
+ recentBlockhash: blockhash,
93
+ instructions,
94
+ }).compileToV0Message();
95
+ return new VersionedTransaction(message);
96
+ }
97
+
98
+ function decodeBase64(serializedTransaction: string): Uint8Array {
99
+ return Buffer.from(serializedTransaction, "base64");
100
+ }
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "4.52.4";
3
+ export const VERSION = "4.53.1-alpha.0";