ERC-20 Permit

Outdated Version

You're viewing an older version (v0.2.0) The latest documentation is available for the current version. Click here to visit latest version.

Adds the permit method, which can be used to change an account’s ERC20 allowance (see IErc20::allowance) by presenting a message signed by the account. By not relying on IErc20::approve, the token holder account doesn’t need to send a transaction, and thus is not required to hold Ether at all.

Usage

In order to have ERC-20 Permit token, you need to use only this contract without ERC-20 as follows:

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 {
    // Add token minting feature.
    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)?)
    }
}

On this page