ERC777.sol 16 KB

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