pragma solidity ^0.5.17;
interface Deployer {
function execute(uint salt) external payable returns (address);
}
contract Team3DPresale {
// Token data
mapping (address => uint256) public balances;
string public constant name = "Team3DPresale";
string public constant symbol = "T3DPre";
uint8 public constant decimals = 18;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
// Presale data
uint public totalTokensSold;
uint public totalEthSpent;
address[] public keys;
mapping (address => bool) helper;
mapping (address => bool) public userExists;
mapping (address => uint) public teamFund;
mapping (address => bool) public whiteListed;
mapping (address => uint) public ethSpent;
uint public constant maxAmount = 5 ether;
uint public constant maxTotalAmount = 400 ether;
uint public constant tokensPerEth = 43750; // 17.5m tokens/400 eth; 43750 tokens/1 eth; 0.000022857 eth/1 token
uint public constant totalSaleSupply = 17500000 * (10 ** 18); // 17.5m = 35% of total supply.
uint public constant totalTeamSupply = 15000000 * (10 ** 18); // 15m = 30% for team/marketing/project
uint public initialTokens = totalSaleSupply + totalTeamSupply; // 65% distributed initially, remaining 35% added to liq later
bool public whitelistOnly = true;
address payable owner;
modifier onlyOwner() {
require(msg.sender == owner || helper[msg.sender] == true);
_;
}
constructor() public {
owner = msg.sender;
balances[owner] = totalTeamSupply;
emit Transfer(address(0), owner, totalTeamSupply);
}
function () external payable {
purchase();
}
function purchase() public payable {
require(msg.value <= maxAmount);
require(ethSpent[msg.sender] + msg.value <= maxAmount);
require(totalEthSpent <= maxTotalAmount);
require(!whitelistOnly || whiteListed[msg.sender], "Not a whitelisted address");
uint _tokenAmount = msg.value * tokensPerEth;
// Global data
totalEthSpent += msg.value;
totalTokensSold += _tokenAmount;
// User data
ethSpent[msg.sender] += msg.value;
balances[msg.sender] += _tokenAmount;
if (!userExists[msg.sender]) {
userExists[msg.sender] = true;
keys.push(msg.sender);
}
emit Transfer(address(0), msg.sender, _tokenAmount);
}
function addToWhitelist(address _addr) public onlyOwner {
whiteListed[_addr] = true;
}
function bulkAddToWhitelist(address[] calldata _addrs) external onlyOwner {
for (uint i=0; i < _addrs.length; i++) {
addToWhitelist(_addrs[i]);
}
}
function assignTeamTokens(address _addr, uint _amount) external onlyOwner {
require(balanceOf(owner) - _amount >= 0, "Underflow");
balances[owner] -= _amount;
balances[_addr] += _amount;
teamFund[_addr] += _amount;
if (!userExists[_addr]) {
userExists[_addr] = true;
keys.push(_addr);
}
emit Transfer(address(owner), _addr, _amount);
}
function removeTeamTokens(address _addr, uint _amount) external onlyOwner {
require(_amount <= teamFund[_addr]);
balances[owner] += _amount;
balances[_addr] -= _amount;
teamFund[_addr] -= _amount;
emit Transfer(_addr, address(owner), _amount);
}
function deployMainToken(address _deployerAddr, uint _salt) external onlyOwner {
// Collect dust if exact amount is not reached
if (getRemainingTokens() > 0) { clearRemainingTokens(); }
// In case someone tries to send eth with selfdestruct
if (address(this).balance > maxTotalAmount) {
uint _amount = address(this).balance - maxTotalAmount;
owner.transfer(_amount);
}
// Deploy liquidity and lock tokens
Deployer(_deployerAddr).execute.value(address(this).balance)(_salt);
}
function toggleWhitelist() external onlyOwner {
whitelistOnly = !whitelistOnly;
}
function refund(address payable _addr) public onlyOwner {
require(balances[_addr] - teamFund[_addr] > 0, "User has no purchased balance");
uint _userBal = balances[_addr] - teamFund[_addr]; // Only refund purchased tokens
uint _ethRefund = _userBal / tokensPerEth;
// Global data
totalEthSpent -= _ethRefund;
totalTokensSold -= _userBal;
// User data
ethSpent[_addr] = 0;
balances[_addr] = teamFund[_addr]; // Will be zero if they have no teamFund tokens
_addr.transfer(_ethRefund);
emit Transfer(_addr, address(0), _userBal);
}
function batchRefund(address payable[] calldata _addrs) external onlyOwner {
for (uint i=0; i < _addrs.length; i++) {
refund(_addrs[i]);
}
}
// Use this to collect any dust before deploy
function clearRemainingTokens() internal {
uint _remainingTokens = getRemainingTokens();
totalTokensSold += _remainingTokens;
balances[owner] += _remainingTokens;
emit Transfer(address(0), owner, _remainingTokens);
}
function addHelper(address _addr, bool _val) public onlyOwner {
helper[_addr] = _val;
}
function totalSupply() public view returns(uint) {
return initialTokens;
}
function balanceOf(address _addr) public view returns(uint) {
return balances[_addr];
}
function getRemainingTokens() public view returns(uint) {
return totalSaleSupply - totalTokensSold;
}
function getTotalPresaleBuyers() public view returns(uint) {
return keys.length;
}
}
{
"compilationTarget": {
"Team3DPresale.sol": "Team3DPresale"
},
"evmVersion": "istanbul",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"bool","name":"_val","type":"bool"}],"name":"addHelper","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"addToWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"assignTeamTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable[]","name":"_addrs","type":"address[]"}],"name":"batchRefund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"_addrs","type":"address[]"}],"name":"bulkAddToWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_deployerAddr","type":"address"},{"internalType":"uint256","name":"_salt","type":"uint256"}],"name":"deployMainToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ethSpent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getRemainingTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTotalPresaleBuyers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initialTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"keys","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxTotalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"purchase","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable","name":"_addr","type":"address"}],"name":"refund","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_addr","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"removeTeamTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"teamFund","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"toggleWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"tokensPerEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalEthSpent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSaleSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalTeamSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalTokensSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whiteListed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"whitelistOnly","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]