SAC 管理员包装器

概述

Stellar Asset Contract (SAC) 管理员包装器模块提供了一种使用包装器方法为 Stellar Asset Contracts (SAC) 实现自定义管理功能的方法。 这种方法为每个管理员函数定义特定的入口点,并将调用转发到相应的 SAC 函数,从而提供了一种简单且模块化的设计。

关键概念

当经典的 Stellar 资产被移植到 Soroban 时,它由 SAC 表示 - 一种智能合约,为资产管理提供面向用户的和管理功能。 SAC 公开用于处理同质化代币的标准功能,例如 transferapproveburn 等。 此外,它们还包括管理功能(mintclawbackset_adminset_authorized),这些功能最初仅限于发行者(G 帐户)。

set_admin 函数能够将管理控制权转移到自定义合约,从而实现更复杂的授权逻辑。 这种灵活性为实施自定义规则开辟了可能性,例如基于角色的访问控制、两步管理员转移、铸币速率限制和可升级性。

包装器方法

SAC 管理员实现的包装器方法:

  • 充当中间件,为每个管理员函数定义特定的入口点

  • 将调用转发到相应的 SAC 函数

  • 在转发调用之前应用自定义逻辑

  • 提供简单且模块化的设计

  • 分离面向用户的和管理员接口

SACAdminWrapper Trait

SACAdminWrapper trait 定义了包装器方法的接口:

pub trait SACAdminWrapper {
    fn set_admin(e: Env, new_admin: Address, operator: Address);
    fn set_authorized(e: Env, id: Address, authorize: bool, operator: Address);
    fn mint(e: Env, to: Address, amount: i128, operator: Address);
    fn clawback(e: Env, from: Address, amount: i128, operator: Address);
}

示例实现

这是一个使用 OpenZeppelin 访问控制库的 SAC 管理员包装器合约的简化示例:

#[contract]
pub struct ExampleContract;

#[contractimpl]
impl ExampleContract {
    pub fn __constructor(
        e: &Env,
        default_admin: Address,
        manager1: Address,
        manager2: Address,
        sac: Address,
    ) {
        access_control::set_admin(e, &default_admin);

        // 创建一个 "manager" 角色并将其授予 `manager1`
        access_control::grant_role_no_auth(e, &default_admin, &manager1, &symbol_short!("manager"));

        // 将其授予 `manager2`
        access_control::grant_role_no_auth(e, &default_admin, &manager2, &symbol_short!("manager"));

        fungible::sac_admin_wrapper::set_sac_address(e, &sac);
    }
}

#[contractimpl]
impl SACAdminWrapper for ExampleContract {
    #[only_admin]
    fn set_admin(e: Env, new_admin: Address, _operator: Address) {
        fungible::sac_admin_wrapper::set_admin(&e, &new_admin);
    }

    #[only_role(operator, "manager")]
    fn set_authorized(e: Env, id: Address, authorize: bool, operator: Address) {
        fungible::sac_admin_wrapper::set_authorized(&e, &id, authorize);
    }

    #[only_role(operator, "manager")]
    fn mint(e: Env, to: Address, amount: i128, operator: Address) {
        fungible::sac_admin_wrapper::mint(&e, &to, amount);
    }

    #[only_role(operator, "manager")]
    fn clawback(e: Env, from: Address, amount: i128, operator: Address) {
        fungible::sac_admin_wrapper::clawback(&e, &from, amount);
    }
}

与访问控制集成

包装器方法与 OpenZeppelin 访问控制库配合得特别好,允许将基于角色的访问控制应用于每个管理功能:

  • #[only_admin]: 限制函数仅由管理员调用

  • #[only_role(operator, "manager")]: 限制函数仅由具有 "manager" 角色的地址调用

优点和缺点

优点

  • 与通用方法相比,实现起来更简单

  • 在函数特定授权方面更灵活

  • 适用于基于角色的访问控制

  • 关注点分离清晰

缺点

  • 每个管理员函数都需要额外的入口点

  • 分离面向用户的和管理员接口

  • 对于复杂的授权方案,可能需要更多代码

完整示例

完整的示例实现可以在 sac-admin-wrapper 示例中找到。