VestingWallet

Vesting wallet 是一个可拥有的合约,可以接收原生货币和 ERC-20 代币,并根据归属时间表将这些资产释放给 wallet 的所有者,也称为“受益人”。

转移到此合约的任何资产都将遵循归属时间表,就像它们从一开始就被锁定一样。因此,如果归属已经开始,则发送到此合约的任何数量的代币将(至少部分地)立即可以释放。

通过将持续时间设置为 0,可以将此合约配置为类似于资产时间锁,该时间锁将代币为受益人持有到指定时间。

由于 wallet 是 Ownable,并且所有权可以转移,因此出售未归属的代币是可能的。 在智能合约中阻止这种情况是很困难的,考虑到:1) 受益人地址可能是一个反事实部署的合约,2) 在不久的将来,EOA 很可能存在迁移到合约的路径。

当将此合约与任何自动调整余额的代币(即 rebase 代币)一起使用时,请确保在归属时间表中考虑供应/余额调整,以确保归属金额与预期一致。

支持原生 ERC20 的链可能允许 vesting wallet 将底层资产作为 ERC20 和原生货币提取。例如,如果链 C 支持代币 A 并且 wallet 被存入了100 A,那么在归属期的 50% 时,受益人可以提取 50 A 作为 ERC20 和 25 A 作为原生货币(总计 75 A)。考虑禁用其中一种提款方式。

用法

为了使 VestingWallet 方法“external”,以便其他合约可以调用它们,您需要为您的最终合约自行实现它们,如下所示:

use openzeppelin_stylus::finance::vesting_wallet::{
    self, IVestingWallet, VestingWallet,
};

#[entrypoint]
#[storage]
struct VestingWalletExample {
    vesting_wallet: VestingWallet,
}

#[public]
#[implements(IVestingWallet<Error = vesting_wallet::Error>)]
impl VestingWalletExample {
    #[constructor]
    fn constructor(
        &mut self,
        beneficiary: Address,
        start_timestamp: U64,
        duration_seconds: U64,
    ) -> Result<(), vesting_wallet::Error> {
        self.vesting_wallet.constructor(
            beneficiary,
            start_timestamp,
            duration_seconds,
        )
    }

    #[receive]
    fn receive(&mut self) -> Result<(), Vec<u8>> {
        self.vesting_wallet.receive()
    }
}

#[public]
impl IVestingWallet for VestingWalletExample {
    type Error = vesting_wallet::Error;

    fn owner(&self) -> Address {
        self.vesting_wallet.owner()
    }

    fn transfer_ownership(
        &mut self,
        new_owner: Address,
    ) -> Result<(), Self::Error> {
        self.vesting_wallet.transfer_ownership(new_owner)
    }

    fn renounce_ownership(
        &mut self,
    ) -> Result<(), Self::Error> {
        self.vesting_wallet.renounce_ownership()
    }

    fn start(&self) -> U256 {
        self.vesting_wallet.start()
    }

    fn duration(&self) -> U256 {
        self.vesting_wallet.duration()
    }

    fn end(&self) -> U256 {
        self.vesting_wallet.end()
    }

    #[selector(name = "released")]
    fn released_eth(&self) -> U256 {
        self.vesting_wallet.released_eth()
    }

    #[selector(name = "released")]
    fn released_erc20(&self, token: Address) -> U256 {
        self.vesting_wallet.released_erc20(token)
    }

    #[selector(name = "releasable")]
    fn releasable_eth(&self) -> U256 {
        self.vesting_wallet.releasable_eth()
    }

    #[selector(name = "releasable")]
    fn releasable_erc20(
        &mut self,
        token: Address,
    ) -> Result<U256, Self::Error> {
        self.vesting_wallet.releasable_erc20(token)
    }

    #[selector(name = "release")]
    fn release_eth(&mut self) -> Result<(), Self::Error> {
        self.vesting_wallet.release_eth()
    }

    #[selector(name = "release")]
    fn release_erc20(
        &mut self,
        token: Address,
    ) -> Result<(), Self::Error> {
        self.vesting_wallet.release_erc20(token)
    }

    #[selector(name = "vestedAmount")]
    fn vested_amount_eth(&self, timestamp: u64) -> U256 {
        self.vesting_wallet.vested_amount_eth(timestamp)
    }

    #[selector(name = "vestedAmount")]
    fn vested_amount_erc20(
        &mut self,
        token: Address,
        timestamp: u64,
    ) -> Result<U256, Self::Error> {
        self.vesting_wallet.vested_amount_erc20(token, timestamp)
    }
}