-
Notifications
You must be signed in to change notification settings - Fork 2
/
ManageableVault.sol
175 lines (151 loc) · 5.51 KB
/
ManageableVault.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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import {IERC20Upgradeable as IERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IERC20MetadataUpgradeable as IERC20Metadata} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import {SafeERC20Upgradeable as SafeERC20} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {EnumerableSetUpgradeable as EnumerableSet} from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
import "../interfaces/IManageableVault.sol";
import "../interfaces/IMTbill.sol";
import "../interfaces/IDataFeed.sol";
import "../access/Greenlistable.sol";
import "../libraries/DecimalsCorrectionLibrary.sol";
import "../access/Pausable.sol";
/**
* @title ManageableVault
* @author RedDuck Software
* @notice Contract with base Vault methods
*/
abstract contract ManageableVault is Greenlistable, Pausable, IManageableVault {
using EnumerableSet for EnumerableSet.AddressSet;
using DecimalsCorrectionLibrary for uint256;
using SafeERC20 for IERC20;
/**
* @notice address that represents off-chain USD bank transfer
*/
address public constant MANUAL_FULLFILMENT_TOKEN = address(0x0);
/**
* @notice 100 percent with base 100
* @dev for example, 10% will be (10 * 100)%
*/
uint256 public constant ONE_HUNDRED_PERCENT = 100 * 100;
/**
* @notice mTBILL token
*/
IMTbill public mTBILL;
/**
* @notice address to which USD and mTokens will be sent
*/
address public tokensReceiver;
/**
* @dev tokens that can be used as USD representation
*/
EnumerableSet.AddressSet internal _paymentTokens;
/**
* @dev checks that msg.sender do have a vaultRole() role
*/
modifier onlyVaultAdmin() {
_onlyRole(vaultRole(), msg.sender);
_;
}
/**
* @dev upgradeable pattern contract`s initializer
* @param _ac address of MidasAccessControll contract
* @param _mTBILL address of mTBILL token
* @param _tokensReceiver address to which USD and mTokens will be sent
*/
// solhint-disable func-name-mixedcase
function __ManageableVault_init(
address _ac,
address _mTBILL,
address _tokensReceiver
) internal onlyInitializing {
require(_mTBILL != address(0), "zero address");
require(_tokensReceiver != address(0), "zero address");
require(_tokensReceiver != address(this), "invalid address");
mTBILL = IMTbill(_mTBILL);
__Greenlistable_init(_ac);
__Pausable_init(_ac);
tokensReceiver = _tokensReceiver;
}
/**
* @notice withdraws `amount` of a given `token` from the contract.
* can be called only from permissioned actor.
* @param token token address
* @param amount token amount
* @param withdrawTo withdraw destination address
*/
function withdrawToken(
address token,
uint256 amount,
address withdrawTo
) external onlyVaultAdmin {
IERC20(token).safeTransfer(withdrawTo, amount);
emit WithdrawToken(msg.sender, token, withdrawTo, amount);
}
/**
* @inheritdoc IManageableVault
* @dev reverts if token is already added
*/
function addPaymentToken(address token) external onlyVaultAdmin {
require(_paymentTokens.add(token), "MV: already added");
emit AddPaymentToken(token, msg.sender);
}
/**
* @inheritdoc IManageableVault
* @dev reverts if token is not presented
*/
function removePaymentToken(address token) external onlyVaultAdmin {
require(_paymentTokens.remove(token), "MV: not exists");
emit RemovePaymentToken(token, msg.sender);
}
/**
* @notice returns array of stablecoins supported by the vault
* can be called only from permissioned actor.
* @return paymentTokens array of payment tokens
*/
function getPaymentTokens() external view returns (address[] memory) {
return _paymentTokens.values();
}
/**
* @notice AC role of vault administrator
* @return role bytes32 role
*/
function vaultRole() public view virtual returns (bytes32);
/**
* @notice AC role of vault`s pauser
* @return role bytes32 role
*/
function pauseAdminRole() public view override returns (bytes32) {
return vaultRole();
}
/**
* @dev do safeTransferFrom on a given token
* and converts `amount` from base18
* to amount with a correct precision. Sends tokens
* from `msg.sender` to `tokensReceiver`
* @param token address of token
* @param amount amount of `token` to transfer from `user`
*/
function _tokenTransferFromUser(address token, uint256 amount) internal {
IERC20(token).safeTransferFrom(
msg.sender,
tokensReceiver,
amount.convertFromBase18(_tokenDecimals(token))
);
}
/**
* @dev retreives decimals of a given `token`
* @param token address of token
* @return decimals decinmals value of a given `token`
*/
function _tokenDecimals(address token) internal view returns (uint8) {
return IERC20Metadata(token).decimals();
}
/**
* @dev checks that `token` is presented in `_paymentTokens`
* @param token address of token
*/
function _requireTokenExists(address token) internal view virtual {
require(_paymentTokens.contains(token), "MV: token not exists");
}
}