/
ERC20BaseToken.sol
227 lines (205 loc) · 9.02 KB
/
ERC20BaseToken.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
//SPDX-License-Identifier: MIT
pragma solidity 0.8.2;
import "@openzeppelin/contracts-0.8/utils/Context.sol";
import "./extensions/ERC20Internal.sol";
import "../../interfaces/IERC20Extended.sol";
import "../WithSuperOperators.sol";
abstract contract ERC20BaseToken is WithSuperOperators, IERC20, IERC20Extended, ERC20Internal, Context {
string internal _name;
string internal _symbol;
address internal immutable _operator;
uint256 internal _totalSupply;
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) internal _allowances;
constructor(
string memory tokenName,
string memory tokenSymbol,
address admin,
address operator
) {
_name = tokenName;
_symbol = tokenSymbol;
_admin = admin;
_operator = operator;
}
/// @notice Transfer `amount` tokens to `to`.
/// @param to The recipient address of the tokens being transfered.
/// @param amount The number of tokens being transfered.
/// @return success Whether or not the transfer succeeded.
function transfer(address to, uint256 amount) external override returns (bool success) {
_transfer(_msgSender(), to, amount);
return true;
}
/// @notice Transfer `amount` tokens from `from` to `to`.
/// @param from The origin address of the tokens being transferred.
/// @param to The recipient address of the tokensbeing transfered.
/// @param amount The number of tokens transfered.
/// @return success Whether or not the transfer succeeded.
function transferFrom(
address from,
address to,
uint256 amount
) external override returns (bool success) {
if (_msgSender() != from && !_superOperators[_msgSender()] && _msgSender() != _operator) {
uint256 currentAllowance = _allowances[from][_msgSender()];
if (currentAllowance != ~uint256(0)) {
// save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)
require(currentAllowance >= amount, "NOT_AUTHORIZED_ALLOWANCE");
_allowances[from][_msgSender()] = currentAllowance - amount;
}
}
_transfer(from, to, amount);
return true;
}
/// @notice Burn `amount` tokens.
/// @param amount The number of tokens to burn.
function burn(uint256 amount) external override {
_burn(_msgSender(), amount);
}
/// @notice Burn `amount` tokens from `owner`.
/// @param from The address whose token to burn.
/// @param amount The number of tokens to burn.
function burnFor(address from, uint256 amount) external override {
_burn(from, amount);
}
/// @notice Approve `spender` to transfer `amount` tokens.
/// @param spender The address to be given rights to transfer.
/// @param amount The number of tokens allowed.
/// @return success Whether or not the call succeeded.
function approve(address spender, uint256 amount) external override returns (bool success) {
_approveFor(_msgSender(), spender, amount);
return true;
}
/// @notice Get the name of the token collection.
/// @return The name of the token collection.
function name() external view virtual returns (string memory) {
//added virtual
return _name;
}
/// @notice Get the symbol for the token collection.
/// @return The symbol of the token collection.
function symbol() external view virtual returns (string memory) {
//added virtual
return _symbol;
}
/// @notice Get the total number of tokens in existence.
/// @return The total number of tokens in existence.
function totalSupply() external view override returns (uint256) {
return _totalSupply;
}
/// @notice Get the balance of `owner`.
/// @param owner The address to query the balance of.
/// @return The amount owned by `owner`.
function balanceOf(address owner) external view override returns (uint256) {
return _balances[owner];
}
/// @notice Get the allowance of `spender` for `owner`'s tokens.
/// @param owner The address whose token is allowed.
/// @param spender The address allowed to transfer.
/// @return remaining The amount of token `spender` is allowed to transfer on behalf of `owner`.
function allowance(address owner, address spender) external view override returns (uint256 remaining) {
return _allowances[owner][spender];
}
/// @notice Get the number of decimals for the token collection.
/// @return The number of decimals.
function decimals() external pure virtual returns (uint8) {
return uint8(18);
}
/// @notice Approve `spender` to transfer `amount` tokens from `owner`.
/// @param owner The address whose token is allowed.
/// @param spender The address to be given rights to transfer.
/// @param amount The number of tokens allowed.
/// @return success Whether or not the call succeeded.
function approveFor(
address owner,
address spender,
uint256 amount
) public override returns (bool success) {
require(_msgSender() == owner || _superOperators[_msgSender()] || _msgSender() == _operator, "NOT_AUTHORIZED");
_approveFor(owner, spender, amount);
return true;
}
/// @notice Increase the allowance for the spender if needed
/// @param owner The address of the owner of the tokens
/// @param spender The address wanting to spend tokens
/// @param amountNeeded The amount requested to spend
/// @return success Whether or not the call succeeded.
function addAllowanceIfNeeded(
address owner,
address spender,
uint256 amountNeeded
) public returns (bool success) {
require(_msgSender() == owner || _superOperators[_msgSender()] || _msgSender() == _operator, "INVALID_SENDER");
_addAllowanceIfNeeded(owner, spender, amountNeeded);
return true;
}
/// @dev See addAllowanceIfNeeded.
function _addAllowanceIfNeeded(
address owner,
address spender,
uint256 amountNeeded /*(ERC20Internal, ERC20ExecuteExtension, ERC20BasicApproveExtension)*/
) internal virtual override {
if (amountNeeded > 0 && !isSuperOperator(spender) && spender != _operator) {
uint256 currentAllowance = _allowances[owner][spender];
if (currentAllowance < amountNeeded) {
_approveFor(owner, spender, amountNeeded);
}
}
}
/// @dev See approveFor.
function _approveFor(
address owner,
address spender,
uint256 amount /*(ERC20BasicApproveExtension, ERC20Internal)*/
) internal virtual override {
require(owner != address(0) && spender != address(0), "INVALID_OWNER_||_SPENDER");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/// @dev See transfer.
function _transfer(
address from,
address to,
uint256 amount /*(ERC20Internal, ERC20ExecuteExtension)*/
) internal virtual override {
require(to != address(0), "NOT_TO_ZEROADDRESS");
require(to != address(this), "NOT_TO_THIS");
uint256 currentBalance = _balances[from];
require(currentBalance >= amount, "INSUFFICIENT_FUNDS");
_balances[from] = currentBalance - amount;
_balances[to] += amount;
emit Transfer(from, to, amount);
}
/// @dev Mint tokens for a recipient.
/// @param to The recipient address.
/// @param amount The number of token to mint.
function _mint(address to, uint256 amount) internal {
require(to != address(0), "NOT_TO_ZEROADDRESS");
require(amount > 0, "MINT_O_TOKENS");
uint256 currentTotalSupply = _totalSupply;
uint256 newTotalSupply = currentTotalSupply + amount;
require(newTotalSupply > currentTotalSupply, "OVERFLOW");
_totalSupply = newTotalSupply;
_balances[to] += amount;
emit Transfer(address(0), to, amount);
}
/// @dev Burn tokens from an address.
/// @param from The address whose tokens to burn.
/// @param amount The number of token to burn.
function _burn(address from, uint256 amount) internal {
require(amount > 0, "BURN_O_TOKENS");
if (_msgSender() != from && !_superOperators[_msgSender()] && _msgSender() != _operator) {
uint256 currentAllowance = _allowances[from][_msgSender()];
if (currentAllowance != ~uint256(0)) {
// save gas when allowance is maximal by not reducing it (see https://github.com/ethereum/EIPs/issues/717)
require(currentAllowance >= amount, "INSUFFICIENT_ALLOWANCE");
_allowances[from][_msgSender()] = currentAllowance - amount;
}
}
uint256 currentBalance = _balances[from];
require(currentBalance >= amount, "INSUFFICIENT_FUNDS");
_balances[from] = currentBalance - amount;
_totalSupply -= amount;
emit Transfer(from, address(0), amount);
}
}