ERC20Tornado.sol 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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 "./Tornado.sol";
  13. contract ERC20Tornado is Tornado {
  14. address public token;
  15. constructor(
  16. IVerifier _verifier,
  17. uint256 _denomination,
  18. uint32 _merkleTreeHeight,
  19. address _operator,
  20. address _token
  21. ) Tornado(_verifier, _denomination, _merkleTreeHeight, _operator) public {
  22. token = _token;
  23. }
  24. function _processDeposit() internal {
  25. require(msg.value == 0, "ETH value is supposed to be 0 for ERC20 instance");
  26. _safeErc20TransferFrom(msg.sender, address(this), denomination);
  27. }
  28. function _processWithdraw(address payable _recipient, address payable _relayer, uint256 _fee, uint256 _refund) internal {
  29. require(msg.value == _refund, "Incorrect refund amount received by the contract");
  30. _safeErc20Transfer(_recipient, denomination - _fee);
  31. if (_fee > 0) {
  32. _safeErc20Transfer(_relayer, _fee);
  33. }
  34. if (_refund > 0) {
  35. (bool success, ) = _recipient.call.value(_refund)("");
  36. if (!success) {
  37. // let's return _refund back to the relayer
  38. _relayer.transfer(_refund);
  39. }
  40. }
  41. }
  42. function _safeErc20TransferFrom(address _from, address _to, uint256 _amount) internal {
  43. (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd /* transferFrom */, _from, _to, _amount));
  44. require(success, "not enough allowed tokens");
  45. // if contract returns some data lets make sure that is `true` according to standard
  46. if (data.length > 0) {
  47. require(data.length == 32, "data length should be either 0 or 32 bytes");
  48. success = abi.decode(data, (bool));
  49. require(success, "not enough allowed tokens. Token returns false.");
  50. }
  51. }
  52. function _safeErc20Transfer(address _to, uint256 _amount) internal {
  53. (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb /* transfer */, _to, _amount));
  54. require(success, "not enough tokens");
  55. // if contract returns some data lets make sure that is `true` according to standard
  56. if (data.length > 0) {
  57. require(data.length == 32, "data length should be either 0 or 32 bytes");
  58. success = abi.decode(data, (bool));
  59. require(success, "not enough tokens. Token returns false.");
  60. }
  61. }
  62. }