const ethers = require('ethers') const glob = require('glob') const jsonfile = require('jsonfile') const fs = require('fs') let data = require('../projects/test/abi.json') const rootFolder = '../projects' const rootFolderTest = '../projects/yfii' // https://docs.soliditylang.org/en/latest/abi-spec.html let knownTypes = [ 'string', 'address', 'bool', 'int', 'int8', 'int16', 'int32', 'int64', 'int128', 'int256', 'uint', 'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256', ]; ([...knownTypes]).forEach(i => knownTypes.push(i + '[]')) // support array type for all known types knownTypes = new Set(knownTypes) function run() { glob(rootFolder + '/**/*.json', {}, async (e, files) => { if (e) throw e console.log('JSON file count', files.length) const objs = files.map(file => ({ file, data: jsonfile.readFileSync(file) })) const isTransformables = objs.filter(i => isTransformable(i.data, i.file)) const isNotTransformables = objs.filter(i => !isTransformable(i.data, i.file)).filter(i => Object.values(i.data).some(i => typeof i !== 'string')) console.log(isNotTransformables.length) const files2 = isNotTransformables.map(i => i.file) console.log(JSON.stringify(files2, null, 2)) // console.log(isTransformables.length) const fileWriteOptions = { spaces: 2, finalEOL: false } isTransformables.forEach(i => i.newData = transform(i.data, i.file)) isTransformables.forEach(i => jsonfile.writeFile(i.file, i.newData, fileWriteOptions)) }) } const validStates = new Set(['view', 'pure', 'nonpayable']) const isValidState = i => validStates.has(i.stateMutability) || i.constant === true function isTransformable(obj, file) { if (typeof obj !== 'object' || Array.isArray(obj)) return false; const values = Object.values(obj) const isAbi0 = i => isValidState(i) const isAbi = i => (i.stateMutability === 'view' || i.stateMutability === 'pure' || i.stateMutability === 'nonpayable') && i.type === 'function' const i = values[0] if (!isAbi0(i)) return false const edgeCase = values.find(i => !isAbi(i)) if (edgeCase) { const first = Object.values(edgeCase).pop() if (!Array.isArray(edgeCase) && !isAbi(first)) console.log('edge case: ', file, edgeCase) } return !edgeCase } function transform(obj, file) { const res = {} for (const [key, value] of Object.entries(obj)) { if (['constructor', 'error'].includes(value.type)) { console.log('skipping element of type: ', value.type) continue; } if (!value.inputs) console.log('inputs missing', file) const iLen = value.inputs.length === 0 const oLen = value.outputs?.length === 1 const oType = oLen && value.outputs[0].type if (iLen && oLen && knownTypes.has(oType)) { res[key] = `${oType}:${value.name}` } else { const iface = new ethers.Interface([value]) res[key] = iface.format()[0] } } return res } function print() { let res = data if (data.name) data = [data] if (Array.isArray(data)) { res = {} data .filter(i => i.type === 'function' || i.type === 'event') // .filter(i => isTransformable({ test: i})) // .filter(i => i.stateMutability === 'view' || i.stateMutability === 'pure') .forEach(i => res[i.name ?? 'ignore'] = i) } console.log(res) res = transform(res) fs.writeFileSync(__dirname+'/../projects/test/abi.json', JSON.stringify(res, null, 2)) // console.log(res) console.log(JSON.stringify(res, null, 2)) } print() async function printRes(abi, target, api) { const res = {} await Promise.all(Object.entries(abi).map(async ([name, abi]) => { res[name] = await api.call({ abi, target}) })) console.log(res) }