UNPKG

@wuwei-labs/srsly

Version:
147 lines 5.33 kB
/** * @purpose Universal signer handling for @solana/kit and @solana/web3.js compatibility * * Accepts signers from both libraries and extracts address strings for use with Codama. */ import { createNoopSigner, address } from '@solana/kit'; /** * Extract address string from any supported signer format * * @param signer - Signer in any supported format * @returns Base58-encoded address string * @throws Error if signer format is invalid * * @example * ```typescript * // String address * const addr1 = getSignerAddress("9WzDXw..."); * * // web3.js Keypair * import { Keypair } from '@solana/web3.js'; * const keypair = Keypair.generate(); * const addr2 = getSignerAddress(keypair); * * // @solana/kit signer * import { createNoopSigner, address } from '@solana/kit'; * const kitSigner = createNoopSigner(address("9WzDXw...")); * const addr3 = getSignerAddress(kitSigner); * ``` */ export function getSignerAddress(signer) { // Handle string address if (typeof signer === 'string') { validateAddress(signer); return address(signer); } // Handle object signers if (signer && typeof signer === 'object') { // web3.js Keypair/Wallet format (has publicKey.toBase58()) if ('publicKey' in signer && signer.publicKey && typeof signer.publicKey.toBase58 === 'function') { const addr = signer.publicKey.toBase58(); validateAddress(addr); return address(addr); } // web3.js PublicKey format (has direct toBase58()) if ('toBase58' in signer && typeof signer.toBase58 === 'function') { const addr = signer.toBase58(); validateAddress(addr); return address(addr); } // @solana/kit signer format if ('address' in signer) { const addr = String(signer.address); validateAddress(addr); return address(addr); } } throw new Error('Invalid signer format. Expected:\n' + ' - string address\n' + ' - web3.js Keypair (with publicKey.toBase58())\n' + ' - web3.js PublicKey (with toBase58())\n' + ' - @solana/kit TransactionSigner (with address property)'); } /** * Validate that a string is a valid Solana address * * Basic validation - checks length only. For full validation, * use @solana/kit's address() function or web3.js PublicKey constructor. * * @param address - Address string to validate * @throws Error if address format is invalid */ export function validateAddress(address) { if (typeof address !== 'string') { throw new Error(`Address must be a string, got ${typeof address}`); } // Solana addresses are base58-encoded 32-byte values // Base58 encoding of 32 bytes = 32-44 characters (typically 43-44) if (address.length < 32 || address.length > 44) { throw new Error(`Invalid Solana address length: ${address.length}. ` + `Expected 32-44 characters (base58-encoded 32 bytes). ` + `Got: "${address}"`); } // Check for invalid base58 characters const base58Regex = /^[1-9A-HJ-NP-Za-km-z]+$/; if (!base58Regex.test(address)) { throw new Error(`Invalid Solana address characters. ` + `Address must be base58-encoded (no 0, O, I, or l characters). ` + `Got: "${address}"`); } } /** * Type guard to check if a value is a web3.js signer */ export function isWeb3jsSigner(signer) { return (typeof signer === 'object' && signer !== null && 'publicKey' in signer && typeof signer.publicKey?.toBase58 === 'function'); } /** * Type guard to check if a value is a @solana/kit signer */ export function isKitSigner(signer) { return typeof signer === 'object' && signer !== null && 'address' in signer; } /** * Type guard to check if a value is a string address */ export function isAddressString(signer) { return typeof signer === 'string'; } /** * Convert UniversalSigner to TransactionSigner * * Intelligently handles different signer types: * - If already a TransactionSigner with signing capability → return as-is * - Otherwise → create noop signer from address (for browser/wallet cases) * * This enables the SDK to work in both: * - Browser/wallet contexts (where you only have addresses, not private keys) * - CLI/backend contexts (where you have full keypair signers) * * @param signer - Signer in any supported format * @returns TransactionSigner (either real or noop) * * @example * ```typescript * // CLI/backend - has private key * const wallet = await createKeyPairSignerFromBytes(secretKey); * const txSigner = toTransactionSigner(wallet); // Returns wallet as-is * * // Browser - only has address * const walletAddress = "9WzDXw..."; * const txSigner = toTransactionSigner(walletAddress); // Creates noop signer * ``` */ export function toTransactionSigner(signer) { // If already a TransactionSigner with signing capability, use it directly if (typeof signer === 'object' && signer !== null && 'signMessages' in signer) { return signer; } // Otherwise, extract address and create noop signer (for browser/wallet cases) return createNoopSigner(getSignerAddress(signer)); } //# sourceMappingURL=signer.js.map