UNPKG

@mountainpass/hooked-cli

Version:
140 lines (139 loc) 7.59 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /* eslint-disable no-template-curly-in-string */ import fs from 'fs/promises'; import path from 'path'; import * as ethers from 'ethers'; import { isString } from '../types.js'; import logger from '../utils/logger.js'; import defaults from '../defaults.js'; const searchJsonFiles = (directory) => __awaiter(void 0, void 0, void 0, function* () { const foundFiles = []; const search = (currentDirectory_1, ...args_1) => __awaiter(void 0, [currentDirectory_1, ...args_1], void 0, function* (currentDirectory, depth = 0) { if (depth > 5) { // logger.debug(`ABI: Max depth reached in ${currentDirectory}`) return; } const files = yield fs.readdir(currentDirectory); for (const file of files) { const filePath = path.join(currentDirectory, file); const stats = yield fs.stat(filePath); if (stats.isDirectory()) { // Recursively search subdirectories yield search(filePath, depth + 1); } else if (stats.isFile() && path.extname(filePath) === '.json') { // Process JSON file try { const jsonContent = yield processJsonFile(filePath); if (typeof jsonContent.address === 'string' && typeof jsonContent.abi === 'object') { foundFiles.push({ filePath: path.relative(directory, filePath), jsonContent }); } } catch (err) { logger.debug(`Error processing ${filePath}: ${err === null || err === void 0 ? void 0 : err.message}`); } } } }); yield search(directory); return foundFiles; }); const processJsonFile = (filePath) => __awaiter(void 0, void 0, void 0, function* () { const data = yield fs.readFile(filePath, 'utf8'); const json = JSON.parse(data); return json; }); // eslint-disable-next-line max-len const getProviderAndWallet = (env) => __awaiter(void 0, void 0, void 0, function* () { const provider = new ethers.JsonRpcProvider(env.PROVIDER_URL); let blockNumber = isString(env.BLOCK_NUMBER) ? env.BLOCK_NUMBER : 'latest'; if (!isNaN(Number(blockNumber))) { blockNumber = Number(blockNumber); } if (typeof env.PRIVATE_KEY === 'string') { logger.debug(`ABI: Using block number: ${blockNumber}, Using private key: ***`); return { provider, blockNumber, wallet: new ethers.Wallet(env.PRIVATE_KEY, provider) }; } else { logger.debug(`ABI: Using block number: ${blockNumber}`); return { provider, blockNumber }; } }); export const generateAbiScripts = () => __awaiter(void 0, void 0, void 0, function* () { logger.debug('ABI: enabled...'); const files = yield searchJsonFiles(defaults.getDefaults().HOOKED_DIR); logger.debug(`ABI: Found files - ${(files).length}`); if (files.length === 0) { return {}; } else { return { '🔑 abi': Object.assign({ // get the current block number 'getBlockNumber()': { $internal: (_a) => __awaiter(void 0, [_a], void 0, function* ({ env }) { const provider = new ethers.JsonRpcProvider(env.PROVIDER_URL); logger.info(yield provider.getBlockNumber()); }) }, // show the address of the current wallet 'getAddress()': { $internal: (_a) => __awaiter(void 0, [_a], void 0, function* ({ env }) { const { wallet } = yield getProviderAndWallet(env); if (typeof (wallet === null || wallet === void 0 ? void 0 : wallet.address) === 'string') { logger.info(wallet.address); } else { throw new Error('No wallet. You can define one by specifying a PRIVATE_KEY environment variable.'); } }) }, // show the native balance of the current wallet 'getBalance()': { $internal: (_a) => __awaiter(void 0, [_a], void 0, function* ({ env }) { const { provider, blockNumber, wallet } = yield getProviderAndWallet(env); if (typeof (wallet === null || wallet === void 0 ? void 0 : wallet.address) === 'string') { logger.info(yield provider.getBalance(wallet.address, blockNumber)); } else { throw new Error('No wallet. You can define one by specifying a PRIVATE_KEY environment variable.'); } }) } }, Object.fromEntries((files).map((file) => { const fns = file.jsonContent.abi.filter((abi) => { // choose only no args (->FREE) transactions for now return abi.type === 'function'; // && // is a function // abi.inputs.length === 0 && // has no inputs // ['view', 'nonpayable'].includes(abi.stateMutability) // is free }); // map each solidity file return [file.filePath, Object.fromEntries(fns.map((fn) => { const contractArgs = Object.fromEntries(fn.inputs.map((input) => { return [input.name, { $ask: `Please enter a ${input.name} (type = ${input.type})?` }]; })); // map each function to a script return [`${fn.name}(${fn.inputs.map(i => i.name).join(', ')}) [${fn.stateMutability}]`, { $env: Object.assign({ PROVIDER_URL: '${PROVIDER_URL}' }, contractArgs), $internal: (_a) => __awaiter(void 0, [_a], void 0, function* ({ env }) { const { provider, wallet, blockNumber } = yield getProviderAndWallet(env); const contract = typeof wallet !== 'undefined' ? new ethers.Contract(file.jsonContent.address, file.jsonContent.abi, wallet) : new ethers.Contract(file.jsonContent.address, file.jsonContent.abi, provider); const params = fn.inputs.map(input => env[input.name]); // logger.debug(`calling ${fn.name}(${params.join(', ')})`) logger.info(yield contract[fn.name](...params, { blockTag: blockNumber })); }) }]; }))]; }))) }; } });