ERC-4626

实现了 ERC-4626 中定义的 ERC-4626 "Tokenized Vault Standard"。

此扩展允许通过标准化的 depositmintredeemburn 工作流程,铸造和销毁“份额”(使用 ERC-20 继承表示)以换取底层“资产”。此合约扩展了 ERC-20 标准。与其一起包含的任何其他扩展将影响此合约表示的“份额”代币,而不是作为独立合约的“资产”代币。

安全问题:通货膨胀攻击

要了解有关与 ERC-4626 相关的安全问题的更多信息,请查看 通货膨胀攻击 描述。

用法

为了使 ERC-4626 方法“外部化”,以便其他合约可以调用它们,您需要像下面这样为您的最终合约自行实现它们:

use openzeppelin_stylus::{
    token::erc20::{
        extensions::{
            erc4626, Erc20Metadata, Erc4626, IErc20Metadata, IErc4626,
        },
        Erc20, IErc20,
    },
    utils::introspection::erc165::IErc165,
};

#[entrypoint]
#[storage]
struct Erc4626Example {
    erc4626: Erc4626,
    erc20: Erc20,
    metadata: Erc20Metadata,
}

#[public]
#[implements(IErc4626<Error = erc4626::Error>, IErc20<Error = erc4626::Error>, IErc20Metadata, IErc165)]
impl Erc4626Example {
    #[constructor]
    fn constructor(
        &mut self,
        asset: Address,
        decimals_offset: U8,
        name: String,
        symbol: String,
    ) {
        self.erc4626.constructor(asset, decimals_offset);
        self.metadata.constructor(name, symbol);
    }
}

#[public]
impl IErc4626 for Erc4626Example {
    type Error = erc4626::Error;

    fn asset(&self) -> Address {
        self.erc4626.asset()
    }

    fn total_assets(&self) -> Result<U256, Self::Error> {
        self.erc4626.total_assets()
    }

    fn convert_to_shares(&self, assets: U256) -> Result<U256, Self::Error> {
        self.erc4626.convert_to_shares(assets, &self.erc20)
    }

    fn convert_to_assets(&self, shares: U256) -> Result<U256, Self::Error> {
        self.erc4626.convert_to_assets(shares, &self.erc20)
    }

    fn max_deposit(&self, receiver: Address) -> U256 {
        self.erc4626.max_deposit(receiver)
    }

    fn preview_deposit(&self, assets: U256) -> Result<U256, Self::Error> {
        self.erc4626.preview_deposit(assets, &self.erc20)
    }

    fn deposit(
        &mut self,
        assets: U256,
        receiver: Address,
    ) -> Result<U256, Self::Error> {
        self.erc4626.deposit(assets, receiver, &mut self.erc20)
    }

    fn max_mint(&self, receiver: Address) -> U256 {
        self.erc4626.max_mint(receiver)
    }

    fn preview_mint(&self, shares: U256) -> Result<U256, Self::Error> {
        self.erc4626.preview_mint(shares, &self.erc20)
    }

    fn mint(
        &mut self,
        shares: U256,
        receiver: Address,
    ) -> Result<U256, Self::Error> {
        self.erc4626.mint(shares, receiver, &mut self.erc20)
    }

    fn max_withdraw(&self, owner: Address) -> Result<U256, Self::Error> {
        self.erc4626.max_withdraw(owner, &self.erc20)
    }

    fn preview_withdraw(&self, assets: U256) -> Result<U256, Self::Error> {
        self.erc4626.preview_withdraw(assets, &self.erc20)
    }

    fn withdraw(
        &mut self,
        assets: U256,
        receiver: Address,
        owner: Address,
    ) -> Result<U256, Self::Error> {
        self.erc4626.withdraw(assets, receiver, owner, &mut self.erc20)
    }

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

    fn preview_redeem(&self, shares: U256) -> Result<U256, Self::Error> {
        self.erc4626.preview_redeem(shares, &self.erc20)
    }

    fn redeem(
        &mut self,
        shares: U256,
        receiver: Address,
        owner: Address,
    ) -> Result<U256, Self::Error> {
        self.erc4626.redeem(shares, receiver, owner, &mut self.erc20)
    }
}

#[public]
impl IErc20 for Erc4626Example {
    type Error = erc4626::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)?)
    }
}

#[public]
impl IErc20Metadata for Erc4626Example {
    fn name(&self) -> String {
        self.metadata.name()
    }

    fn symbol(&self) -> String {
        self.metadata.symbol()
    }

    fn decimals(&self) -> U8 {
        self.erc4626.decimals()
    }
}

#[public]
impl IErc165 for Erc4626Example {
    fn supports_interface(&self, interface_id: B32) -> bool {
        <Self as IErc4626>::interface_id() == interface_id
            || self.erc20.supports_interface(interface_id)
            || self.metadata.supports_interface(interface_id)
    }
}