mirror of
https://github.com/tornadocash/torn-token.git
synced 2024-12-29 16:17:56 +01:00
111 lines
3.3 KiB
Solidity
111 lines
3.3 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.6.0;
|
|
pragma experimental ABIEncoderV2;
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "@openzeppelin/contracts/utils/Pausable.sol";
|
|
import "@openzeppelin/contracts/math/Math.sol";
|
|
import "./ERC20Permit.sol";
|
|
import "./ENS.sol";
|
|
|
|
contract TORN is ERC20("TornadoCash", "TORN"), ERC20Burnable, ERC20Permit, Pausable, EnsResolve {
|
|
using SafeERC20 for IERC20;
|
|
|
|
uint256 public immutable canUnpauseAfter;
|
|
address public immutable governance;
|
|
mapping(address => bool) public allowedTransferee;
|
|
|
|
event Allowed(address target);
|
|
event Disallowed(address target);
|
|
|
|
struct Recipient {
|
|
bytes32 to;
|
|
uint256 amount;
|
|
}
|
|
|
|
constructor(
|
|
bytes32 _governance,
|
|
uint256 _pausePeriod,
|
|
Recipient[] memory _vestings
|
|
) public {
|
|
address _resolvedGovernance = resolve(_governance);
|
|
governance = _resolvedGovernance;
|
|
allowedTransferee[_resolvedGovernance] = true;
|
|
|
|
for (uint256 i = 0; i < _vestings.length; i++) {
|
|
address to = resolve(_vestings[i].to);
|
|
_mint(to, _vestings[i].amount);
|
|
allowedTransferee[to] = true;
|
|
}
|
|
|
|
canUnpauseAfter = blockTimestamp().add(_pausePeriod);
|
|
_pause();
|
|
require(totalSupply() == 10000000 ether, "TORN: incorrect distribution");
|
|
}
|
|
|
|
modifier onlyGovernance() {
|
|
require(_msgSender() == governance, "TORN: only governance can perform this action");
|
|
_;
|
|
}
|
|
|
|
function changeTransferability(bool decision) public onlyGovernance {
|
|
require(blockTimestamp() > canUnpauseAfter, "TORN: cannot change transferability yet");
|
|
if (decision) {
|
|
_unpause();
|
|
} else {
|
|
_pause();
|
|
}
|
|
}
|
|
|
|
function addToAllowedList(address[] memory target) public onlyGovernance {
|
|
for (uint256 i = 0; i < target.length; i++) {
|
|
allowedTransferee[target[i]] = true;
|
|
emit Allowed(target[i]);
|
|
}
|
|
}
|
|
|
|
function removeFromAllowedList(address[] memory target) public onlyGovernance {
|
|
for (uint256 i = 0; i < target.length; i++) {
|
|
allowedTransferee[target[i]] = false;
|
|
emit Disallowed(target[i]);
|
|
}
|
|
}
|
|
|
|
function _beforeTokenTransfer(
|
|
address from,
|
|
address to,
|
|
uint256 amount
|
|
) internal override {
|
|
super._beforeTokenTransfer(from, to, amount);
|
|
require(!paused() || allowedTransferee[from] || allowedTransferee[to], "TORN: paused");
|
|
require(to != address(this), "TORN: invalid recipient");
|
|
}
|
|
|
|
/// @dev Method to claim junk and accidentally sent tokens
|
|
function rescueTokens(
|
|
IERC20 _token,
|
|
address payable _to,
|
|
uint256 _balance
|
|
) external onlyGovernance {
|
|
require(_to != address(0), "TORN: can not send to zero address");
|
|
|
|
if (_token == IERC20(0)) {
|
|
// for Ether
|
|
uint256 totalBalance = address(this).balance;
|
|
uint256 balance = _balance == 0 ? totalBalance : Math.min(totalBalance, _balance);
|
|
_to.transfer(balance);
|
|
} else {
|
|
// any other erc20
|
|
uint256 totalBalance = _token.balanceOf(address(this));
|
|
uint256 balance = _balance == 0 ? totalBalance : Math.min(totalBalance, _balance);
|
|
require(balance > 0, "TORN: trying to send 0 balance");
|
|
_token.safeTransfer(_to, balance);
|
|
}
|
|
}
|
|
}
|