Skip to main content
Glama

OpenZeppelin Contracts MCP Server

Official
by OpenZeppelin
contract.ts7.75 kB
import { toByteArray, toIdentifier } from './utils/convert-strings'; export interface Contract { metadata: Map<string, string>; license: string; documentations: string[]; name: string; useClauses: UseClause[]; constructorCode: string[]; constructorArgs: Argument[]; implementedTraits: TraitImplBlock[]; freeFunctions: ContractFunction[]; variables: Variable[]; errors: Error[]; ownable: boolean; derives: string[]; } export interface Error { name: string; num: number; } export type Value = string | number | bigint | { lit: string } | { note: string; value: Value }; export interface UseClause { containerPath: string; name: string; groupable?: boolean; alias?: string; } export interface BaseTraitImplBlock { traitName: string; structName: string; tags: string[]; assocType?: string; section?: string; /** * Priority for which trait to print first. * Lower numbers are higher priority, undefined is lowest priority. */ priority?: number; } export interface TraitImplBlock extends BaseTraitImplBlock { functions: ContractFunction[]; } export interface BaseFunction { name: string; args: Argument[]; code: string[]; pub?: boolean; returns?: string; } export interface ContractFunction extends BaseFunction { tags: string[]; codeBefore?: string[]; } export interface Variable { name: string; type: string; value: string; } export interface Argument { name: string; type?: string; } export class ContractBuilder implements Contract { readonly name: string; license = 'MIT'; metadata = new Map<string, string>(); ownable = false; readonly documentations: string[] = []; readonly constructorArgs: Argument[] = []; readonly constructorCode: string[] = []; private implementedTraitsMap: Map<string, TraitImplBlock> = new Map(); private freeFunctionsMap: Map<string, ContractFunction> = new Map(); private variablesMap: Map<string, Variable> = new Map(); private useClausesMap: Map<string, UseClause> = new Map(); private errorsMap: Map<string, Error> = new Map(); private derivesSet: Set<string> = new Set(); constructor(name: string) { this.name = toIdentifier(name, true); } get implementedTraits(): TraitImplBlock[] { return [...this.implementedTraitsMap.values()]; } get freeFunctions(): ContractFunction[] { return [...this.freeFunctionsMap.values()]; } get variables(): Variable[] { return [...this.variablesMap.values()]; } get useClauses(): UseClause[] { return [...this.useClausesMap.values()]; } get errors(): Error[] { return [...this.errorsMap.values()]; } get derives(): string[] { return [...this.derivesSet]; } addError(name: string, num: number): boolean { if (this.errorsMap.has(name)) { return false; } else { this.addUseClause('soroban_sdk', 'contracterror'); this.errorsMap.set(name, { name, num }); return true; } } addUseClause(containerPath: string, name: string, options?: { groupable?: boolean; alias?: string }): void { // groupable defaults to true const groupable = options?.groupable ?? true; const alias = options?.alias ?? ''; const uniqueName = alias.length > 0 ? alias : name; const present = this.useClausesMap.has(uniqueName); if (!present) { this.useClausesMap.set(uniqueName, { containerPath, name, groupable, alias }); } } addVariable(variable: Variable): boolean { if (this.variablesMap.has(variable.name)) { return false; } else { this.variablesMap.set(variable.name, variable); return true; } } addTraitImplBlock(baseTrait: BaseTraitImplBlock): TraitImplBlock { const key = baseTrait.traitName; const existingTrait = this.implementedTraitsMap.get(key); if (existingTrait !== undefined) { return existingTrait; } else { const t: TraitImplBlock = { traitName: baseTrait.traitName, structName: baseTrait.structName, tags: [...baseTrait.tags], assocType: baseTrait.assocType, functions: [], section: baseTrait.section, priority: baseTrait.priority, }; this.implementedTraitsMap.set(key, t); return t; } } // used for adding a function to the `impl Contract` block addFreeFunction(fn: BaseFunction): ContractFunction { const signature = this.getFunctionSignature(fn); const existingFn = this.freeFunctionsMap.get(signature); if (existingFn !== undefined) { return existingFn; } else { const contractFn: ContractFunction = { ...fn, pub: true, tags: [], codeBefore: [], }; this.freeFunctionsMap.set(signature, contractFn); return contractFn; } } // used for adding a function to a trait implementation block addTraitFunction(baseTrait: BaseTraitImplBlock, fn: BaseFunction): ContractFunction { const t = this.addTraitImplBlock(baseTrait); const signature = this.getFunctionSignature(fn); // Look for the existing function with the same signature and return it if found for (let i = 0; i < t.functions.length; i++) { const existingFn = t.functions[i]; if (existingFn !== undefined && this.getFunctionSignature(existingFn) === signature) { return existingFn; } } // Otherwise, add the function const contractFn: ContractFunction = { ...fn, tags: [], codeBefore: [], }; t.functions.push(contractFn); return contractFn; } overrideAssocType(traitName: string, newAssocType: string): void { const trait = this.implementedTraitsMap.get(traitName); if (trait) { trait.assocType = newAssocType; } else { throw new Error(`Trait '${traitName}' does not exist and cannot be overridden.`); } } private getFunctionSignature(fn: BaseFunction): string { return [fn.name, '(', ...fn.args.map(a => a.name), ')'].join(''); } private getOrCreateFunction(fn: BaseFunction, baseTrait?: BaseTraitImplBlock): ContractFunction { if (baseTrait === undefined) { return this.addFreeFunction(fn); } else { this.addTraitImplBlock(baseTrait); return this.addTraitFunction(baseTrait, fn); } } addFunctionCodeBefore(fn: BaseFunction, codeBefore: string[], baseTrait?: BaseTraitImplBlock): void { const existingFn = this.getOrCreateFunction(fn, baseTrait); existingFn.codeBefore = [...(existingFn.codeBefore ?? []), ...codeBefore]; } addFunctionTag(fn: BaseFunction, tag: string, baseTrait?: BaseTraitImplBlock): void { const existingFn = this.getOrCreateFunction(fn, baseTrait); existingFn.tags = [...(existingFn.tags ?? []), tag]; } addConstructorArgument(arg: Argument): void { for (const existingArg of this.constructorArgs) { if (existingArg.name == arg.name) { return; } } this.constructorArgs.push(arg); } addConstructorCode(code: string): void { for (const existingCode of this.constructorCode) { if (existingCode === code) { return; } } this.constructorCode.push(code); } addDerives(derive: string): void { this.derivesSet.add(derive); } addDocumentation(description: string) { this.documentations.push(description); } addContractMetadata(metadata: { key: string; value: string }[] | { key: string; value: string }) { (Array.isArray(metadata) ? metadata : [metadata]).forEach(({ key, value }) => { if (this.metadata.has(key)) throw new Error(`Setting metadata failed: ${key} is already set`); this.metadata.set(key, toByteArray(value)); }); if (this.metadata.size > 0) this.addUseClause('soroban_sdk', 'contractmeta'); } }

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