ERC777.sol 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.0;
  3. import "./IERC777.sol";
  4. import "./IERC777Recipient.sol";
  5. import "./IERC777Sender.sol";
  6. import "../ERC20/IERC20.sol";
  7. import "../../utils/Address.sol";
  8. import "../../utils/Context.sol";
  9. import "../../utils/introspection/IERC1820Registry.sol";
  10. /**
  11. * @dev Implementation of the {IERC777} interface.
  12. *
  13. * This implementation is agnostic to the way tokens are created. This means
  14. * that a supply mechanism has to be added in a derived contract using {_mint}.
  15. *
  16. * Support for ERC20 is included in this contract, as specified by the EIP: both
  17. * the ERC777 and ERC20 interfaces can be safely used when interacting with it.
  18. * Both {IERC777-Sent} and {IERC20-Transfer} events are emitted on token
  19. * movements.
  20. *
  21. * Additionally, the {IERC777-granularity} value is hard-coded to `1`, meaning that there
  22. * are no special restrictions in the amount of tokens that created, moved, or
  23. * destroyed. This makes integration with ERC20 applications seamless.
  24. */
  25. contract ERC777 is Context, IERC777, IERC20 {
  26. using Address for address;
  27. IERC1820Registry internal constant _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);
  28. mapping(address => uint256) private _balances;
  29. uint256 private _totalSupply;
  30. string private _name;
  31. string private _symbol;
  32. bytes32 private constant _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender");
  33. bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient");
  34. // This isn't ever read from - it's only used to respond to the defaultOperators query.
  35. address[] private _defaultOperatorsArray;
  36. // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).
  37. mapping(address => bool) private _defaultOperators;
  38. // For each account, a mapping of its operators and revoked default operators.
  39. mapping(address => mapping(address => bool)) private _operators;
  40. mapping(address => mapping(address => bool)) private _revokedDefaultOperators;
  41. // ERC20-allowances
  42. mapping(address => mapping(address => uint256)) private _allowances;
  43. /**
  44. * @dev `defaultOperators` may be an empty array.
  45. */
  46. constructor(
  47. string memory name_,
  48. string memory symbol_,
  49. address[] memory defaultOperators_
  50. ) {
  51. _name = name_;
  52. _symbol = symbol_;
  53. _defaultOperatorsArray = defaultOperators_;
  54. for (uint256 i = 0; i < defaultOperators_.length; i++) {
  55. _defaultOperators[defaultOperators_[i]] = true;
  56. }
  57. // register interfaces
  58. _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this));
  59. _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this));
  60. }
  61. /**
  62. * @dev See {IERC777-name}.
  63. */
  64. function name() public view virtual override returns (string memory) {
  65. return _name;
  66. }
  67. /**
  68. * @dev See {IERC777-symbol}.
  69. */
  70. function symbol() public view virtual override returns (string memory) {
  71. return _symbol;
  72. }
  73. /**
  74. * @dev See {ERC20-decimals}.
  75. *
  76. * Always returns 18, as per the
  77. * [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility).
  78. */
  79. function decimals() public pure virtual returns (uint8) {
  80. return 18;
  81. }
  82. /**
  83. * @dev See {IERC777-granularity}.
  84. *
  85. * This implementation always returns `1`.
  86. */
  87. function granularity() public view virtual override returns (uint256) {
  88. return 1;
  89. }
  90. /**
  91. * @dev See {IERC777-totalSupply}.
  92. */
  93. function totalSupply() public view virtual override(IERC20, IERC777) returns (uint256) {
  94. return _totalSupply;
  95. }
  96. /**
  97. * @dev Returns the amount of tokens owned by an account (`tokenHolder`).
  98. */
  99. function balanceOf(address tokenHolder) public view virtual override(IERC20, IERC777) returns (uint256) {
  100. return _balances[tokenHolder];
  101. }
  102. /**
  103. * @dev See {IERC777-send}.
  104. *
  105. * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
  106. */
  107. function send(
  108. address recipient,
  109. uint256 amount,
  110. bytes memory data
  111. ) public virtual override {
  112. _send(_msgSender(), recipient, amount, data, "", true);
  113. }
  114. /**
  115. * @dev See {IERC20-transfer}.
  116. *
  117. * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}
  118. * interface if it is a contract.
  119. *
  120. * Also emits a {Sent} event.
  121. */
  122. function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
  123. require(recipient != address(0), "ERC777: transfer to the zero address");
  124. address from = _msgSender();
  125. _callTokensToSend(from, from, recipient, amount, "", "");
  126. _move(from, from, recipient, amount, "", "");
  127. _callTokensReceived(from, from, recipient, amount, "", "", false);
  128. return true;
  129. }
  130. /**
  131. * @dev See {IERC777-burn}.
  132. *
  133. * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
  134. */
  135. function burn(uint256 amount, bytes memory data) public virtual override {
  136. _burn(_msgSender(), amount, data, "");
  137. }
  138. /**
  139. * @dev See {IERC777-isOperatorFor}.
  140. */
  141. function isOperatorFor(address operator, address tokenHolder) public view virtual override returns (bool) {
  142. return
  143. operator == tokenHolder ||
  144. (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||
  145. _operators[tokenHolder][operator];
  146. }
  147. /**
  148. * @dev See {IERC777-authorizeOperator}.
  149. */
  150. function authorizeOperator(address operator) public virtual override {
  151. require(_msgSender() != operator, "ERC777: authorizing self as operator");
  152. if (_defaultOperators[operator]) {
  153. delete _revokedDefaultOperators[_msgSender()][operator];
  154. } else {
  155. _operators[_msgSender()][operator] = true;
  156. }
  157. emit AuthorizedOperator(operator, _msgSender());
  158. }
  159. /**
  160. * @dev See {IERC777-revokeOperator}.
  161. */
  162. function revokeOperator(address operator) public virtual override {
  163. require(operator != _msgSender(), "ERC777: revoking self as operator");
  164. if (_defaultOperators[operator]) {
  165. _revokedDefaultOperators[_msgSender()][operator] = true;
  166. } else {
  167. delete _operators[_msgSender()][operator];
  168. }
  169. emit RevokedOperator(operator, _msgSender());
  170. }
  171. /**
  172. * @dev See {IERC777-defaultOperators}.
  173. */
  174. function defaultOperators() public view virtual override returns (address[] memory) {
  175. return _defaultOperatorsArray;
  176. }
  177. /**
  178. * @dev See {IERC777-operatorSend}.
  179. *
  180. * Emits {Sent} and {IERC20-Transfer} events.
  181. */
  182. function operatorSend(
  183. address sender,
  184. address recipient,
  185. uint256 amount,
  186. bytes memory data,
  187. bytes memory operatorData
  188. ) public virtual override {
  189. require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder");
  190. _send(sender, recipient, amount, data, operatorData, true);
  191. }
  192. /**
  193. * @dev See {IERC777-operatorBurn}.
  194. *
  195. * Emits {Burned} and {IERC20-Transfer} events.
  196. */
  197. function operatorBurn(
  198. address account,
  199. uint256 amount,
  200. bytes memory data,
  201. bytes memory operatorData
  202. ) public virtual override {
  203. require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder");
  204. _burn(account, amount, data, operatorData);
  205. }
  206. /**
  207. * @dev See {IERC20-allowance}.
  208. *
  209. * Note that operator and allowance concepts are orthogonal: operators may
  210. * not have allowance, and accounts with allowance may not be operators
  211. * themselves.
  212. */
  213. function allowance(address holder, address spender) public view virtual override returns (uint256) {
  214. return _allowances[holder][spender];
  215. }
  216. /**
  217. * @dev See {IERC20-approve}.
  218. *
  219. * Note that accounts cannot have allowance issued by their operators.
  220. */
  221. function approve(address spender, uint256 value) public virtual override returns (bool) {
  222. address holder = _msgSender();
  223. _approve(holder, spender, value);
  224. return true;
  225. }
  226. /**
  227. * @dev See {IERC20-transferFrom}.
  228. *
  229. * Note that operator and allowance concepts are orthogonal: operators cannot
  230. * call `transferFrom` (unless they have allowance), and accounts with
  231. * allowance cannot call `operatorSend` (unless they are operators).
  232. *
  233. * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.
  234. */
  235. function transferFrom(
  236. address holder,
  237. address recipient,
  238. uint256 amount
  239. ) public virtual override returns (bool) {
  240. require(recipient != address(0), "ERC777: transfer to the zero address");
  241. require(holder != address(0), "ERC777: transfer from the zero address");
  242. address spender = _msgSender();
  243. _callTokensToSend(spender, holder, recipient, amount, "", "");
  244. _move(spender, holder, recipient, amount, "", "");
  245. uint256 currentAllowance = _allowances[holder][spender];
  246. require(currentAllowance >= amount, "ERC777: transfer amount exceeds allowance");
  247. _approve(holder, spender, currentAllowance - amount);
  248. _callTokensReceived(spender, holder, recipient, amount, "", "", false);
  249. return true;
  250. }
  251. /**
  252. * @dev Creates `amount` tokens and assigns them to `account`, increasing
  253. * the total supply.
  254. *
  255. * If a send hook is registered for `account`, the corresponding function
  256. * will be called with `operator`, `data` and `operatorData`.
  257. *
  258. * See {IERC777Sender} and {IERC777Recipient}.
  259. *
  260. * Emits {Minted} and {IERC20-Transfer} events.
  261. *
  262. * Requirements
  263. *
  264. * - `account` cannot be the zero address.
  265. * - if `account` is a contract, it must implement the {IERC777Recipient}
  266. * interface.
  267. */
  268. function _mint(
  269. address account,
  270. uint256 amount,
  271. bytes memory userData,
  272. bytes memory operatorData
  273. ) internal virtual {
  274. _mint(account, amount, userData, operatorData, true);
  275. }
  276. /**
  277. * @dev Creates `amount` tokens and assigns them to `account`, increasing
  278. * the total supply.
  279. *
  280. * If `requireReceptionAck` is set to true, and if a send hook is
  281. * registered for `account`, the corresponding function will be called with
  282. * `operator`, `data` and `operatorData`.
  283. *
  284. * See {IERC777Sender} and {IERC777Recipient}.
  285. *
  286. * Emits {Minted} and {IERC20-Transfer} events.
  287. *
  288. * Requirements
  289. *
  290. * - `account` cannot be the zero address.
  291. * - if `account` is a contract, it must implement the {IERC777Recipient}
  292. * interface.
  293. */
  294. function _mint(
  295. address account,
  296. uint256 amount,
  297. bytes memory userData,
  298. bytes memory operatorData,
  299. bool requireReceptionAck
  300. ) internal virtual {
  301. require(account != address(0), "ERC777: mint to the zero address");
  302. address operator = _msgSender();
  303. _beforeTokenTransfer(operator, address(0), account, amount);
  304. // Update state variables
  305. _totalSupply += amount;
  306. _balances[account] += amount;
  307. _callTokensReceived(operator, address(0), account, amount, userData, operatorData, requireReceptionAck);
  308. emit Minted(operator, account, amount, userData, operatorData);
  309. emit Transfer(address(0), account, amount);
  310. }
  311. /**
  312. * @dev Send tokens
  313. * @param from address token holder address
  314. * @param to address recipient address
  315. * @param amount uint256 amount of tokens to transfer
  316. * @param userData bytes extra information provided by the token holder (if any)
  317. * @param operatorData bytes extra information provided by the operator (if any)
  318. * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
  319. */
  320. function _send(
  321. address from,
  322. address to,
  323. uint256 amount,
  324. bytes memory userData,
  325. bytes memory operatorData,
  326. bool requireReceptionAck
  327. ) internal virtual {
  328. require(from != address(0), "ERC777: send from the zero address");
  329. require(to != address(0), "ERC777: send to the zero address");
  330. address operator = _msgSender();
  331. _callTokensToSend(operator, from, to, amount, userData, operatorData);
  332. _move(operator, from, to, amount, userData, operatorData);
  333. _callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);
  334. }
  335. /**
  336. * @dev Burn tokens
  337. * @param from address token holder address
  338. * @param amount uint256 amount of tokens to burn
  339. * @param data bytes extra information provided by the token holder
  340. * @param operatorData bytes extra information provided by the operator (if any)
  341. */
  342. function _burn(
  343. address from,
  344. uint256 amount,
  345. bytes memory data,
  346. bytes memory operatorData
  347. ) internal virtual {
  348. require(from != address(0), "ERC777: burn from the zero address");
  349. address operator = _msgSender();
  350. _callTokensToSend(operator, from, address(0), amount, data, operatorData);
  351. _beforeTokenTransfer(operator, from, address(0), amount);
  352. // Update state variables
  353. uint256 fromBalance = _balances[from];
  354. require(fromBalance >= amount, "ERC777: burn amount exceeds balance");
  355. unchecked {
  356. _balances[from] = fromBalance - amount;
  357. }
  358. _totalSupply -= amount;
  359. emit Burned(operator, from, amount, data, operatorData);
  360. emit Transfer(from, address(0), amount);
  361. }
  362. function _move(
  363. address operator,
  364. address from,
  365. address to,
  366. uint256 amount,
  367. bytes memory userData,
  368. bytes memory operatorData
  369. ) private {
  370. _beforeTokenTransfer(operator, from, to, amount);
  371. uint256 fromBalance = _balances[from];
  372. require(fromBalance >= amount, "ERC777: transfer amount exceeds balance");
  373. unchecked {
  374. _balances[from] = fromBalance - amount;
  375. }
  376. _balances[to] += amount;
  377. emit Sent(operator, from, to, amount, userData, operatorData);
  378. emit Transfer(from, to, amount);
  379. }
  380. /**
  381. * @dev See {ERC20-_approve}.
  382. *
  383. * Note that accounts cannot have allowance issued by their operators.
  384. */
  385. function _approve(
  386. address holder,
  387. address spender,
  388. uint256 value
  389. ) internal {
  390. require(holder != address(0), "ERC777: approve from the zero address");
  391. require(spender != address(0), "ERC777: approve to the zero address");
  392. _allowances[holder][spender] = value;
  393. emit Approval(holder, spender, value);
  394. }
  395. /**
  396. * @dev Call from.tokensToSend() if the interface is registered
  397. * @param operator address operator requesting the transfer
  398. * @param from address token holder address
  399. * @param to address recipient address
  400. * @param amount uint256 amount of tokens to transfer
  401. * @param userData bytes extra information provided by the token holder (if any)
  402. * @param operatorData bytes extra information provided by the operator (if any)
  403. */
  404. function _callTokensToSend(
  405. address operator,
  406. address from,
  407. address to,
  408. uint256 amount,
  409. bytes memory userData,
  410. bytes memory operatorData
  411. ) private {
  412. address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(from, _TOKENS_SENDER_INTERFACE_HASH);
  413. if (implementer != address(0)) {
  414. IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData);
  415. }
  416. }
  417. /**
  418. * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but
  419. * tokensReceived() was not registered for the recipient
  420. * @param operator address operator requesting the transfer
  421. * @param from address token holder address
  422. * @param to address recipient address
  423. * @param amount uint256 amount of tokens to transfer
  424. * @param userData bytes extra information provided by the token holder (if any)
  425. * @param operatorData bytes extra information provided by the operator (if any)
  426. * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient
  427. */
  428. function _callTokensReceived(
  429. address operator,
  430. address from,
  431. address to,
  432. uint256 amount,
  433. bytes memory userData,
  434. bytes memory operatorData,
  435. bool requireReceptionAck
  436. ) private {
  437. address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(to, _TOKENS_RECIPIENT_INTERFACE_HASH);
  438. if (implementer != address(0)) {
  439. IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData);
  440. } else if (requireReceptionAck) {
  441. require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient");
  442. }
  443. }
  444. /**
  445. * @dev Hook that is called before any token transfer. This includes
  446. * calls to {send}, {transfer}, {operatorSend}, minting and burning.
  447. *
  448. * Calling conditions:
  449. *
  450. * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
  451. * will be to transferred to `to`.
  452. * - when `from` is zero, `amount` tokens will be minted for `to`.
  453. * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
  454. * - `from` and `to` are never both zero.
  455. *
  456. * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
  457. */
  458. function _beforeTokenTransfer(
  459. address operator,
  460. address from,
  461. address to,
  462. uint256 amount
  463. ) internal virtual {}
  464. }