Contract Source Code:
pragma solidity 0.8.17;
// SPDX-License-Identifier: AGPL-3.0-only
import "./lib/TransferHelper.sol";
contract DYSON {
using TransferHelper for address;
// For EIP-2612 permit()
bytes32 public immutable DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
string public constant symbol = "DYSN";
string public constant name = "Dyson Sphere";
uint8 public constant decimals = 18;
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
mapping(address => bool) public isMinter;
mapping(address => uint256) public nonces;
address public owner;
event TransferOwnership(address newOwner);
event Transfer(address indexed from, address indexed to, uint amount);
event Approval(address indexed owner, address indexed spender, uint amount);
constructor(address _owner) {
require(_owner != address(0), "invalid owner");
owner = _owner;
uint256 chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes("1")),
chainId,
address(this)
)
);
}
modifier onlyOwner() {
require(msg.sender == owner, "forbidden");
_;
}
/// @notice rescue token stucked in this contract
/// @param tokenAddress Address of token to be rescued
/// @param to Address that will receive token
/// @param amount Amount of token to be rescued
function rescueERC20(address tokenAddress, address to, uint256 amount) onlyOwner external {
tokenAddress.safeTransfer(to, amount);
}
function transferOwnership(address _owner) external onlyOwner {
require(_owner != address(0), "invalid owner");
owner = _owner;
emit TransferOwnership(_owner);
}
function addMinter(address _minter) external onlyOwner {
isMinter[_minter] = true;
}
function removeMinter(address _minter) external onlyOwner {
isMinter[_minter] = false;
}
function approve(address spender, uint amount) external returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
function _approve(
address _owner,
address _spender,
uint256 _amount
) internal virtual {
require(_owner != address(0), "ERC20: approve from the zero address");
require(_spender != address(0), "ERC20: approve to the zero address");
allowance[_owner][_spender] = _amount;
emit Approval(_owner, _spender, _amount);
}
function _mint(address to, uint amount) internal returns (bool) {
balanceOf[to] += amount;
totalSupply += amount;
emit Transfer(address(0), to, amount);
return true;
}
function _burn(address from, uint256 amount) internal returns (bool) {
balanceOf[from] -= amount;
totalSupply -= amount;
emit Transfer(from, address(0), amount);
return true;
}
function _transfer(address from, address to, uint amount) internal returns (bool) {
balanceOf[from] -= amount;
balanceOf[to] += amount;
emit Transfer(from, to, amount);
return true;
}
function transfer(address to, uint amount) external returns (bool) {
return _transfer(msg.sender, to, amount);
}
function transferFrom(address from, address to, uint amount) external returns (bool) {
if (allowance[from][msg.sender] != type(uint).max) {
allowance[from][msg.sender] -= amount;
}
return _transfer(from, to, amount);
}
function mint(address to, uint amount) external returns (bool) {
require(isMinter[msg.sender] || (owner == msg.sender), "forbidden");
return _mint(to, amount);
}
function burn(address from, uint amount) external returns (bool) {
if (allowance[from][msg.sender] != type(uint).max) {
allowance[from][msg.sender] -= amount;
}
return _burn(from, amount);
}
// implement the eip-2612
function permit(
address _owner,
address _spender,
uint256 _amount,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external {
require(_owner != address(0), "zero address");
require(block.timestamp <= _deadline || _deadline == 0, "permit is expired");
bytes32 digest = keccak256(
abi.encodePacked(uint16(0x1901), DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, _owner, _spender, _amount, nonces[_owner]++, _deadline)))
);
require(_owner == ecrecover(digest, _v, _r, _s), "invalid signature");
_approve(_owner, _spender, _amount);
}
}
pragma solidity 0.8.17;
// SPDX-License-Identifier: AGPL-2.0
library TransferHelper {
function safeApprove(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('approve(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'transferHelper: approve failed');
}
function safeTransfer(address token, address to, uint value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'transferHelper: transfer failed');
}
function safeTransferFrom(address token, address from, address to, uint value) internal {
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'transferHelper: transferFrom failed');
}
function safeTransferETH(address to, uint value) internal {
(bool success,) = to.call{value:value}(new bytes(0));
require(success, 'transferHelper: ETH transfer failed');
}
}