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