Rust智能合约编译器工具foundry-compilers-artifacts的使用,高效解析与生成Solidity和Vyper合约编译产物

Rust智能合约编译器工具foundry-compilers-artifacts的使用,高效解析与生成Solidity和Vyper合约编译产物

安装

在项目目录中运行以下Cargo命令:

cargo add foundry-compilers-artifacts

或者在Cargo.toml中添加以下行:

foundry-compilers-artifacts = "0.18.2"

基本使用示例

以下是一个使用foundry-compilers-artifacts解析和生成Solidity合约编译产物的完整示例:

use foundry_compilers_artifacts::{Artifact, SolcArtifact};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取已编译的Solidity合约JSON文件
    let artifact_json = r#"
    {
        "abi": [/* ABI定义 */],
        "bytecode": "0x...",
        "deployedBytecode": "0x...",
        "metadata": { /* 元数据 */ }
    }"#;

    // 解析JSON为Artifact
    let artifact: Artifact = serde_json::from_str(artifact_json)?;

    // 访问合约信息
    if let Some(contract) = artifact.contracts.values().next() {
        println!("合约ABI: {:?}", contract.abi);
        println!("字节码: {}", contract.evm.bytecode.object);
        println!("部署字节码: {}", contract.evm.deployed_bytecode.object);
    }

    Ok(())
}

处理Vyper合约示例

以下示例展示如何处理Vyper合约的编译产物:

use foundry_compilers_artifacts::{VyperArtifact, Artifact};

fn process_vyper_artifact() -> Result<(), Box<dyn std::error::Error>> {
    // 读取Vyper合约编译产物
    let vyper_json = r#"
    {
        "abi": [/* ABI定义 */],
        "bytecode": "0x...",
        "bytecode_runtime": "0x...",
        "compiler_version": "0.3.7"
    }"#;

    // 解析为VyperArtifact
    let artifact: VyperArtifact = serde_json::from_str(vyper_json)?;

    println!("Vyper合约详细信息:");
    println!("编译器版本: {}", artifact.compiler_version);
    println!("ABI: {:?}", artifact.abi);
    println!("字节码: {}", artifact.bytecode);
    println!("运行时字节码: {}", artifact.bytecode_runtime);

    Ok(())
}

高级用法:生成编译产物

use foundry_compilers_artifacts::{Contract, Bytecode, DeployedBytecode};

fn generate_artifact() -> Result<(), Box<dyn std::error::Error>> {
    // 创建一个新的合约编译产物
    let contract = Contract {
        abi: Some(vec![/* ABI条目 */]),
        evm: Bytecode {
            bytecode: Some(BytecodeObject {
                object: "0x6060...".to_string(),
                // 其他字段...
            }),
            deployed_bytecode: DeployedBytecode {
                bytecode: Some(BytecodeObject {
                    object: "0x6060...".to_string(),
                    // 其他字段...
                }),
                // 其他字段...
            },
            // 其他字段...
        },
        // 其他字段...
    };

    // 序列化为JSON
    let json = serde_json::to_string_pretty(&contract)?;
    println!("生成的合约JSON:\n{}", json);

    Ok(())
}

完整示例demo

以下是一个结合所有功能的完整示例:

use foundry_compilers_artifacts::{
    Artifact, SolcArtifact, VyperArtifact, 
    Contract, Bytecode, DeployedBytecode, BytecodeObject
};
use serde_json;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 解析Solidity合约
    let sol_artifact_json = r#"
    {
        "contracts": {
            "MyContract.sol": {
                "MyContract": {
                    "abi": [{"inputs":[],"name":"getValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}],
                    "evm": {
                        "bytecode": {
                            "object": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c80632096525514602d575b600080fd5b60336047565b604051603e9190605b565b60405180910390f35b60005481565b6055816074565b82525050565b6000602082019050606e6000830184604e565b92915050565b600081905091905056fea2646970667358221220b5d4a1c4f8f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e64736f6c63430008110033"
                        },
                        "deployedBytecode": {
                            "object": "0x6080604052348015600f57600080fd5b506004361060285760003560e01c80632096525514602d575b600080fd5b60336047565b604051603e9190605b565b60405180910390f35b60005481565b6055816074565b82525050565b6000602082019050606e6000830184604e565b92915050565b600081905091905056fea2646970667358221220b5d4a1c4f8f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e64736f6c63430008110033"
                        }
                    }
                }
            }
        }
    }"#;
    
    let sol_artifact: Artifact = serde_json::from_str(sol_artifact_json)?;
    println!("=== Solidity合约 ===");
    if let Some(contract) = sol_artifact.contracts.values().next() {
        if let Some(c) = contract.values().next() {
            println!("ABI: {:?}", c.abi);
            println!("字节码: {}", c.evm.bytecode.object);
        }
    }

    // 2. 解析Vyper合约
    let vyper_json = r#"
    {
        "abi": [{"name": "foo", "inputs": [], "outputs": [{"type": "uint256"}], "stateMutability": "view", "type": "function"}],
        "bytecode": "0x6060604052341561000c57fe5b5b6000805460010190555b5b6097806100256000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c298557814603d575bfe5b3415604457fe5b605560048080359060200190919050506057565b005b80600054016000819055505b505600a165627a7a7230582010b5d4a1c4f8f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e0029",
        "bytecode_runtime": "0x60606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c298557814603d575bfe5b3415604457fe5b605560048080359060200190919050506057565b005b80600054016000819055505b505600a165627a7a7230582010b5d4a1c4f8f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e4b4f4b4e0029",
        "compiler_version": "0.3.7"
    }"#;
    
    let vyper_artifact: VyperArtifact = serde_json::from_str(vyper_json)?;
    println!("\n=== Vyper合约 ===");
    println!("编译器版本: {}", vyper_artifact.compiler_version);
    println!("运行时字节码: {}", vyper_artifact.bytecode_runtime);

    // 3. 生成新的合约编译产物
    let new_contract = Contract {
        abi: Some(vec![
            serde_json::from_str(r#"{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}"#)?
        ]),
        evm: Bytecode {
            bytecode: Some(BytecodeObject {
                object: "0x6080604052348015600f57600080fd5b506004361060285760003560e01c80636d4ce63c14602d575b600080fd5b60336047565b6040518082815260200191505060405180910390f35b600080549050905600a165627a7a7230582042b0bb89d7e7e1e5b0f0b0e0b0f0b0e0b0f0b0e0b0f0b0e0b0f0b0e0b0f0b0e0029".to_string(),
                ..Default::default()
            }),
            deployed_bytecode: DeployedBytecode {
                bytecode: Some(BytecodeObject {
                    object: "0x6080604052348015600f57600080fd5b506004361060285760003560e01c80636d4ce63c14602d575b600080fd5b60336047565b6040518082815260200191505060405180910390f35b600080549050905600a165627a7a7230582042b0bb89d7e7e1e5b0f0b0e0b0f0b0e0b0f0b0e0b0f0b0e0b0f0b0e0b0f0b0e0029".to_string(),
                    ..Default::default()
                }),
                ..Default::default()
            },
            ..Default::default()
        },
        ..Default::default()
    };

    println!("\n=== 生成的合约 ===");
    println!("{}", serde_json::to_string_pretty(&new_contract)?);

    Ok(())
}

维护团队

  • alloy-rs/core团队
  • Matthias Seitz
  • DaniPopes
  • Arsenii Kulikov

1 回复

Rust智能合约编译器工具foundry-compilers-artifacts使用指南

工具介绍

foundry-compilers-artifacts 是一个Rust库,专门用于高效解析和生成Solidity和Vyper智能合约的编译产物。它是Foundry工具链的一部分,主要用于处理智能合约编译后的JSON格式输出文件(artifacts)。

该工具的主要功能包括:

  • 解析Solidity/Vyper合约编译后的JSON artifacts
  • 生成标准化的合约编译产物
  • 提供类型安全的Rust接口访问编译信息
  • 支持合约ABI、字节码、部署字节码等关键信息的提取

安装方法

在Cargo.toml中添加依赖:

[dependencies]
foundry-compilers-artifacts = "0.1.0"

基本使用方法

1. 解析合约Artifacts

use foundry_compilers_artifacts::{Artifact, SolcArtifact};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 从文件读取artifacts
    let artifact_json = std::fs::read_to_string("MyContract.json")?;
    let artifact: SolcArtifact = serde_json::from_str(&artifact_json)?;
    
    // 访问合约ABI
    println!("Contract ABI: {:?}", artifact.abi);
    
    // 访问字节码
    if let Some(bytecode) = artifact.bytecode {
        println!("Bytecode: {}", bytecode.object);
    }
    
    Ok(())
}

2. 生成Artifacts

use foundry_compilers_artifacts::{
    ArtifactOutput, BytecodeObject, ContractBytecode, Settings, SolcArtifact
};

fn generate_artifact() -> SolcArtifact {
    SolcArtifact {
        abi: Some(vec![/* ABI条目 */]),
        bytecode: Some(ContractBytecode {
            object: BytecodeObject::new("0x6060..."),
            // 其他字节码相关字段
        }),
        deployed_bytecode: Some(ContractBytecode {
            object: BytecodeObject::new("0x6080..."),
            // 其他部署字节码相关字段
        }),
        // 其他字段
        ..Default::default()
    }
}

3. 处理多个合约

use foundry_compilers_artifacts::{Artifacts, SolcArtifact};

fn process_multiple_contracts(artifacts: Artifacts<SolcArtifact>) {
    for (contract_name, artifact) in artifacts.into_contracts() {
        println!("Processing contract: {}", contract_name);
        
        if let Some(abi) = artifact.abi {
            println!("ABI length: {}", abi.len());
        }
        
        // 处理字节码等其他信息
    }
}

4. 与Vyper合约交互

use foundry_compilers_artifacts::VyperArtifact;

fn process_vyper_artifact(vyper_json: &str) {
    let artifact: VyperArtifact = serde_json::from_str(vyper_json).unwrap();
    
    println!("Vyper contract ABI: {:?}", artifact.abi);
    println!("Vyper bytecode: {:?}", artifact.bytecode);
}

高级用法

1. 自定义Artifacts输出格式

use foundry_compilers_artifacts::{ArtifactOutput, Settings};

let settings = Settings {
    additional_values: serde_json::json!({
        "custom_field": "custom_value"
    }),
    // 其他设置字段
    ..Default::default()
};

let output = ArtifactOutput::new(artifact, settings);
let json = serde_json::to_string_pretty(&output)?;

2. 过滤和转换Artifacts

use foundry_compilers_artifacts::{Artifacts, SolcArtifact};

fn filter_contracts(artifacts: Artifacts<SolcArtifact>) -> Artifacts<SolcArtifact> {
    // 过滤出以ERC20开头的合约
    artifacts.into_contracts()
        .filter(|(name, _)| name.starts_with("ERC20"))
        .collect()
}

完整示例demo

以下是一个完整的示例,展示如何使用foundry-compilers-artifacts处理多个合约artifacts:

use foundry_compilers_artifacts::{Artifacts, SolcArtifact};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 读取目录中的所有合约artifacts
    let artifacts_dir = Path::new("./artifacts");
    let artifacts = Artifacts::<SolcArtifact>::read_from_dir(artifacts_dir)?;
    
    // 2. 过滤出ERC20合约
    let erc20_artifacts = artifacts.into_contracts()
        .filter(|(name, _)| name.starts_with("ERC20"))
        .collect::<Artifacts<SolcArtifact>>();
    
    // 3. 处理每个ERC20合约
    for (contract_name, artifact) in erc20_artifacts.into_contracts() {
        println!("Processing ERC20 contract: {}", contract_name);
        
        // 检查并打印ABI信息
        if let Some(abi) = &artifact.abi {
            println!("  ABI contains {} items", abi.len());
            
            // 查找transfer函数
            let has_transfer = abi.iter().any(|item| {
                if let serde_json::Value::Object(obj) = item {
                    obj.get("name") == Some(&serde_json::Value::String("transfer".to_string())) &&
                    obj.get("type") == Some(&serde_json::Value::String("function".to_string()))
                } else {
                    false
                }
            });
            
            println!("  Has transfer function: {}", has_transfer);
        }
        
        // 检查并打印字节码信息
        if let Some(bytecode) = &artifact.bytecode {
            println!("  Bytecode length: {} bytes", bytecode.object.as_str().unwrap().len() / 2);
        }
    }
    
    Ok(())
}

性能提示

  1. 对于大量合约处理,考虑使用Artifacts::read_from_dir而不是逐个文件读取
  2. 如果只需要部分信息(如仅ABI),可以使用serde_json::Value进行初步过滤后再解析
  3. 对于重复处理相同artifacts,可以考虑缓存解析结果

foundry-compilers-artifacts为Rust开发者提供了强大而灵活的工具来处理智能合约编译产物,无论是构建开发工具、测试框架还是部署脚本,都能显著提高开发效率。

回到顶部