Finance
Smart contract finance utilities and implementations
This directory includes primitives for financial systems:
VestingWallet
handles the vesting of Ether and ERC-20 tokens for a given beneficiary. Custody of multiple tokens can be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting schedule.
Contracts
import "@openzeppelin/contracts/finance/VestingWallet.sol";
A vesting wallet is an ownable contract that can receive native currency and ERC-20 tokens, and release these assets to the wallet owner, also referred to as "beneficiary", according to a vesting schedule.
Any assets transferred to this contract will follow the vesting schedule as if they were locked from the beginning. Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly) be immediately releasable.
By setting the duration to 0, one can configure this contract to behave like an asset timelock that holds tokens for a beneficiary until a specified time.
NOTE: Since the wallet is Ownable
, and ownership can be transferred, it is possible to sell unvested tokens.
Preventing this in a smart contract is difficult, considering that: 1) a beneficiary address could be a
counterfactually deployed contract, 2) there is likely to be a migration path for EOAs to become contracts in the
near future.
NOTE: When using this contract with any token whose balance is adjusted automatically (i.e. a rebase token), make sure to account the supply/balance adjustment in the vesting schedule to ensure the vested amount is as intended.
NOTE: Chains with support for native ERC20s may allow the vesting wallet to withdraw the underlying asset as both an ERC20 and as native currency. For example, if chain C supports token A and the wallet gets deposited 100 A, then at 50% of the vesting period, the beneficiary can withdraw 50 A as ERC20 and 25 A as native currency (totaling 75 A). Consider disabling one of the withdrawal methods.
Functions
Events
constructor(address beneficiary, uint64 startTimestamp, uint64 durationSeconds)
public
#Sets the beneficiary (owner), the start timestamp and the vesting duration (in seconds) of the vesting wallet.
receive()
external
#The contract should be able to receive Eth.
start() → uint256
public
#Getter for the start timestamp.
duration() → uint256
public
#Getter for the vesting duration.
end() → uint256
public
#Getter for the end timestamp.
released() → uint256
public
#Amount of eth already released
released(address token) → uint256
public
#Amount of token already released
releasable() → uint256
public
#Getter for the amount of releasable eth.
releasable(address token) → uint256
public
#Getter for the amount of releasable token
tokens. token
should be the address of an
IERC20
contract.
release()
public
#Release the native token (ether) that have already vested.
Emits a VestingWallet.EtherReleased
event.
release(address token)
public
#Release the tokens that have already vested.
Emits a VestingWallet.ERC20Released
event.
vestedAmount(uint64 timestamp) → uint256
public
#Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve.
vestedAmount(address token, uint64 timestamp) → uint256
public
#Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve.
_vestingSchedule(uint256 totalAllocation, uint64 timestamp) → uint256
internal
#Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for an asset given its total historical allocation.
EtherReleased(uint256 amount)
event
#ERC20Released(address indexed token, uint256 amount)
event
#import "@openzeppelin/contracts/finance/VestingWalletCliff.sol";
Extension of VestingWallet
that adds a cliff to the vesting schedule.
Available since v5.1.
Functions
Events
Errors
constructor(uint64 cliffSeconds)
internal
#Set the duration of the cliff, in seconds. The cliff starts vesting schedule (see VestingWallet
's
constructor) and ends cliffSeconds
later.
cliff() → uint256
public
#Getter for the cliff timestamp.
_vestingSchedule(uint256 totalAllocation, uint64 timestamp) → uint256
internal
#Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for
an asset given its total historical allocation. Returns 0 if the VestingWalletCliff.cliff
timestamp is not met.
The cliff not only makes the schedule return 0, but it also ignores every possible side
effect from calling the inherited implementation (i.e. super._vestingSchedule
). Carefully consider
this caveat if the overridden implementation of this function has any (e.g. writing to memory or reverting).
InvalidCliffDuration(uint64 cliffSeconds, uint64 durationSeconds)
error
#The specified cliff duration is larger than the vesting duration.