// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
// Interfaces for contract interaction
interface INterfaces {
function balanceOf(address) external returns (uint256);
function transfer(address, uint256) external returns (bool);
function transferFrom(
address,
address,
uint256
) external returns (bool);
function allowance(address, address) external returns (uint256);
//usdc
function transferWithAuthorization(
address from,
address to,
uint256 value,
uint256 validAfter,
uint256 validBefore,
bytes32 nonce,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
// USDT is not ERC-20 compliant, not returning true on transfers
interface IUsdt {
function transfer(address, uint256) external;
function transferFrom(
address,
address,
uint256
) external;
}
// BigShortBets.com presale contract - via StableCoins and ETH
//
// USE ONLY OWN WALLET (Metamask, Trezor, Ledger...)
// DO NOT SEND FROM EXCHANGES OR ANY SERVICES
//
// Use ONLY ETH network, ERC20 tokens (Not Binance/Tron/whatever!)
//
// Set approval to contract address or use USDC authorization first
//
// DO NOT SEND STABLE TOKENS DIRECTLY - IT WILL NOT COUNT THAT!
//
// send ONLY round number of USD(c|t)/DAI!
// ie 20, 500, 2000 NOT 20.1, 500.5, 2000.3
// contract will ignore decimals
//
// Need 150k gas limit
// use proper pay* function
contract BigShortBetsPresale2 {
// max USD per user
uint256 private immutable _maxUsd;
// soft limit USD total
uint256 private immutable _limitUsd;
// max ETH per user
uint256 private immutable _maxEth;
// soft limit ETH total
uint256 private immutable _limitEth;
// contract starts accepting transfers
uint256 private immutable _dateStart;
// hard time limit
uint256 private immutable _dateEnd;
// total collected USD
uint256 private _usdCollected;
uint256 private constant DECIMALS_DAI = 18;
uint256 private constant DECIMALS_USDC = 6;
uint256 private constant DECIMALS_USDT = 6;
// addresses of tokens
address private immutable usdt;
address private immutable usdc;
address private immutable dai;
address public owner;
address public newOwner;
bool private _presaleEnded;
// deposited per user
mapping(address => uint256) private _usdBalance;
mapping(address => uint256) private _ethBalance;
// deposited per tokens
mapping(address => uint256) private _deposited;
// will be set after presale
uint256 private _tokensPerEth;
string private constant ERROR_ANS = "Approval not set!";
event AcceptedUSD(address indexed user, uint256 amount);
event AcceptedETH(address indexed user, uint256 amount);
constructor(
address _owner,
uint256 maxUsd,
uint256 limitUsd,
uint256 maxEth,
uint256 limitEth,
uint256 startDate,
uint256 endDate,
address _usdt,
address _usdc,
address _dai
) {
owner = _owner;
_maxUsd = maxUsd;
_limitUsd = limitUsd;
_maxEth = maxEth;
_limitEth = limitEth;
_dateStart = startDate;
_dateEnd = endDate;
usdt = _usdt;
usdc = _usdc;
dai = _dai;
/**
mainnet:
usdt=0xdAC17F958D2ee523a2206206994597C13D831ec7;
usdc=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
dai=0x6B175474E89094C44Da98b954EedeAC495271d0F;
*/
}
//pay in using USDC
//need prepare and sign approval first
//not included in dapp
function payUsdcByAuthorization(
address from,
address to,
uint256 value,
uint256 validAfter,
uint256 validBefore,
bytes32 nonce,
uint8 v,
bytes32 r,
bytes32 s
) external {
require(to == address(this), "Wrong authorization address");
// should throw on any error
INterfaces(usdc).transferWithAuthorization(
from,
to,
value,
validAfter,
validBefore,
nonce,
v,
r,
s
);
// not msg.sender, approval can be sent by anyone
_pay(from, value, DECIMALS_USDC);
_deposited[usdc] += value;
}
//pay in using USDC
//use approve/transferFrom
function payUSDC(uint256 amount) external {
require(
INterfaces(usdc).allowance(msg.sender, address(this)) >= amount,
ERROR_ANS
);
require(
INterfaces(usdc).transferFrom(msg.sender, address(this), amount),
"USDC transfer failed"
);
_pay(msg.sender, amount, DECIMALS_USDC);
_deposited[usdc] += amount;
}
//pay in using USDT
//need set approval first
function payUSDT(uint256 amount) external {
require(
INterfaces(usdt).allowance(msg.sender, address(this)) >= amount,
ERROR_ANS
);
IUsdt(usdt).transferFrom(msg.sender, address(this), amount);
_pay(msg.sender, amount, DECIMALS_USDT);
_deposited[usdt] += amount;
}
//pay in using DAI
//need set approval first
function payDAI(uint256 amount) external {
require(
INterfaces(dai).allowance(msg.sender, address(this)) >= amount,
ERROR_ANS
);
require(
INterfaces(dai).transferFrom(msg.sender, address(this), amount),
"DAI transfer failed"
);
_pay(msg.sender, amount, DECIMALS_DAI);
_deposited[dai] += amount;
}
//direct ETH send will not back
//
//accept ETH
// takes about 50k gas
receive() external payable {
_payEth(msg.sender, msg.value);
}
// takes about 35k gas
function payETH() external payable {
_payEth(msg.sender, msg.value);
}
function _payEth(address user, uint256 amount) internal notEnded {
uint256 amt = _ethBalance[user] + amount;
require(amt <= _maxEth, "ETH per user reached");
_ethBalance[user] += amt;
emit AcceptedETH(user, amount);
}
function _pay(
address user,
uint256 amount,
uint256 decimals
) internal notEnded {
uint256 usd = amount / (10**decimals);
_usdBalance[user] += usd;
require(_usdBalance[user] <= _maxUsd, "USD amount too high");
_usdCollected += usd;
emit AcceptedUSD(user, usd);
}
//
// external readers
//
function USDcollected() external view returns (uint256) {
return _usdCollected;
}
function ETHcollected() external view returns (uint256) {
return address(this).balance;
}
function USDmax() external view returns (uint256) {
return _maxUsd;
}
function USDlimit() external view returns (uint256) {
return _limitUsd;
}
function ETHmax() external view returns (uint256) {
return _maxEth;
}
function ETHlimit() external view returns (uint256) {
return _limitEth;
}
function dateStart() external view returns (uint256) {
return _dateStart;
}
function dateEnd() external view returns (uint256) {
return _dateEnd;
}
function tokensBoughtOf(address user) external view returns (uint256 amt) {
require(_tokensPerEth > 0, "Tokens/ETH ratio not set yet");
amt = (_usdBalance[user] * 95) / 100;
amt += _ethBalance[user] * _tokensPerEth;
return amt;
}
function usdDepositOf(address user) external view returns (uint256) {
return _usdBalance[user];
}
function ethDepositOf(address user) external view returns (uint256) {
return _ethBalance[user];
}
modifier notEnded() {
require(!_presaleEnded, "Presale ended");
require(
block.timestamp > _dateStart && block.timestamp < _dateEnd,
"Too soon or too late"
);
_;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only for contract Owner");
_;
}
modifier timeIsUp() {
require(block.timestamp > _dateEnd, "SOON");
_;
}
function endPresale() external onlyOwner {
require(
_usdCollected > _limitUsd || address(this).balance > _limitEth,
"Limit not reached"
);
_presaleEnded = true;
}
function setTokensPerEth(uint256 ratio) external onlyOwner {
require(_tokensPerEth == 0, "Ratio already set");
_tokensPerEth = ratio;
}
// take out all stables and ETH
function takeAll() external onlyOwner timeIsUp {
_presaleEnded = true; //just to save gas for ppl that want buy too late
uint256 amt = INterfaces(usdt).balanceOf(address(this));
if (amt > 0) {
IUsdt(usdt).transfer(owner, amt);
}
amt = INterfaces(usdc).balanceOf(address(this));
if (amt > 0) {
INterfaces(usdc).transfer(owner, amt);
}
amt = INterfaces(dai).balanceOf(address(this));
if (amt > 0) {
INterfaces(dai).transfer(owner, amt);
}
amt = address(this).balance;
if (amt > 0) {
payable(owner).transfer(amt);
}
}
// we can recover any ERC20 token send in wrong way... for price!
function recoverErc20(address token) external onlyOwner {
uint256 amt = INterfaces(token).balanceOf(address(this));
// do not take deposits
amt -= _deposited[token];
if (amt > 0) {
INterfaces(token).transfer(owner, amt);
}
}
// should not be needed, but...
function recoverEth() external onlyOwner timeIsUp {
payable(owner).transfer(address(this).balance);
}
function changeOwner(address _newOwner) external onlyOwner {
newOwner = _newOwner;
}
function acceptOwnership() external {
require(
msg.sender != address(0) && msg.sender == newOwner,
"Only NewOwner"
);
newOwner = address(0);
owner = msg.sender;
}
}
// rav3n_pl was here
{
"compilationTarget": {
"bsb2.sol": "BigShortBetsPresale2"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"maxUsd","type":"uint256"},{"internalType":"uint256","name":"limitUsd","type":"uint256"},{"internalType":"uint256","name":"maxEth","type":"uint256"},{"internalType":"uint256","name":"limitEth","type":"uint256"},{"internalType":"uint256","name":"startDate","type":"uint256"},{"internalType":"uint256","name":"endDate","type":"uint256"},{"internalType":"address","name":"_usdt","type":"address"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_dai","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AcceptedETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AcceptedUSD","type":"event"},{"inputs":[],"name":"ETHcollected","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETHlimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETHmax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDcollected","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDlimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDmax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dateEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dateStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endPresale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"ethDepositOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"payDAI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"payETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"payUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"payUSDT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"payUsdcByAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"recoverErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ratio","type":"uint256"}],"name":"setTokensPerEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"takeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"tokensBoughtOf","outputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"usdDepositOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]