Rust智能合约开发库near-abi的使用,NEAR协议ABI编码与解码工具

Rust智能合约开发库near-abi的使用,NEAR协议ABI编码与解码工具

概述

警告:ABI仍处于早期开发阶段,在达到1.0版本前可能会有重大变更

near-abi-rs是一个为Rust提供NEAR ABI模型的库,可作为NEAR ABI的参考实现。

安装

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

cargo add near-abi

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

near-abi = "0.4.3"

ABI元模式

该库还包含ABI的元JSON Schemas,这些模式可用于验证JSON文件是否为有效的NEAR ABI。

使用示例

下面是一个使用near-abi进行编码和解码的完整示例:

use near_abi::{AbiFunction, AbiParameter, AbiType};

// 创建ABI函数定义
let function = AbiFunction {
    name: "transfer".to_string(),
    doc: Some("Transfer tokens".to_string()),
    modifiers: vec![],
    params: vec![
        AbiParameter {
            name: "receiver_id".to_string(),
            ty: AbiType::String,
            doc: None,
        },
        AbiParameter {
            name: "amount".to_string(),
            ty: AbiType::U128,
            doc: None,
        },
    ],
    result: Some(AbiType::Unit),
    is_view: false,
    is_payable: false,
    is_mutable: true,
};

// 序列化为JSON
let json = serde_json::to_string_pretty(&function).unwrap();
println!("{}", json);

// 从JSON反序列化
let deserialized: AbiFunction = serde_json::from_str(&json).unwrap();
assert_eq!(function, deserialized);

完整示例demo

以下是基于near-abi的完整使用示例,展示了如何定义、序列化和反序列化ABI:

use near_abi::{AbiFunction, AbiParameter, AbiType};

fn main() {
    // 定义一个转账函数ABI
    let transfer_function = AbiFunction {
        name: "transfer".to_string(),
        doc: Some("Transfer tokens between accounts".to_string()),
        modifiers: vec![],
        params: vec![
            AbiParameter {
                name: "receiver_id".to_string(),
                ty: AbiType::String,
                doc: Some("Account ID of the receiver".to_string()),
            },
            AbiParameter {
                name: "amount".to_string(),
                ty: AbiType::U128,
                doc: Some("Amount of tokens to transfer".to_string()),
            },
        ],
        result: Some(AbiType::Unit),
        is_view: false,
        is_payable: false,
        is_mutable: true,
    };

    // 序列化为JSON字符串
    let json_str = serde_json::to_string_pretty(&transfer_function).unwrap();
    println!("序列化后的ABI JSON:");
    println!("{}", json_str);

    // 从JSON字符串反序列化
    let deserialized: AbiFunction = serde_json::from_str(&json_str).unwrap();
    println!("\n反序列化后的ABI:");
    println!("函数名: {}", deserialized.name);
    println!("参数:");
    for param in deserialized.params {
        println!("  - {}: {:?}", param.name, param.ty);
    }
    
    // 验证原始对象和反序列化对象是否相等
    assert_eq!(transfer_function, deserialized);
    println!("\n验证通过: 原始ABI与反序列化ABI一致");
}

贡献

如果您有兴趣贡献,请查看贡献指南。

许可证

根据以下任一许可证授权:

  • Apache License, Version 2.0
  • MIT license

1 回复

Rust智能合约开发库near-abi的使用:NEAR协议ABI编码与解码工具

介绍

near-abi 是 NEAR 协议生态中的一个 Rust 库,用于处理智能合约的 ABI(Application Binary Interface)编码与解码。它提供了在 NEAR 区块链上开发智能合约时所需的类型系统和序列化工具,使得合约与外部调用者之间的数据交互更加安全和方便。

主要功能包括:

  • 类型定义(如 FunctionParameterType 等)
  • ABI 编码与解码
  • JSON ABI 格式支持
  • 与 NEAR SDK 的无缝集成

安装方法

在 Cargo.toml 中添加依赖:

[dependencies]
near-abi = "0.4.0"

基本使用方法

1. 定义 ABI

use near_abi::{AbiFunction, AbiParameters, AbiType};

// 定义一个函数的ABI
let function_abi = AbiFunction {
    name: "transfer".to_string(),
    doc: Some("Transfer tokens to another account".to_string()),
    params: AbiParameters {
        args: vec![
            ("receiver_id".to_string(), AbiType::String),
            ("amount".to_string(), AbiType::U64),
        ],
    },
    result: Some(AbiType::Bool),
};

2. 序列化 ABI 到 JSON

use near_abi::AbiRoot;

let abi_root = AbiRoot {
    functions: vec![function_abi],
    ..Default::default()
};

let json_str = serde_json::to_string_pretty(&abi_root).unwrap();
println!("{}", json_str);

3. 从 JSON 反序列化 ABI

let json_str = r#"
{
    "functions": [
        {
            "name": "transfer",
            "doc": "Transfer tokens to another account",
            "params": {
                "args": [
                    ["receiver_id", "string"],
                    ["amount", "u64"]
                ]
            },
            "result": "bool"
        }
    ]
}"#;

let abi_root: AbiRoot = serde_json::from_str(json_str).unwrap();

4. 编码函数调用参数

use near_abi::AbiSerializer;

let serializer = AbiSerializer::new(&abi_root);
let args = serializer.serialize("transfer", &["alice.near", "100"]).unwrap();

// args 现在可以用于合约调用

5. 解码函数调用结果

let result_bytes: Vec<u8> = // 从合约调用获取的结果
let result: bool = serializer.deserialize_result("transfer", &result_bytes).unwrap();

完整示例:NEAR 智能合约 ABI 定义

use near_abi::{AbiRoot, AbiFunction, AbiParameters, AbiType};

fn create_token_abi() → AbiRoot {
    let transfer = AbiFunction {
        name: "transfer".to_string(),
        doc: Some("Transfer tokens to another account".to_string()),
        params: AbiParameters {
            args: vec![
                ("receiver_id".to_string(), AbiType::String),
                ("amount".to_string(), AbiType::U64),
            ],
        },
        result: Some(AbiType::Bool),
    };

    let balance_of = AbiFunction {
        name: "balance_of".to_string(),
        doc: Some("Get account balance".to_string()),
        params: AbiParameters {
            args: vec![
                ("account_id".to_string(), AbiType::String),
            ],
        },
        result: Some(AbiType::U64),
    };

    AbiRoot {
        functions: vec![transfer, balance_of],
        ..Default::default()
    }
}

fn main() {
    let token_abi = create_token_abi();
    
    // 序列化为JSON
    let json = serde_json::to_string_pretty(&token_abi).unwrap();
    println!("Token ABI:\n{}", json);
    
    // 创建序列化器
    let serializer = near_abi::AbiSerializer::new(&token_abi);
    
    // 编码transfer调用参数
    let args = serializer.serialize("transfer", &["bob.near", "50"]).unwrap();
    println!("Encoded args: {:?}", args);
    
    // 解码balance_of结果
    let result_bytes = vec![0, 0, 0, 0, 0, 0, 1, 100]; // 假设返回300
    let balance: u64 = serializer.deserialize_result("balance_of", &result_bytes).unwrap();
    println!("Decoded balance: {}", balance);
}

高级用法

自定义类型支持

use near_abi::{AbiType, AbiRoot};

let mut abi_root = AbiRoot::default();
abi_root.types.push((
    "MyStruct".to_string(),
    AbiType::Struct(vec![
        ("field1".to_string(), AbiType::String),
        ("field2".to_string(), AbiType::U32),
    ]),
));

事件定义

use near_abi::{AbiEvent, AbiRoot};

let mut abi_root = AbiRoot::default();
abi_root.events.push(AbiEvent {
    name: "Transfer".to_string(),
    doc: Some("Token transfer event".to_string()),
    params: vec![
        ("from".to_string(), AbiType::String),
        ("to".to_string(), AbiType::String),
        ("amount".to_string(), AbiType::U64),
    ],
});

完整示例demo

以下是一个完整的 NEAR 智能合约 ABI 定义和使用示例:

use near_abi::{AbiRoot, AbiFunction, AbiParameters, AbiType, AbiSerializer};

// 定义一个NFT合约的ABI
fn create_nft_abi() -> AbiRoot {
    // 定义mint函数
    let mint = AbiFunction {
        name: "mint".to_string(),
        doc: Some("Mint a new NFT".to_string()),
        params: AbiParameters {
            args: vec![
                ("token_id".to_string(), AbiType::String),
                ("owner_id".to_string(), AbiType::String),
                ("metadata".to_string(), AbiType::String),
            ],
        },
        result: Some(AbiType::Bool),
    };

    // 定义get_owner函数
    let get_owner = AbiFunction {
        name: "get_owner".to_string(),
        doc: Some("Get NFT owner".to_string()),
        params: AbiParameters {
            args: vec![
                ("token_id".to_string(), AbiType::String),
            ],
        },
        result: Some(AbiType::String),
    };

    // 定义NFT转移事件
    let transfer_event = AbiEvent {
        name: "NftTransferred".to_string(),
        doc: Some("NFT transfer event".to_string()),
        params: vec![
            ("from".to_string(), AbiType::String),
            ("to".to_string(), AbiType::String),
            ("token_id".to_string(), AbiType::String),
        ],
    };

    // 创建ABI根对象
    AbiRoot {
        functions: vec![mint, get_owner],
        events: vec![transfer_event],
        ..Default::default()
    }
}

fn main() {
    // 创建NFT合约ABI
    let nft_abi = create_nft_abi();
    
    // 序列化为JSON
    let json = serde_json::to_string_pretty(&nft_abi).unwrap();
    println!("NFT Contract ABI:\n{}", json);
    
    // 创建ABI序列化器
    let serializer = AbiSerializer::new(&nft_abi);
    
    // 编码mint函数调用参数
    let mint_args = serializer.serialize(
        "mint", 
        &["nft-001", "alice.near", "{\"title\":\"My NFT\"}"]
    ).unwrap();
    println!("Encoded mint args: {:?}", mint_args);
    
    // 解码get_owner函数结果
    let owner_bytes = b"bob.near".to_vec(); // 假设返回"bob.near"
    let owner: String = serializer.deserialize_result("get_owner", &owner_bytes).unwrap();
    println!("Decoded owner: {}", owner);
    
    // 编码事件数据
    let event_data = serializer.serialize_event(
        "NftTransferred",
        &["alice.near", "bob.near", "nft-001"]
    ).unwrap();
    println!("Encoded event data: {:?}", event_data);
}

注意事项

  1. near-abi 主要设计用于 NEAR 协议的智能合约开发
  2. ABI 定义应与合约实际的函数签名严格匹配
  3. 编码/解码时确保使用正确的函数名和参数类型
  4. 对于生产环境,建议将 ABI JSON 存储在单独的文件中

通过 near-abi,开发者可以更方便地在 NEAR 生态系统中构建类型安全的智能合约接口,并确保合约与前端应用之间的数据交互正确无误。

回到顶部