Rust StarkNet智能合约开发宏库starknet-macros的使用,简化Cairo合约与Rust集成

Rust StarkNet智能合约开发宏库starknet-macros的使用,简化Cairo合约与Rust集成

安装

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

cargo add starknet-macros

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

starknet-macros = "0.2.4"

使用示例

以下是一个完整的starknet-macros使用示例,展示了如何简化Cairo合约与Rust的集成:

use starknet::macros::contract;

// 使用contract宏定义一个StarkNet合约
#[contract]
mod MyContract {
    // 定义存储变量
    #[storage]
    struct Storage {
        balance: felt252,
        owner: ContractAddress,
    }

    // 定义事件
    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        BalanceIncreased: BalanceIncreased,
    }

    #[derive(Drop, starknet::Event)]
    struct BalanceIncreased {
        #[key]
        amount: felt252,
    }

    // 定义合约函数
    #[external(v0)]
    fn increase_balance(ref self: ContractState, amount: felt252) {
        let current = self.balance.read();
        self.balance.write(current + amount);
        
        // 触发事件
        self.emit(Event::BalanceIncreased(BalanceIncreased { amount }));
    }

    #[external(v0)]
    fn get_balance(self: @ContractState) -> felt252 {
        self.balance.read()
    }
}

完整示例代码

以下是一个更完整的StarkNet合约示例,展示了存储变量、事件和多种函数的用法:

use starknet::macros::contract;
use starknet::ContractAddress;

#[contract]
mod TokenContract {
    // 存储结构体定义合约状态
    #[storage]
    struct Storage {
        total_supply: felt252,
        balances: LegacyMap<ContractAddress, felt252>,
        allowances: LegacyMap<(ContractAddress, ContractAddress), felt252>,
        owner: ContractAddress,
    }

    // 定义合约事件
    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        Transfer: Transfer,
        Approval: Approval,
    }

    #[derive(Drop, starknet::Event)]
    struct Transfer {
        #[key]
        from: ContractAddress,
        #[key]
        to: ContractAddress,
        value: felt252,
    }

    #[derive(Drop, starknet::Event)]
    struct Approval {
        #[key]
        owner: ContractAddress,
        #[key]
        spender: ContractAddress,
        value: felt252,
    }

    // 构造函数 - 只在部署时执行一次
    #[constructor]
    fn constructor(ref self: ContractState, initial_supply: felt252) {
        let deployer = get_caller_address();
        self.owner.write(deployer);
        self.total_supply.write(initial_supply);
        self.balances.write(deployer, initial_supply);
    }

    // 转账函数
    #[external(v0)]
    fn transfer(ref self: ContractState, to: ContractAddress, value: felt252) {
        let sender = get_caller_address();
        let sender_balance = self.balances.read(sender);
        assert(sender_balance >= value, "Insufficient balance");
        
        self.balances.write(sender, sender_balance - value);
        let recipient_balance = self.balances.read(to);
        self.balances.write(to, recipient_balance + value);
        
        self.emit(Event::Transfer(Transfer {
            from: sender,
            to,
            value,
        }));
    }

    // 查询余额函数
    #[external(v0)]
    fn balance_of(self: @ContractState, owner: ContractAddress) -> felt252 {
        self.balances.read(owner)
    }

    // 授权函数
    #[external(v0)]
    fn approve(ref self: ContractState, spender: ContractAddress, value: felt252) {
        let owner = get_caller_address();
        self.allowances.write((owner, spender), value);
        self.emit(Event::Approval(Approval { owner, spender, value }));
    }
}

代码说明

  1. #[contract]宏用于标记整个合约模块
  2. #[storage]结构体定义了合约的存储变量,包括基本类型和映射
  3. #[event]#[derive(Drop, starknet::Event)]用于定义合约事件
  4. #[constructor]标记合约的构造函数
  5. #[external(v0)]标记合约的外部可调用函数

特性

  • 自动生成必要的合约ABI
  • 简化存储变量的定义和访问
  • 提供便捷的事件系统
  • 类型安全的合约交互
  • 与Cairo合约的无缝集成

许可证

该项目采用MIT或Apache-2.0许可证。


1 回复

Rust StarkNet智能合约开发宏库starknet-macros使用指南

starknet-macros是一个简化Rust与Cairo智能合约集成的宏库,专为StarkNet开发设计。它提供了一系列过程宏,让开发者能够更轻松地在Rust中编写与StarkNet兼容的智能合约。

主要功能

  • 简化合约接口定义
  • 自动生成ABI兼容代码
  • 提供类型安全的数据转换
  • 减少样板代码

安装

在Cargo.toml中添加依赖:

[dependencies]
starknet-macros = "0.1"

核心宏介绍

#[starknet::contract]

用于标记一个合约实现:

#[starknet::contract]
mod MyContract {
    // 合约代码
}

#[starknet::interface]

定义合约接口:

#[starknet::interface]
trait IMyContract<T> {
    fn get_value(self: @T) -> u32;
    fn set_value(ref self: T, value: u32);
}

#[external]

标记外部可调用的合约函数:

#[external]
impl MyContractImpl of IMyContract<ContractState> {
    fn get_value(self: @ContractState) -> u32 {
        self.value.read()
    }
    
    fn set_value(ref self: ContractState, value: u32) {
        self.value.write(value);
    }
}

#[storage]

定义合约存储:

#[storage]
struct Storage {
    value: u32,
    owner: ContractAddress,
}

完整示例

use starknet::ContractAddress;

#[starknet::interface]
trait ICounter<T> {
    fn get_count(self: @T) -> u32;
    fn increment(ref self: T);
}

#[starknet::contract]
mod Counter {
    use starknet::ContractAddress;
    
    #[storage]
    struct Storage {
        count: u32,
        owner: ContractAddress,
    }
    
    #[external]
    impl CounterImpl of super::ICounter<ContractState> {
        fn get_count(self: @ContractState) -> u32 {
            self.count.read()
        }
        
        fn increment(ref self: ContractState) {
            let current = self.count.read();
            self.count.write(current + 1);
        }
    }
    
    #[constructor]
    fn constructor(ref self: ContractState, owner: ContractAddress) {
        self.count.write(0);
        self.owner.write(owner);
    }
}

扩展完整示例

下面是一个更完整的StarkNet智能合约示例,包含事件定义和错误处理:

use starknet::ContractAddress;

// 定义合约接口
#[starknet::interface]
trait IBankContract<T> {
    fn deposit(ref self: T, amount: u128);
    fn withdraw(ref self: T, amount: u128) -> bool;
    fn get_balance(self: @T) -> u128;
    fn get_owner(self: @T) -> ContractAddress;
}

// 定义合约事件
#[event]
enum Event {
    Deposit: DepositEvent,
    Withdraw: WithdrawEvent,
}

// 事件结构体
#[derive(Drop, starknet::Event)]
struct DepositEvent {
    account: ContractAddress,
    amount: u128,
}

#[derive(Drop, starknet::Event)]
struct WithdrawEvent {
    account: ContractAddress,
    amount: u128,
    success: bool,
}

// 定义自定义错误
#[derive(Drop, starknet::Error)]
enum BankError {
    InsufficientBalance: (),
    Unauthorized: (),
}

#[starknet::contract]
mod BankContract {
    use super::{ContractAddress, IBankContract, BankError, Event, DepositEvent, WithdrawEvent};
    
    #[storage]
    struct Storage {
        balances: LegacyMap<ContractAddress, u128>,  // 用户余额映射
        owner: ContractAddress,  // 合约所有者
    }
    
    #[external]
    impl BankContractImpl of IBankContract<ContractState> {
        fn deposit(ref self: ContractState, amount: u128) {
            let caller = get_caller_address();
            let current_balance = self.balances.read(caller);
            self.balances.write(caller, current_balance + amount);
            
            // 触发存款事件
            self.emit(Event::Deposit(DepositEvent {
                account: caller,
                amount,
            }));
        }
        
        fn withdraw(ref self: ContractState, amount: u128) -> bool {
            let caller = get_caller_address();
            let current_balance = self.balances.read(caller);
            
            if current_balance < amount {
                // 触发取款失败事件
                self.emit(Event::Withdraw(WithdrawEvent {
                    account: caller,
                    amount,
                    success: false,
                }));
                return false;
            }
            
            self.balances.write(caller, current_balance - amount);
            
            // 触发取款成功事件
            self.emit(Event::Withdraw(WithdrawEvent {
                account: caller,
                amount,
                success: true,
            }));
            
            true
        }
        
        fn get_balance(self: @ContractState) -> u128 {
            let caller = get_caller_address();
            self.balances.read(caller)
        }
        
        fn get_owner(self: @ContractState) -> ContractAddress {
            self.owner.read()
        }
    }
    
    #[constructor]
    fn constructor(ref self: ContractState, owner: ContractAddress) {
        self.owner.write(owner);
    }
    
    // 只有所有者可以调用的管理函数
    #[external]
    fn add_liquidity(ref self: ContractState, amount: u128) {
        assert(self.owner.read() == get_caller_address(), BankError::Unauthorized);
        let owner = self.owner.read();
        let current_balance = self.balances.read(owner);
        self.balances.write(owner, current_balance + amount);
    }
}

使用建议

  1. 类型安全:宏会自动检查类型是否与Cairo兼容
  2. ABI生成:合约编译时会自动生成正确的ABI
  3. 错误处理:使用#[derive(starknet::Error)]定义自定义错误
  4. 事件:使用#[event]宏定义合约事件

注意事项

  • 确保使用的Rust类型与Cairo类型兼容
  • 存储结构体中的字段必须是可序列化的
  • 函数参数和返回值需要是StarkNet支持的类型

这个宏库大大简化了Rust与StarkNet/Cairo的集成工作,让开发者可以专注于业务逻辑而不是底层细节。

回到顶部