@tuwaio/siwx-solana 0.3.0 → 0.4.1

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/README.md CHANGED
@@ -1,17 +1,17 @@
1
- # `@tuwaio/siwx-solana`
1
+ # @tuwaio/siwx-solana
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/@tuwaio/siwx-solana.svg)](https://www.npmjs.com/package/@tuwaio/siwx-solana)
4
- [![License](https://img.shields.io/npm/l/@tuwaio/siwx-solana.svg)](./LICENSE)
4
+ [![License](https://img.shields.io/npm/l/@tuwaio/siwx-solana.svg)](https://github.com/TuwaIO/siwx/blob/main/packages/siwx-solana/LICENSE)
5
5
 
6
- > Solana adapter for `@tuwaio/siwx` (L2). Verifies CAIP-122 messages for Solana using native ed25519 cryptography via SubtleCrypto. Compatible with all Wallet Standard wallets.
6
+ `@tuwaio/siwx-solana` is the Solana Layer 2 (L2) package of **SIWX** (Sign-In With X), the authentication project of TUWA Stage 1 ("Core Auth & Primitives", next to Orbit Utils). Built on **`@tuwaio/siwx-core`** and **`@solana/kit`**, it signs CAIP-122 messages with Solana wallets and verifies `solana` ed25519 signatures with the native Web Crypto API. It does not use the legacy `@solana/web3.js` or `gill`.
7
7
 
8
8
  ---
9
9
 
10
10
  ## 🏛️ Core Capabilities
11
11
 
12
- - **ed25519 Verification**: Verifies Solana wallet signatures against CAIP-122 messages using the native `SubtleCrypto` API (no native module dependencies).
13
- - Extracts and validates Solana addresses from CAIP-10 strings using `@solana/kit`.
14
- - Compatible with Node.js (v19+), browsers, and Edge runtimes (Cloudflare Workers, Vercel Edge).
12
+ - **Signing:** `createSolanaSiwxSigner` turns a Wallet Standard wallet and account (typed with `@wallet-standard/base`), an `@solana/kit` message signer or a legacy adapter into the `(message) => signature` function that `useSiwx` from [`@tuwaio/siwx-react`](https://siwx.docs.tuwa.io/packages/siwx-react) expects. Signatures are returned as base58 strings.
13
+ - **Verification:** `verifyEd25519` accepts a `{ message, signature }` payload (base58 strings or bytes) or the output of the Wallet Standard `solana:signIn` feature. It requires a `solana` chain and a 64-byte signature, validates the message (format, expiration, `notBefore` and an `issuedAt` in the future) and the address, and checks the signature with `crypto.subtle`. It runs locally, without RPC calls, and returns `{ success, data, error }` instead of throwing.
14
+ - **Runtimes:** any runtime whose Web Crypto API supports Ed25519, such as Node.js 20+ and current browsers. No native modules or polyfills.
15
15
 
16
16
  ---
17
17
 
@@ -21,70 +21,73 @@
21
21
  pnpm add @tuwaio/siwx-solana @tuwaio/siwx-core @solana/kit @wallet-standard/base
22
22
  ```
23
23
 
24
+ > [!IMPORTANT]
25
+ > `@tuwaio/siwx-core`, `@solana/kit` (>=8.2) and `@wallet-standard/base` (>=1.1.1) are peer dependencies and must be installed alongside `@tuwaio/siwx-solana`.
26
+
24
27
  ---
25
28
 
26
- ## 🚀 API & Module Architecture
29
+ ## 🚀 Usage
27
30
 
28
- ### `verifyEd25519(payload, options?): Promise<SiwxVerifyResult>`
31
+ ### Signing with a Wallet Standard wallet
29
32
 
30
- Verifies a Solana wallet signature. The signature must be base58-encoded (as produced by all Wallet Standard adapters). Accepts optional `options?: { skipExpiration?: boolean }`.
33
+ ```typescript
34
+ import { createSolanaSiwxSigner } from '@tuwaio/siwx-solana';
35
+ import type { Wallet, WalletAccount } from '@wallet-standard/base';
31
36
 
32
- ```ts
33
- import { verifyEd25519 } from '@tuwaio/siwx-solana';
37
+ declare const wallet: Wallet; // a wallet with the `solana:signMessage` feature
38
+ declare const account: WalletAccount; // the connected account, one of `wallet.accounts`
39
+ declare const message: string;
34
40
 
35
- const result = await verifyEd25519({
36
- message: rawCaip122Message,
37
- signature: base58EncodedSignature,
38
- });
41
+ const signer = createSolanaSiwxSigner({ wallet, account });
39
42
 
40
- if (result.success) {
41
- console.log('Solana auth verified for:', result.data?.address);
42
- }
43
+ // Opens the wallet prompt. Rejects with "[SIWX-SOLANA] Signing failed: …" (original error in `cause`).
44
+ const signature = await signer(message); // base58
43
45
  ```
44
46
 
45
- ---
46
-
47
- ### `createSolanaSiwxSigner(signer)`
47
+ Pass the Wallet Standard `Wallet` and `WalletAccount` objects. The UI handles of `@wallet-standard/ui` (`UiWallet`, `UiWalletAccount`) only list feature names and cannot sign.
48
48
 
49
- Creates a standard SIWX signer callback for Solana chains. Automatically adapts to Wallet Standard, Web3 v2 (@solana/kit), or legacy Solana signers.
49
+ ### Signing with other signers
50
50
 
51
- ```ts
51
+ ```typescript
52
+ import type { MessageModifyingSigner } from '@solana/kit';
52
53
  import { createSolanaSiwxSigner } from '@tuwaio/siwx-solana';
53
54
 
54
- const signer = createSolanaSiwxSigner(connectedAccount);
55
- const signature = await signer('Message to sign');
56
- ```
55
+ declare const kitSigner: MessageModifyingSigner; // an @solana/kit message signer
56
+ declare const walletAdapter: { signMessage(message: Uint8Array): Promise<Uint8Array> }; // legacy wallet adapter
57
57
 
58
- ---
58
+ const signWithKit = createSolanaSiwxSigner(kitSigner);
59
+ const signWithAdapter = createSolanaSiwxSigner(walletAdapter);
60
+ ```
59
61
 
60
- ## Wallet Standard Integration
62
+ The signer uses the first capability it finds: `modifyAndSignMessages` (an `@solana/kit` `MessageModifyingSigner`), the `solana:signMessage` feature of `wallet.features`, a `signMessages` method, or a legacy `signMessage` method (also on `adapter`).
61
63
 
62
- When using a Wallet Standard compatible wallet (Phantom, Solflare, Backpack), integration is seamless with the factory:
64
+ ### Verifying a signature
63
65
 
64
- ```ts
65
- import { useSiwx } from '@tuwaio/siwx-react';
66
- import { createSolanaSiwxSigner } from '@tuwaio/siwx-solana';
66
+ ```typescript
67
+ import { verifyEd25519 } from '@tuwaio/siwx-solana';
67
68
 
68
- const { signIn } = useSiwx();
69
+ declare const message: string;
70
+ declare const signature: string; // base58, as returned by createSolanaSiwxSigner
69
71
 
70
- // `connectedAccount` is the `UiWalletAccount` from `@wallet-standard/react`
71
- const signer = createSolanaSiwxSigner(connectedAccount);
72
+ const result = await verifyEd25519({ message, signature });
72
73
 
73
- await signIn({ signer, verifier, fields: { ... } });
74
+ if (result.success) {
75
+ console.log(result.data?.address); // "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpK:…"
76
+ } else {
77
+ console.error(result.error);
78
+ }
74
79
  ```
75
80
 
76
- ---
77
-
78
- ## Peer Dependencies
81
+ The output of the Wallet Standard `solana:signIn` feature can be passed as-is (or as `{ output }`); the signed message must be a CAIP-122 message.
79
82
 
80
- | Package | Version |
81
- | ----------------------- | ------------- |
82
- | `@tuwaio/siwx-core` | `workspace:*` |
83
- | `@solana/kit` | `>=8.2.0` |
84
- | `@wallet-standard/base` | `^1.1.1` |
83
+ `verifyEd25519` does not check the domain, URI, nonce or other policy rules. On a server, use [`@tuwaio/siwx-server`](https://siwx.docs.tuwa.io/packages/siwx-server), which adds the policy and single-use nonces, or run `validatePolicy` from `@tuwaio/siwx-core` yourself.
85
84
 
86
85
  ---
87
86
 
87
+ ## 📚 API Reference
88
+
89
+ Every export, with signatures and types generated from the source, is documented at **[siwx.docs.tuwa.io/packages/siwx-solana](https://siwx.docs.tuwa.io/packages/siwx-solana)**.
90
+
88
91
  ## 📄 License
89
92
 
90
- Licensed under the **Apache-2.0 License**. See the [LICENSE](./LICENSE) file for details.
93
+ Licensed under the **Apache-2.0 License**. See the [LICENSE](https://github.com/TuwaIO/siwx/blob/main/packages/siwx-solana/LICENSE) file for details.
package/dist/index.d.mts CHANGED
@@ -1,51 +1,96 @@
1
+ import { MessageModifyingSigner } from '@solana/kit';
2
+ import { Wallet, WalletAccount } from '@wallet-standard/base';
1
3
  import { SiwxVerifyPayload, SiwxVerifyResult } from '@tuwaio/siwx-core';
2
4
 
3
5
  /**
4
- * Target input for the Solana SIWX signer.
5
- * Accepts raw wallet and account objects, or a unified signer object.
6
+ * @file Solana signer adapter for SIWX authentication.
6
7
  */
7
- interface SolanaSiwxSignerTarget {
8
- account?: Record<string, unknown>;
9
- wallet?: Record<string, unknown>;
10
- [key: string]: unknown;
8
+
9
+ /**
10
+ * A Wallet Standard wallet and the account to sign with. The wallet must provide the `solana:signMessage` feature.
11
+ */
12
+ interface SolanaWalletStandardSignerTarget {
13
+ /** The Wallet Standard wallet. */
14
+ wallet: Wallet;
15
+ /** The connected account, one of `wallet.accounts`. Its `address` identifies the signature. */
16
+ account: WalletAccount;
11
17
  }
12
18
  /**
13
- * Creates a standard SIWX signer callback for Solana chains.
14
- * Automatically adapts to Wallet Standard, Web3 v2 (@solana/kit), or legacy Solana signers.
19
+ * A legacy wallet adapter (for example from `@solana/wallet-adapter-react`) that signs raw message bytes.
20
+ */
21
+ interface SolanaLegacyMessageSigner {
22
+ /**
23
+ * Signs the message bytes.
24
+ * @param message - UTF-8 bytes of the message.
25
+ * @returns The 64-byte ed25519 signature, or an object that contains it.
26
+ */
27
+ signMessage(message: Uint8Array): Promise<Uint8Array | {
28
+ signature: Uint8Array;
29
+ }>;
30
+ }
31
+ /**
32
+ * What {@link createSolanaSiwxSigner} can sign with:
33
+ *
34
+ * - a Wallet Standard `{ wallet, account }` pair ({@link SolanaWalletStandardSignerTarget});
35
+ * - an `@solana/kit` `MessageModifyingSigner`;
36
+ * - a legacy adapter with `signMessage(bytes)` ({@link SolanaLegacyMessageSigner});
37
+ * - any `{ wallet, account }` objects with one of these capabilities, such as a wallet exposing an `adapter` or a
38
+ * `signMessages` method.
15
39
  *
16
- * @param target - A Solana signer target containing raw wallet and account, or a direct signer instance.
17
- * @returns A standardized signer function accepting a message string and returning a promise with the base58 signature.
40
+ * The signer uses the first capability it finds: `modifyAndSignMessages`, the `solana:signMessage` feature of
41
+ * `wallet.features`, a `signMessages` method, or a `signMessage` method (also looked up on `adapter`).
42
+ */
43
+ type SolanaSiwxSignerTarget = SolanaWalletStandardSignerTarget | MessageModifyingSigner | SolanaLegacyMessageSigner | {
44
+ wallet?: object;
45
+ account?: object;
46
+ };
47
+ /**
48
+ * Creates a SIWX signer for Solana wallets: a function that signs a message (UTF-8 bytes) with the wallet and returns
49
+ * the ed25519 signature as a base58 string. Pass it as `signer` to `useSiwx().signIn` from `@tuwaio/siwx-react`.
50
+ *
51
+ * Works with Wallet Standard wallets, `@solana/kit` message signers and legacy adapters; see
52
+ * {@link SolanaSiwxSignerTarget} for how the signing method is chosen.
53
+ *
54
+ * @param target - The Wallet Standard wallet and account, an `@solana/kit` message signer or a legacy adapter.
55
+ * @returns An async signer. Calling it opens the wallet signature prompt; it rejects with an `Error` whose message
56
+ * starts with `[SIWX-SOLANA] Signing failed:` (original error in `cause`) when the target has no signing
57
+ * capability, the wallet rejects, or no signature is returned for the account address.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const signer = createSolanaSiwxSigner({ wallet, account });
62
+ * const signature = await signer(message);
63
+ * ```
18
64
  */
19
65
  declare function createSolanaSiwxSigner(target: SolanaSiwxSignerTarget): (message: string) => Promise<string>;
20
66
 
21
67
  /**
22
- * @fileoverview Solana-specific types for the @tuwaio/siwx-solana package.
68
+ * @file Solana-specific types for the @tuwaio/siwx-solana package.
23
69
  */
24
70
 
25
71
  /**
26
- * Minimal Wallet Standard account interface returned by `solana:signIn`.
72
+ * Minimal account shape of a Wallet Standard `solana:signIn` output.
27
73
  */
28
74
  interface SolanaSignInAccount {
29
- /** Base58 encoded wallet address. */
75
+ /** Base58-encoded wallet address. Not used for verification: the signer is taken from the message `address`. */
30
76
  address: string;
31
- /** Raw public key bytes. */
77
+ /** Raw public key bytes. Not used for verification. */
32
78
  publicKey?: Uint8Array;
33
79
  }
34
80
  /**
35
- * Output object structure returned by Wallet Standard `solana:signIn` feature.
81
+ * Output of the Wallet Standard `solana:signIn` feature, accepted as-is by {@link verifyEd25519}.
36
82
  */
37
83
  interface SolanaSignInOutput {
38
84
  /** Account that signed the message. */
39
85
  account: SolanaSignInAccount;
40
- /** Raw message bytes or string that was signed. */
86
+ /** The signed message, as UTF-8 bytes or a string. It must be a CAIP-122 message. */
41
87
  signedMessage: Uint8Array | string;
42
- /** Raw signature bytes or base58 string. */
88
+ /** The ed25519 signature, as 64 raw bytes or a base58 string. */
43
89
  signature: Uint8Array | string;
44
90
  }
45
91
  /**
46
- * Flexible input type for Solana SIWX verification.
47
- * Accepts standard SIWX payload `{ message, signature }`,
48
- * raw Uint8Array buffers, or Wallet Standard `solana:signIn` output objects.
92
+ * Input of {@link verifyEd25519}: a `{ message, signature }` payload (strings or bytes), a Wallet Standard
93
+ * `solana:signIn` output, or that output wrapped as `{ output }`. String signatures are base58-encoded.
49
94
  */
50
95
  type SolanaVerifyPayload = SiwxVerifyPayload | {
51
96
  message: string | Uint8Array;
@@ -55,21 +100,24 @@ type SolanaVerifyPayload = SiwxVerifyPayload | {
55
100
  };
56
101
 
57
102
  /**
58
- * @fileoverview Solana signature verification for CAIP-122 messages.
103
+ * @file Solana signature verification for CAIP-122 messages.
59
104
  * Uses ed25519 cryptography via the native SubtleCrypto API (Node.js & browser compatible).
60
105
  */
61
106
 
62
107
  /**
63
- * Verifies a Solana CAIP-122 signature using ed25519 cryptography.
64
- * Compatible with all Wallet Standard wallets (Phantom, Solflare, Backpack, etc.)
65
- * and accepts raw `solana:signIn` output objects as well as string payloads.
108
+ * Verifies a `solana` CAIP-122 message signed with ed25519.
109
+ *
110
+ * Parses the message, requires a `solana` chain and a 64-byte signature, runs `validateMessage` from `@tuwaio/siwx-core` (format,
111
+ * expiration, `notBefore` and an `issuedAt` in the future), validates the message `address` with `@solana/kit` and checks the signature against
112
+ * that public key with Web Crypto (`crypto.subtle`, algorithm `Ed25519`). Runs locally, without RPC calls. Nonce,
113
+ * domain and policy checks are the caller's job (see `@tuwaio/siwx-server`).
66
114
  *
67
- * Uses the native `SubtleCrypto` API for ed25519 verification, ensuring
68
- * compatibility with both Node.js (v19+) and browser environments without polyfills.
115
+ * Requires a runtime with Ed25519 support in Web Crypto (current browsers, Node.js 20+, edge runtimes).
69
116
  *
70
- * @param payload - Standard SIWX payload, Uint8Array buffers, or Wallet Standard `solana:signIn` output.
71
- * @param options - Verification options.
72
- * @returns A `SiwxVerifyResult` with `success: true` and parsed data, or an error result.
117
+ * @param payload - `{ message, signature }` (base58 string or bytes), or a Wallet Standard `solana:signIn` output.
118
+ * @param options - `skipExpiration` skips the check that `expirationTime` has not passed.
119
+ * @returns `{ success: true, data }`, or `{ success: false, error }`. Never throws: decoding, parse, validation and
120
+ * crypto errors are returned as `error`.
73
121
  *
74
122
  * @example
75
123
  * ```ts
@@ -81,4 +129,4 @@ declare function verifyEd25519(payload: SolanaVerifyPayload, options?: {
81
129
  skipExpiration?: boolean;
82
130
  }): Promise<SiwxVerifyResult>;
83
131
 
84
- export { type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, createSolanaSiwxSigner, verifyEd25519 };
132
+ export { type SolanaLegacyMessageSigner, type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, type SolanaWalletStandardSignerTarget, createSolanaSiwxSigner, verifyEd25519 };
package/dist/index.d.ts CHANGED
@@ -1,51 +1,96 @@
1
+ import { MessageModifyingSigner } from '@solana/kit';
2
+ import { Wallet, WalletAccount } from '@wallet-standard/base';
1
3
  import { SiwxVerifyPayload, SiwxVerifyResult } from '@tuwaio/siwx-core';
2
4
 
3
5
  /**
4
- * Target input for the Solana SIWX signer.
5
- * Accepts raw wallet and account objects, or a unified signer object.
6
+ * @file Solana signer adapter for SIWX authentication.
6
7
  */
7
- interface SolanaSiwxSignerTarget {
8
- account?: Record<string, unknown>;
9
- wallet?: Record<string, unknown>;
10
- [key: string]: unknown;
8
+
9
+ /**
10
+ * A Wallet Standard wallet and the account to sign with. The wallet must provide the `solana:signMessage` feature.
11
+ */
12
+ interface SolanaWalletStandardSignerTarget {
13
+ /** The Wallet Standard wallet. */
14
+ wallet: Wallet;
15
+ /** The connected account, one of `wallet.accounts`. Its `address` identifies the signature. */
16
+ account: WalletAccount;
11
17
  }
12
18
  /**
13
- * Creates a standard SIWX signer callback for Solana chains.
14
- * Automatically adapts to Wallet Standard, Web3 v2 (@solana/kit), or legacy Solana signers.
19
+ * A legacy wallet adapter (for example from `@solana/wallet-adapter-react`) that signs raw message bytes.
20
+ */
21
+ interface SolanaLegacyMessageSigner {
22
+ /**
23
+ * Signs the message bytes.
24
+ * @param message - UTF-8 bytes of the message.
25
+ * @returns The 64-byte ed25519 signature, or an object that contains it.
26
+ */
27
+ signMessage(message: Uint8Array): Promise<Uint8Array | {
28
+ signature: Uint8Array;
29
+ }>;
30
+ }
31
+ /**
32
+ * What {@link createSolanaSiwxSigner} can sign with:
33
+ *
34
+ * - a Wallet Standard `{ wallet, account }` pair ({@link SolanaWalletStandardSignerTarget});
35
+ * - an `@solana/kit` `MessageModifyingSigner`;
36
+ * - a legacy adapter with `signMessage(bytes)` ({@link SolanaLegacyMessageSigner});
37
+ * - any `{ wallet, account }` objects with one of these capabilities, such as a wallet exposing an `adapter` or a
38
+ * `signMessages` method.
15
39
  *
16
- * @param target - A Solana signer target containing raw wallet and account, or a direct signer instance.
17
- * @returns A standardized signer function accepting a message string and returning a promise with the base58 signature.
40
+ * The signer uses the first capability it finds: `modifyAndSignMessages`, the `solana:signMessage` feature of
41
+ * `wallet.features`, a `signMessages` method, or a `signMessage` method (also looked up on `adapter`).
42
+ */
43
+ type SolanaSiwxSignerTarget = SolanaWalletStandardSignerTarget | MessageModifyingSigner | SolanaLegacyMessageSigner | {
44
+ wallet?: object;
45
+ account?: object;
46
+ };
47
+ /**
48
+ * Creates a SIWX signer for Solana wallets: a function that signs a message (UTF-8 bytes) with the wallet and returns
49
+ * the ed25519 signature as a base58 string. Pass it as `signer` to `useSiwx().signIn` from `@tuwaio/siwx-react`.
50
+ *
51
+ * Works with Wallet Standard wallets, `@solana/kit` message signers and legacy adapters; see
52
+ * {@link SolanaSiwxSignerTarget} for how the signing method is chosen.
53
+ *
54
+ * @param target - The Wallet Standard wallet and account, an `@solana/kit` message signer or a legacy adapter.
55
+ * @returns An async signer. Calling it opens the wallet signature prompt; it rejects with an `Error` whose message
56
+ * starts with `[SIWX-SOLANA] Signing failed:` (original error in `cause`) when the target has no signing
57
+ * capability, the wallet rejects, or no signature is returned for the account address.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const signer = createSolanaSiwxSigner({ wallet, account });
62
+ * const signature = await signer(message);
63
+ * ```
18
64
  */
19
65
  declare function createSolanaSiwxSigner(target: SolanaSiwxSignerTarget): (message: string) => Promise<string>;
20
66
 
21
67
  /**
22
- * @fileoverview Solana-specific types for the @tuwaio/siwx-solana package.
68
+ * @file Solana-specific types for the @tuwaio/siwx-solana package.
23
69
  */
24
70
 
25
71
  /**
26
- * Minimal Wallet Standard account interface returned by `solana:signIn`.
72
+ * Minimal account shape of a Wallet Standard `solana:signIn` output.
27
73
  */
28
74
  interface SolanaSignInAccount {
29
- /** Base58 encoded wallet address. */
75
+ /** Base58-encoded wallet address. Not used for verification: the signer is taken from the message `address`. */
30
76
  address: string;
31
- /** Raw public key bytes. */
77
+ /** Raw public key bytes. Not used for verification. */
32
78
  publicKey?: Uint8Array;
33
79
  }
34
80
  /**
35
- * Output object structure returned by Wallet Standard `solana:signIn` feature.
81
+ * Output of the Wallet Standard `solana:signIn` feature, accepted as-is by {@link verifyEd25519}.
36
82
  */
37
83
  interface SolanaSignInOutput {
38
84
  /** Account that signed the message. */
39
85
  account: SolanaSignInAccount;
40
- /** Raw message bytes or string that was signed. */
86
+ /** The signed message, as UTF-8 bytes or a string. It must be a CAIP-122 message. */
41
87
  signedMessage: Uint8Array | string;
42
- /** Raw signature bytes or base58 string. */
88
+ /** The ed25519 signature, as 64 raw bytes or a base58 string. */
43
89
  signature: Uint8Array | string;
44
90
  }
45
91
  /**
46
- * Flexible input type for Solana SIWX verification.
47
- * Accepts standard SIWX payload `{ message, signature }`,
48
- * raw Uint8Array buffers, or Wallet Standard `solana:signIn` output objects.
92
+ * Input of {@link verifyEd25519}: a `{ message, signature }` payload (strings or bytes), a Wallet Standard
93
+ * `solana:signIn` output, or that output wrapped as `{ output }`. String signatures are base58-encoded.
49
94
  */
50
95
  type SolanaVerifyPayload = SiwxVerifyPayload | {
51
96
  message: string | Uint8Array;
@@ -55,21 +100,24 @@ type SolanaVerifyPayload = SiwxVerifyPayload | {
55
100
  };
56
101
 
57
102
  /**
58
- * @fileoverview Solana signature verification for CAIP-122 messages.
103
+ * @file Solana signature verification for CAIP-122 messages.
59
104
  * Uses ed25519 cryptography via the native SubtleCrypto API (Node.js & browser compatible).
60
105
  */
61
106
 
62
107
  /**
63
- * Verifies a Solana CAIP-122 signature using ed25519 cryptography.
64
- * Compatible with all Wallet Standard wallets (Phantom, Solflare, Backpack, etc.)
65
- * and accepts raw `solana:signIn` output objects as well as string payloads.
108
+ * Verifies a `solana` CAIP-122 message signed with ed25519.
109
+ *
110
+ * Parses the message, requires a `solana` chain and a 64-byte signature, runs `validateMessage` from `@tuwaio/siwx-core` (format,
111
+ * expiration, `notBefore` and an `issuedAt` in the future), validates the message `address` with `@solana/kit` and checks the signature against
112
+ * that public key with Web Crypto (`crypto.subtle`, algorithm `Ed25519`). Runs locally, without RPC calls. Nonce,
113
+ * domain and policy checks are the caller's job (see `@tuwaio/siwx-server`).
66
114
  *
67
- * Uses the native `SubtleCrypto` API for ed25519 verification, ensuring
68
- * compatibility with both Node.js (v19+) and browser environments without polyfills.
115
+ * Requires a runtime with Ed25519 support in Web Crypto (current browsers, Node.js 20+, edge runtimes).
69
116
  *
70
- * @param payload - Standard SIWX payload, Uint8Array buffers, or Wallet Standard `solana:signIn` output.
71
- * @param options - Verification options.
72
- * @returns A `SiwxVerifyResult` with `success: true` and parsed data, or an error result.
117
+ * @param payload - `{ message, signature }` (base58 string or bytes), or a Wallet Standard `solana:signIn` output.
118
+ * @param options - `skipExpiration` skips the check that `expirationTime` has not passed.
119
+ * @returns `{ success: true, data }`, or `{ success: false, error }`. Never throws: decoding, parse, validation and
120
+ * crypto errors are returned as `error`.
73
121
  *
74
122
  * @example
75
123
  * ```ts
@@ -81,4 +129,4 @@ declare function verifyEd25519(payload: SolanaVerifyPayload, options?: {
81
129
  skipExpiration?: boolean;
82
130
  }): Promise<SiwxVerifyResult>;
83
131
 
84
- export { type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, createSolanaSiwxSigner, verifyEd25519 };
132
+ export { type SolanaLegacyMessageSigner, type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, type SolanaWalletStandardSignerTarget, createSolanaSiwxSigner, verifyEd25519 };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var kit=require('@solana/kit'),siwxCore=require('@tuwaio/siwx-core');function v(e,n){if(e===n)return true;if(e.length!==n.length)return false;for(let s=0;s<e.length;s++)if(e[s]!==n[s])return false;return true}function P(e,n){if(typeof e?.modifyAndSignMessages=="function")return e;if(typeof n?.modifyAndSignMessages=="function")return n;let s=n?.features,a=e?.features,r;Array.isArray(s)&&s.includes("solana:signMessage"),a&&typeof a=="object"&&!Array.isArray(a)&&(r=a["solana:signMessage"]);let i=e?.adapter??n?.adapter,o=e?.signMessage??i?.signMessage??n?.signMessage,d=e?.signMessages??n?.signMessages;if(!r&&!o&&!d)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let t=String(n?.address??e?.address??"solana:signer");return {address:t,async modifyAndSignMessages(g,y={}){if(y.abortSignal?.aborted)throw new Error("Aborted");if(g.length===0)return g;let M=[];for(let A=0;A<g.length;A++){let l=g[A],f,S;if(r){let u=[{account:n,message:l.content}],p=(await r.signMessage(...u))[0];if(!p||!p.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");f=p.signature,S=p.signedMessage??l.content;}else if(typeof d=="function"){let c=(await d([{account:n,message:l.content}]))[0];if(!c||!c.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");f=c.signature,S=c.signedMessage??l.content;}else if(typeof o=="function"){let u=await o.call(i??e??n,l.content);if(S=l.content,u instanceof Uint8Array||u&&u.buffer instanceof ArrayBuffer)f=u;else if(u&&typeof u=="object"&&"signature"in u)f=u.signature;else throw new Error("[SIWX-SOLANA] Unexpected legacy signMessage result format.")}else throw new Error("[SIWX-SOLANA] Missing signing implementation.");let m=l.content.length!==S.length||l.content.some((u,c)=>u!==S[c]),h=l.signatures[t];if(!(h===void 0||!v(h,f))&&!m){M.push(l);continue}let U=m?{[t]:f}:{...l.signatures,[t]:f};M.push(Object.freeze({content:S,signatures:Object.freeze(U)}));}return M}}}function N(e){return async n=>{try{if(!e)throw new Error("[SIWX-SOLANA] Invalid signer target.");let s=e.wallet??e,a=e.account??e,i=kit.getUtf8Encoder().encode(n),o=P(s,a),d=kit.createSignableMessage(i),g=(await o.modifyAndSignMessages([d]))[0];if(!g)throw new Error("[SIWX-SOLANA] No signed message returned.");let y=g.signatures[o.address];if(!y)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${o.address}`);return kit.getBase58Decoder().decode(y)}catch(s){throw new Error(`[SIWX-SOLANA] Signing failed: ${s.message}`,{cause:s})}}}function b(e){let n="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",s=new Map(n.split("").map((t,g)=>[t,BigInt(g)])),a=0n;for(let t of e){let g=s.get(t);if(g===void 0)throw new siwxCore.SiwxVerificationError(`Invalid base58 character: "${t}"`);a=a*58n+g;}let r=a.toString(16);r.length%2!==0&&(r="0"+r);let i=[];for(let t=0;t<r.length;t+=2)i.push(parseInt(r.slice(t,t+2),16));let o=0;for(let t of e)if(t==="1")o++;else break;let d=new Uint8Array(o+i.length);return d.set(i,o),d}function V(e){let n=e.split(":");if(n.length!==3||n[0]!=="solana")throw new siwxCore.SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${e}"`);return n[2]}function T(e){let n="output"in e?e.output:e,s="signedMessage"in n?n.signedMessage:n.message,a=n.signature,r,i;s instanceof Uint8Array?(i=s,r=new TextDecoder().decode(s)):(r=s,i=new TextEncoder().encode(s));let o;return a instanceof Uint8Array?o=a:o=b(a),{messageString:r,messageBytes:i,signatureBytes:o}}async function X(e,n){try{let{messageString:s,messageBytes:a,signatureBytes:r}=T(e),i=siwxCore.parseMessage(s);if(!i.chainId.startsWith("solana:"))throw new siwxCore.SiwxUnsupportedNamespaceError(i.chainId.split(":")[0]??"unknown");if(r.length!==64)throw new siwxCore.SiwxVerificationError(`Invalid Solana signature length: ${r.length} bytes (expected 64)`);let o=siwxCore.validateMessage(i,{skipExpiration:n?.skipExpiration,policy:{enforceNotBefore:!0}});if(!o.valid)throw new siwxCore.SiwxValidationError(o.errors);let d=V(i.address),t=kit.address(d),g=b(t),y=await globalThis.crypto.subtle.importKey("raw",g.buffer,{name:"Ed25519"},!1,["verify"]);if(!await globalThis.crypto.subtle.verify({name:"Ed25519"},y,r.buffer,a.buffer))throw new siwxCore.SiwxVerificationError(`ed25519 signature verification failed for address: ${d}`);return {success:!0,data:i}}catch(s){return s instanceof siwxCore.SiwxVerificationError||s instanceof siwxCore.SiwxValidationError?{success:false,error:s.message}:{success:false,error:`ed25519 verification failed: ${String(s)}`}}}exports.createSolanaSiwxSigner=N;exports.verifyEd25519=X;
1
+ 'use strict';var kit=require('@solana/kit'),siwxCore=require('@tuwaio/siwx-core');function W(e,n){if(e===n)return true;if(e.length!==n.length)return false;for(let s=0;s<e.length;s++)if(e[s]!==n[s])return false;return true}function v(e,n){if(typeof e?.modifyAndSignMessages=="function")return e;if(typeof n?.modifyAndSignMessages=="function")return n;let s=n?.features,t=e?.features,r;Array.isArray(s)&&s.includes("solana:signMessage"),t&&typeof t=="object"&&!Array.isArray(t)&&(r=t["solana:signMessage"]);let i=e?.adapter??n?.adapter,o=e?.signMessage??i?.signMessage??n?.signMessage,l=e?.signMessages??n?.signMessages;if(!r&&!o&&!l)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let a=String(n?.address??e?.address??"solana:signer");return {address:a,async modifyAndSignMessages(g,p={}){if(p.abortSignal?.aborted)throw new Error("Aborted");if(g.length===0)return g;let y=[];for(let m=0;m<g.length;m++){let d=g[m],c,S;if(r){let u=[{account:n,message:d.content}],A=(await r.signMessage(...u))[0];if(!A||!A.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");c=A.signature,S=A.signedMessage??d.content;}else if(typeof l=="function"){let f=(await l([{account:n,message:d.content}]))[0];if(!f||!f.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");c=f.signature,S=f.signedMessage??d.content;}else if(typeof o=="function"){let u=await o.call(i??e??n,d.content);if(S=d.content,u instanceof Uint8Array||u&&u.buffer instanceof ArrayBuffer)c=u;else if(u&&typeof u=="object"&&"signature"in u)c=u.signature;else throw new Error("[SIWX-SOLANA] Unexpected legacy signMessage result format.")}else throw new Error("[SIWX-SOLANA] Missing signing implementation.");let h=d.content.length!==S.length||d.content.some((u,f)=>u!==S[f]),b=d.signatures[a];if(!(b===void 0||!W(b,c))&&!h){y.push(d);continue}let U=h?{[a]:c}:{...d.signatures,[a]:c};y.push(Object.freeze({content:S,signatures:Object.freeze(U)}));}return y}}}function P(e){return async n=>{try{if(!e)throw new Error("[SIWX-SOLANA] Invalid signer target.");let{wallet:s,account:t}=e,r=s??e,i=t??e,l=kit.getUtf8Encoder().encode(n),a=v(r,i),g=kit.createSignableMessage(l),M=(await a.modifyAndSignMessages([g]))[0];if(!M)throw new Error("[SIWX-SOLANA] No signed message returned.");let y=M.signatures[a.address];if(!y)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${a.address}`);return kit.getBase58Decoder().decode(y)}catch(s){throw new Error(`[SIWX-SOLANA] Signing failed: ${s.message}`,{cause:s})}}}function x(e){let n="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",s=new Map(n.split("").map((a,g)=>[a,BigInt(g)])),t=0n;for(let a of e){let g=s.get(a);if(g===void 0)throw new siwxCore.SiwxVerificationError(`Invalid base58 character: "${a}"`);t=t*58n+g;}let r=t.toString(16);r.length%2!==0&&(r="0"+r);let i=[];for(let a=0;a<r.length;a+=2)i.push(parseInt(r.slice(a,a+2),16));let o=0;for(let a of e)if(a==="1")o++;else break;let l=new Uint8Array(o+i.length);return l.set(i,o),l}function V(e){let n=e.split(":");if(n.length!==3||n[0]!=="solana")throw new siwxCore.SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${e}"`);return n[2]}function j(e){let n="output"in e?e.output:e,s="signedMessage"in n?n.signedMessage:n.message,t=n.signature,r,i;s instanceof Uint8Array?(i=s,r=new TextDecoder().decode(s)):(r=s,i=new TextEncoder().encode(s));let o;return t instanceof Uint8Array?o=t:o=x(t),{messageString:r,messageBytes:i,signatureBytes:o}}async function R(e,n){try{let{messageString:s,messageBytes:t,signatureBytes:r}=j(e),i=siwxCore.parseMessage(s);if(!i.chainId.startsWith("solana:"))throw new siwxCore.SiwxUnsupportedNamespaceError(i.chainId.split(":")[0]??"unknown");if(r.length!==64)throw new siwxCore.SiwxVerificationError(`Invalid Solana signature length: ${r.length} bytes (expected 64)`);let o=siwxCore.validateMessage(i,{skipExpiration:n?.skipExpiration,policy:{enforceNotBefore:!0}});if(!o.valid)throw new siwxCore.SiwxValidationError(o.errors);let l=V(i.address),a=kit.address(l),g=x(a),p=await globalThis.crypto.subtle.importKey("raw",g.buffer,{name:"Ed25519"},!1,["verify"]);if(!await globalThis.crypto.subtle.verify({name:"Ed25519"},p,r.buffer,t.buffer))throw new siwxCore.SiwxVerificationError(`ed25519 signature verification failed for address: ${l}`);return {success:!0,data:i}}catch(s){return s instanceof siwxCore.SiwxVerificationError||s instanceof siwxCore.SiwxValidationError?{success:false,error:s.message}:{success:false,error:`ed25519 verification failed: ${String(s)}`}}}exports.createSolanaSiwxSigner=P;exports.verifyEd25519=R;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {getUtf8Encoder,createSignableMessage,getBase58Decoder,address}from'@solana/kit';import {parseMessage,SiwxUnsupportedNamespaceError,SiwxVerificationError,validateMessage,SiwxValidationError}from'@tuwaio/siwx-core';function v(e,n){if(e===n)return true;if(e.length!==n.length)return false;for(let s=0;s<e.length;s++)if(e[s]!==n[s])return false;return true}function P(e,n){if(typeof e?.modifyAndSignMessages=="function")return e;if(typeof n?.modifyAndSignMessages=="function")return n;let s=n?.features,a=e?.features,r;Array.isArray(s)&&s.includes("solana:signMessage"),a&&typeof a=="object"&&!Array.isArray(a)&&(r=a["solana:signMessage"]);let i=e?.adapter??n?.adapter,o=e?.signMessage??i?.signMessage??n?.signMessage,d=e?.signMessages??n?.signMessages;if(!r&&!o&&!d)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let t=String(n?.address??e?.address??"solana:signer");return {address:t,async modifyAndSignMessages(g,y={}){if(y.abortSignal?.aborted)throw new Error("Aborted");if(g.length===0)return g;let M=[];for(let A=0;A<g.length;A++){let l=g[A],f,S;if(r){let u=[{account:n,message:l.content}],p=(await r.signMessage(...u))[0];if(!p||!p.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");f=p.signature,S=p.signedMessage??l.content;}else if(typeof d=="function"){let c=(await d([{account:n,message:l.content}]))[0];if(!c||!c.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");f=c.signature,S=c.signedMessage??l.content;}else if(typeof o=="function"){let u=await o.call(i??e??n,l.content);if(S=l.content,u instanceof Uint8Array||u&&u.buffer instanceof ArrayBuffer)f=u;else if(u&&typeof u=="object"&&"signature"in u)f=u.signature;else throw new Error("[SIWX-SOLANA] Unexpected legacy signMessage result format.")}else throw new Error("[SIWX-SOLANA] Missing signing implementation.");let m=l.content.length!==S.length||l.content.some((u,c)=>u!==S[c]),h=l.signatures[t];if(!(h===void 0||!v(h,f))&&!m){M.push(l);continue}let U=m?{[t]:f}:{...l.signatures,[t]:f};M.push(Object.freeze({content:S,signatures:Object.freeze(U)}));}return M}}}function N(e){return async n=>{try{if(!e)throw new Error("[SIWX-SOLANA] Invalid signer target.");let s=e.wallet??e,a=e.account??e,i=getUtf8Encoder().encode(n),o=P(s,a),d=createSignableMessage(i),g=(await o.modifyAndSignMessages([d]))[0];if(!g)throw new Error("[SIWX-SOLANA] No signed message returned.");let y=g.signatures[o.address];if(!y)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${o.address}`);return getBase58Decoder().decode(y)}catch(s){throw new Error(`[SIWX-SOLANA] Signing failed: ${s.message}`,{cause:s})}}}function b(e){let n="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",s=new Map(n.split("").map((t,g)=>[t,BigInt(g)])),a=0n;for(let t of e){let g=s.get(t);if(g===void 0)throw new SiwxVerificationError(`Invalid base58 character: "${t}"`);a=a*58n+g;}let r=a.toString(16);r.length%2!==0&&(r="0"+r);let i=[];for(let t=0;t<r.length;t+=2)i.push(parseInt(r.slice(t,t+2),16));let o=0;for(let t of e)if(t==="1")o++;else break;let d=new Uint8Array(o+i.length);return d.set(i,o),d}function V(e){let n=e.split(":");if(n.length!==3||n[0]!=="solana")throw new SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${e}"`);return n[2]}function T(e){let n="output"in e?e.output:e,s="signedMessage"in n?n.signedMessage:n.message,a=n.signature,r,i;s instanceof Uint8Array?(i=s,r=new TextDecoder().decode(s)):(r=s,i=new TextEncoder().encode(s));let o;return a instanceof Uint8Array?o=a:o=b(a),{messageString:r,messageBytes:i,signatureBytes:o}}async function X(e,n){try{let{messageString:s,messageBytes:a,signatureBytes:r}=T(e),i=parseMessage(s);if(!i.chainId.startsWith("solana:"))throw new SiwxUnsupportedNamespaceError(i.chainId.split(":")[0]??"unknown");if(r.length!==64)throw new SiwxVerificationError(`Invalid Solana signature length: ${r.length} bytes (expected 64)`);let o=validateMessage(i,{skipExpiration:n?.skipExpiration,policy:{enforceNotBefore:!0}});if(!o.valid)throw new SiwxValidationError(o.errors);let d=V(i.address),t=address(d),g=b(t),y=await globalThis.crypto.subtle.importKey("raw",g.buffer,{name:"Ed25519"},!1,["verify"]);if(!await globalThis.crypto.subtle.verify({name:"Ed25519"},y,r.buffer,a.buffer))throw new SiwxVerificationError(`ed25519 signature verification failed for address: ${d}`);return {success:!0,data:i}}catch(s){return s instanceof SiwxVerificationError||s instanceof SiwxValidationError?{success:false,error:s.message}:{success:false,error:`ed25519 verification failed: ${String(s)}`}}}export{N as createSolanaSiwxSigner,X as verifyEd25519};
1
+ import {getUtf8Encoder,createSignableMessage,getBase58Decoder,address}from'@solana/kit';import {parseMessage,SiwxUnsupportedNamespaceError,SiwxVerificationError,validateMessage,SiwxValidationError}from'@tuwaio/siwx-core';function W(e,n){if(e===n)return true;if(e.length!==n.length)return false;for(let s=0;s<e.length;s++)if(e[s]!==n[s])return false;return true}function v(e,n){if(typeof e?.modifyAndSignMessages=="function")return e;if(typeof n?.modifyAndSignMessages=="function")return n;let s=n?.features,t=e?.features,r;Array.isArray(s)&&s.includes("solana:signMessage"),t&&typeof t=="object"&&!Array.isArray(t)&&(r=t["solana:signMessage"]);let i=e?.adapter??n?.adapter,o=e?.signMessage??i?.signMessage??n?.signMessage,l=e?.signMessages??n?.signMessages;if(!r&&!o&&!l)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let a=String(n?.address??e?.address??"solana:signer");return {address:a,async modifyAndSignMessages(g,p={}){if(p.abortSignal?.aborted)throw new Error("Aborted");if(g.length===0)return g;let y=[];for(let m=0;m<g.length;m++){let d=g[m],c,S;if(r){let u=[{account:n,message:d.content}],A=(await r.signMessage(...u))[0];if(!A||!A.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");c=A.signature,S=A.signedMessage??d.content;}else if(typeof l=="function"){let f=(await l([{account:n,message:d.content}]))[0];if(!f||!f.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");c=f.signature,S=f.signedMessage??d.content;}else if(typeof o=="function"){let u=await o.call(i??e??n,d.content);if(S=d.content,u instanceof Uint8Array||u&&u.buffer instanceof ArrayBuffer)c=u;else if(u&&typeof u=="object"&&"signature"in u)c=u.signature;else throw new Error("[SIWX-SOLANA] Unexpected legacy signMessage result format.")}else throw new Error("[SIWX-SOLANA] Missing signing implementation.");let h=d.content.length!==S.length||d.content.some((u,f)=>u!==S[f]),b=d.signatures[a];if(!(b===void 0||!W(b,c))&&!h){y.push(d);continue}let U=h?{[a]:c}:{...d.signatures,[a]:c};y.push(Object.freeze({content:S,signatures:Object.freeze(U)}));}return y}}}function P(e){return async n=>{try{if(!e)throw new Error("[SIWX-SOLANA] Invalid signer target.");let{wallet:s,account:t}=e,r=s??e,i=t??e,l=getUtf8Encoder().encode(n),a=v(r,i),g=createSignableMessage(l),M=(await a.modifyAndSignMessages([g]))[0];if(!M)throw new Error("[SIWX-SOLANA] No signed message returned.");let y=M.signatures[a.address];if(!y)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${a.address}`);return getBase58Decoder().decode(y)}catch(s){throw new Error(`[SIWX-SOLANA] Signing failed: ${s.message}`,{cause:s})}}}function x(e){let n="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",s=new Map(n.split("").map((a,g)=>[a,BigInt(g)])),t=0n;for(let a of e){let g=s.get(a);if(g===void 0)throw new SiwxVerificationError(`Invalid base58 character: "${a}"`);t=t*58n+g;}let r=t.toString(16);r.length%2!==0&&(r="0"+r);let i=[];for(let a=0;a<r.length;a+=2)i.push(parseInt(r.slice(a,a+2),16));let o=0;for(let a of e)if(a==="1")o++;else break;let l=new Uint8Array(o+i.length);return l.set(i,o),l}function V(e){let n=e.split(":");if(n.length!==3||n[0]!=="solana")throw new SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${e}"`);return n[2]}function j(e){let n="output"in e?e.output:e,s="signedMessage"in n?n.signedMessage:n.message,t=n.signature,r,i;s instanceof Uint8Array?(i=s,r=new TextDecoder().decode(s)):(r=s,i=new TextEncoder().encode(s));let o;return t instanceof Uint8Array?o=t:o=x(t),{messageString:r,messageBytes:i,signatureBytes:o}}async function R(e,n){try{let{messageString:s,messageBytes:t,signatureBytes:r}=j(e),i=parseMessage(s);if(!i.chainId.startsWith("solana:"))throw new SiwxUnsupportedNamespaceError(i.chainId.split(":")[0]??"unknown");if(r.length!==64)throw new SiwxVerificationError(`Invalid Solana signature length: ${r.length} bytes (expected 64)`);let o=validateMessage(i,{skipExpiration:n?.skipExpiration,policy:{enforceNotBefore:!0}});if(!o.valid)throw new SiwxValidationError(o.errors);let l=V(i.address),a=address(l),g=x(a),p=await globalThis.crypto.subtle.importKey("raw",g.buffer,{name:"Ed25519"},!1,["verify"]);if(!await globalThis.crypto.subtle.verify({name:"Ed25519"},p,r.buffer,t.buffer))throw new SiwxVerificationError(`ed25519 signature verification failed for address: ${l}`);return {success:!0,data:i}}catch(s){return s instanceof SiwxVerificationError||s instanceof SiwxValidationError?{success:false,error:s.message}:{success:false,error:`ed25519 verification failed: ${String(s)}`}}}export{P as createSolanaSiwxSigner,R as verifyEd25519};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@tuwaio/siwx-solana",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
7
- "description": "Layer 2 (L2) of the TUWA Ecosystem. Solana adapter for @tuwaio/siwx. Signs and verifies CAIP-122 messages for Solana via @solana/kit and @wallet-standard using ed25519 cryptography.",
7
+ "description": "L2 Solana package of SIWX (TUWA): CAIP-122 signer for Wallet Standard and @solana/kit wallets, and ed25519 signature verification with Web Crypto, built on @solana/kit.",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
10
10
  "types": "./dist/index.d.ts",
@@ -16,16 +16,18 @@
16
16
  "socket.json"
17
17
  ],
18
18
  "keywords": [
19
- "web3",
20
- "typescript",
19
+ "tuwa",
20
+ "siwx",
21
+ "sign-in-with-x",
21
22
  "caip-122",
23
+ "authentication",
24
+ "web3",
22
25
  "solana",
23
26
  "ed25519",
24
27
  "@solana/kit",
25
28
  "wallet-standard",
26
- "sign-in-with-solana",
27
- "authentication",
28
- "tuwa"
29
+ "typescript",
30
+ "headless"
29
31
  ],
30
32
  "repository": {
31
33
  "type": "git",
@@ -43,16 +45,16 @@
43
45
  }
44
46
  ],
45
47
  "peerDependencies": {
46
- "@tuwaio/siwx-core": "0.3.0",
48
+ "@tuwaio/siwx-core": "0.4.0",
47
49
  "@wallet-standard/base": ">=1.1.1",
48
50
  "@solana/kit": ">=8.2"
49
51
  },
50
52
  "devDependencies": {
51
- "@tuwaio/siwx-core": "0.3.0",
53
+ "@tuwaio/siwx-core": "0.4.0",
52
54
  "@wallet-standard/base": "^1.1.1",
53
- "@solana/kit": "^8.2.0",
55
+ "@solana/kit": "^8.4.0",
54
56
  "tsup": "^8.5.1",
55
- "typescript": "^6.0.3"
57
+ "typescript": "6.0.3"
56
58
  },
57
59
  "scripts": {
58
60
  "start": "tsup src/index.ts --watch",