@turnkey/eip-1193-provider
Version:
EIP-1193 Provider for Turnkey.
111 lines (107 loc) • 4.67 kB
JavaScript
;
var viem = require('viem');
var errors = require('./errors.js');
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 = viem.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 errors.RpcUrlsRequiredError();
}
if (!rpcUrls.every(isValidUrl)) {
throw new errors.InvalidRpcUrlError();
}
};
const validateChain = (chain, addedChains) => {
const { rpcUrls, blockExplorerUrls, chainId, nativeCurrency } = chain;
if (addedChains.some((c) => c.chainId === chainId)) {
// Chain already added; return early
return;
}
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 errors.InvalidChainIdFormatError(chainId);
}
}
catch (error) {
throw new errors.InvalidChainIdFormatError(chainId);
}
// Validate chain ID value is not greater than max safe integer value
if (decimalChainId > Number.MAX_SAFE_INTEGER) {
throw new errors.ChainIdValueExceedsError(chainId);
}
validateRpcUrls(rpcUrls);
// Validate RPC URLs
if (!rpcUrls || rpcUrls.length === 0 || !rpcUrls.every(isValidUrl)) {
throw new errors.InvalidRpcUrlError();
}
// Validate Block Explorer URLs
if (blockExplorerUrls &&
(!Array.isArray(blockExplorerUrls) ||
blockExplorerUrls.length === 0 ||
!blockExplorerUrls.every(isValidUrl))) {
throw new errors.BlockExplorerUrlError();
}
// Validate native currency symbol length
if (nativeCurrency &&
(nativeCurrency.symbol.length < 2 || nativeCurrency.symbol.length > 6)) {
throw new errors.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 errors.NativeCurrencySymbolMismatchError(nativeCurrency.symbol);
}
};
exports.isValidUrl = isValidUrl;
exports.preprocessTransaction = preprocessTransaction;
exports.validateChain = validateChain;
exports.validateRpcUrls = validateRpcUrls;
//# sourceMappingURL=utils.js.map