UNPKG

@tevm/runtime

Version:

Tools for generating the Tevm contract runtime

120 lines (111 loc) 4.2 kB
import { formatAbi } from 'abitype' import { succeed } from 'effect/Effect' import { generateDtsBody } from './generateTevmBodyDts.js' /** * Generates the body of a JavaScript/TypeScript module for Tevm contracts. * * This function transforms Solidity compilation artifacts into JavaScript/TypeScript code * that creates Tevm Contract objects. It handles different output formats (cjs, ts, mjs) * and can include or exclude bytecode based on the provided options. * * For TypeScript declaration files (.d.ts), it delegates to generateDtsBody * which creates appropriate type definitions. * * @param {import("@tevm/compiler").Artifacts} artifacts - Compiled Solidity artifacts * containing ABI, bytecode, and other contract information * @param {import('./types.js').ModuleType} moduleType - The target module format * ('cjs', 'dts', 'ts', or 'mjs') * @param {boolean} includeBytecode - Whether to include bytecode in the output, * true for script/deployable contracts, false for interface-only contracts * @returns {import('effect/Effect').Effect<string, never, never>} - Effect that * resolves to the generated module body code as a string * * @example * ```javascript * import { generateTevmBody } from '@tevm/runtime' * import { runPromise } from 'effect/Effect' * * // Generate the body of a TypeScript module * const body = await runPromise( * generateTevmBody( * artifacts, // Solidity compilation results * 'ts', // Generate TypeScript code * true // Include bytecode * ) * ) * * console.log(body) * ``` * * @internal This function is primarily used by generateRuntime */ export const generateTevmBody = (artifacts, moduleType, includeBytecode) => { // For TypeScript declaration files, delegate to generateDtsBody if (moduleType === 'dts') { return generateDtsBody(artifacts, includeBytecode) } // Generate JavaScript/TypeScript code for the contracts return succeed( Object.entries(artifacts) .flatMap(([contractName, { abi, userdoc = {}, evm }], i) => { // Create the contract configuration object const contract = JSON.stringify( { name: contractName, humanReadableAbi: formatAbi(abi), // Include bytecode if requested and available (checking for empty string for interfaces) ...(includeBytecode ? { bytecode: evm?.bytecode?.object && evm.bytecode.object !== '' ? `0x${evm.bytecode.object}` : undefined, deployedBytecode: evm?.deployedBytecode?.object && evm.deployedBytecode.object !== '' ? `0x${evm.deployedBytecode.object}` : undefined, } : {}), }, null, 2, ) // Generate JSDoc documentation from NatSpec comments const natspec = Object.entries(userdoc.methods ?? {}).map( ([method, { notice }]) => ` * @property ${method} ${notice}`, ) // Add contract-level documentation if available if (userdoc.notice) { natspec.unshift(` * ${userdoc.notice}`) } // Add link to additional documentation natspec.push(' * @see [contract docs](https://tevm.sh/learn/contracts/) for more documentation') natspec.unshift('/**') natspec.push(' */') // Generate CommonJS format if (moduleType === 'cjs') { return [ `const _${contractName} = ${contract};`, ...natspec, `module.exports.${contractName} = createContract(_${contractName});`, i === 0 ? `module.exports.artifacts = ${JSON.stringify(artifacts, null, 2)};` : '', ] } // Generate TypeScript format with const assertion if (moduleType === 'ts') { return [ `const _${contractName} = ${contract} as const`, ...natspec, `export const ${contractName} = createContract(_${contractName});`, i === 0 ? `export const artifacts = ${JSON.stringify(artifacts, null, 2)};` : '', ] } // Generate ES module format return [ `const _${contractName} = ${contract};`, ...natspec, `export const ${contractName} = createContract(_${contractName});`, i === 0 ? `export const artifacts = ${JSON.stringify(artifacts, null, 2)};` : '', ] }) .join('\n'), ) }