@account-kit/signer 4.15.2 → 4.16.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 +27 -1
- package/dist/esm/base.js +37 -1
- package/dist/esm/base.js.map +1 -1
- package/dist/esm/client/base.d.ts +3 -1
- package/dist/esm/client/base.js +12 -5
- package/dist/esm/client/base.js.map +1 -1
- package/dist/esm/client/index.d.ts +22 -0
- package/dist/esm/client/index.js +29 -0
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/types.d.ts +1 -0
- package/dist/esm/client/types.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/solanaSigner.d.ts +12 -0
- package/dist/esm/solanaSigner.js +67 -0
- package/dist/esm/solanaSigner.js.map +1 -0
- 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 +27 -1
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/client/base.d.ts +3 -1
- package/dist/types/client/base.d.ts.map +1 -1
- package/dist/types/client/index.d.ts +22 -0
- package/dist/types/client/index.d.ts.map +1 -1
- package/dist/types/client/types.d.ts +1 -0
- package/dist/types/client/types.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/solanaSigner.d.ts +13 -0
- package/dist/types/solanaSigner.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/package.json +5 -4
- package/src/base.ts +35 -2
- package/src/client/base.ts +21 -6
- package/src/client/index.ts +25 -0
- package/src/client/types.ts +1 -0
- package/src/index.ts +2 -1
- package/src/solanaSigner.ts +83 -0
- package/src/version.ts +1 -1
package/dist/types/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "4.
|
|
1
|
+
export declare const VERSION = "4.16.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@account-kit/signer",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.16.0",
|
|
4
4
|
"description": "Core interfaces and clients for interfacing with the Alchemy Signer API",
|
|
5
5
|
"author": "Alchemy",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,8 +49,9 @@
|
|
|
49
49
|
"vitest": "^2.0.4"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@aa-sdk/core": "^4.
|
|
53
|
-
"@account-kit/logging": "^4.
|
|
52
|
+
"@aa-sdk/core": "^4.16.0",
|
|
53
|
+
"@account-kit/logging": "^4.16.0",
|
|
54
|
+
"@solana/web3.js": "^1.98.0",
|
|
54
55
|
"@turnkey/http": "^2.6.2",
|
|
55
56
|
"@turnkey/iframe-stamper": "^1.0.0",
|
|
56
57
|
"@turnkey/viem": "^0.4.8",
|
|
@@ -73,5 +74,5 @@
|
|
|
73
74
|
"url": "https://github.com/alchemyplatform/aa-sdk/issues"
|
|
74
75
|
},
|
|
75
76
|
"homepage": "https://github.com/alchemyplatform/aa-sdk#readme",
|
|
76
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "d0a8f15fb7d10812c29b98f334d9705d46a31e7f"
|
|
77
78
|
}
|
package/src/base.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
type TypedDataDefinition,
|
|
17
17
|
} from "viem";
|
|
18
18
|
import { toAccount } from "viem/accounts";
|
|
19
|
+
import { hashAuthorization, type Authorization } from "viem/experimental";
|
|
19
20
|
import type { Mutate, StoreApi } from "zustand";
|
|
20
21
|
import { subscribeWithSelector } from "zustand/middleware";
|
|
21
22
|
import { createStore } from "zustand/vanilla";
|
|
@@ -27,7 +28,9 @@ import {
|
|
|
27
28
|
SessionManager,
|
|
28
29
|
type SessionManagerParams,
|
|
29
30
|
} from "./session/manager.js";
|
|
31
|
+
import type { SessionManagerEvents } from "./session/types";
|
|
30
32
|
import type { AuthParams } from "./signer";
|
|
33
|
+
import { SolanaSigner } from "./solanaSigner.js";
|
|
31
34
|
import {
|
|
32
35
|
AlchemySignerStatus,
|
|
33
36
|
type AlchemySignerEvent,
|
|
@@ -35,8 +38,6 @@ import {
|
|
|
35
38
|
type ErrorInfo,
|
|
36
39
|
} from "./types.js";
|
|
37
40
|
import { assertNever } from "./utils/typeAssertions.js";
|
|
38
|
-
import type { SessionManagerEvents } from "./session/types";
|
|
39
|
-
import { hashAuthorization, type Authorization } from "viem/experimental";
|
|
40
41
|
|
|
41
42
|
export interface BaseAlchemySignerParams<TClient extends BaseSignerClient> {
|
|
42
43
|
client: TClient;
|
|
@@ -733,6 +734,38 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
733
734
|
});
|
|
734
735
|
};
|
|
735
736
|
|
|
737
|
+
/**
|
|
738
|
+
* Creates a new instance of `SolanaSigner` using the provided inner value.
|
|
739
|
+
* This requires the signer to be authenticated first
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* ```ts
|
|
743
|
+
* import { AlchemyWebSigner } from "@account-kit/signer";
|
|
744
|
+
*
|
|
745
|
+
* const signer = new AlchemyWebSigner({
|
|
746
|
+
* client: {
|
|
747
|
+
* connection: {
|
|
748
|
+
* rpcUrl: "/api/rpc",
|
|
749
|
+
* },
|
|
750
|
+
* iframeConfig: {
|
|
751
|
+
* iframeContainerId: "alchemy-signer-iframe-container",
|
|
752
|
+
* },
|
|
753
|
+
* },
|
|
754
|
+
* });
|
|
755
|
+
*
|
|
756
|
+
* const solanaSigner = signer.toSolanaSigner();
|
|
757
|
+
* ```
|
|
758
|
+
*
|
|
759
|
+
* @returns {SolanaSigner} A new instance of `SolanaSigner`
|
|
760
|
+
*/
|
|
761
|
+
experimental_toSolanaSigner = (): SolanaSigner => {
|
|
762
|
+
if (!this.inner.getUser()) {
|
|
763
|
+
throw new NotAuthenticatedError();
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
return new SolanaSigner(this.inner);
|
|
767
|
+
};
|
|
768
|
+
|
|
736
769
|
private authenticateWithEmail = async (
|
|
737
770
|
params: Extract<AuthParams, { type: "email" }>
|
|
738
771
|
): Promise<User> => {
|
package/src/client/base.ts
CHANGED
|
@@ -4,9 +4,11 @@ import EventEmitter from "eventemitter3";
|
|
|
4
4
|
import { jwtDecode } from "jwt-decode";
|
|
5
5
|
import { sha256, type Hex } from "viem";
|
|
6
6
|
import { NotAuthenticatedError, OAuthProvidersError } from "../errors.js";
|
|
7
|
+
import { addOpenIdIfAbsent, getDefaultScopeAndClaims } from "../oauth.js";
|
|
8
|
+
import type { OauthMode } from "../signer.js";
|
|
7
9
|
import { base64UrlEncode } from "../utils/base64UrlEncode.js";
|
|
8
|
-
import { assertNever } from "../utils/typeAssertions.js";
|
|
9
10
|
import { resolveRelativeUrl } from "../utils/resolveRelativeUrl.js";
|
|
11
|
+
import { assertNever } from "../utils/typeAssertions.js";
|
|
10
12
|
import type {
|
|
11
13
|
AlchemySignerClientEvent,
|
|
12
14
|
AlchemySignerClientEvents,
|
|
@@ -25,8 +27,6 @@ import type {
|
|
|
25
27
|
SignupResponse,
|
|
26
28
|
User,
|
|
27
29
|
} from "./types.js";
|
|
28
|
-
import type { OauthMode } from "../signer.js";
|
|
29
|
-
import { addOpenIdIfAbsent, getDefaultScopeAndClaims } from "../oauth.js";
|
|
30
30
|
|
|
31
31
|
export interface BaseSignerClientParams {
|
|
32
32
|
stamper: TurnkeyClient["stamper"];
|
|
@@ -159,6 +159,8 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
|
|
|
159
159
|
|
|
160
160
|
public abstract lookupUserWithPasskey(user?: User): Promise<User>;
|
|
161
161
|
|
|
162
|
+
public abstract targetPublicKey(): Promise<string>;
|
|
163
|
+
|
|
162
164
|
protected abstract getOauthConfig(): Promise<OauthConfig>;
|
|
163
165
|
|
|
164
166
|
protected abstract getWebAuthnAttestation(
|
|
@@ -315,22 +317,35 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
|
|
|
315
317
|
* that result here.
|
|
316
318
|
*
|
|
317
319
|
* @param {Hex} msg the hex representation of the bytes to sign
|
|
320
|
+
* @param {string} mode specify if signing should happen for solana or ethereum
|
|
318
321
|
* @returns {Promise<Hex>} the signature over the raw hex
|
|
319
322
|
*/
|
|
320
|
-
public signRawMessage = async (
|
|
323
|
+
public signRawMessage = async (
|
|
324
|
+
msg: Hex,
|
|
325
|
+
mode: "SOLANA" | "ETHEREUM" = "ETHEREUM"
|
|
326
|
+
): Promise<Hex> => {
|
|
321
327
|
if (!this.user) {
|
|
322
328
|
throw new NotAuthenticatedError();
|
|
323
329
|
}
|
|
324
330
|
|
|
331
|
+
if (!this.user.solanaAddress && mode === "SOLANA") {
|
|
332
|
+
// TODO: we need to add backwards compatibility for users who signed up before we added Solana support
|
|
333
|
+
throw new Error("No Solana address available for the user");
|
|
334
|
+
}
|
|
335
|
+
|
|
325
336
|
const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
|
|
326
337
|
organizationId: this.user.orgId,
|
|
327
338
|
type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
|
|
328
339
|
timestampMs: Date.now().toString(),
|
|
329
340
|
parameters: {
|
|
330
341
|
encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
|
|
331
|
-
hashFunction:
|
|
342
|
+
hashFunction:
|
|
343
|
+
mode === "ETHEREUM"
|
|
344
|
+
? "HASH_FUNCTION_NO_OP"
|
|
345
|
+
: "HASH_FUNCTION_NOT_APPLICABLE",
|
|
332
346
|
payload: msg,
|
|
333
|
-
signWith:
|
|
347
|
+
signWith:
|
|
348
|
+
mode === "ETHEREUM" ? this.user.address : this.user.solanaAddress!,
|
|
334
349
|
},
|
|
335
350
|
});
|
|
336
351
|
|
package/src/client/index.ts
CHANGED
|
@@ -557,6 +557,31 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
557
557
|
});
|
|
558
558
|
};
|
|
559
559
|
|
|
560
|
+
/**
|
|
561
|
+
* Initializes the iframe stamper and returns its public key.
|
|
562
|
+
*
|
|
563
|
+
* @example
|
|
564
|
+
* ```ts twoslash
|
|
565
|
+
* import { AlchemySignerWebClient } from "@account-kit/signer";
|
|
566
|
+
*
|
|
567
|
+
* const client = new AlchemySignerWebClient({
|
|
568
|
+
* connection: {
|
|
569
|
+
* apiKey: "your-api-key",
|
|
570
|
+
* },
|
|
571
|
+
* iframeConfig: {
|
|
572
|
+
* iframeContainerId: "signer-iframe-container",
|
|
573
|
+
* },
|
|
574
|
+
* });
|
|
575
|
+
*
|
|
576
|
+
* const publicKey = await client.targetPublicKey();
|
|
577
|
+
* ```
|
|
578
|
+
*
|
|
579
|
+
* @returns {Promise<string>} A promise that resolves with the target public key when the iframe stamper is successfully initialized, or throws an error if the target public key is not supported.
|
|
580
|
+
*/
|
|
581
|
+
public override targetPublicKey = async (): Promise<string> => {
|
|
582
|
+
return this.initIframeStamper();
|
|
583
|
+
};
|
|
584
|
+
|
|
560
585
|
private initIframeStamper = async () => {
|
|
561
586
|
if (!this.iframeStamper.publicKey()) {
|
|
562
587
|
await this.iframeStamper.init();
|
package/src/client/types.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -6,12 +6,13 @@ export {
|
|
|
6
6
|
OauthFailedError,
|
|
7
7
|
} from "./client/index.js";
|
|
8
8
|
export type * from "./client/types.js";
|
|
9
|
+
export { NotAuthenticatedError, OAuthProvidersError } from "./errors.js";
|
|
9
10
|
export {
|
|
10
11
|
DEFAULT_SESSION_MS,
|
|
11
12
|
SessionManagerParamsSchema,
|
|
12
13
|
} from "./session/manager.js";
|
|
13
14
|
export type * from "./signer.js";
|
|
14
15
|
export { AlchemyWebSigner } from "./signer.js";
|
|
16
|
+
export type * from "./solanaSigner.js";
|
|
15
17
|
export type * from "./types.js";
|
|
16
18
|
export { AlchemySignerStatus } from "./types.js";
|
|
17
|
-
export { OAuthProvidersError, NotAuthenticatedError } from "./errors.js";
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PublicKey,
|
|
3
|
+
Transaction,
|
|
4
|
+
type VersionedTransaction,
|
|
5
|
+
} from "@solana/web3.js";
|
|
6
|
+
import { size, slice, toBytes, toHex, type ByteArray, type Hex } from "viem";
|
|
7
|
+
import type { BaseSignerClient } from "./client/base";
|
|
8
|
+
import { NotAuthenticatedError } from "./errors.js";
|
|
9
|
+
|
|
10
|
+
// TODO: I don't want this to be a class so that the flow is closer to how we do this for `toViemAccount`
|
|
11
|
+
export class SolanaSigner {
|
|
12
|
+
private alchemyClient: BaseSignerClient;
|
|
13
|
+
public address: string;
|
|
14
|
+
|
|
15
|
+
constructor(client: BaseSignerClient) {
|
|
16
|
+
this.alchemyClient = client;
|
|
17
|
+
if (!client.getUser()) throw new Error("Must be authenticated!");
|
|
18
|
+
|
|
19
|
+
// TODO: also throw here
|
|
20
|
+
this.address = client.getUser()!.solanaAddress!;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async addSignature(
|
|
24
|
+
tx: Transaction | VersionedTransaction
|
|
25
|
+
): Promise<Transaction | VersionedTransaction> {
|
|
26
|
+
const user = this.alchemyClient.getUser();
|
|
27
|
+
if (!user) {
|
|
28
|
+
throw new NotAuthenticatedError();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!user.solanaAddress) {
|
|
32
|
+
throw new Error("no solana address");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const fromKey = new PublicKey(user.solanaAddress);
|
|
36
|
+
const messageToSign = this.getMessageToSign(tx);
|
|
37
|
+
const signature = await this.alchemyClient.signRawMessage(
|
|
38
|
+
messageToSign,
|
|
39
|
+
"SOLANA"
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
tx.addSignature(
|
|
43
|
+
fromKey,
|
|
44
|
+
Buffer.from(toBytes(this.formatSignatureForSolana(signature)))
|
|
45
|
+
);
|
|
46
|
+
return tx;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async signMessage(message: Uint8Array): Promise<ByteArray> {
|
|
50
|
+
const user = this.alchemyClient.getUser();
|
|
51
|
+
if (!user) {
|
|
52
|
+
throw new NotAuthenticatedError();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!user.solanaAddress) {
|
|
56
|
+
throw new Error("no solana address");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const messageToSign = toHex(message);
|
|
60
|
+
const signature = await this.alchemyClient.signRawMessage(
|
|
61
|
+
messageToSign,
|
|
62
|
+
"SOLANA"
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return toBytes(this.formatSignatureForSolana(signature));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private formatSignatureForSolana(signature: Hex): Hex {
|
|
69
|
+
if (size(signature) === 64) return signature;
|
|
70
|
+
|
|
71
|
+
return slice(signature, 0, 64);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private getMessageToSign(tx: Transaction | VersionedTransaction): Hex {
|
|
75
|
+
let messageToSign;
|
|
76
|
+
if (tx instanceof Transaction) {
|
|
77
|
+
messageToSign = tx.serializeMessage();
|
|
78
|
+
} else {
|
|
79
|
+
messageToSign = Buffer.from(tx.message.serialize());
|
|
80
|
+
}
|
|
81
|
+
return toHex(messageToSign);
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/version.ts
CHANGED