ERC-20 可暂停

具有可暂停的 token 转移、铸造和销毁的 ERC20 token。

适用于诸如防止在评估期结束前进行交易,或在发生重大错误时拥有冻结所有 token 转移的紧急开关等场景。

用法

为了使你的 ERC20 token pausable,你需要使用 Pausable 合约,并将它的机制应用到 ERC20 token 函数,如下所示:

use openzeppelin_stylus::{
    token::erc20::{self, Erc20, IErc20},
    utils::{pausable, IPausable, Pausable},
};

#[derive(SolidityError, Debug)]
enum Error {
    InsufficientBalance(erc20::ERC20InsufficientBalance),
    InvalidSender(erc20::ERC20InvalidSender),
    InvalidReceiver(erc20::ERC20InvalidReceiver),
    InsufficientAllowance(erc20::ERC20InsufficientAllowance),
    InvalidSpender(erc20::ERC20InvalidSpender),
    InvalidApprover(erc20::ERC20InvalidApprover),
    EnforcedPause(pausable::EnforcedPause),
    ExpectedPause(pausable::ExpectedPause),
}

impl From<erc20::Error> for Error {
    fn from(value: erc20::Error) -> Self {
        match value {
            erc20::Error::InsufficientBalance(e) => {
                Error::InsufficientBalance(e)
            }
            erc20::Error::InvalidSender(e) => Error::InvalidSender(e),
            erc20::Error::InvalidReceiver(e) => Error::InvalidReceiver(e),
            erc20::Error::InsufficientAllowance(e) => {
                Error::InsufficientAllowance(e)
            }
            erc20::Error::InvalidSpender(e) => Error::InvalidSpender(e),
            erc20::Error::InvalidApprover(e) => Error::InvalidApprover(e),
        }
    }
}

impl From<pausable::Error> for Error {
    fn from(value: pausable::Error) -> Self {
        match value {
            pausable::Error::EnforcedPause(e) => Error::EnforcedPause(e),
            pausable::Error::ExpectedPause(e) => Error::ExpectedPause(e),
        }
    }
}

#[entrypoint]
#[storage]
struct Erc20Example {
    erc20: Erc20,
    pausable: Pausable,
}

#[public]
#[implements(IErc20<Error = Error>, IPausable)]
impl Erc20Example {
    fn mint(&mut self, account: Address, value: U256) -> Result<(), Error> {
        // ...
        self.pausable.when_not_paused()?;
        // ...
        self.erc20._mint(account, value)?;
        Ok(())
    }
}

#[public]
impl IErc20 for Erc20Example {
    type Error = Error;

    fn transfer(&mut self, to: Address, value: U256) -> Result<bool, Error> {
        // ...
        self.pausable.when_not_paused()?;
        // ...
        let result = self.erc20.transfer(to, value)?;
        // ...
        Ok(result)
    }

    fn transfer_from(
        &mut self,
        from: Address,
        to: Address,
        value: U256,
    ) -> Result<bool, Error> {
        // ...
        self.pausable.when_not_paused()?;
        // ...
        let result = self.erc20.transfer_from(from, to, value)?;
        // ...
        Ok(result)
    }

    fn total_supply(&self) -> U256 {
        self.erc20.total_supply()
    }

    fn balance_of(&self, account: Address) -> U256 {
        self.erc20.balance_of(account)
    }

    fn allowance(&self, owner: Address, spender: Address) -> U256 {
        self.erc20.allowance(owner, spender)
    }

    fn approve(
        &mut self,
        spender: Address,
        value: U256,
    ) -> Result<bool, Self::Error> {
        Ok(self.erc20.approve(spender, value)?)
    }
}

#[public]
impl IPausable for Erc20Example {
    fn paused(&self) -> bool {
        self.pausable.paused()
    }
}