Vesting
Ether sent to the contract vests linearly between start and start + duration. Anyone can call release, and the funds always go to the beneficiary.
vesting.lithe
(* Ether vests linearly to a beneficiary between `start` and `start + duration`.
Anyone can trigger a release; the funds only ever go to the beneficiary. *)
import "std/address";
import "std/evm";
error AlreadyInitialized;
event Released of record {
amount : wei;
}
storage is record {
beneficiary : address;
start : timestamp;
duration : uint;
released : wei;
}
external function init(const beneficiary : address; const start : timestamp; const duration : uint)
raises AlreadyInitialized
is {
assert(storage.beneficiary = Address.zero, AlreadyInitialized);
storage.beneficiary := beneficiary;
storage.start := start;
storage.duration := duration;
}
external payable function fund() is {
skip
}
view function vestedAt(const time : timestamp) : wei is {
const total : wei := Evm.balance(Evm.self()) + storage.released;
var vested : wei := 0wei;
if time >= storage.start + storage.duration then {
vested := total;
} else if time > storage.start then {
vested := wei(uint(total) * (time - storage.start) / storage.duration);
}
} with vested
external view function releasable() : wei is
vestedAt(Evm.blockTimestamp()) - storage.released
external nonreentrant function release() is {
const amount : wei := vestedAt(Evm.blockTimestamp()) - storage.released;
storage.released := storage.released + amount;
emit Released { amount = amount; };
defer Evm.transfer(storage.beneficiary, amount);
}
