-
Notifications
You must be signed in to change notification settings - Fork 0
/
BalancerMinter.sol
239 lines (202 loc) · 8.93 KB
/
BalancerMinter.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.7.0;
import "@balancer-labs/v2-interfaces/contracts/liquidity-mining/IBalancerMinter.sol";
import "@balancer-labs/v2-interfaces/contracts/liquidity-mining/IBalancerTokenAdmin.sol";
import "@balancer-labs/v2-interfaces/contracts/liquidity-mining/IGaugeController.sol";
import "@balancer-labs/v2-interfaces/contracts/liquidity-mining/ILiquidityGauge.sol";
import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/ReentrancyGuard.sol";
import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/SafeMath.sol";
import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/EIP712.sol";
import "@balancer-labs/v2-solidity-utils/contracts/helpers/EOASignaturesValidator.sol";
contract BalancerMinter is IBalancerMinter, ReentrancyGuard, EOASignaturesValidator {
using SafeMath for uint256;
IERC20 private immutable _token;
IBalancerTokenAdmin private immutable _tokenAdmin;
IGaugeController private immutable _gaugeController;
// user -> gauge -> value
mapping(address => mapping(address => uint256)) private _minted;
// minter -> user -> can mint?
mapping(address => mapping(address => bool)) private _allowedMinter;
// solhint-disable-next-line var-name-mixedcase
bytes32 private constant _SET_MINTER_APPROVAL_TYPEHASH = keccak256(
"SetMinterApproval(address minter,bool approval,uint256 nonce,uint256 deadline)"
);
event MinterApprovalSet(address indexed user, address indexed minter, bool approval);
constructor(IBalancerTokenAdmin tokenAdmin, IGaugeController gaugeController) EIP712("Balancer Minter", "1") {
_token = tokenAdmin.getBalancerToken();
_tokenAdmin = tokenAdmin;
_gaugeController = gaugeController;
}
/**
* @notice Returns the address of the Balancer Governance Token
*/
function getBalancerToken() external view override returns (IERC20) {
return _token;
}
/**
* @notice Returns the address of the Balancer Token Admin contract
*/
function getBalancerTokenAdmin() external view override returns (IBalancerTokenAdmin) {
return _tokenAdmin;
}
/**
* @notice Returns the address of the Gauge Controller
*/
function getGaugeController() external view override returns (IGaugeController) {
return _gaugeController;
}
/**
* @notice Mint everything which belongs to `msg.sender` and send to them
* @param gauge `LiquidityGauge` address to get mintable amount from
*/
function mint(address gauge) external override nonReentrant returns (uint256) {
return _mintFor(gauge, msg.sender);
}
/**
* @notice Mint everything which belongs to `msg.sender` across multiple gauges
* @param gauges List of `LiquidityGauge` addresses
*/
function mintMany(address[] calldata gauges) external override nonReentrant returns (uint256) {
return _mintForMany(gauges, msg.sender);
}
/**
* @notice Mint tokens for `user`
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauge `LiquidityGauge` address to get mintable amount from
* @param user Address to mint to
*/
function mintFor(address gauge, address user) external override nonReentrant returns (uint256) {
require(_allowedMinter[msg.sender][user], "Caller not allowed to mint for user");
return _mintFor(gauge, user);
}
/**
* @notice Mint tokens for `user` across multiple gauges
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauges List of `LiquidityGauge` addresses
* @param user Address to mint to
*/
function mintManyFor(address[] calldata gauges, address user) external override nonReentrant returns (uint256) {
require(_allowedMinter[msg.sender][user], "Caller not allowed to mint for user");
return _mintForMany(gauges, user);
}
/**
* @notice The total number of tokens minted for `user` from `gauge`
*/
function minted(address user, address gauge) external view override returns (uint256) {
return _minted[user][gauge];
}
/**
* @notice Whether `minter` is approved to mint tokens for `user`
*/
function getMinterApproval(address minter, address user) external view override returns (bool) {
return _allowedMinter[minter][user];
}
/**
* @notice Set whether `minter` is approved to mint tokens on your behalf
*/
function setMinterApproval(address minter, bool approval) public override {
_setMinterApproval(minter, msg.sender, approval);
}
/**
* @notice Set whether `minter` is approved to mint tokens on behalf of `user`, who has signed a message authorizing
* them.
*/
function setMinterApprovalWithSignature(
address minter,
bool approval,
address user,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
bytes32 structHash = keccak256(
abi.encode(_SET_MINTER_APPROVAL_TYPEHASH, minter, approval, getNextNonce(user), deadline)
);
_ensureValidSignature(user, structHash, _toArraySignature(v, r, s), deadline, Errors.INVALID_SIGNATURE);
_setMinterApproval(minter, user, approval);
}
function _setMinterApproval(
address minter,
address user,
bool approval
) private {
_allowedMinter[minter][user] = approval;
emit MinterApprovalSet(user, minter, approval);
}
// Internal functions
function _mintFor(address gauge, address user) internal returns (uint256 tokensToMint) {
tokensToMint = _updateGauge(gauge, user);
if (tokensToMint > 0) {
_tokenAdmin.mint(user, tokensToMint);
}
}
function _mintForMany(address[] calldata gauges, address user) internal returns (uint256 tokensToMint) {
uint256 length = gauges.length;
for (uint256 i = 0; i < length; ++i) {
tokensToMint = tokensToMint.add(_updateGauge(gauges[i], user));
}
if (tokensToMint > 0) {
_tokenAdmin.mint(user, tokensToMint);
}
}
function _updateGauge(address gauge, address user) internal returns (uint256 tokensToMint) {
require(_gaugeController.gauge_types(gauge) >= 0, "Gauge does not exist on Controller");
ILiquidityGauge(gauge).user_checkpoint(user);
uint256 totalMint = ILiquidityGauge(gauge).integrate_fraction(user);
tokensToMint = totalMint.sub(_minted[user][gauge]);
if (tokensToMint > 0) {
_minted[user][gauge] = totalMint;
emit Minted(user, gauge, totalMint);
}
}
// The below functions are near-duplicates of functions available above.
// They are included for ABI compatibility with snake_casing as used in vyper contracts.
// solhint-disable func-name-mixedcase
/**
* @notice Whether `minter` is approved to mint tokens for `user`
*/
function allowed_to_mint_for(address minter, address user) external view override returns (bool) {
return _allowedMinter[minter][user];
}
/**
* @notice Mint everything which belongs to `msg.sender` across multiple gauges
* @dev This function is not recommended as `mintMany()` is more flexible and gas efficient
* @param gauges List of `LiquidityGauge` addresses
*/
function mint_many(address[8] calldata gauges) external override nonReentrant {
for (uint256 i = 0; i < 8; ++i) {
if (gauges[i] == address(0)) {
break;
}
_mintFor(gauges[i], msg.sender);
}
}
/**
* @notice Mint tokens for `user`
* @dev Only possible when `msg.sender` has been approved by `user` to mint on their behalf
* @param gauge `LiquidityGauge` address to get mintable amount from
* @param user Address to mint to
*/
function mint_for(address gauge, address user) external override nonReentrant {
if (_allowedMinter[msg.sender][user]) {
_mintFor(gauge, user);
}
}
/**
* @notice Toggle whether `minter` is approved to mint tokens for `user`
*/
function toggle_approve_mint(address minter) external override {
setMinterApproval(minter, !_allowedMinter[minter][msg.sender]);
}
}