| 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 |
14×
14×
14×
14×
14×
14×
14×
14×
14×
14×
14×
14×
14×
96×
96×
96×
96×
96×
96×
| // SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.3;
import "@openzeppelin/contracts-upgradeable/token/ERC20/presets/ERC20PresetMinterPauserUpgradeable.sol";
import "./interfaces/IFloatToken.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
/**
@title FloatToken
@notice The Float Token is the governance token for the Float Capital protocol
*/
contract FloatToken is
IFloatToken,
Initializable,
ERC20Upgradeable,
ERC20BurnableUpgradeable,
PausableUpgradeable,
AccessControlUpgradeable,
ERC20PermitUpgradeable,
ERC20VotesUpgradeable,
UUPSUpgradeable
{
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
/**
@notice Initialize the Float Token with relevant
@dev This function is called `initialize` to differentiate it from `initialize(string,string)` in the parent contract which should NOT be called to initialize this contract.
@param name The name of the Float governance token
@param symbol The ticker representing the token
@param stakerAddress The staker contract that controls minting of the token
*/
function initialize(
string calldata name,
string calldata symbol,
address stakerAddress
) external initializer {
__ERC20_init(name, symbol);
__ERC20Burnable_init();
__Pausable_init();
__AccessControl_init();
__ERC20Permit_init(name);
__UUPSUpgradeable_init();
renounceRole(DEFAULT_ADMIN_ROLE, msg.sender);
renounceRole(MINTER_ROLE, msg.sender);
_setupRole(DEFAULT_ADMIN_ROLE, stakerAddress);
_setupRole(MINTER_ROLE, stakerAddress);
_setupRole(PAUSER_ROLE, msg.sender);
_setupRole(UPGRADER_ROLE, msg.sender);
// Token starts as paused
_pause();
}
/*╔═══════════════════════════════════════════════════════════════════╗
║ FUNCTIONS INHERITED BY ERC20PresetMinterPauserUpgradeable ║
╚═══════════════════════════════════════════════════════════════════╝*/
/**
@notice Mints an amount of Float tokens for an address.
@dev Can only be called by addresses with a MINTER_ROLE.
This should correspond to the Staker contract.
@param to The address for which to mint the tokens for.
@param amount Amount of synthetic tokens to mint in wei.
*/
function mint(address to, uint256 amount) external override(IFloatToken) onlyRole(MINTER_ROLE) {
_mint(to, amount);
}
/**
@notice modify token functionality so that a pausing this token doesn't affect minting
@dev Pause functionality in the open zeppelin ERC20PresetMinterPauserUpgradeable comes from the below function.
We override it to exclude anyone with the minter role (ie the Staker contract)
@param from address tokens are being sent from
@param to address tokens are being sent to
@param amount amount of tokens being sent
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual override {
Erequire(!paused() || hasRole(MINTER_ROLE, _msgSender()), "Paused and not minter");
super._beforeTokenTransfer(from, to, amount);
}
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
function _authorizeUpgrade(address newImplementation) internal override onlyRole(UPGRADER_ROLE) {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._afterTokenTransfer(from, to, amount);
}
function _mint(address to, uint256 amount)
internal
override(ERC20Upgradeable, ERC20VotesUpgradeable)
{
super._mint(to, amount);
}
function _burn(address account, uint256 amount)
internal
override(ERC20Upgradeable, ERC20VotesUpgradeable)
{
super._burn(account, amount);
}
function totalSupply()
public
view
virtual
override(ERC20Upgradeable, IFloatToken)
returns (uint256)
{
return ERC20Upgradeable.totalSupply();
}
function transfer(address recipient, uint256 amount)
public
virtual
override(ERC20Upgradeable, IFloatToken)
returns (bool)
{
return ERC20Upgradeable.transfer(recipient, amount);
}
function burnFrom(address account, uint256 amount)
public
virtual
override(ERC20BurnableUpgradeable, IFloatToken)
{
ERC20BurnableUpgradeable.burnFrom(account, amount);
}
}
|