@tuwaio/siwx-solana 0.5.0 → 0.6.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/README.md CHANGED
@@ -9,8 +9,9 @@
9
9
 
10
10
  ## 🏛️ Core Capabilities
11
11
 
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.
12
+ - **Signing:** `createSolanaSiwxSigner` turns a Wallet Standard wallet and account (typed with `@wallet-standard/base`), an `@solana/kit` message signer, a legacy adapter or `useWallet()` of `@solana/wallet-adapter` (v1 or v3) 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
+ - **Off-chain messages and hardware wallets:** the wallet signs either the UTF-8 bytes of the message (`solana:signMessage`) or its [version 1 off-chain message](https://github.com/solana-foundation/SRFCs/discussions/3) (`solana:signOffchainMessage`), which hardware wallets can show and sign. By default the signer picks the off-chain message when the account supports it but not `solana:signMessage`; `messageFormat` forces one or the other.
14
+ - **Verification:** `verifyEd25519` accepts a `{ message, signature }` payload (base58 strings or bytes) or the output of the Wallet Standard `solana:signIn` feature, signed as the message itself or as its version 1 off-chain message. 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
15
  - **Runtimes:** any runtime whose Web Crypto API supports Ed25519, such as Node.js 20+ and current browsers. No native modules or polyfills.
15
16
 
16
17
  ---
@@ -22,7 +23,7 @@ pnpm add @tuwaio/siwx-solana @tuwaio/siwx-core @tuwaio/orbit-core @solana/kit @w
22
23
  ```
23
24
 
24
25
  > [!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
+ > `@tuwaio/siwx-core`, `@solana/kit` (>=6) and `@wallet-standard/base` (>=1.1.0) are peer dependencies and must be installed alongside `@tuwaio/siwx-solana`.
26
27
 
27
28
  ---
28
29
 
@@ -59,7 +60,25 @@ const signWithKit = createSolanaSiwxSigner(kitSigner);
59
60
  const signWithAdapter = createSolanaSiwxSigner(walletAdapter);
60
61
  ```
61
62
 
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`).
63
+ 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 (on the wallet, its `adapter`, the account or the target itself, so `useWallet()` of `@solana/wallet-adapter` v1 and v3 can be passed as is).
64
+
65
+ ### Off-chain messages (hardware wallets)
66
+
67
+ ```typescript
68
+ import { createSolanaSiwxSigner } from '@tuwaio/siwx-solana';
69
+ import type { Wallet, WalletAccount } from '@wallet-standard/base';
70
+
71
+ declare const wallet: Wallet; // a wallet with the `solana:signOffchainMessage` feature
72
+ declare const account: WalletAccount;
73
+ declare const message: string;
74
+
75
+ // 'auto' (default): the off-chain message when the account has `solana:signOffchainMessage` but not
76
+ // `solana:signMessage`. 'offchainMessage' always signs it, 'message' never does.
77
+ const signer = createSolanaSiwxSigner({ wallet, account }, { messageFormat: 'offchainMessage' });
78
+ const signature = await signer(message); // base58; verifyEd25519 and @tuwaio/siwx-server accept it as is
79
+ ```
80
+
81
+ The wallet signs the [version 1 off-chain message](https://github.com/solana-foundation/SRFCs/discussions/3) of the text with the account as its only signer. When the wallet returns the bytes it signed, the signer checks that they are that envelope and rejects otherwise. The signature is sent to the server like any other: the envelope is fully determined by the text and the address, so no server option is needed. A `signOffchainMessage(message)` method, as on `useWallet()` of `@solana/wallet-adapter` v3, works too.
63
82
 
64
83
  ### Verifying a signature
65
84
 
@@ -78,7 +97,7 @@ if (result.success) {
78
97
  }
79
98
  ```
80
99
 
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.
100
+ 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. The signature may cover the message itself or its version 1 off-chain message; signed message bytes that are such an envelope are decoded, and its only signer must be the address of the message.
82
101
 
83
102
  `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.
84
103
 
package/dist/index.d.mts CHANGED
@@ -7,7 +7,28 @@ import { SiwxVerifyPayload, SiwxVerifyResult } from '@tuwaio/siwx-core';
7
7
  */
8
8
 
9
9
  /**
10
- * A Wallet Standard wallet and the account to sign with. The wallet must provide the `solana:signMessage` feature.
10
+ * How {@link createSolanaSiwxSigner} has the wallet sign the message:
11
+ *
12
+ * - `'auto'` (default): the UTF-8 bytes of the message, or its version 1 off-chain message when the account supports
13
+ * `solana:signOffchainMessage` but not `solana:signMessage` (as hardware wallet accounts may), or when the target
14
+ * has no other way to sign;
15
+ * - `'message'`: always the UTF-8 bytes (`solana:signMessage` and the fallbacks of {@link SolanaSiwxSignerTarget});
16
+ * - `'offchainMessage'`: always the version 1 off-chain message (`solana:signOffchainMessage`, or a
17
+ * `signOffchainMessage(message)` method such as the one of `useWallet()` from `@solana/wallet-adapter` v3).
18
+ *
19
+ * `verifyEd25519` and `@tuwaio/siwx-server` accept both, so the format needs no server setting.
20
+ */
21
+ type SolanaSiwxMessageFormat = 'auto' | 'message' | 'offchainMessage';
22
+ /**
23
+ * Options of {@link createSolanaSiwxSigner}.
24
+ */
25
+ interface SolanaSiwxSignerOptions {
26
+ /** How the wallet signs the message. Defaults to `'auto'`; see {@link SolanaSiwxMessageFormat}. */
27
+ messageFormat?: SolanaSiwxMessageFormat;
28
+ }
29
+ /**
30
+ * A Wallet Standard wallet and the account to sign with. The wallet must provide the `solana:signMessage` feature,
31
+ * or `solana:signOffchainMessage` (see {@link SolanaSiwxMessageFormat}).
11
32
  */
12
33
  interface SolanaWalletStandardSignerTarget {
13
34
  /** The Wallet Standard wallet. */
@@ -38,23 +59,29 @@ interface SolanaLegacyMessageSigner {
38
59
  * `signMessages` method.
39
60
  *
40
61
  * 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`).
62
+ * `wallet.features`, a `signMessages` method, or a `signMessage` method (looked up on `wallet`, its `adapter`, `account`
63
+ * and the target itself, so `useWallet()` of `@solana/wallet-adapter` v1 and v3 works as is). Off-chain messages use
64
+ * the `solana:signOffchainMessage` feature of `wallet.features` or a `signOffchainMessage` method.
42
65
  */
43
66
  type SolanaSiwxSignerTarget = SolanaWalletStandardSignerTarget | MessageModifyingSigner | SolanaLegacyMessageSigner | {
44
67
  wallet?: object;
45
68
  account?: object;
46
69
  };
47
70
  /**
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`.
71
+ * Creates a SIWX signer for Solana wallets: a function that signs a message with the wallet and returns the ed25519
72
+ * signature as a base58 string. Pass it as `signer` to `useSiwx().signIn` from `@tuwaio/siwx-react`.
50
73
  *
51
- * Works with Wallet Standard wallets, `@solana/kit` message signers and legacy adapters; see
52
- * {@link SolanaSiwxSignerTarget} for how the signing method is chosen.
74
+ * Works with Wallet Standard wallets, `@solana/kit` message signers, legacy adapters and `useWallet()` of
75
+ * `@solana/wallet-adapter`; see {@link SolanaSiwxSignerTarget} for how the signing method is chosen. The wallet signs
76
+ * the UTF-8 bytes of the message or its version 1 off-chain message (which hardware wallets can show and sign), as
77
+ * `options.messageFormat` decides ({@link SolanaSiwxMessageFormat}); servers verify both.
53
78
  *
54
79
  * @param target - The Wallet Standard wallet and account, an `@solana/kit` message signer or a legacy adapter.
80
+ * @param options - `messageFormat`: `'auto'` (default), `'message'` or `'offchainMessage'`.
55
81
  * @returns An async signer. Calling it opens the wallet signature prompt; it rejects with an `Error` whose message
56
82
  * 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.
83
+ * capability, the wallet rejects, cannot sign version 1 off-chain messages or signs a different off-chain message, or
84
+ * no signature is returned for the account address.
58
85
  *
59
86
  * @example
60
87
  * ```ts
@@ -62,7 +89,7 @@ type SolanaSiwxSignerTarget = SolanaWalletStandardSignerTarget | MessageModifyin
62
89
  * const signature = await signer(message);
63
90
  * ```
64
91
  */
65
- declare function createSolanaSiwxSigner(target: SolanaSiwxSignerTarget): (message: string) => Promise<string>;
92
+ declare function createSolanaSiwxSigner(target: SolanaSiwxSignerTarget, options?: SolanaSiwxSignerOptions): (message: string) => Promise<string>;
66
93
 
67
94
  /**
68
95
  * @file Solana-specific types for the @tuwaio/siwx-solana package.
@@ -112,6 +139,12 @@ type SolanaVerifyPayload = SiwxVerifyPayload | {
112
139
  * that public key with Web Crypto (`crypto.subtle`, algorithm `Ed25519`). Runs locally, without RPC calls. Nonce,
113
140
  * domain and policy checks are the caller's job (see `@tuwaio/siwx-server`).
114
141
  *
142
+ * Accepts the two ways a Solana wallet signs text: the UTF-8 bytes of the message (`solana:signMessage`) or the
143
+ * version 1 off-chain message envelope of the message (`solana:signOffchainMessage`, which hardware wallets can show
144
+ * and sign). With a string message both are tried, since the envelope is fully determined by the text and the address
145
+ * of the message. Signed message bytes that are a version 1 envelope are decoded, and their only required signatory
146
+ * must be the address of the message; other off-chain message versions are rejected.
147
+ *
115
148
  * Requires a runtime with Ed25519 support in Web Crypto (current browsers, Node.js 20+, edge runtimes).
116
149
  *
117
150
  * @param payload - `{ message, signature }` (base58 string or bytes), or a Wallet Standard `solana:signIn` output.
@@ -129,4 +162,4 @@ declare function verifyEd25519(payload: SolanaVerifyPayload, options?: {
129
162
  skipExpiration?: boolean;
130
163
  }): Promise<SiwxVerifyResult>;
131
164
 
132
- export { type SolanaLegacyMessageSigner, type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, type SolanaWalletStandardSignerTarget, createSolanaSiwxSigner, verifyEd25519 };
165
+ export { type SolanaLegacyMessageSigner, type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxMessageFormat, type SolanaSiwxSignerOptions, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, type SolanaWalletStandardSignerTarget, createSolanaSiwxSigner, verifyEd25519 };
package/dist/index.d.ts CHANGED
@@ -7,7 +7,28 @@ import { SiwxVerifyPayload, SiwxVerifyResult } from '@tuwaio/siwx-core';
7
7
  */
8
8
 
9
9
  /**
10
- * A Wallet Standard wallet and the account to sign with. The wallet must provide the `solana:signMessage` feature.
10
+ * How {@link createSolanaSiwxSigner} has the wallet sign the message:
11
+ *
12
+ * - `'auto'` (default): the UTF-8 bytes of the message, or its version 1 off-chain message when the account supports
13
+ * `solana:signOffchainMessage` but not `solana:signMessage` (as hardware wallet accounts may), or when the target
14
+ * has no other way to sign;
15
+ * - `'message'`: always the UTF-8 bytes (`solana:signMessage` and the fallbacks of {@link SolanaSiwxSignerTarget});
16
+ * - `'offchainMessage'`: always the version 1 off-chain message (`solana:signOffchainMessage`, or a
17
+ * `signOffchainMessage(message)` method such as the one of `useWallet()` from `@solana/wallet-adapter` v3).
18
+ *
19
+ * `verifyEd25519` and `@tuwaio/siwx-server` accept both, so the format needs no server setting.
20
+ */
21
+ type SolanaSiwxMessageFormat = 'auto' | 'message' | 'offchainMessage';
22
+ /**
23
+ * Options of {@link createSolanaSiwxSigner}.
24
+ */
25
+ interface SolanaSiwxSignerOptions {
26
+ /** How the wallet signs the message. Defaults to `'auto'`; see {@link SolanaSiwxMessageFormat}. */
27
+ messageFormat?: SolanaSiwxMessageFormat;
28
+ }
29
+ /**
30
+ * A Wallet Standard wallet and the account to sign with. The wallet must provide the `solana:signMessage` feature,
31
+ * or `solana:signOffchainMessage` (see {@link SolanaSiwxMessageFormat}).
11
32
  */
12
33
  interface SolanaWalletStandardSignerTarget {
13
34
  /** The Wallet Standard wallet. */
@@ -38,23 +59,29 @@ interface SolanaLegacyMessageSigner {
38
59
  * `signMessages` method.
39
60
  *
40
61
  * 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`).
62
+ * `wallet.features`, a `signMessages` method, or a `signMessage` method (looked up on `wallet`, its `adapter`, `account`
63
+ * and the target itself, so `useWallet()` of `@solana/wallet-adapter` v1 and v3 works as is). Off-chain messages use
64
+ * the `solana:signOffchainMessage` feature of `wallet.features` or a `signOffchainMessage` method.
42
65
  */
43
66
  type SolanaSiwxSignerTarget = SolanaWalletStandardSignerTarget | MessageModifyingSigner | SolanaLegacyMessageSigner | {
44
67
  wallet?: object;
45
68
  account?: object;
46
69
  };
47
70
  /**
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`.
71
+ * Creates a SIWX signer for Solana wallets: a function that signs a message with the wallet and returns the ed25519
72
+ * signature as a base58 string. Pass it as `signer` to `useSiwx().signIn` from `@tuwaio/siwx-react`.
50
73
  *
51
- * Works with Wallet Standard wallets, `@solana/kit` message signers and legacy adapters; see
52
- * {@link SolanaSiwxSignerTarget} for how the signing method is chosen.
74
+ * Works with Wallet Standard wallets, `@solana/kit` message signers, legacy adapters and `useWallet()` of
75
+ * `@solana/wallet-adapter`; see {@link SolanaSiwxSignerTarget} for how the signing method is chosen. The wallet signs
76
+ * the UTF-8 bytes of the message or its version 1 off-chain message (which hardware wallets can show and sign), as
77
+ * `options.messageFormat` decides ({@link SolanaSiwxMessageFormat}); servers verify both.
53
78
  *
54
79
  * @param target - The Wallet Standard wallet and account, an `@solana/kit` message signer or a legacy adapter.
80
+ * @param options - `messageFormat`: `'auto'` (default), `'message'` or `'offchainMessage'`.
55
81
  * @returns An async signer. Calling it opens the wallet signature prompt; it rejects with an `Error` whose message
56
82
  * 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.
83
+ * capability, the wallet rejects, cannot sign version 1 off-chain messages or signs a different off-chain message, or
84
+ * no signature is returned for the account address.
58
85
  *
59
86
  * @example
60
87
  * ```ts
@@ -62,7 +89,7 @@ type SolanaSiwxSignerTarget = SolanaWalletStandardSignerTarget | MessageModifyin
62
89
  * const signature = await signer(message);
63
90
  * ```
64
91
  */
65
- declare function createSolanaSiwxSigner(target: SolanaSiwxSignerTarget): (message: string) => Promise<string>;
92
+ declare function createSolanaSiwxSigner(target: SolanaSiwxSignerTarget, options?: SolanaSiwxSignerOptions): (message: string) => Promise<string>;
66
93
 
67
94
  /**
68
95
  * @file Solana-specific types for the @tuwaio/siwx-solana package.
@@ -112,6 +139,12 @@ type SolanaVerifyPayload = SiwxVerifyPayload | {
112
139
  * that public key with Web Crypto (`crypto.subtle`, algorithm `Ed25519`). Runs locally, without RPC calls. Nonce,
113
140
  * domain and policy checks are the caller's job (see `@tuwaio/siwx-server`).
114
141
  *
142
+ * Accepts the two ways a Solana wallet signs text: the UTF-8 bytes of the message (`solana:signMessage`) or the
143
+ * version 1 off-chain message envelope of the message (`solana:signOffchainMessage`, which hardware wallets can show
144
+ * and sign). With a string message both are tried, since the envelope is fully determined by the text and the address
145
+ * of the message. Signed message bytes that are a version 1 envelope are decoded, and their only required signatory
146
+ * must be the address of the message; other off-chain message versions are rejected.
147
+ *
115
148
  * Requires a runtime with Ed25519 support in Web Crypto (current browsers, Node.js 20+, edge runtimes).
116
149
  *
117
150
  * @param payload - `{ message, signature }` (base58 string or bytes), or a Wallet Standard `solana:signIn` output.
@@ -129,4 +162,4 @@ declare function verifyEd25519(payload: SolanaVerifyPayload, options?: {
129
162
  skipExpiration?: boolean;
130
163
  }): Promise<SiwxVerifyResult>;
131
164
 
132
- export { type SolanaLegacyMessageSigner, type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, type SolanaWalletStandardSignerTarget, createSolanaSiwxSigner, verifyEd25519 };
165
+ export { type SolanaLegacyMessageSigner, type SolanaSignInAccount, type SolanaSignInOutput, type SolanaSiwxMessageFormat, type SolanaSiwxSignerOptions, type SolanaSiwxSignerTarget, type SolanaVerifyPayload, type SolanaWalletStandardSignerTarget, createSolanaSiwxSigner, verifyEd25519 };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var kit=require('@solana/kit'),orbitCore=require('@tuwaio/orbit-core'),siwxCore=require('@tuwaio/siwx-core');function W(e,s){if(e===s)return true;if(e.length!==s.length)return false;for(let n=0;n<e.length;n++)if(e[n]!==s[n])return false;return true}function v(e,s){if(typeof e?.modifyAndSignMessages=="function")return e;if(typeof s?.modifyAndSignMessages=="function")return s;let n=s?.features,t=e?.features,r;Array.isArray(n)&&n.includes("solana:signMessage"),t&&typeof t=="object"&&!Array.isArray(t)&&(r=t["solana:signMessage"]);let i=e?.adapter??s?.adapter,o=e?.signMessage??i?.signMessage??s?.signMessage,l=e?.signMessages??s?.signMessages;if(!r&&!o&&!l)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let a=String(s?.address??e?.address??"solana:signer");return {address:a,async modifyAndSignMessages(g,M={}){if(M.abortSignal?.aborted)throw new Error("Aborted");if(g.length===0)return g;let c=[];for(let A=0;A<g.length;A++){let d=g[A],f,S;if(r){let u=[{account:s,message:d.content}],m=(await r.signMessage(...u))[0];if(!m||!m.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");f=m.signature,S=m.signedMessage??d.content;}else if(typeof l=="function"){let y=(await l([{account:s,message:d.content}]))[0];if(!y||!y.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");f=y.signature,S=y.signedMessage??d.content;}else if(typeof o=="function"){let u=await o.call(i??e??s,d.content);if(S=d.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 b=d.content.length!==S.length||d.content.some((u,y)=>u!==S[y]),h=d.signatures[a];if(!(h===void 0||!W(h,f))&&!b){c.push(d);continue}let U=b?{[a]:f}:{...d.signatures,[a]:f};c.push(Object.freeze({content:S,signatures:Object.freeze(U)}));}return c}}}function P(e){return async s=>{try{if(!e)throw new Error("[SIWX-SOLANA] Invalid signer target.");let{wallet:n,account:t}=e,r=n??e,i=t??e,l=kit.getUtf8Encoder().encode(s),a=v(r,i),g=kit.createSignableMessage(l),p=(await a.modifyAndSignMessages([g]))[0];if(!p)throw new Error("[SIWX-SOLANA] No signed message returned.");let c=p.signatures[a.address];if(!c)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${a.address}`);return kit.getBase58Decoder().decode(c)}catch(n){throw new Error(`[SIWX-SOLANA] Signing failed: ${n.message}`,{cause:n})}}}function x(e){let s="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",n=new Map(s.split("").map((a,g)=>[a,BigInt(g)])),t=0n;for(let a of e){let g=n.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 R(e){let s="output"in e?e.output:e,n="signedMessage"in s?s.signedMessage:s.message,t=s.signature,r,i;n instanceof Uint8Array?(i=n,r=new TextDecoder().decode(n)):(r=n,i=new TextEncoder().encode(n));let o;return t instanceof Uint8Array?o=t:o=x(t),{messageString:r,messageBytes:i,signatureBytes:o}}async function X(e,s){try{let{messageString:n,messageBytes:t,signatureBytes:r}=R(e),i=siwxCore.parseMessage(n),o=orbitCore.parseCaip2ChainId(i.chainId)?.namespace;if(o!=="solana")throw new siwxCore.SiwxUnsupportedNamespaceError(o??"unknown");if(r.length!==64)throw new siwxCore.SiwxVerificationError(`Invalid Solana signature length: ${r.length} bytes (expected 64)`);let l=siwxCore.validateMessage(i,{skipExpiration:s?.skipExpiration,policy:{enforceNotBefore:!0}});if(!l.valid)throw new siwxCore.SiwxValidationError(l.errors);let a=orbitCore.parseCaip10AccountId(i.address);if(a?.namespace!=="solana")throw new siwxCore.SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${i.address}"`);let g=a.address,M=kit.address(g),p=x(M),c=await globalThis.crypto.subtle.importKey("raw",p.buffer,{name:"Ed25519"},!1,["verify"]);if(!await globalThis.crypto.subtle.verify({name:"Ed25519"},c,r.buffer,t.buffer))throw new siwxCore.SiwxVerificationError(`ed25519 signature verification failed for address: ${g}`);return {success:!0,data:i}}catch(n){return n instanceof siwxCore.SiwxVerificationError||n instanceof siwxCore.SiwxValidationError?{success:false,error:n.message}:{success:false,error:`ed25519 verification failed: ${String(n)}`}}}exports.createSolanaSiwxSigner=P;exports.verifyEd25519=X;
1
+ 'use strict';var kit=require('@solana/kit'),orbitCore=require('@tuwaio/orbit-core'),siwxCore=require('@tuwaio/siwx-core');function B(n,e){if(n===e)return true;if(n.length!==e.length)return false;for(let s=0;s<n.length;s++)if(n[s]!==e[s])return false;return true}function K(n,e,s){if(typeof n?.modifyAndSignMessages=="function")return n;if(typeof e?.modifyAndSignMessages=="function")return e;let t=e?.features,a=n?.features,i;Array.isArray(t)&&t.includes("solana:signMessage"),a&&typeof a=="object"&&!Array.isArray(a)&&(i=a["solana:signMessage"]);let o=n?.adapter??e?.adapter,g=[n,o,e,s].find(l=>typeof l?.signMessage=="function"),r=g?.signMessage,f=n?.signMessages??e?.signMessages;if(!i&&!r&&!f)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let c=String(e?.address??n?.address??"solana:signer");return {address:c,async modifyAndSignMessages(l,m={}){if(m.abortSignal?.aborted)throw new Error("Aborted");if(l.length===0)return l;let y=[];for(let M=0;M<l.length;M++){let u=l[M],S,p;if(i){let d=[{account:e,message:u.content}],O=(await i.signMessage(...d))[0];if(!O||!O.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");S=O.signature,p=O.signedMessage??u.content;}else if(typeof f=="function"){let h=(await f([{account:e,message:u.content}]))[0];if(!h||!h.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");S=h.signature,p=h.signedMessage??u.content;}else if(typeof r=="function"){let d=await r.call(g,u.content);if(p=u.content,d instanceof Uint8Array||d&&d.buffer instanceof ArrayBuffer)S=d;else if(d&&typeof d=="object"&&"signature"in d)S=d.signature;else throw new Error("[SIWX-SOLANA] Unexpected legacy signMessage result format.")}else throw new Error("[SIWX-SOLANA] Missing signing implementation.");let k=u.content.length!==p.length||u.content.some((d,h)=>d!==p[h]),x=u.signatures[c];if(!(x===void 0||!B(x,S))&&!k){y.push(u);continue}let F=k?{[c]:S}:{...u.signatures,[c]:S};y.push(Object.freeze({content:p,signatures:Object.freeze(F)}));}return y}}}function $(n,e,s){let t=n.features,a=t&&typeof t=="object"&&!Array.isArray(t)?t["solana:signOffchainMessage"]:void 0;if(a&&typeof a.signOffchainMessage=="function")return a.supportedMessageVersions?.includes(1)?{async sign(o){let r=(await a.signOffchainMessage({account:e,message:o,messageVersion:1,requiredSigners:[q(e)]}))[0];if(!r?.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signOffchainMessage output.");return r}}:{error:"The wallet cannot sign version 1 off-chain messages."};let i=[n,e,s].find(o=>typeof o.signOffchainMessage=="function");if(i){let o=i.signOffchainMessage;return {async sign(g){let r=await o.call(i,g);if(!r?.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signOffchainMessage output.");return r}}}}function q(n){let e=n.publicKey;return e instanceof Uint8Array?e:new Uint8Array(kit.getAddressEncoder().encode(kit.address(String(n.address))))}function U(n,e,s){for(let a of [e,n,s]){let i=a.address;if(typeof i=="string")return i}let t=s.publicKey;return typeof t?.toBase58=="function"?t.toBase58():void 0}async function E(n,e,s){if(!n.sign)throw new Error(`[SIWX-SOLANA] ${n.error}`);let t=await n.sign(e);if(t.signedOffchainMessage&&s){let a=kit.compileOffchainMessageV1Envelope({version:1,content:e,requiredSignatories:[{address:kit.address(s)}]}).content;if(!B(new Uint8Array(t.signedOffchainMessage),a))throw new Error("[SIWX-SOLANA] Wallet signed a different off-chain message than requested.")}return kit.getBase58Decoder().decode(new Uint8Array(t.signature))}function v(n,e){let s=n.features;return !Array.isArray(s)||s.includes(e)}function C(n,e={}){let s=e.messageFormat??"auto";return async t=>{try{if(!n)throw new Error("[SIWX-SOLANA] Invalid signer target.");let a=n,{wallet:i,account:o}=n,g=i??n,r=o??n,f=s==="message"?void 0:$(g,r,a);if(s==="offchainMessage"){if(!f)throw new Error("[SIWX-SOLANA] Signer cannot sign off-chain messages.");return await E(f,t,U(g,r,a))}let c;try{c=K(g,r,a);}catch(p){if(!f?.sign)throw p}if(f?.sign&&(!c||!v(r,"solana:signMessage")&&v(r,"solana:signOffchainMessage"))||!c)return await E(f,t,U(g,r,a));let A=kit.getUtf8Encoder().encode(t),y=kit.createSignableMessage(A),u=(await c.modifyAndSignMessages([y]))[0];if(!u)throw new Error("[SIWX-SOLANA] No signed message returned.");let S=u.signatures[c.address];if(!S)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${c.address}`);return kit.getBase58Decoder().decode(S)}catch(a){throw new Error(`[SIWX-SOLANA] Signing failed: ${a.message}`,{cause:a})}}}function L(n){let e="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",s=new Map(e.split("").map((r,f)=>[r,BigInt(f)])),t=0n;for(let r of n){let f=s.get(r);if(f===void 0)throw new siwxCore.SiwxVerificationError(`Invalid base58 character: "${r}"`);t=t*58n+f;}let a=t.toString(16);a.length%2!==0&&(a="0"+a);let i=[];for(let r=0;r<a.length;r+=2)i.push(parseInt(a.slice(r,r+2),16));let o=0;for(let r of n)if(r==="1")o++;else break;let g=new Uint8Array(o+i.length);return g.set(i,o),g}var P=new Uint8Array([255,...new TextEncoder().encode("solana offchain")]);function Q(n){return n.length>P.length&&P.every((e,s)=>n[s]===e)}function Y(n){let e;try{e=kit.getOffchainMessageDecoder().decode(n);}catch(s){throw new siwxCore.SiwxVerificationError(`Invalid off-chain message: ${String(s)}`)}if(e.version!==1)throw new siwxCore.SiwxVerificationError(`Unsupported off-chain message version: ${e.version} (expected 1)`);return {content:e.content,signatories:e.requiredSignatories.map(({address:s})=>s)}}function ee(n,e){try{return kit.compileOffchainMessageV1Envelope({version:1,content:n,requiredSignatories:[{address:kit.address(e)}]}).content}catch{return}}function ne(n){let e="output"in n?n.output:n,s="signedMessage"in e?e.signedMessage:e.message,t=e.signature,a,i,o;if(s instanceof Uint8Array)if(i=s,Q(s)){let r=Y(s);a=r.content,o=r.signatories;}else a=new TextDecoder().decode(s);else a=s,i=new TextEncoder().encode(s);let g;return t instanceof Uint8Array?g=t:g=L(t),{messageString:a,messageBytes:i,signatureBytes:g,offchainSignatories:o}}async function b(n,e,s){return globalThis.crypto.subtle.verify({name:"Ed25519"},n,e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength),s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength))}async function se(n,e){try{let{messageString:s,messageBytes:t,signatureBytes:a,offchainSignatories:i}=ne(n),o=siwxCore.parseMessage(s),g=orbitCore.parseCaip2ChainId(o.chainId)?.namespace;if(g!=="solana")throw new siwxCore.SiwxUnsupportedNamespaceError(g??"unknown");if(a.length!==64)throw new siwxCore.SiwxVerificationError(`Invalid Solana signature length: ${a.length} bytes (expected 64)`);let r=siwxCore.validateMessage(o,{skipExpiration:e?.skipExpiration,policy:{enforceNotBefore:!0}});if(!r.valid)throw new siwxCore.SiwxValidationError(r.errors);let f=orbitCore.parseCaip10AccountId(o.address);if(f?.namespace!=="solana")throw new siwxCore.SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${o.address}"`);let c=f.address,l=kit.address(c),m=L(l),A=await globalThis.crypto.subtle.importKey("raw",m.buffer,{name:"Ed25519"},!1,["verify"]),y;if(i){if(i.length!==1||i[0]!==l)throw new siwxCore.SiwxVerificationError(`Off-chain message signatory must be the message address only. Got: ${i.join(", ")}`);y=await b(A,a,t);}else if(y=await b(A,a,t),!y){let M=ee(s,l);M&&(y=await b(A,a,M));}if(!y)throw new siwxCore.SiwxVerificationError(`ed25519 signature verification failed for address: ${c}`);return {success:!0,data:o}}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=C;exports.verifyEd25519=se;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {getUtf8Encoder,createSignableMessage,getBase58Decoder,address}from'@solana/kit';import {parseCaip2ChainId,parseCaip10AccountId}from'@tuwaio/orbit-core';import {parseMessage,SiwxUnsupportedNamespaceError,SiwxVerificationError,validateMessage,SiwxValidationError}from'@tuwaio/siwx-core';function W(e,s){if(e===s)return true;if(e.length!==s.length)return false;for(let n=0;n<e.length;n++)if(e[n]!==s[n])return false;return true}function v(e,s){if(typeof e?.modifyAndSignMessages=="function")return e;if(typeof s?.modifyAndSignMessages=="function")return s;let n=s?.features,t=e?.features,r;Array.isArray(n)&&n.includes("solana:signMessage"),t&&typeof t=="object"&&!Array.isArray(t)&&(r=t["solana:signMessage"]);let i=e?.adapter??s?.adapter,o=e?.signMessage??i?.signMessage??s?.signMessage,l=e?.signMessages??s?.signMessages;if(!r&&!o&&!l)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let a=String(s?.address??e?.address??"solana:signer");return {address:a,async modifyAndSignMessages(g,M={}){if(M.abortSignal?.aborted)throw new Error("Aborted");if(g.length===0)return g;let c=[];for(let A=0;A<g.length;A++){let d=g[A],f,S;if(r){let u=[{account:s,message:d.content}],m=(await r.signMessage(...u))[0];if(!m||!m.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");f=m.signature,S=m.signedMessage??d.content;}else if(typeof l=="function"){let y=(await l([{account:s,message:d.content}]))[0];if(!y||!y.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");f=y.signature,S=y.signedMessage??d.content;}else if(typeof o=="function"){let u=await o.call(i??e??s,d.content);if(S=d.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 b=d.content.length!==S.length||d.content.some((u,y)=>u!==S[y]),h=d.signatures[a];if(!(h===void 0||!W(h,f))&&!b){c.push(d);continue}let U=b?{[a]:f}:{...d.signatures,[a]:f};c.push(Object.freeze({content:S,signatures:Object.freeze(U)}));}return c}}}function P(e){return async s=>{try{if(!e)throw new Error("[SIWX-SOLANA] Invalid signer target.");let{wallet:n,account:t}=e,r=n??e,i=t??e,l=getUtf8Encoder().encode(s),a=v(r,i),g=createSignableMessage(l),p=(await a.modifyAndSignMessages([g]))[0];if(!p)throw new Error("[SIWX-SOLANA] No signed message returned.");let c=p.signatures[a.address];if(!c)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${a.address}`);return getBase58Decoder().decode(c)}catch(n){throw new Error(`[SIWX-SOLANA] Signing failed: ${n.message}`,{cause:n})}}}function x(e){let s="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",n=new Map(s.split("").map((a,g)=>[a,BigInt(g)])),t=0n;for(let a of e){let g=n.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 R(e){let s="output"in e?e.output:e,n="signedMessage"in s?s.signedMessage:s.message,t=s.signature,r,i;n instanceof Uint8Array?(i=n,r=new TextDecoder().decode(n)):(r=n,i=new TextEncoder().encode(n));let o;return t instanceof Uint8Array?o=t:o=x(t),{messageString:r,messageBytes:i,signatureBytes:o}}async function X(e,s){try{let{messageString:n,messageBytes:t,signatureBytes:r}=R(e),i=parseMessage(n),o=parseCaip2ChainId(i.chainId)?.namespace;if(o!=="solana")throw new SiwxUnsupportedNamespaceError(o??"unknown");if(r.length!==64)throw new SiwxVerificationError(`Invalid Solana signature length: ${r.length} bytes (expected 64)`);let l=validateMessage(i,{skipExpiration:s?.skipExpiration,policy:{enforceNotBefore:!0}});if(!l.valid)throw new SiwxValidationError(l.errors);let a=parseCaip10AccountId(i.address);if(a?.namespace!=="solana")throw new SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${i.address}"`);let g=a.address,M=address(g),p=x(M),c=await globalThis.crypto.subtle.importKey("raw",p.buffer,{name:"Ed25519"},!1,["verify"]);if(!await globalThis.crypto.subtle.verify({name:"Ed25519"},c,r.buffer,t.buffer))throw new SiwxVerificationError(`ed25519 signature verification failed for address: ${g}`);return {success:!0,data:i}}catch(n){return n instanceof SiwxVerificationError||n instanceof SiwxValidationError?{success:false,error:n.message}:{success:false,error:`ed25519 verification failed: ${String(n)}`}}}export{P as createSolanaSiwxSigner,X as verifyEd25519};
1
+ import {getUtf8Encoder,createSignableMessage,getBase58Decoder,address,compileOffchainMessageV1Envelope,getAddressEncoder,getOffchainMessageDecoder}from'@solana/kit';import {parseCaip2ChainId,parseCaip10AccountId}from'@tuwaio/orbit-core';import {parseMessage,SiwxUnsupportedNamespaceError,SiwxVerificationError,validateMessage,SiwxValidationError}from'@tuwaio/siwx-core';function B(n,e){if(n===e)return true;if(n.length!==e.length)return false;for(let s=0;s<n.length;s++)if(n[s]!==e[s])return false;return true}function K(n,e,s){if(typeof n?.modifyAndSignMessages=="function")return n;if(typeof e?.modifyAndSignMessages=="function")return e;let t=e?.features,a=n?.features,i;Array.isArray(t)&&t.includes("solana:signMessage"),a&&typeof a=="object"&&!Array.isArray(a)&&(i=a["solana:signMessage"]);let o=n?.adapter??e?.adapter,g=[n,o,e,s].find(l=>typeof l?.signMessage=="function"),r=g?.signMessage,f=n?.signMessages??e?.signMessages;if(!i&&!r&&!f)throw new Error("[SIWX-SOLANA] Signer lacks known message signing capabilities.");let c=String(e?.address??n?.address??"solana:signer");return {address:c,async modifyAndSignMessages(l,m={}){if(m.abortSignal?.aborted)throw new Error("Aborted");if(l.length===0)return l;let y=[];for(let M=0;M<l.length;M++){let u=l[M],S,p;if(i){let d=[{account:e,message:u.content}],O=(await i.signMessage(...d))[0];if(!O||!O.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessage output.");S=O.signature,p=O.signedMessage??u.content;}else if(typeof f=="function"){let h=(await f([{account:e,message:u.content}]))[0];if(!h||!h.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signMessages output.");S=h.signature,p=h.signedMessage??u.content;}else if(typeof r=="function"){let d=await r.call(g,u.content);if(p=u.content,d instanceof Uint8Array||d&&d.buffer instanceof ArrayBuffer)S=d;else if(d&&typeof d=="object"&&"signature"in d)S=d.signature;else throw new Error("[SIWX-SOLANA] Unexpected legacy signMessage result format.")}else throw new Error("[SIWX-SOLANA] Missing signing implementation.");let k=u.content.length!==p.length||u.content.some((d,h)=>d!==p[h]),x=u.signatures[c];if(!(x===void 0||!B(x,S))&&!k){y.push(u);continue}let F=k?{[c]:S}:{...u.signatures,[c]:S};y.push(Object.freeze({content:p,signatures:Object.freeze(F)}));}return y}}}function $(n,e,s){let t=n.features,a=t&&typeof t=="object"&&!Array.isArray(t)?t["solana:signOffchainMessage"]:void 0;if(a&&typeof a.signOffchainMessage=="function")return a.supportedMessageVersions?.includes(1)?{async sign(o){let r=(await a.signOffchainMessage({account:e,message:o,messageVersion:1,requiredSigners:[q(e)]}))[0];if(!r?.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signOffchainMessage output.");return r}}:{error:"The wallet cannot sign version 1 off-chain messages."};let i=[n,e,s].find(o=>typeof o.signOffchainMessage=="function");if(i){let o=i.signOffchainMessage;return {async sign(g){let r=await o.call(i,g);if(!r?.signature)throw new Error("[SIWX-SOLANA] Wallet returned invalid signOffchainMessage output.");return r}}}}function q(n){let e=n.publicKey;return e instanceof Uint8Array?e:new Uint8Array(getAddressEncoder().encode(address(String(n.address))))}function U(n,e,s){for(let a of [e,n,s]){let i=a.address;if(typeof i=="string")return i}let t=s.publicKey;return typeof t?.toBase58=="function"?t.toBase58():void 0}async function E(n,e,s){if(!n.sign)throw new Error(`[SIWX-SOLANA] ${n.error}`);let t=await n.sign(e);if(t.signedOffchainMessage&&s){let a=compileOffchainMessageV1Envelope({version:1,content:e,requiredSignatories:[{address:address(s)}]}).content;if(!B(new Uint8Array(t.signedOffchainMessage),a))throw new Error("[SIWX-SOLANA] Wallet signed a different off-chain message than requested.")}return getBase58Decoder().decode(new Uint8Array(t.signature))}function v(n,e){let s=n.features;return !Array.isArray(s)||s.includes(e)}function C(n,e={}){let s=e.messageFormat??"auto";return async t=>{try{if(!n)throw new Error("[SIWX-SOLANA] Invalid signer target.");let a=n,{wallet:i,account:o}=n,g=i??n,r=o??n,f=s==="message"?void 0:$(g,r,a);if(s==="offchainMessage"){if(!f)throw new Error("[SIWX-SOLANA] Signer cannot sign off-chain messages.");return await E(f,t,U(g,r,a))}let c;try{c=K(g,r,a);}catch(p){if(!f?.sign)throw p}if(f?.sign&&(!c||!v(r,"solana:signMessage")&&v(r,"solana:signOffchainMessage"))||!c)return await E(f,t,U(g,r,a));let A=getUtf8Encoder().encode(t),y=createSignableMessage(A),u=(await c.modifyAndSignMessages([y]))[0];if(!u)throw new Error("[SIWX-SOLANA] No signed message returned.");let S=u.signatures[c.address];if(!S)throw new Error(`[SIWX-SOLANA] Signature missing for address: ${c.address}`);return getBase58Decoder().decode(S)}catch(a){throw new Error(`[SIWX-SOLANA] Signing failed: ${a.message}`,{cause:a})}}}function L(n){let e="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",s=new Map(e.split("").map((r,f)=>[r,BigInt(f)])),t=0n;for(let r of n){let f=s.get(r);if(f===void 0)throw new SiwxVerificationError(`Invalid base58 character: "${r}"`);t=t*58n+f;}let a=t.toString(16);a.length%2!==0&&(a="0"+a);let i=[];for(let r=0;r<a.length;r+=2)i.push(parseInt(a.slice(r,r+2),16));let o=0;for(let r of n)if(r==="1")o++;else break;let g=new Uint8Array(o+i.length);return g.set(i,o),g}var P=new Uint8Array([255,...new TextEncoder().encode("solana offchain")]);function Q(n){return n.length>P.length&&P.every((e,s)=>n[s]===e)}function Y(n){let e;try{e=getOffchainMessageDecoder().decode(n);}catch(s){throw new SiwxVerificationError(`Invalid off-chain message: ${String(s)}`)}if(e.version!==1)throw new SiwxVerificationError(`Unsupported off-chain message version: ${e.version} (expected 1)`);return {content:e.content,signatories:e.requiredSignatories.map(({address:s})=>s)}}function ee(n,e){try{return compileOffchainMessageV1Envelope({version:1,content:n,requiredSignatories:[{address:address(e)}]}).content}catch{return}}function ne(n){let e="output"in n?n.output:n,s="signedMessage"in e?e.signedMessage:e.message,t=e.signature,a,i,o;if(s instanceof Uint8Array)if(i=s,Q(s)){let r=Y(s);a=r.content,o=r.signatories;}else a=new TextDecoder().decode(s);else a=s,i=new TextEncoder().encode(s);let g;return t instanceof Uint8Array?g=t:g=L(t),{messageString:a,messageBytes:i,signatureBytes:g,offchainSignatories:o}}async function b(n,e,s){return globalThis.crypto.subtle.verify({name:"Ed25519"},n,e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength),s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength))}async function se(n,e){try{let{messageString:s,messageBytes:t,signatureBytes:a,offchainSignatories:i}=ne(n),o=parseMessage(s),g=parseCaip2ChainId(o.chainId)?.namespace;if(g!=="solana")throw new SiwxUnsupportedNamespaceError(g??"unknown");if(a.length!==64)throw new SiwxVerificationError(`Invalid Solana signature length: ${a.length} bytes (expected 64)`);let r=validateMessage(o,{skipExpiration:e?.skipExpiration,policy:{enforceNotBefore:!0}});if(!r.valid)throw new SiwxValidationError(r.errors);let f=parseCaip10AccountId(o.address);if(f?.namespace!=="solana")throw new SiwxVerificationError(`Expected solana CAIP-10 address format. Got: "${o.address}"`);let c=f.address,l=address(c),m=L(l),A=await globalThis.crypto.subtle.importKey("raw",m.buffer,{name:"Ed25519"},!1,["verify"]),y;if(i){if(i.length!==1||i[0]!==l)throw new SiwxVerificationError(`Off-chain message signatory must be the message address only. Got: ${i.join(", ")}`);y=await b(A,a,t);}else if(y=await b(A,a,t),!y){let M=ee(s,l);M&&(y=await b(A,a,M));}if(!y)throw new SiwxVerificationError(`ed25519 signature verification failed for address: ${c}`);return {success:!0,data:o}}catch(s){return s instanceof SiwxVerificationError||s instanceof SiwxValidationError?{success:false,error:s.message}:{success:false,error:`ed25519 verification failed: ${String(s)}`}}}export{C as createSolanaSiwxSigner,se as verifyEd25519};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuwaio/siwx-solana",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "author": "Oleksandr Tkach",
6
6
  "license": "Apache-2.0",
@@ -47,12 +47,12 @@
47
47
  "peerDependencies": {
48
48
  "@tuwaio/orbit-core": ">=0.5",
49
49
  "@tuwaio/siwx-core": ">=0.4.1",
50
- "@wallet-standard/base": ">=1.1.1",
51
- "@solana/kit": ">=8.2"
50
+ "@wallet-standard/base": ">=1.1.0",
51
+ "@solana/kit": ">=6"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@tuwaio/orbit-core": "^0.5.0",
55
- "@tuwaio/siwx-core": "0.6.0",
55
+ "@tuwaio/siwx-core": "0.7.0",
56
56
  "@wallet-standard/base": "^1.1.1",
57
57
  "@solana/kit": "^8.4.0",
58
58
  "tsup": "^8.5.1",