@tuwaio/siwx-solana
@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.
🏛️ Core Capabilities
- Signing:
createSolanaSiwxSignerturns a Wallet Standard wallet and account (typed with@wallet-standard/base), an@solana/kitmessage signer or a legacy adapter into the(message) => signaturefunction thatuseSiwxfrom@tuwaio/siwx-reactexpects. Signatures are returned as base58 strings. - Verification:
verifyEd25519accepts a{ message, signature }payload (base58 strings or bytes) or the output of the Wallet Standardsolana:signInfeature. It requires asolanachain and a 64-byte signature, validates the message (format, expiration,notBeforeand anissuedAtin the future) and the address, and checks the signature withcrypto.subtle. It runs locally, without RPC calls, and returns{ success, data, error }instead of throwing. - Runtimes: any runtime whose Web Crypto API supports Ed25519, such as Node.js 20+ and current browsers. No native modules or polyfills.
💾 Installation
pnpm add @tuwaio/siwx-solana @tuwaio/siwx-core @solana/kit @wallet-standard/base[!IMPORTANT]
@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.
🚀 Usage
Signing with a Wallet Standard wallet
import { createSolanaSiwxSigner } from '@tuwaio/siwx-solana';
import type { Wallet, WalletAccount } from '@wallet-standard/base';
declare const wallet: Wallet; // a wallet with the `solana:signMessage` feature
declare const account: WalletAccount; // the connected account, one of `wallet.accounts`
declare const message: string;
const signer = createSolanaSiwxSigner({ wallet, account });
// Opens the wallet prompt. Rejects with "[SIWX-SOLANA] Signing failed: …" (original error in `cause`).
const signature = await signer(message); // base58Pass the Wallet Standard Wallet and WalletAccount objects. The UI handles of @wallet-standard/ui (UiWallet, UiWalletAccount) only list feature names and cannot sign.
Signing with other signers
import type { MessageModifyingSigner } from '@solana/kit';
import { createSolanaSiwxSigner } from '@tuwaio/siwx-solana';
declare const kitSigner: MessageModifyingSigner; // an @solana/kit message signer
declare const walletAdapter: { signMessage(message: Uint8Array): Promise<Uint8Array> }; // legacy wallet adapter
const signWithKit = createSolanaSiwxSigner(kitSigner);
const signWithAdapter = createSolanaSiwxSigner(walletAdapter);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).
Verifying a signature
import { verifyEd25519 } from '@tuwaio/siwx-solana';
declare const message: string;
declare const signature: string; // base58, as returned by createSolanaSiwxSigner
const result = await verifyEd25519({ message, signature });
if (result.success) {
console.log(result.data?.address); // "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpK:…"
} else {
console.error(result.error);
}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.
verifyEd25519 does not check the domain, URI, nonce or other policy rules. On a server, use @tuwaio/siwx-server, which adds the policy and single-use nonces, or run validatePolicy from @tuwaio/siwx-core yourself.
📚 API Reference
Every export, with signatures and types generated from the source, is documented at siwx.docs.tuwa.io/packages/siwx-solana .
📄 License
Licensed under the Apache-2.0 License. See the LICENSE file for details.