Icon Link访问控制

在 Sway 中,智能合约需要能够限制对某些用户或合约的访问。与基于账户的区块链不同,基于 UTXO 的区块链(例如 Fuel)中的交易不一定有一个唯一的交易发送者。需要额外的逻辑来处理这种差异,并由标准库提供支持。

Icon Linkmsg_sender

为了提供类似于 EVM 中的访问控制体验,std 库提供了一个 msg_sender 函数,该函数基于调用和/或交易输入数据来标识一个唯一的调用者。

contract;
 
abi MyOwnedContract {
    fn receive(field_1: u64) -> bool;
}
 
const OWNER = Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);
 
impl MyOwnedContract for Contract {
    fn receive(field_1: u64) -> bool {
        let sender = msg_sender().unwrap();
        if let Identity::Address(addr) = sender {
            assert(addr == OWNER);
        } else {
            revert(0);
        }
 
        true
    }
}
 

msg_sender 函数的工作原理如下:

  • 如果调用者是一个合约,则返回带有 ContractId 发送者变体的 Ok(Sender)
  • 如果调用者是外部的(即来自脚本),则检查交易中的所有币输入所有者。如果所有者都相同,则返回带有 Address 发送者变体的 Ok(Sender)
  • 如果调用者是外部的且币输入所有者不同,则无法确定调用者,返回 Err(AuthError)

Icon Link合约所有权

许多合约需要某种形式的所有权以进行访问控制。SRC-5 拥有权标准 Icon Link 已经定义了一个可互操作的合约内部所有权接口。

为了实现这一点,使用 Ownership 库 来跟踪所有者。这允许使用变体 Some(..)None 来设置和撤销所有权。这比直接使用 Identity 类型更好、更安全、更可读,其中撤销所有权必须使用某些魔术值如 b256::zero() 或其他方式。

以下是正确锁定函数以使只有所有者可以调用函数的示例:

#[storage(read)]
fn only_owner() {
    storage.owner.only_owner();
    // Do stuff here
}

设置所有权可以通过两种方式之一来完成:在编译时或运行时。

以下是在编译时正确设置合约所有权的示例:

storage {
    owner: Ownership = Ownership::initialized(Identity::Address(Address::zero())),
}

以下是在运行时正确设置合约所有权的示例:

#[storage(write)]
fn set_owner(identity: Identity) {
    storage.owner.set_ownership(identity);
}

以下是正确撤销合约所有权的示例:

#[storage(write)]
fn revoke_ownership() {
    storage.owner.renounce_ownership();
}

以下是正确检索所有权状态的示例:

#[storage(read)]
fn owner() -> State {
    storage.owner.owner()
}

Icon Link访问控制库

Sway-Libs 提供以下库以进一步实现访问控制。