ERC-20 许可

添加了 permit 方法,该方法可用于更改帐户的 ERC20 授权额度(参见 IErc20::allowance),方法是出示由帐户签名的消息。通过不依赖于 IErc20::approve,token 持有者帐户不需要发送交易,因此根本不需要持有 Ether 。

用法

为了拥有 ERC-20 Permit token,您只需要使用此合约,而无需使用 ERC-20,如下所示:

use openzeppelin_stylus::{
    token::erc20::{
        extensions::{permit, Erc20Permit, IErc20Permit},
        Erc20, IErc20,
    },
    utils::{
        cryptography::eip712::IEip712,
        nonces::{INonces, Nonces},
    },
};

#[entrypoint]
#[storage]
struct Erc20PermitExample {
    erc20: Erc20,
    nonces: Nonces,
    erc20_permit: Erc20Permit<Eip712>,
}

#[storage]
struct Eip712;

impl IEip712 for Eip712 {
    const NAME: &'static str = "ERC-20 Permit Example";
    const VERSION: &'static str = "1";
}

#[public]
#[implements(IErc20<Error = permit::Error>, INonces, IErc20Permit<Error = permit::Error>)]
impl Erc20PermitExample {
    // 添加 token 铸造功能。
    fn mint(
        &mut self,
        account: Address,
        value: U256,
    ) -> Result<(), permit::Error> {
        Ok(self.erc20._mint(account, value)?)
    }
}

#[public]
impl INonces for Erc20PermitExample {
    fn nonces(&self, owner: Address) -> U256 {
        self.nonces.nonces(owner)
    }
}

#[public]
impl IErc20Permit for Erc20PermitExample {
    type Error = permit::Error;

    #[selector(name = "DOMAIN_SEPARATOR")]
    fn domain_separator(&self) -> B256 {
        self.erc20_permit.domain_separator()
    }

    fn permit(
        &mut self,
        owner: Address,
        spender: Address,
        value: U256,
        deadline: U256,
        v: u8,
        r: B256,
        s: B256,
    ) -> Result<(), Self::Error> {
        self.erc20_permit.permit(
            owner,
            spender,
            value,
            deadline,
            v,
            r,
            s,
            &mut self.erc20,
            &mut self.nonces,
        )
    }
}

#[public]
impl IErc20 for Erc20PermitExample {
    type Error = permit::Error;

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

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

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

    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)?)
    }

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