forked from catellaTech/ERC20-FOUNDRY-TEST
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathERC20.sol
279 lines (258 loc) Β· 9.62 KB
/
ERC20.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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./IERC20.sol";
// Smart Contract de los tokens ERC20
contract ERC20 is IERC20 {
// Estructuras de datos
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// Variables
uint256 private _totalSupply;
string private _name;
string private _symbol;
/* Establece el valor del nombre y el simbolo del token.
El valor por defecto de {decimaes} es 18. Para seleccionar un valor diferente para
{decimals} debemos remplazarlo. */
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
// Devuelve el nombre del token.
function name() public view virtual returns (string memory) {
return _name;
}
// Devuelve el simbolo del token, normalmente una version mas corta del nombre.
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/* Devuelve el numero de decimales utilizados para obtener su representacion de usuario.
Por ejemplo, si `decimals` es igual a `2`, un saldo de `505` tokens deberia
mostrarse al usuario como `5.05` (`505 / 10 ** 2`).
Los tokens suelen optar por un valor de 18, imitando la relacion entre
Ether y Wei. Este es el valor que utiliza {ERC20}, a menos que esta funcion sea
sea anulada. */
function decimals() public view virtual returns (uint8) {
return 18;
}
// Ver: {IERC20-totalSupply}.
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
// Ver: {IERC20-balanceOf}.
function balanceOf(address account)
public
view
virtual
override
returns (uint256)
{
return _balances[account];
}
/* Ver: {IERC20-transfer}.
Requisitos:
- `to` no puede ser la direccion cero.
- la persona que ejecuta debe tener un saldo de al menos `amount`. */
function transfer(address to, uint256 amount)
public
virtual
override
returns (bool)
{
address owner = msg.sender;
_transfer(owner, to, amount);
return true;
}
// Ver: {IERC20-allowance}.
function allowance(address owner, address spender)
public
view
virtual
override
returns (uint256)
{
return _allowances[owner][spender];
}
/* Ver: {IERC20-approve}.
Requisitos:
- `spender` no puede ser una direccion cero. */
function approve(address spender, uint256 amount)
public
virtual
override
returns (bool)
{
address owner = msg.sender;
_approve(owner, spender, amount);
return true;
}
/* Ver: {IERC20-transferFrom}.
Emite un evento de {Approval} indicando el permiso actualizado. Esto no es
requerido por la EIP.
Requisitos:
- `from` y `to` no pueden ser direcciones cero.
- `from` debe tener un saldo de al menos `amount`.
- la persona que ejecuta debe tener una asignacion para los tokens de `from` de al menos `amount`. */
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = msg.sender;
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/* Aumenta atomicamente la asignacion concedida al `spender` por el usuario que ejecuta.
Emite un evento de {Approval} indicando el permiso actualizado.
Requisitos:
- `spender` no puede ser una direccion cero. */
function increaseAllowance(address spender, uint256 addedValue)
public
virtual
returns (bool)
{
address owner = msg.sender;
_approve(owner, spender, _allowances[owner][spender] + addedValue);
return true;
}
/* Disminuye atomicamente la asignacion concedida al `spender` por el usuario que ejecuta.
Emite un evento de {Approval} indicando el permiso actualizado.
Requisitos:
- `spender` no puede ser la direccion cero.
- `spender` debe tener una asignacion para el usuario que ejecuta de al menos `subtractedValue`. */
function decreaseAllowance(address spender, uint256 subtractedValue)
public
virtual
returns (bool)
{
address owner = msg.sender;
uint256 currentAllowance = _allowances[owner][spender];
require(
currentAllowance >= subtractedValue,
"ERC20: decreased allowance below zero"
);
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/* Mueve `amount` de tokens del `sender` al `recipient`.
Esta funcion interna es equivalente a {transfer}, y puede utilizarse para
por ejemplo, implementar fees (tarifas) automaticas de tokens, etc.
Emite un evento {Transfer}.
Requisitos:
- `from` y `to` no pueden ser direcciones cero.
- `from` debe tener un saldo de al menos `amount`. */
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(
fromBalance >= amount,
"ERC20: transfer amount exceeds balance"
);
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/* Crea tokens de `amount` y las asigna a `account`, aumentando
el suministro total.
Emite un evento {Transfer} con "from" como direccion cero.
Requisitos:
- `account` no puede ser la direccion cero. */
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/* Destruye la `amount` de tokens de `account`, reduciendo el
suministro total.
Emite un evento {Transfer} con "to" como direccion cero.
Requisitos:
- `account` no puede ser la direccion cero.
- `account` debe tener al menos tokens de `amount`. */
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/* Establece la `amount` como la asignacion de `spender` sobre los tokens del `owner`.
Emite un evento de {Approval}.
Requisitos:
- `owner` no puede ser la direccion cero.
- `spender` no puede ser la direccion cero. */
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/* Gasta `amount` de la asignacion del `owner` hacia el `spender`.
- No actualiza el importe de la asignacion en caso de asignacion infinita.
- Revertir si no hay suficiente asignacion disponible.
Puede emitir un evento de {Approval}. */
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(
currentAllowance >= amount,
"ERC20: insufficient allowance"
);
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/* Hook que se llama antes de cualquier transferencia de tokens. Esto incluye
"minting" y "burning".
Condiciones de llamada:
- cuando `from` y `to` son ambos distintos de cero, `amount` de los tokens de `from`
se transferira a `to` .
- cuando `from` es cero, se acuΓ±aran tokens `amount` para `to` .
- cuando `to` sea cero, se quemara la `amount` de tokens de `from`.
- `from` y `to` nunca son ambos cero. */
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/* Hook que se llama despues de cualquier transferencia de tokens. Esto incluye
"minting" y "burning".
Condiciones de llamada:
- cuando `from` y `to` son ambos distintos de cero, `amount` de los tokens de
`from` ha sido transferido a `to` .
- cuando `from` es cero, se han minteado tokens `amount` para `to`.
- cuando `to` es cero, se han quemado la `amount` de tokens de `from`.
- `from` y `to` nunca son ambos cero. */
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}