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 }));
}
}
代码说明
#[contract]
宏用于标记整个合约模块#[storage]
结构体定义了合约的存储变量,包括基本类型和映射#[event]
和#[derive(Drop, starknet::Event)]
用于定义合约事件#[constructor]
标记合约的构造函数#[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);
}
}
使用建议
- 类型安全:宏会自动检查类型是否与Cairo兼容
- ABI生成:合约编译时会自动生成正确的ABI
- 错误处理:使用
#[derive(starknet::Error)]
定义自定义错误 - 事件:使用
#[event]
宏定义合约事件
注意事项
- 确保使用的Rust类型与Cairo类型兼容
- 存储结构体中的字段必须是可序列化的
- 函数参数和返回值需要是StarkNet支持的类型
这个宏库大大简化了Rust与StarkNet/Cairo的集成工作,让开发者可以专注于业务逻辑而不是底层细节。