Skip to main content
Glama

OpenZeppelin Contracts MCP Server

Official
by OpenZeppelin
zip-hardhat.ts6.84 kB
import JSZip from 'jszip'; import type { GenericOptions } from './build-generic'; import type { Contract } from './contract'; import { printContract } from './print'; import SOLIDITY_VERSION from './solidity-version.json'; import type { Lines } from './utils/format-lines'; import { formatLinesWithSpaces, spaceBetween } from './utils/format-lines'; const hardhatConfig = (upgradeable: boolean) => `\ import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; ${upgradeable ? `import "@openzeppelin/hardhat-upgrades";` : ''} const config: HardhatUserConfig = { solidity: { version: "${SOLIDITY_VERSION}", settings: { optimizer: { enabled: true, }, }, }, }; export default config; `; const tsConfig = `\ { "compilerOptions": { "target": "es2020", "module": "commonjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "resolveJsonModule": true } } `; const gitIgnore = `\ node_modules .env coverage coverage.json typechain typechain-types # Hardhat files cache artifacts `; const test = (c: Contract, opts?: GenericOptions) => { return formatLinesWithSpaces(2, ...spaceBetween(getImports(c), getTestCase(c))); function getTestCase(c: Contract) { const args = getAddressArgs(c); return [ `describe("${c.name}", function () {`, [ 'it("Test contract", async function () {', spaceBetween( [`const ContractFactory = await ethers.getContractFactory("${c.name}");`], getAddressVariables(args), [`const instance = await ${getDeploymentCall(c, args)};`, 'await instance.waitForDeployment();'], getExpects(), ), '});', ], '});', ]; } function getImports(c: Contract) { return ['import { expect } from "chai";', `import { ${getHardhatPlugins(c).join(', ')} } from "hardhat";`]; } function getExpects(): Lines[] { if (opts !== undefined) { switch (opts.kind) { case 'ERC20': case 'ERC721': return [`expect(await instance.name()).to.equal("${opts.name}");`]; case 'ERC1155': return [`expect(await instance.uri(0)).to.equal("${opts.uri}");`]; case 'Account': case 'Governor': case 'Custom': break; default: throw new Error('Unknown ERC'); } } return []; } function getAddressVariables(args: string[]): Lines[] { const vars = []; for (let i = 0; i < args.length; i++) { vars.push(`const ${args[i]} = (await ethers.getSigners())[${i}].address;`); } return vars; } }; function getAddressArgs(c: Contract): string[] { const args = []; for (const constructorArg of c.constructorArgs) { if (constructorArg.type === 'address') { args.push(constructorArg.name); } } return args; } function getDeploymentCall(c: Contract, args: string[]): string { // TODO: remove that selector when the upgrades plugin supports @custom:oz-upgrades-unsafe-allow-reachable const unsafeAllowConstructor = c.parents.find(p => ['EIP712'].includes(p.contract.name)) !== undefined; return !c.upgradeable ? `ContractFactory.deploy(${args.join(', ')})` : unsafeAllowConstructor ? `upgrades.deployProxy(ContractFactory, [${args.join(', ')}], { unsafeAllow: 'constructor' })` : `upgrades.deployProxy(ContractFactory, [${args.join(', ')}])`; } const script = (c: Contract) => { const args = getAddressArgs(c); return `\ import { ${getHardhatPlugins(c).join(', ')} } from "hardhat"; async function main() { const ContractFactory = await ethers.getContractFactory("${c.name}"); ${args.length > 0 ? '// TODO: Set addresses for the contract arguments below' : ''} const instance = await ${getDeploymentCall(c, args)}; await instance.waitForDeployment(); console.log(\`${c.upgradeable ? 'Proxy' : 'Contract'} deployed to \${await instance.getAddress()}\`); } // We recommend this pattern to be able to use async/await everywhere // and properly handle errors. main().catch((error) => { console.error(error); process.exitCode = 1; }); `; }; const lowerFirstCharacter = (str: string) => str.charAt(0).toLowerCase() + str.slice(1); const ignitionModule = (c: Contract) => { const deployArguments = getAddressArgs(c); const contractVariableName = lowerFirstCharacter(c.name); return `import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; export default buildModule("${c.name}Module", (m) => { ${deployArguments.length > 0 ? '// TODO: Set addresses for the contract arguments below' : ''} const ${contractVariableName} = m.contract("${c.name}", [${deployArguments.join(', ')}]); return { ${contractVariableName} }; }); `; }; const readme = (c: Contract) => `\ # Sample Hardhat Project This project demonstrates a basic Hardhat use case. It comes with a contract generated by [OpenZeppelin Wizard](https://wizard.openzeppelin.com/), a test for that contract, ${c.upgradeable ? 'and a script that deploys that contract' : 'and a Hardhat Ignition module that deploys that contract'}. ## Installing dependencies \`\`\` npm install \`\`\` ## Testing the contract \`\`\` npm test \`\`\` ## Deploying the contract You can target any network from your Hardhat config using: \`\`\` ${c.upgradeable ? 'npx hardhat run --network <network-name> scripts/deploy.ts' : `npx hardhat ignition deploy ignition/modules/${c.name}.ts --network <network-name>`} \`\`\` `; function getHardhatPlugins(c: Contract) { const plugins = ['ethers']; if (c.upgradeable) { plugins.push('upgrades'); } return plugins; } export async function zipHardhat(c: Contract, opts?: GenericOptions) { const zip = new JSZip(); const { default: packageJson } = c.upgradeable ? await import('./environments/hardhat/upgradeable/package.json') : await import('./environments/hardhat/package.json'); packageJson.license = c.license; const { default: packageLock } = c.upgradeable ? await import('./environments/hardhat/upgradeable/package-lock.json') : await import('./environments/hardhat/package-lock.json'); packageLock.packages[''].license = c.license; zip.file(`contracts/${c.name}.sol`, printContract(c)); zip.file('test/test.ts', test(c, opts)); if (c.upgradeable) { zip.file('scripts/deploy.ts', script(c)); } else { zip.file(`ignition/modules/${c.name}.ts`, ignitionModule(c)); } zip.file('.gitignore', gitIgnore); zip.file('hardhat.config.ts', hardhatConfig(c.upgradeable)); zip.file('package.json', JSON.stringify(packageJson, null, 2)); zip.file(`package-lock.json`, JSON.stringify(packageLock, null, 2)); zip.file('README.md', readme(c)); zip.file('tsconfig.json', tsConfig); return zip; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/OpenZeppelin/contracts-wizard'

If you have feedback or need assistance with the MCP directory API, please join our Discord server