UNPKG

@turnkey/eip-1193-provider

Version:

EIP-1193 Provider for Turnkey.

105 lines (102 loc) 4.71 kB
import { serializeTransaction } from 'viem'; import { ChainIdAlreadyAddedError, InvalidChainIdFormatError, ChainIdValueExceedsError, InvalidRpcUrlError, BlockExplorerUrlError, NativeCurrencySymbolLengthError, NativeCurrencySymbolMismatchError, RpcUrlsRequiredError } from './errors.mjs'; const DEV_ENVS = ["test", "development"]; const preprocessTransaction = ({ from, ...transaction }) => { // Helper function to handle undefined values and conversion const convertValue = (value, converter, defaultValue) => (value !== undefined ? converter(value) : defaultValue); const typeMapping = { "0x0": "legacy", "0x1": "eip2930", "0x2": "eip1559", // TODO: enable these once ready // "0x3": "eip4844", // "0x4": "eip7702", }; const processedTransaction = { ...transaction, // @ts-ignore chainId: parseInt(transaction.chainId, 16), type: (transaction.type && typeMapping[transaction.type]) || "eip1559", maxPriorityFeePerGas: convertValue(transaction.maxPriorityFeePerGas, BigInt, 0n), maxFeePerGas: convertValue(transaction.maxFeePerGas, BigInt, 0n), gasPrice: convertValue(transaction.gasPrice, BigInt, 0n), value: convertValue(transaction.value, BigInt, 0n), nonce: convertValue(transaction.nonce, (value) => parseInt(value.toString(), 16), 0), gas: convertValue(transaction.gas, BigInt, 0n), }; const serializedTransaction = serializeTransaction(processedTransaction); return serializedTransaction.replace(/^0x/, ""); }; const isValidUrl = (url) => { // Allow http URLs in non-production environments, https URLs in production const protocolRegex = DEV_ENVS.includes(process.env.NODE_ENV ?? "") ? /^https?:\/\// : /^https:\/\//; return protocolRegex.test(url); }; /** * Validates the array of RPC URLs provided in the AddEthereumChainParameter. * It checks if the array is not empty and if every URL in the array starts with "https://". * Throws an RpcUrlsRequiredError if the array is empty or undefined. * Throws an InvalidRpcUrlError if any URL in the array does not start with "https://". * * @param {AddEthereumChainParameter['rpcUrls']} rpcUrls - The array of RPC URLs to validate. * @throws {RpcUrlsRequiredError} If the rpcUrls array is empty or undefined. * @throws {InvalidRpcUrlError} If any URL in the rpcUrls array is invalid. */ const validateRpcUrls = (rpcUrls) => { if (!rpcUrls || rpcUrls.length === 0) { throw new RpcUrlsRequiredError(); } if (!rpcUrls.every(isValidUrl)) { throw new InvalidRpcUrlError(); } }; const validateChain = (chain, addedChains) => { const { rpcUrls, blockExplorerUrls, chainId, nativeCurrency } = chain; if (addedChains.some((c) => c.chainId === chainId)) { throw new ChainIdAlreadyAddedError(); } let decimalChainId; try { decimalChainId = parseInt(chainId, 16); // Ensure the chain ID is a 0x-prefixed hexadecimal string and can be parsed to an integer if (!/^0x[0-9a-fA-F]+$/.test(chainId) || isNaN(decimalChainId)) { throw new InvalidChainIdFormatError(chainId); } } catch (error) { throw new InvalidChainIdFormatError(chainId); } // Validate chain ID value is not greater than max safe integer value if (decimalChainId > Number.MAX_SAFE_INTEGER) { throw new ChainIdValueExceedsError(chainId); } validateRpcUrls(rpcUrls); // Validate RPC URLs if (!rpcUrls || rpcUrls.length === 0 || !rpcUrls.every(isValidUrl)) { throw new InvalidRpcUrlError(); } // Validate Block Explorer URLs if (blockExplorerUrls && (!Array.isArray(blockExplorerUrls) || blockExplorerUrls.length === 0 || !blockExplorerUrls.every(isValidUrl))) { throw new BlockExplorerUrlError(); } // Validate native currency symbol length if (nativeCurrency && (nativeCurrency.symbol.length < 2 || nativeCurrency.symbol.length > 6)) { throw new NativeCurrencySymbolLengthError(nativeCurrency.symbol); } // Validate native currency symbol does not mismatch for a network the user already has added with the same chainId const existingChain = addedChains.find((c) => c.chainId === chainId); if (existingChain && existingChain.nativeCurrency && nativeCurrency && existingChain.nativeCurrency.symbol !== nativeCurrency.symbol) { throw new NativeCurrencySymbolMismatchError(nativeCurrency.symbol); } }; export { isValidUrl, preprocessTransaction, validateChain, validateRpcUrls }; //# sourceMappingURL=utils.mjs.map