-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathConfidentialVestingWallet.sol
124 lines (106 loc) · 4.83 KB
/
ConfidentialVestingWallet.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.24;
import "fhevm/lib/TFHE.sol";
import { IConfidentialERC20 } from "../token/ERC20/IConfidentialERC20.sol";
/**
* @title ConfidentialVestingWallet.
* @notice This contract offers a simple vesting wallet for ConfidentialERC20 tokens.
* This is based on the VestingWallet.sol contract written by OpenZeppelin.
* see: openzeppelin/openzeppelin-contracts/blob/master/contracts/finance/VestingWallet.sol
* @dev Default implementation is a linear vesting curve.
* To use with the native asset, it is necessary to wrap the native asset to a ConfidentialERC20-like token.
*/
abstract contract ConfidentialVestingWallet {
/// @notice Emitted when tokens are released to the beneficiary address.
/// @param token Address of the token being released.
event ConfidentialERC20Released(address indexed token);
/// @notice Beneficiary address.
address public immutable BENEFICIARY;
/// @notice Duration (in seconds).
uint128 public immutable DURATION;
/// @notice End timestamp.
uint128 public immutable END_TIMESTAMP;
/// @notice Start timestamp.
uint128 public immutable START_TIMESTAMP;
/// @notice Constant for zero using TFHE.
/// @dev Since it is expensive to compute 0, it is stored instead.
euint64 internal immutable _EUINT64_ZERO;
/// @notice Total encrypted amount released (to the beneficiary).
mapping(address token => euint64 amountReleased) internal _amountReleased;
/**
* @param beneficiary_ Beneficiary address.
* @param startTimestamp_ Start timestamp.
* @param duration_ Duration (in seconds).
*/
constructor(address beneficiary_, uint128 startTimestamp_, uint128 duration_) {
START_TIMESTAMP = startTimestamp_;
DURATION = duration_;
END_TIMESTAMP = startTimestamp_ + duration_;
BENEFICIARY = beneficiary_;
/// @dev Store this constant variable in the storage.
_EUINT64_ZERO = TFHE.asEuint64(0);
TFHE.allow(_EUINT64_ZERO, beneficiary_);
TFHE.allowThis(_EUINT64_ZERO);
}
/**
* @notice Release the tokens that have already vested.
* @dev Anyone can call this function but the beneficiary receives the tokens.
*/
function release(address token) public virtual {
euint64 amount = _releasable(token);
euint64 amountReleased = TFHE.add(_amountReleased[token], amount);
_amountReleased[token] = amountReleased;
TFHE.allow(amountReleased, BENEFICIARY);
TFHE.allowThis(amountReleased);
TFHE.allowTransient(amount, token);
IConfidentialERC20(token).transfer(BENEFICIARY, amount);
emit ConfidentialERC20Released(token);
}
/**
* @notice Return the encrypted amount of total tokens released.
* @dev It is only reencryptable by the owner.
* @return amountReleased Total amount of tokens released.
*/
function released(address token) public view virtual returns (euint64 amountReleased) {
return _amountReleased[token];
}
/**
* @notice Calculate the amount of tokens that can be released.
* @return releasableAmount Releasable amount.
*/
function _releasable(address token) internal virtual returns (euint64 releasableAmount) {
return TFHE.sub(_vestedAmount(token, uint128(block.timestamp)), released(token));
}
/**
* @notice Calculate the amount of tokens that has already vested.
* @param timestamp Current timestamp.
* @return vestedAmount Vested amount.
*/
function _vestedAmount(address token, uint128 timestamp) internal virtual returns (euint64 vestedAmount) {
return
_vestingSchedule(TFHE.add(IConfidentialERC20(token).balanceOf(address(this)), released(token)), timestamp);
}
/**
* @notice Return the vested amount based on a linear vesting schedule.
* @dev It must be overriden for non-linear schedules.
* @param totalAllocation Total allocation that is vested.
* @param timestamp Current timestamp.
* @return vestedAmount Vested amount.
*/
function _vestingSchedule(
euint64 totalAllocation,
uint128 timestamp
) internal virtual returns (euint64 vestedAmount) {
if (timestamp < START_TIMESTAMP) {
return _EUINT64_ZERO;
} else if (timestamp >= END_TIMESTAMP) {
return totalAllocation;
} else {
/// @dev It casts to euint128 to prevent overflow with the multiplication.
return
TFHE.asEuint64(
TFHE.div(TFHE.mul(TFHE.asEuint128(totalAllocation), timestamp - START_TIMESTAMP), DURATION)
);
}
}
}