UNPKG

@wttp/site

Version:

Web3 Transfer Protocol (WTTP) - Site Contracts and deployment tools

200 lines 8.48 kB
// Shared utilities used by both Hardhat and standalone ethers.js scripts import path from "path"; import mime from "mime-types"; import { ethers } from "ethers"; // Helper function to loosely compare two objects export function looseEqual(obj1, obj2) { if (obj1 === obj2) return true; if (obj1 == null || obj2 == null) return false; const values1 = Object.values(obj1); const values2 = Object.values(obj2); if (values1.length !== values2.length) return false; for (let i = 0; i < values1.length; i++) { if (typeof values1[i] === 'object' || typeof values2[i] === 'object') { if (!looseEqual(values1[i], values2[i])) return false; } else { if (values1[i].toString() != values2[i].toString()) return false; } } return true; } // Helper function to chunk file data export function chunkData(data, chunkSize) { const chunks = []; for (let i = 0; i < data.length; i += chunkSize) { chunks.push(data.slice(i, i + chunkSize)); } return chunks; } // Helper function to determine MIME type from file extension export function getMimeType(filePath) { // Special case for directories if (path.extname(filePath) === "") { return "directory"; } // Use mime-types package for lookup const mimeType = mime.lookup(filePath); return mimeType ? mimeType.toString() : "application/octet-stream"; } // Helper function to determine if a MIME type is text-based and should include charset function isTextMimeType(mimeType) { return mimeType.startsWith('text/') || mimeType.includes('javascript') || mimeType.includes('json') || mimeType.includes('xml') || mimeType.includes('html') || mimeType.includes('css') || mimeType.includes('svg'); } // Helper function to get MIME type with charset for text files export function getMimeTypeWithCharset(filePath) { const baseMimeType = getMimeType(filePath); // For text-based files, add charset if (isTextMimeType(baseMimeType)) { return { mimeType: baseMimeType, charset: "utf-8" }; } // For non-text files, no charset needed return { mimeType: baseMimeType, charset: undefined }; } // Helper function to get chain currency symbol (POL for Polygon, ETH otherwise) // Provider-based version for standalone use export async function getChainSymbol(provider) { if (!provider) return "ETH"; try { const network = await provider.getNetwork(); return network.chainId === 137n ? "POL" : "ETH"; } catch (error) { // Default to ETH if we can't detect network return "ETH"; } } // Helper function to get chain symbol from chain ID export function getChainSymbolFromChainId(chainId) { const id = typeof chainId === 'bigint' ? Number(chainId) : chainId; return id === 137 ? "POL" : "ETH"; } // Helper function to wait until gas price is below the specified limit export async function waitForGasPriceBelowLimit(provider, gasLimitGwei, checkIntervalMs = 10000) { const gasLimit = ethers.parseUnits(gasLimitGwei.toString(), "gwei"); while (true) { try { const feeData = await provider.getFeeData(); let currentGasPrice; if (feeData.gasPrice) { currentGasPrice = feeData.gasPrice; } else if (feeData.maxFeePerGas) { currentGasPrice = feeData.maxFeePerGas; } else { console.warn("⚠️ Could not fetch gas price, proceeding anyway"); return; } if (currentGasPrice <= gasLimit) { console.log(`✅ Gas price is below limit: ${ethers.formatUnits(currentGasPrice, "gwei")} gwei <= ${gasLimitGwei} gwei`); return; } console.log(`⏳ Gas price (${ethers.formatUnits(currentGasPrice, "gwei")} gwei/${ethers.formatUnits(feeData.maxFeePerGas ?? 9n, "gwei")} gwei) is above limit (${gasLimitGwei} gwei), waiting ${checkIntervalMs / 1000}s...`); await new Promise(resolve => setTimeout(resolve, checkIntervalMs)); } catch (error) { console.warn("⚠️ Error checking gas price, proceeding anyway:", error); return; } } } // Helper function to get dynamic gas settings based on current network conditions export async function getDynamicGasSettings(provider) { try { // Get current network fee data const feeData = await provider.getFeeData(); console.log(`🔍 Current network gas prices - Max Fee: ${feeData.maxFeePerGas ? ethers.formatUnits(feeData.maxFeePerGas, "gwei") : "N/A"} gwei, Priority Fee: ${feeData.maxPriorityFeePerGas ? ethers.formatUnits(feeData.maxPriorityFeePerGas, "gwei") : "N/A"} gwei`); // Apply 25% buffer for faster confirmation const bufferMultiplier = 1.25; let maxFeePerGas; let maxPriorityFeePerGas; if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) { // EIP-1559 network (Ethereum mainnet, etc.) maxFeePerGas = BigInt(Math.floor(Number(feeData.maxFeePerGas) * bufferMultiplier)); maxPriorityFeePerGas = BigInt(Math.floor(Number(feeData.maxPriorityFeePerGas) * bufferMultiplier)); } else if (feeData.gasPrice) { // Legacy network pricing const bufferedGasPrice = BigInt(Math.floor(Number(feeData.gasPrice) * bufferMultiplier)); maxFeePerGas = bufferedGasPrice; maxPriorityFeePerGas = ethers.parseUnits("2", "gwei"); // Minimum tip } else { // Fallback to reasonable defaults with buffer console.warn("⚠️ Could not fetch network gas prices, using fallback values"); maxFeePerGas = ethers.parseUnits("62.5", "gwei"); // 50 * 1.25 maxPriorityFeePerGas = ethers.parseUnits("2.5", "gwei"); // 2 * 1.25 } const gasSettings = { // Let ethers.js estimate gasLimit automatically for each transaction maxFeePerGas, maxPriorityFeePerGas }; console.log(`⚡ Optimized gas settings - Max Fee: ${ethers.formatUnits(maxFeePerGas, "gwei")} gwei, Priority Fee: ${ethers.formatUnits(maxPriorityFeePerGas, "gwei")} gwei (25% buffer applied)`); return gasSettings; } catch (error) { console.error("❌ Error fetching gas prices:", error); // Fallback to reasonable defaults return { // Let ethers.js estimate gasLimit automatically maxFeePerGas: ethers.parseUnits("50", "gwei"), maxPriorityFeePerGas: ethers.parseUnits("2", "gwei") }; } } // Helper function to get gas price for estimation (custom or multiply current by rate, with optional minimum) export async function getEstimationGasPrice(provider, customGasPriceGwei, rate = 2, minGasPriceGwei = 150) { if (customGasPriceGwei !== undefined) { return ethers.parseUnits(customGasPriceGwei.toString(), "gwei"); } try { const feeData = await provider.getFeeData(); let currentGasPrice; if (feeData.maxFeePerGas) { // EIP-1559 network currentGasPrice = feeData.maxFeePerGas; } else if (feeData.gasPrice) { // Legacy network currentGasPrice = feeData.gasPrice; } else { // Fallback currentGasPrice = ethers.parseUnits("75", "gwei"); // Default to 75 gwei } // Multiply the current gas price by the rate // Convert to number, multiply, then back to bigint to handle decimals const currentGasPriceNumber = Number(currentGasPrice); const multipliedGasPriceNumber = currentGasPriceNumber * rate; const multipliedGasPrice = BigInt(Math.floor(multipliedGasPriceNumber)); // Apply minimum gas price const minGasPrice = ethers.parseUnits(minGasPriceGwei.toString(), "gwei"); return multipliedGasPrice > minGasPrice ? multipliedGasPrice : minGasPrice; } catch (error) { console.warn(`⚠️ Could not fetch network gas prices, using minimum ${minGasPriceGwei} gwei`); return ethers.parseUnits(minGasPriceGwei.toString(), "gwei"); } } //# sourceMappingURL=utils.js.map