@tevm/runtime
Version:
Tools for generating the Tevm contract runtime
152 lines (148 loc) • 6.3 kB
JavaScript
import { die, map, succeed } from 'effect/Effect';
import { formatAbi } from 'abitype';
// src/generateRuntime.js
var generateDtsBody = (artifacts, includeBytecode) => {
return succeed(
`
${Object.entries(artifacts).flatMap(([contractName, { abi, userdoc = {} }]) => {
const contract = {
humanReadableAbi: formatAbi(abi)
};
const natspec = Object.entries(userdoc.methods ?? {}).map(
([method, { notice }]) => ` * @property ${method} ${notice}`
);
if (userdoc.notice) {
natspec.unshift(` * @notice ${userdoc.notice}`);
}
if (includeBytecode) {
return [
// Define constants for name and ABI with const assertions for type safety
`const _name${contractName} = ${JSON.stringify(contractName, null, 2)} as const;`,
`const _abi${contractName} = ${JSON.stringify(contract.humanReadableAbi, null, 2)} as const;`,
// JSDoc comments for the contract
"/**",
` * ${contractName} Contract (with bytecode)`,
...natspec,
" * @see [contract docs](https://tevm.sh/learn/contracts/) for more documentation",
" */",
// Type declaration for the contract
`export const ${contractName}: Contract<`,
` typeof _name${contractName},`,
// Contract name
` typeof _abi${contractName},`,
// ABI
" undefined,",
// Address placeholder
" `0x${string}`,",
// Bytecode
" `0x${string}`,",
// Deployed bytecode
" undefined",
// Additional data - removed trailing comma
">;"
].filter(Boolean);
}
return [
// Define constants for ABI and name with const assertions
`const _abi${contractName} = ${JSON.stringify(contract.humanReadableAbi)} as const;`,
`const _name${contractName} = ${JSON.stringify(contractName)} as const;`,
// JSDoc comments for the contract
"/**",
` * ${contractName} Contract (no bytecode)`,
` * change file name or add file that ends in '.s.sol' extension if you wish to compile the bytecode`,
" * @see [contract docs](https://tevm.sh/learn/contracts/) for more documentation",
...natspec,
" */",
// Type declaration for the contract (without bytecode)
`export const ${contractName}: Contract<typeof _name${contractName}, typeof _abi${contractName}, undefined, undefined, undefined, undefined>;`
].filter(Boolean);
}).join("\n")}
// solc artifacts of compilation
export const artifacts = ${JSON.stringify(artifacts, null, 2)};
`
);
};
// src/generateTevmBody.js
var generateTevmBody = (artifacts, moduleType, includeBytecode) => {
if (moduleType === "dts") {
return generateDtsBody(artifacts, includeBytecode);
}
return succeed(
Object.entries(artifacts).flatMap(([contractName, { abi, userdoc = {}, evm }], i) => {
var _a, _b;
const contract = JSON.stringify(
{
name: contractName,
humanReadableAbi: formatAbi(abi),
// Include bytecode if requested and available (checking for empty string for interfaces)
...includeBytecode ? {
bytecode: ((_a = evm == null ? void 0 : evm.bytecode) == null ? void 0 : _a.object) && evm.bytecode.object !== "" ? `0x${evm.bytecode.object}` : void 0,
deployedBytecode: ((_b = evm == null ? void 0 : evm.deployedBytecode) == null ? void 0 : _b.object) && evm.deployedBytecode.object !== "" ? `0x${evm.deployedBytecode.object}` : void 0
} : {}
},
null,
2
);
const natspec = Object.entries(userdoc.methods ?? {}).map(
([method, { notice }]) => ` * @property ${method} ${notice}`
);
if (userdoc.notice) {
natspec.unshift(` * ${userdoc.notice}`);
}
natspec.push(" * @see [contract docs](https://tevm.sh/learn/contracts/) for more documentation");
natspec.unshift("/**");
natspec.push(" */");
if (moduleType === "cjs") {
return [
`const _${contractName} = ${contract};`,
...natspec,
`module.exports.${contractName} = createContract(_${contractName});`,
i === 0 ? `module.exports.artifacts = ${JSON.stringify(artifacts, null, 2)};` : ""
];
}
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)};` : ""
];
}
return [
`const _${contractName} = ${contract};`,
...natspec,
`export const ${contractName} = createContract(_${contractName});`,
i === 0 ? `export const artifacts = ${JSON.stringify(artifacts, null, 2)};` : ""
];
}).join("\n")
);
};
// src/generateRuntime.js
var importsByModuleType = (contractPackage) => ({
contract: {
cjs: `const { createContract } = require('${contractPackage}')`,
dts: `import type { Contract } from '${contractPackage}'`,
ts: `import { createContract } from '${contractPackage}'`,
mjs: `import { createContract } from '${contractPackage}'`
},
script: {
cjs: `const { createContract } = require('${contractPackage}')`,
dts: `import type { Contract } from '${contractPackage}'`,
ts: `import { createContract } from '${contractPackage}'`,
mjs: `import { createContract } from '${contractPackage}'`
}
});
var generateRuntime = (artifacts, moduleType, includeBytecode, tevmPackage) => {
if (!artifacts || Object.keys(artifacts).length === 0) {
return die("No artifacts provided to generateRuntime");
}
const contractType = includeBytecode ? "script" : "contract";
const imports = importsByModuleType(tevmPackage)[contractType][moduleType];
if (!imports) {
return die(`Unknown module type: ${moduleType}. Valid module types include 'cjs', 'dts', 'ts', and 'mjs'`);
}
return generateTevmBody(artifacts, moduleType, includeBytecode).pipe(map((body) => [imports, body].join("\n")));
};
export { generateRuntime };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map