Created
February 17, 2025 20:04
-
-
Save yann300/6ec876735e2fc4f393b8764eda78c7f6 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.28+commit.7893614a.js&optimize=false&runs=NaN&gist=
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Replace with your actual API key and agent ID | |
| const API_KEY = 'mRU8ku8wCiVYm1aDQWW6tnfsWY7qu0jm'; | |
| const AGENT_ID = 'ag:90ac4fd0:20250208:untitled-agent:3cb5361b'; | |
| const API_URL = 'https://api.mistral.ai/v1/agents/completions'; | |
| // Function to call the Mistral AI endpoint | |
| export async function callMistralAI(messages) { | |
| try { | |
| const response = await fetch(API_URL, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Authorization': `Bearer ${API_KEY}` | |
| }, | |
| body: JSON.stringify({ | |
| agent_id: AGENT_ID, | |
| messages: messages, | |
| // Add other parameters as needed | |
| }) | |
| }); | |
| if (!response.ok) { | |
| // Log the response status and text for debugging | |
| const errorText = await response.text(); | |
| throw new Error(`HTTP error! status: ${response.status}, response: ${errorText}`); | |
| } | |
| const data = await response.json(); | |
| // console.log('Response from Mistral AI:', data); | |
| return data; | |
| } catch (error) { | |
| console.error('Error calling Mistral AI:', error); | |
| } | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { callMistralAI } from "./mistral-api" | |
| const message = 'Write a soulbound ERC721 contract and mocha/chai unit tests. This should use the following implementation: @openzeppelin/contracts/token/ERC721/ERC721.sol' | |
| const params = { | |
| optimize: false, | |
| evmVersion: null, | |
| language: 'Solidity', | |
| version: '0.8.28+commit.7893614a' | |
| } | |
| // Example usage | |
| let messages = [ | |
| { | |
| role: 'user', | |
| content: `${message} using the following compiler config: ${JSON.stringify(params)}` | |
| } | |
| ]; | |
| const mmaxNbIteration = 6 | |
| let iteration = 0 | |
| console.log(messages) | |
| let json_mes | |
| const run = async () => { | |
| if (iteration > mmaxNbIteration) { | |
| console.error('failed compiling') | |
| return | |
| } | |
| console.log('running iteration', iteration) | |
| json_mes = null | |
| const data = await callMistralAI(messages) | |
| const mes = data.choices[0].message.content.replace('```json\n', '').replace('```', '') | |
| json_mes = JSON.parse(mes) | |
| let compiled = false | |
| for (const index in json_mes) { | |
| const file = json_mes[index] | |
| await remix.call('fileManager', 'writeFile', file.fileName, file.content) | |
| if (file.fileName.endsWith('.sol')) { | |
| console.log(`compiling ${file.fileName}`) | |
| const contract = {} | |
| contract[file.fileName] = { content : file.content } | |
| const result = await remix.call('solidity' as any, 'compileWithParameters', contract, params) | |
| let data = result.data | |
| if (data.errors && data.errors.length && data.errors.find((error) => error.type !== 'Warning')) { | |
| iteration++ | |
| const imports = extractImportPaths(file.content) | |
| console.log(file.content) | |
| let contentImports = {} | |
| for (const file of imports) { | |
| contentImports[file] = await remix.call('contentImport', 'resolve', file) | |
| } | |
| // console.log(contentImports) | |
| messages.push({ | |
| role: 'user', | |
| content: `Here is the code you generated: ${file.content} . Here is the code of the imports: ${JSON.stringify(contentImports)} . Here are compilation errors: ${JSON.stringify(data.errors)}. Fix errors.` | |
| }) | |
| await run() | |
| } else { | |
| console.log('compiled successfully...') | |
| console.log('reset compilation config...') | |
| await remix.call('solidity' as any, 'setCompilerConfig', params) | |
| await remix.call('solidity' as any, 'compile', file.fileName) | |
| await new Promise(() => { setTimeout((resolve) => { resolve({}) }, 5000)}) | |
| compiled = true | |
| } | |
| } | |
| } | |
| if (compiled) { | |
| console.log('running tests...') | |
| const scripts = json_mes.find((item) => item.fileName.endsWith('.ts')) | |
| remix.call('scriptRunnerBridge' as any, 'execute', scripts.content, scripts.fileName) | |
| } | |
| } | |
| function extractImportPaths(text) { | |
| // Define the regex pattern to match import paths | |
| const regex = /import\s*\"([^\"]+)\"\s*;/g; | |
| const paths = []; | |
| let match; | |
| // Use the regex to find all matches in the text | |
| while ((match = regex.exec(text)) !== null) { | |
| // Push the captured path to the paths array | |
| paths.push(match[1]); | |
| } | |
| return paths; | |
| } | |
| run().catch((e) => { console.error(e.message) }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export interface CompilationFileSources { | |
| [fileName: string]: { | |
| keccak256?: string; | |
| content: string; | |
| urls?: string[]; | |
| }; | |
| } | |
| export interface SourceWithTarget { | |
| sources?: CompilationFileSources; | |
| target?: string | null | undefined; | |
| } | |
| export interface CompilationResult { | |
| /** not present if no errors/warnings were encountered */ | |
| errors?: CompilationError[]; | |
| /** This contains the file-level outputs. In can be limited/filtered by the outputSelection settings */ | |
| sources: { | |
| [contractName: string]: CompilationSource; | |
| }; | |
| /** This contains the contract-level outputs. It can be limited/filtered by the outputSelection settings */ | |
| contracts: { | |
| /** If the language used has no contract names, this field should equal to an empty string. */ | |
| [fileName: string]: { | |
| [contract: string]: CompiledContract; | |
| }; | |
| }; | |
| } | |
| export interface lastCompilationResult { | |
| data: CompilationResult | null; | |
| source: SourceWithTarget | null | undefined; | |
| } | |
| export interface CompilationError { | |
| /** Location within the source file */ | |
| sourceLocation?: { | |
| file: string; | |
| start: number; | |
| end: number; | |
| }; | |
| /** Error type */ | |
| type: CompilationErrorType; | |
| /** Component where the error originated, such as "general", "ewasm", etc. */ | |
| component: 'general' | 'ewasm' | string; | |
| severity: 'error' | 'warning'; | |
| message: string; | |
| /** the message formatted with source location */ | |
| formattedMessage?: string; | |
| } | |
| declare type CompilationErrorType = 'JSONError' | 'IOError' | 'ParserError' | 'DocstringParsingError' | 'SyntaxError' | 'DeclarationError' | 'TypeError' | 'UnimplementedFeatureError' | 'InternalCompilerError' | 'Exception' | 'CompilerError' | 'FatalError' | 'Warning'; | |
| export interface CompilationSource { | |
| /** Identifier of the source (used in source maps) */ | |
| id: number; | |
| /** The AST object */ | |
| ast: AstNode; | |
| /** The legacy AST object */ | |
| legacyAST: AstNodeLegacy; | |
| } | |
| export interface AstNode { | |
| absolutePath?: string; | |
| exportedSymbols?: Object; | |
| id: number; | |
| nodeType: string; | |
| nodes?: Array<AstNode>; | |
| src: string; | |
| literals?: Array<string>; | |
| file?: string; | |
| scope?: number; | |
| sourceUnit?: number; | |
| symbolAliases?: Array<string>; | |
| [x: string]: any; | |
| } | |
| export interface AstNodeLegacy { | |
| id: number; | |
| name: string; | |
| src: string; | |
| children?: Array<AstNodeLegacy>; | |
| attributes?: AstNodeAtt; | |
| } | |
| export interface AstNodeAtt { | |
| operator?: string; | |
| string?: null; | |
| type?: string; | |
| value?: string; | |
| constant?: boolean; | |
| name?: string; | |
| public?: boolean; | |
| exportedSymbols?: Object; | |
| argumentTypes?: null; | |
| absolutePath?: string; | |
| [x: string]: any; | |
| } | |
| export interface CompiledContract { | |
| /** The Ethereum Contract ABI. If empty, it is represented as an empty array. */ | |
| abi: ABIDescription[]; | |
| metadata: string; | |
| /** User documentation (natural specification) */ | |
| userdoc: UserDocumentation; | |
| /** Developer documentation (natural specification) */ | |
| devdoc: DeveloperDocumentation; | |
| /** Intermediate representation (string) */ | |
| ir: string; | |
| /** EVM-related outputs */ | |
| evm: { | |
| assembly: string; | |
| legacyAssembly: {}; | |
| /** Bytecode and related details. */ | |
| bytecode: BytecodeObject; | |
| deployedBytecode: BytecodeObject; | |
| /** The list of function hashes */ | |
| methodIdentifiers: { | |
| [functionIdentifier: string]: string; | |
| }; | |
| gasEstimates: { | |
| creation: { | |
| codeDepositCost: string; | |
| executionCost: 'infinite' | string; | |
| totalCost: 'infinite' | string; | |
| }; | |
| external: { | |
| [functionIdentifier: string]: string; | |
| }; | |
| internal: { | |
| [functionIdentifier: string]: 'infinite' | string; | |
| }; | |
| }; | |
| }; | |
| /** eWASM related outputs */ | |
| ewasm: { | |
| /** S-expressions format */ | |
| wast: string; | |
| /** Binary format (hex string) */ | |
| wasm: string; | |
| }; | |
| } | |
| export declare type ABIDescription = FunctionDescription | EventDescription; | |
| export interface FunctionDescription { | |
| /** Type of the method. default is 'function' */ | |
| type?: 'function' | 'constructor' | 'fallback'; | |
| /** The name of the function. Constructor and fallback functions never have a name */ | |
| name?: string; | |
| /** List of parameters of the method. Fallback functions don’t have inputs. */ | |
| inputs?: ABIParameter[]; | |
| /** List of the output parameters for the method, if any */ | |
| outputs?: ABIParameter[]; | |
| /** State mutability of the method */ | |
| stateMutability: 'pure' | 'view' | 'nonpayable' | 'payable'; | |
| /** true if function accepts Ether, false otherwise. Default is false */ | |
| payable?: boolean; | |
| /** true if function is either pure or view, false otherwise. Default is false */ | |
| constant?: boolean; | |
| } | |
| export interface EventDescription { | |
| type: 'event'; | |
| name: string; | |
| inputs: ABIParameter & { | |
| /** true if the field is part of the log’s topics, false if it one of the log’s data segment. */ | |
| indexed: boolean; | |
| }[]; | |
| /** true if the event was declared as anonymous. */ | |
| anonymous: boolean; | |
| } | |
| export interface ABIParameter { | |
| /** The name of the parameter */ | |
| name: string; | |
| /** The canonical type of the parameter */ | |
| type: ABITypeParameter; | |
| /** Used for tuple types */ | |
| components?: ABIParameter[]; | |
| } | |
| export declare type ABITypeParameter = 'uint' | 'uint[]' | 'int' | 'int[]' | 'address' | 'address[]' | 'bool' | 'bool[]' | 'fixed' | 'fixed[]' | 'ufixed' | 'ufixed[]' | 'bytes' | 'bytes[]' | 'function' | 'function[]' | 'tuple' | 'tuple[]' | string; | |
| export interface UserDocumentation { | |
| methods: UserMethodList; | |
| notice: string; | |
| } | |
| export declare type UserMethodList = { | |
| [functionIdentifier: string]: UserMethodDoc; | |
| } & { | |
| 'constructor'?: string; | |
| }; | |
| export interface UserMethodDoc { | |
| notice: string; | |
| } | |
| export interface DeveloperDocumentation { | |
| author: string; | |
| title: string; | |
| details: string; | |
| methods: DevMethodList; | |
| } | |
| export interface DevMethodList { | |
| [functionIdentifier: string]: DevMethodDoc; | |
| } | |
| export interface DevMethodDoc { | |
| author: string; | |
| details: string; | |
| return: string; | |
| returns: { | |
| [param: string]: string; | |
| }; | |
| params: { | |
| [param: string]: string; | |
| }; | |
| } | |
| export interface BytecodeObject { | |
| /** The bytecode as a hex string. */ | |
| object: string; | |
| /** Opcodes list */ | |
| opcodes: string; | |
| /** The source mapping as a string. See the source mapping definition. */ | |
| sourceMap: string; | |
| /** If given, this is an unlinked object. */ | |
| linkReferences?: { | |
| [contractName: string]: { | |
| /** Byte offsets into the bytecode. */ | |
| [library: string]: { | |
| start: number; | |
| length: number; | |
| }[]; | |
| }; | |
| }; | |
| } | |
| export {}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment