ERC20Mixer.sol 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // https://tornado.cash
  2. /*
  3. * d888888P dP a88888b. dP
  4. * 88 88 d8' `88 88
  5. * 88 .d8888b. 88d888b. 88d888b. .d8888b. .d888b88 .d8888b. 88 .d8888b. .d8888b. 88d888b.
  6. * 88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88 88' `88 Y8ooooo. 88' `88
  7. * 88 88. .88 88 88 88 88. .88 88. .88 88. .88 dP Y8. .88 88. .88 88 88 88
  8. * dP `88888P' dP dP dP `88888P8 `88888P8 `88888P' 88 Y88888P' `88888P8 `88888P' dP dP
  9. * ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
  10. */
  11. pragma solidity ^0.5.8;
  12. import "./Mixer.sol";
  13. contract ERC20Mixer is Mixer {
  14. address public token;
  15. constructor(
  16. address _verifier,
  17. uint256 _denomination,
  18. uint8 _merkleTreeHeight,
  19. uint256 _emptyElement,
  20. address payable _operator,
  21. address _token
  22. ) Mixer(_verifier, _denomination, _merkleTreeHeight, _emptyElement, _operator) public {
  23. token = _token;
  24. }
  25. function _processDeposit() internal {
  26. safeErc20TransferFrom(msg.sender, address(this), denomination);
  27. }
  28. function _processWithdraw(address payable _receiver, address payable _relayer, uint256 _fee, uint256 _refund) internal {
  29. require(msg.value == _refund, "Incorrect refund amount received by the contract");
  30. safeErc20Transfer(_receiver, denomination - _fee);
  31. if (_fee > 0) {
  32. safeErc20Transfer(_relayer, _fee);
  33. }
  34. if (_refund > 0) {
  35. _receiver.transfer(_refund);
  36. }
  37. }
  38. function safeErc20TransferFrom(address from, address to, uint256 amount) internal {
  39. bool success;
  40. bytes memory data;
  41. bytes4 transferFromSelector = 0x23b872dd;
  42. (success, data) = token.call(
  43. abi.encodeWithSelector(
  44. transferFromSelector,
  45. from, to, amount
  46. )
  47. );
  48. require(success, "not enough allowed tokens");
  49. // if contract returns some data let's make sure that is `true` according to standard
  50. if (data.length > 0) {
  51. assembly {
  52. success := mload(add(data, 0x20))
  53. }
  54. require(success, "not enough allowed tokens. Token returns false.");
  55. }
  56. }
  57. function safeErc20Transfer(address to, uint256 amount) internal {
  58. bool success;
  59. bytes memory data;
  60. bytes4 transferSelector = 0xa9059cbb;
  61. (success, data) = token.call(
  62. abi.encodeWithSelector(
  63. transferSelector,
  64. to, amount
  65. )
  66. );
  67. require(success, "not enough tokens");
  68. // if contract returns some data let's make sure that is `true` according to standard
  69. if (data.length > 0) {
  70. assembly {
  71. success := mload(add(data, 0x20))
  72. }
  73. require(success, "not enough tokens. Token returns false.");
  74. }
  75. }
  76. }