UNPKG

0xweb

Version:

Contract package manager and other web3 tools

109 lines (91 loc) 3.91 kB
import alot from 'alot'; import type { ContractDefinition, StructDefinition } from '@solidity-parser/parser/dist/src/ast-types'; import { SourceFile, TSourceFileContract } from './SlotsParser/SourceFile'; import { Ast } from './SlotsParser/Ast'; import { ISlotsParserOption } from './SlotsParser/models'; import type { TAbiItem } from '@dequanto/types/TAbi'; import { $require } from '@dequanto/utils/$require'; export namespace SolidityParser { export async function extractAbi (source: { path: string, code?: string }, contractName?: string, opts?: ISlotsParserOption): Promise<{ abi: TAbiItem[] source: { contractName: string, files: { [path: string]: { content: string } } } }> { const sourceFile = new SourceFile(source.path, source.code, opts?.files); const chain = await sourceFile.getContractInheritanceChain(contractName); $require.notEq(chain.length, 0, `No contract "${contractName}" found in ${source.path}`); const abi = await extractAbiInner(chain, opts); const contract = await sourceFile.getContract(); const content = await sourceFile.getContent(); return { abi, source: { contractName: contract.name ?? contractName, files: { [sourceFile.path]: { content: content } } } }; } async function extractAbiInner(inheritanceChain: TSourceFileContract[], opts?: ISlotsParserOption) { let count = inheritanceChain.length; let abisDef = await alot(inheritanceChain) .mapManyAsync(async (item, i) => { let cloned = { ...item }; // get the base classes for the item, as inheritanceChain has the base(root)->...->derived direction let inheritance = inheritanceChain.slice(0, i).reverse(); let abis = await extractAbiInnerSingle(cloned, inheritance, opts, count - i - 1); return abis; }) .toArrayAsync({ threads: 1 }); return abisDef; } async function extractAbiInnerSingle (ctx: ITypeCtx, inheritanceChain: TSourceFileContract[], opts: { withConstants?: boolean withImmutables?: boolean }, inheritanceChainIndex?: number) { let contract = ctx.contract as ContractDefinition; if (Ast.isContractDefinition(contract) === false) { throw new Error(`Contract expected for ${ctx.contract.name}`); } let abiFns = await alot(Ast.getFunctionDeclarations(contract)) .filter($fn => { if ($fn.isConstructor) { // Skip constructors in base classes return inheritanceChainIndex === 0; } let isPublic = $fn.visibility === 'external' || $fn.visibility === 'public' || $fn.isConstructor; return isPublic; }) .mapAsync(async $fn => Ast.getAbi($fn, ctx, inheritanceChain)) .toArrayAsync(); let abiGetters = await alot(Ast.getVariableDeclarations(contract)) .filter($var => { let isPublic = $var.visibility === 'public'; return isPublic; }) .mapAsync(async $var => Ast.getAbi($var, ctx, inheritanceChain)) .toArrayAsync(); let abiEvents = await alot(Ast.getEventDefinitions(contract)) .mapAsync(async $event => Ast.getAbi($event, ctx, inheritanceChain)) .toArrayAsync(); return [ ...abiFns, ...abiGetters, ...abiEvents, ]; } } interface ITypeCtx { contract: ContractDefinition | StructDefinition contractBase?: ContractDefinition[] file: SourceFile };