UNPKG

@shogun-sdk/accounts

Version:

Shogun with Turnkey: configs, encryption, authentication with Telegram/Turnkey OIDC, etc.

162 lines (135 loc) 4.63 kB
import { getSecret } from './aes.js'; import { ApiKeyStamper, TurnkeyServerClient } from '@turnkey/sdk-server'; import { getPublicKey } from '@turnkey/crypto'; import { createAccount } from '@turnkey/viem'; import { createWalletClient, fallback, http, WalletClient, Chain } from 'viem'; import { getRpcUrls, getEthChainViem, SOLANA_CHAIN_ID } from '@shogun-sdk/money-legos'; import { TurnkeySigner } from '@turnkey/solana'; export function uint8ArrayToHex(uint8Array: Uint8Array): string { return Array.from(uint8Array) .map((byte) => byte.toString(16).padStart(2, '0')) .join(''); } export const getTurnkeyClient = async ( orgId: string, encryptedPrivateKey: string, publicOrganizationId: string, dataEncryptionKey: string, ): Promise<TurnkeyServerClient> => { if (!orgId) { throw new Error('Org ID is required'); } const decryptedPrivateKey = getSecret(orgId, encryptedPrivateKey, publicOrganizationId, dataEncryptionKey); if (!decryptedPrivateKey) { throw new Error('Failed to decrypt private key'); } const publicKey = uint8ArrayToHex(getPublicKey(decryptedPrivateKey)); const user_stamper = new ApiKeyStamper({ apiPublicKey: publicKey, apiPrivateKey: decryptedPrivateKey, }); return new TurnkeyServerClient({ apiBaseUrl: 'https://api.turnkey.com', organizationId: orgId, stamper: user_stamper, }); }; /** * Returns a Viem WalletClient for EVM chains using Turnkey Server. * @param orgId Organization ID * @param walletAddress The EVM address to sign with * @param chainId The EVM chain ID */ export const getEVMSignerTurnkeyServer = async ( orgId: string, walletAddress: string, chainId: number, encryptedPrivateKey: string, publicOrganizationId: string, dataEncryptionKey: string, ): Promise<WalletClient> => { if (!orgId) { throw new Error('Org ID is required'); } if (!walletAddress) { throw new Error('Wallet address is required'); } const decryptedPrivateKey = getSecret(orgId, encryptedPrivateKey, publicOrganizationId, dataEncryptionKey); if (!decryptedPrivateKey) { throw new Error('Failed to decrypt private key'); } const publicKey = uint8ArrayToHex(getPublicKey(decryptedPrivateKey)); const user_stamper = new ApiKeyStamper({ apiPublicKey: publicKey, apiPrivateKey: decryptedPrivateKey, }); const httpClient = new TurnkeyServerClient({ apiBaseUrl: 'https://api.turnkey.com', organizationId: orgId, stamper: user_stamper, }); // Use the same logic as getEVMChains to get the correct chain object const chain = getEthChainViem(chainId) as Chain; if (!chain) { throw new Error(`Unsupported EVM chainId: ${chainId}`); } const turnkeyAccount = await createAccount({ client: httpClient as any, organizationId: orgId, signWith: walletAddress, ethereumAddress: walletAddress, }); const rpcUrls = getRpcUrls()[chainId]?.rpc; if (!rpcUrls || rpcUrls.length === 0) { throw new Error(`No RPC URLs found for chainId: ${chainId}`); } const transports = rpcUrls.map((url: string) => http(url)); const client = createWalletClient({ account: turnkeyAccount as any, chain, transport: fallback(transports), }); return client; }; /** * Returns a TurnkeySigner for Solana using Turnkey Server. * @param orgId Organization ID * @param address The Solana address to sign with (optional, not required for TurnkeySigner) */ export const getTurnkeySolanaSignerServer = async ( orgId: string, encryptedPrivateKey: string, publicOrganizationId: string, dataEncryptionKey: string, ): Promise<TurnkeySigner> => { if (!orgId) { throw new Error('Org ID is required'); } const decryptedPrivateKey = getSecret(orgId, encryptedPrivateKey, publicOrganizationId, dataEncryptionKey); if (!decryptedPrivateKey) { throw new Error('Failed to decrypt private key'); } const publicKey = uint8ArrayToHex(getPublicKey(decryptedPrivateKey)); const user_stamper = new ApiKeyStamper({ apiPublicKey: publicKey, apiPrivateKey: decryptedPrivateKey, }); const httpClient = new TurnkeyServerClient({ apiBaseUrl: 'https://api.turnkey.com', organizationId: orgId, stamper: user_stamper, }); const turnkeySigner = new TurnkeySigner({ organizationId: orgId, client: httpClient as any, }); return turnkeySigner; }; export const getChainTurnkeySigner = ( chainId: number, ): typeof getEVMSignerTurnkeyServer | typeof getTurnkeySolanaSignerServer => { if (chainId === SOLANA_CHAIN_ID) { return getTurnkeySolanaSignerServer; } return getEVMSignerTurnkeyServer; };