UNPKG

@tenprotocol/session-keys

Version:

Framework-agnostic session key management for TEN Protocol

1 lines 30.8 kB
{"version":3,"sources":["../src/utils/constants.ts","../src/core/state.ts","../src/utils/encoding.ts","../src/core/sessionKey.ts","../src/core/transaction.ts"],"sourcesContent":["export const TEN_ADDRESSES = {\n SESSION_KEY_CREATE: '0x0000000000000000000000000000000000000003',\n SESSION_KEY_RETRIEVE: '0x0000000000000000000000000000000000000007',\n SESSION_KEY_ACTIVATE: '0x0000000000000000000000000000000000000004',\n SESSION_KEY_DEACTIVATE: '0x0000000000000000000000000000000000000005',\n SESSION_KEY_DELETE: '0x0000000000000000000000000000000000000006',\n SESSION_KEY_EXECUTE: '0x0000000000000000000000000000000000000008'\n} as const\n\nexport const TEN_CHAIN_ID = 443\n\nexport const DEFAULT_GAS_SETTINGS = {\n // Use percentiles for different network conditions\n PRIORITY_FEE_PERCENTILES: [25, 50, 75],\n // Number of blocks to look back for fee estimation\n FEE_HISTORY_BLOCKS: 10,\n // Base fee multipliers for different network conditions\n BASE_FEE_MULTIPLIERS: {\n LOW: 1.1, // Low priority\n MEDIUM: 1.2, // Medium priority (default)\n HIGH: 1.5 // High priority\n }\n} as const","import type { SessionKeyState, StateSubscriber } from '../types'\n\n// Internal state\nlet state: SessionKeyState = {\n sessionKey: null,\n isActive: false,\n balance: null,\n isLoading: false,\n error: null\n}\n\n// Subscribers\nconst subscribers = new Set<StateSubscriber>()\n\n// Simple mutex for state updates\nlet isUpdating = false\n\n// Load persisted state on init\ntry {\n const persisted = localStorage.getItem('ten-session-key-state')\n if (persisted) {\n const parsed = JSON.parse(persisted)\n state = {\n ...state,\n sessionKey: parsed.sessionKey,\n isActive: parsed.isActive\n }\n }\n} catch (error) {\n console.warn('Failed to load persisted state:', error)\n}\n\nexport const getState = (): SessionKeyState => ({ ...state })\n\nexport const updateState = async (updates: Partial<SessionKeyState>): Promise<void> => {\n // Wait if another update is in progress\n while (isUpdating) {\n await new Promise(resolve => setTimeout(resolve, 50))\n }\n \n try {\n isUpdating = true\n state = { ...state, ...updates }\n \n // Persist key state changes\n if ('sessionKey' in updates || 'isActive' in updates) {\n try {\n localStorage.setItem('ten-session-key-state', JSON.stringify({\n sessionKey: state.sessionKey,\n isActive: state.isActive\n }))\n } catch (error) {\n console.warn('Failed to persist state:', error)\n }\n }\n\n // Notify all subscribers\n subscribers.forEach(callback => {\n try {\n callback(getState())\n } catch (error) {\n console.error('Error in state subscriber:', error)\n }\n })\n } finally {\n isUpdating = false\n }\n}\n\nexport const subscribeToState = (callback: StateSubscriber): (() => void) => {\n subscribers.add(callback)\n return () => {\n subscribers.delete(callback)\n }\n}\n\nexport const clearPersistedState = (): void => {\n try {\n localStorage.removeItem('ten-session-key-state')\n } catch (error) {\n console.warn('Failed to clear persisted state:', error)\n }\n}\n\n// State getters\nexport const getSessionKey = (): string | null => state.sessionKey\nexport const getIsActive = (): boolean => state.isActive\nexport const getBalance = (): SessionKeyState['balance'] => state.balance\nexport const getIsLoading = (): boolean => state.isLoading\nexport const getError = (): Error | null => state.error","export const toHex = (value: number | bigint | string): string => {\n // Convert to hex string and remove leading zeros\n let hexStr = BigInt(value).toString(16)\n // Ensure at least one digit\n hexStr = hexStr || '0'\n // Add 0x prefix\n return '0x' + hexStr\n}\n\nexport const hexToBytes = (hex: string): Uint8Array => {\n const cleanHex = hex.replace('0x', '')\n const bytes = new Uint8Array(cleanHex.length / 2)\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16)\n }\n return bytes\n}\n\nexport const bytesToHex = (bytes: Uint8Array): string => {\n return '0x' + Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\nexport const parseEther = (value: string): bigint => {\n const [whole, decimal = ''] = value.split('.')\n const paddedDecimal = decimal.padEnd(18, '0').slice(0, 18)\n return BigInt(whole + paddedDecimal)\n}\n\nexport const formatEther = (wei: bigint): number => {\n const ethString = wei.toString()\n if (ethString.length <= 18) {\n return parseFloat('0.' + ethString.padStart(18, '0'))\n }\n const wholePart = ethString.slice(0, -18)\n const decimalPart = ethString.slice(-18)\n return parseFloat(wholePart + '.' + decimalPart)\n}\n\nexport const estimateTransactions = (ethBalance: number): number => {\n // Rough estimate: each transaction costs ~0.005 ETH\n return Math.floor(ethBalance / 0.005)\n}","import type { EIP1193Provider } from '../types'\nimport { TEN_ADDRESSES, TEN_CHAIN_ID } from '../utils/constants'\nimport { updateState, clearPersistedState } from './state'\nimport { parseEther, toHex, formatEther, estimateTransactions } from '../utils/encoding'\n\n// Track provider event listeners\nlet providerCleanup: (() => void) | null = null\n\nconst setupProviderListeners = (provider: EIP1193Provider) => {\n if (providerCleanup) {\n providerCleanup()\n }\n\n const handleDisconnect = () => {\n updateState({ \n isActive: false,\n error: new Error('Provider disconnected')\n })\n }\n\n const handleChainChanged = () => {\n updateState({ \n isActive: false,\n error: new Error('Chain changed')\n })\n }\n\n provider.on?.('disconnect', handleDisconnect)\n provider.on?.('chainChanged', handleChainChanged)\n\n providerCleanup = () => {\n provider.removeListener?.('disconnect', handleDisconnect)\n provider.removeListener?.('chainChanged', handleChainChanged)\n }\n}\n\nconst checkTenNetwork = async (provider: EIP1193Provider): Promise<void> => {\n const chainId = await provider.request({ method: 'eth_chainId' })\n const chainIdInt = parseInt(chainId, 16)\n \n if (chainIdInt !== TEN_CHAIN_ID) {\n throw new Error('Session Keys is only for TEN chain, please add or switch to TEN.')\n }\n}\n\nexport const createSessionKey = async (provider: EIP1193Provider): Promise<string> => {\n try {\n updateState({ isLoading: true, error: null })\n\n // Setup provider listeners\n setupProviderListeners(provider)\n\n // Check if connected to TEN network\n await checkTenNetwork(provider)\n\n console.log('🔑 Creating session key on TEN network...')\n console.log('🔑 Using address:', TEN_ADDRESSES.SESSION_KEY_CREATE)\n\n // Try to create a new session key\n const response = await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_CREATE,\n '0x0',\n 'latest'\n ]\n })\n\n console.log('🔑 Create response:', response)\n\n if (!response || response === '0x0000000000000000000000000000000000000000000000000000000000000000') {\n console.log('🔑 Creation failed, trying to retrieve existing session key...')\n \n // If creation failed, try to retrieve existing session key\n const existingKey = await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_RETRIEVE,\n '0x0',\n 'latest'\n ]\n })\n\n console.log('🔑 Existing key response:', existingKey)\n\n if (existingKey && existingKey !== '0x0000000000000000000000000000000000000000000000000000000000000000') {\n const sessionKeyAddress = '0x' + existingKey.slice(-40) // Extract address from response\n console.log('🔑 Retrieved existing session key:', sessionKeyAddress)\n updateState({ \n sessionKey: sessionKeyAddress,\n isLoading: false \n })\n return sessionKeyAddress\n }\n\n throw new Error('Failed to create session key - both creation and retrieval returned empty response')\n }\n\n const sessionKeyAddress = '0x' + response.slice(-40) // Extract address from response\n console.log('🔑 Created new session key:', sessionKeyAddress)\n updateState({ \n sessionKey: sessionKeyAddress,\n isLoading: false \n })\n\n return sessionKeyAddress\n } catch (error) {\n console.error('🔑 Session key creation error:', error)\n const err = error instanceof Error ? error : new Error('Unknown error')\n updateState({ error: err, isLoading: false })\n throw err\n }\n}\n\nexport const fundSessionKey = async (\n sessionKeyAddress: string,\n amount: string,\n provider: EIP1193Provider,\n userAddress: string\n): Promise<string> => {\n try {\n updateState({ isLoading: true, error: null })\n\n // Check if connected to TEN network\n await checkTenNetwork(provider)\n\n console.log('💰 Funding session key:', sessionKeyAddress, 'with', amount, 'ETH')\n\n // Convert amount to hex\n const valueInWei = parseEther(amount)\n const valueHex = toHex(valueInWei)\n\n // Send transaction\n const txHash = await provider.request({\n method: 'eth_sendTransaction',\n params: [{\n to: sessionKeyAddress,\n value: valueHex,\n from: userAddress\n }]\n })\n\n console.log('💰 Funding transaction sent:', txHash)\n\n // Monitor transaction confirmation\n const checkTx = async () => {\n const receipt = await provider.request({\n method: 'eth_getTransactionReceipt',\n params: [txHash]\n })\n if (receipt) {\n console.log('💰 Funding confirmed!')\n return receipt\n }\n // Check again in 2 seconds\n await new Promise(resolve => setTimeout(resolve, 2000))\n return checkTx()\n }\n\n await checkTx()\n updateState({ isLoading: false })\n return txHash\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Unknown error')\n updateState({ error: err, isLoading: false })\n throw err\n }\n}\n\nexport const activateSessionKey = async (provider: EIP1193Provider): Promise<void> => {\n try {\n updateState({ isLoading: true, error: null })\n\n // Check if connected to TEN network\n await checkTenNetwork(provider)\n\n await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_ACTIVATE,\n '0x0',\n 'latest'\n ]\n })\n\n updateState({ \n isActive: true,\n isLoading: false \n })\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Activation failed')\n updateState({ error: err, isLoading: false })\n throw err\n }\n}\n\nexport const deactivateSessionKey = async (provider: EIP1193Provider): Promise<void> => {\n try {\n updateState({ isLoading: true, error: null })\n\n // Check if connected to TEN network\n await checkTenNetwork(provider)\n\n await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_DEACTIVATE,\n '0x0',\n 'latest'\n ]\n })\n\n updateState({ \n isActive: false,\n isLoading: false \n })\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Deactivation failed')\n updateState({ error: err, isLoading: false })\n throw err\n }\n}\n\nexport const deleteSessionKey = async (provider: EIP1193Provider): Promise<void> => {\n try {\n updateState({ isLoading: true, error: null })\n\n // Check if connected to TEN network\n await checkTenNetwork(provider)\n\n await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_DELETE,\n '0x0',\n 'latest'\n ]\n })\n\n // Clear persisted state when deleting\n clearPersistedState()\n \n // Remove provider listeners\n if (providerCleanup) {\n providerCleanup()\n providerCleanup = null\n }\n\n updateState({ \n sessionKey: null,\n isActive: false,\n balance: null,\n isLoading: false \n })\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Deletion failed')\n updateState({ error: err, isLoading: false })\n throw err\n }\n}\n\nexport const cleanupSessionKey = async (provider: EIP1193Provider): Promise<void> => {\n try {\n updateState({ isLoading: true, error: null })\n\n // Check if connected to TEN network\n await checkTenNetwork(provider)\n\n // First deactivate\n await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_DEACTIVATE,\n '0x0',\n 'latest'\n ]\n })\n\n // Then delete\n await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_DELETE,\n '0x0',\n 'latest'\n ]\n })\n\n updateState({ \n sessionKey: null,\n isActive: false,\n balance: null,\n isLoading: false \n })\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Cleanup failed')\n updateState({ error: err, isLoading: false })\n throw err\n }\n}\n\n// Helper function to update balance\nconst updateBalance = async (sessionKeyAddress: string, provider: EIP1193Provider): Promise<void> => {\n try {\n const balanceHex = await provider.request({\n method: 'eth_getBalance',\n params: [sessionKeyAddress, 'latest']\n })\n\n const balanceWei = BigInt(balanceHex)\n const ethBalance = formatEther(balanceWei)\n \n updateState({\n balance: {\n eth: ethBalance,\n estimatedTransactions: estimateTransactions(ethBalance)\n }\n })\n } catch (error) {\n console.warn('Failed to update balance:', error)\n }\n}","import { encode as rlpEncode } from 'rlp'\nimport type { EIP1193Provider, TransactionParams } from '../types'\nimport { TEN_ADDRESSES, TEN_CHAIN_ID, DEFAULT_GAS_SETTINGS } from '../utils/constants'\nimport { toHex, hexToBytes } from '../utils/encoding'\nimport { getSessionKey, updateState } from './state'\n\nconst checkTenNetwork = async (provider: EIP1193Provider): Promise<void> => {\n const chainId = await provider.request({ method: 'eth_chainId' })\n const chainIdInt = parseInt(chainId, 16)\n \n if (chainIdInt !== TEN_CHAIN_ID) {\n throw new Error('Session Keys is only for TEN chain, please add or switch to TEN.')\n }\n}\n\nconst calculateGasFees = async (\n provider: EIP1193Provider,\n priority: 'LOW' | 'MEDIUM' | 'HIGH' = 'MEDIUM'\n): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }> => {\n const { BASE_FEE_MULTIPLIERS } = DEFAULT_GAS_SETTINGS\n \n try {\n // Get fee history for last block\n const feeHistory = await provider.request({\n method: 'eth_feeHistory',\n params: [\n 1, // just get latest block\n 'latest',\n [] // no percentiles needed since we don't get rewards\n ]\n })\n\n console.log('Fee history response:', feeHistory)\n\n if (!feeHistory?.baseFeePerGas?.[0]) {\n throw new Error('Invalid fee history response')\n }\n\n // Get base fee from response\n const baseFee = BigInt(feeHistory.baseFeePerGas[0])\n console.log('Base fee:', baseFee.toString())\n \n // Use a fixed priority fee since the network doesn't provide reward data\n const priorityFeePerGas = BigInt(100000000) // 0.1 gwei\n \n // Calculate max fee using appropriate multiplier\n const multiplier = BASE_FEE_MULTIPLIERS[priority]\n const maxFeePerGas = BigInt(Math.floor(Number(baseFee) * multiplier)) + priorityFeePerGas\n console.log('Priority fee:', priorityFeePerGas.toString())\n console.log('Max fee:', maxFeePerGas.toString())\n\n return { maxFeePerGas, maxPriorityFeePerGas: priorityFeePerGas }\n } catch (error) {\n console.warn('Error getting fee history, using fallback values:', error)\n // Fallback to fixed values if anything goes wrong\n const baseFeePerGas = BigInt(1000000000) // 1 gwei\n const priorityFeePerGas = BigInt(100000000) // 0.1 gwei\n const multiplier = BASE_FEE_MULTIPLIERS[priority]\n const maxFeePerGas = BigInt(Math.floor(Number(baseFeePerGas) * multiplier)) + priorityFeePerGas\n return { maxFeePerGas, maxPriorityFeePerGas: priorityFeePerGas }\n }\n}\n\nexport const sendTransaction = async (\n txParams: TransactionParams,\n provider: EIP1193Provider\n): Promise<string> => {\n try {\n updateState({ isLoading: true, error: null })\n\n // Check if connected to TEN network\n await checkTenNetwork(provider)\n\n const sessionKeyAddress = getSessionKey()\n if (!sessionKeyAddress) {\n throw new Error('No active session key. Create and activate a session key first.')\n }\n\n // 1. Get chain ID\n const chainId = await provider.request({ method: 'eth_chainId' })\n const chainIdInt = parseInt(chainId, 16)\n\n // 2. Get nonce\n let nonce: number\n if (txParams.nonce !== undefined) {\n nonce = txParams.nonce\n } else {\n const nonceHex = await provider.request({\n method: 'eth_getTransactionCount',\n params: [sessionKeyAddress, 'latest']\n })\n nonce = parseInt(nonceHex, 16)\n }\n\n // 3. Calculate gas fees\n let maxFeePerGas: bigint\n let maxPriorityFeePerGas: bigint\n\n if (txParams.maxFeePerGas && txParams.maxPriorityFeePerGas) {\n maxFeePerGas = BigInt(txParams.maxFeePerGas)\n maxPriorityFeePerGas = BigInt(txParams.maxPriorityFeePerGas)\n } else {\n // Use dynamic fee calculation\n const gasFees = await calculateGasFees(provider, 'MEDIUM')\n maxFeePerGas = gasFees.maxFeePerGas\n maxPriorityFeePerGas = gasFees.maxPriorityFeePerGas\n }\n\n // 4. Get gas limit (use provided or estimate)\n let gasLimit: number\n if (txParams.gasLimit) {\n gasLimit = txParams.gasLimit\n } else {\n const gasEstimate = await provider.request({\n method: 'eth_estimateGas',\n params: [{\n to: txParams.to,\n data: txParams.data,\n value: txParams.value || '0x0',\n from: sessionKeyAddress\n }]\n })\n gasLimit = parseInt(gasEstimate, 16)\n }\n\n // 5. Build EIP-1559 transaction array\n const txArray = [\n toHex(chainIdInt), // chainId\n nonce === 0 ? '0x' : toHex(nonce), // nonce (special case for 0)\n toHex(maxPriorityFeePerGas), // maxPriorityFeePerGas\n toHex(maxFeePerGas), // maxFeePerGas\n toHex(gasLimit), // gasLimit\n txParams.to.toLowerCase(), // to (ensure lowercase)\n txParams.value?.toLowerCase() || '0x0', // value (ensure lowercase)\n txParams.data?.toLowerCase() || '0x', // data (ensure lowercase)\n [], // accessList (empty for now)\n '0x', // v (signature placeholder)\n '0x', // r (signature placeholder)\n '0x' // s (signature placeholder)\n ].map(value => {\n // Ensure all hex strings start with 0x\n if (typeof value === 'string' && !value.startsWith('0x')) {\n return '0x' + value;\n }\n return value;\n });\n\n // 6. RLP encode the transaction\n const rlpEncoded = rlpEncode(txArray)\n \n // 7. Prepare EIP-1559 transaction (type 2)\n // Convert RLP result to hex string - handle any type\n let rlpHex: string\n \n // The RLP library returns a Buffer or Uint8Array\n if (rlpEncoded && typeof rlpEncoded === 'object' && 'length' in rlpEncoded) {\n // It's array-like (Buffer or Uint8Array)\n const bytes = Array.from(rlpEncoded as Uint8Array)\n rlpHex = bytes.map((byte: number) => byte.toString(16).padStart(2, '0')).join('')\n } else {\n // Fallback - shouldn't happen with RLP but just in case\n throw new Error('Unexpected RLP encoding result')\n }\n \n const txBytes = new Uint8Array([\n 2, // EIP-1559 transaction type\n ...hexToBytes('0x' + rlpHex) // RLP encoded transaction\n ])\n\n // 8. Convert to base64 for TEN\n const txBase64 = btoa(String.fromCharCode(...txBytes))\n\n // 9. Send through TEN session key execution\n const txHash = await provider.request({\n method: 'eth_getStorageAt',\n params: [\n TEN_ADDRESSES.SESSION_KEY_EXECUTE,\n txBase64,\n 'latest'\n ]\n })\n\n updateState({ isLoading: false })\n return txHash\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error('Transaction failed')\n updateState({ error: err, isLoading: false })\n throw err\n }\n}"],"mappings":"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","names":["TEN_ADDRESSES","TEN_CHAIN_ID","DEFAULT_GAS_SETTINGS","state","subscribers","isUpdating","persisted","parsed","error","getState","updateState","updates","resolve","callback","subscribeToState","clearPersistedState","getSessionKey","getIsActive","getBalance","getIsLoading","getError","toHex","value","hexStr","hexToBytes","hex","cleanHex","bytes","i","parseEther","value","whole","decimal","paddedDecimal","providerCleanup","setupProviderListeners","provider","handleDisconnect","updateState","handleChainChanged","checkTenNetwork","chainId","TEN_CHAIN_ID","createSessionKey","TEN_ADDRESSES","response","existingKey","sessionKeyAddress","error","err","fundSessionKey","amount","userAddress","valueInWei","parseEther","valueHex","toHex","txHash","checkTx","receipt","resolve","activateSessionKey","deactivateSessionKey","deleteSessionKey","clearPersistedState","cleanupSessionKey","rlpEncode","checkTenNetwork","provider","chainId","TEN_CHAIN_ID","calculateGasFees","priority","BASE_FEE_MULTIPLIERS","DEFAULT_GAS_SETTINGS","feeHistory","baseFee","priorityFeePerGas","multiplier","maxFeePerGas","error","baseFeePerGas","sendTransaction","txParams","updateState","sessionKeyAddress","getSessionKey","chainIdInt","nonce","nonceHex","maxPriorityFeePerGas","gasFees","gasLimit","gasEstimate","txArray","toHex","value","rlpEncoded","rlpEncode","rlpHex","byte","txBytes","hexToBytes","txBase64","txHash","TEN_ADDRESSES","err"]}