默认实现宏

概述

#[default_impl] 宏是一个实用工具,通过自动生成 trait 方法的默认实现,简化了 OpenZeppelin Stellar 合约 trait 的实现。这允许开发者只专注于重写他们需要自定义的方法,而宏会处理其余部分。

背景

当使用 Soroban 的 #[contractimpl] 宏时,所有方法(包括默认实现)必须显式地包含在实现块中,以便它们可以被生成的客户端访问。这是由于 Rust 宏的工作方式——它们无法访问不在宏作用域内的 trait 方法的默认实现。

#[default_impl] 宏通过自动为 OpenZeppelin Stellar trait 生成缺失的默认实现来解决这个问题。

支持的 Traits

#[default_impl] 宏支持以下 OpenZeppelin Stellar traits:

  • FungibleToken

  • FungibleBurnable

  • NonFungibleToken

  • NonFungibleBurnable

  • NonFungibleEnumerable

  • AccessControl

  • Ownable

#[default_impl] 宏有意不支持以下 traits:

  • FungibleAllowlist

  • FungibleBlocklist

  • NonFungibleRoyalties

这种限制是特意设计的:授权配置需要根据每个项目的安全需求进行特定的实现。通过要求手动实现这些 traits,我们确保 开发者仔细考虑并显式定义他们的授权逻辑,而不是依赖于通用的默认设置。

用法

要使用 [default_impl] 宏,当实现一个支持的 traits 时,将其放在 [contractimpl] 宏之上:

#[default_impl] // 重要:将其放在 `#[contractimpl]` 之上
#[contractimpl]
impl NonFungibleToken for MyContract {
    type ContractType = Base;

    // 只重写你需要自定义的方法
    // 所有其他方法将自动使用其默认行为实现
}

工作原理

#[default_impl] 宏:

  1. 识别正在实现的 trait

  2. 确定用户显式定义了哪些方法

  3. 使用用户定义的方法覆盖默认实现

  4. 使用默认实现填充其余的方法(未由用户定义)

  5. 为 trait 添加任何必要的导入

这个过程确保了所有 trait 方法都可以被 #[contractimpl] 生成的客户端访问,同时允许开发者只编写他们需要自定义的代码。

示例

Fungible Token 示例

use soroban_sdk::{contract, contractimpl, Address, Env};
use stellar_tokens::fungible::FungibleToken;
use stellar_macros::default_impl;

#[contract]
pub struct MyToken;

#[default_impl]
#[contractimpl]
impl FungibleToken for MyToken {
    type ContractType = Base;

    // 只重写需要自定义行为的方法
    fn transfer(e: &Env, from: Address, to: Address, amount: i128) {
        // 自定义 transfer 逻辑在这里
    }

    // 所有其他 FungibleToken 方法将自动实现
}