// SPDX-License-Identifier: UNLICENSE
// Rzucam worki w tłum w tłum .. kto łapie ten jara ... XD
/**
Apes Together Strong!
About BigShortBets DeFi project:
We are creating a social&trading p2p platform that guarantees encrypted interaction between investors.
Logging in is possible via a cryptocurrency wallet (e.g. Metamask).
The security level is one comparable to the Tor network.
https://bigsb.io/ - Our Tool
https://bigshortbets.com - Project&Team info
Video explainer:
https://youtu.be/wbhUo5IvKdk
Zaorski, You Son of a bitch I’m in …
*/
pragma solidity 0.8.7;
import "./interfaces.sol";
import "./owned.sol";
/**
BigShortBets.com BigSB token claiming contract
Contract need tokens on its address to send them to owners
*/
contract ClaimBigSB is Owned {
// presale contracts
address public immutable presale1;
address public immutable presale2;
address public immutable sale;
// BigSB token contract
address public immutable token;
// 1-year claiming window after which Owner can sweep remaining tokens
uint256 public immutable claimDateLimit;
// claiming process need to be enabled
bool public claimStarted;
// Presale2 is bugged in handling multiple ETH deposits
// we need handle that
mapping(address => uint256) internal buggedTokens;
// mark users that already claim tokens
mapping(address => bool) public isClaimed;
// handle ETH/tokens send from exchanges
mapping(address => address) internal _morty;
// AML-ed users address->tokens
mapping(address => uint256) internal _aml;
// events
event TokensClaimed(
address indexed from,
address indexed to,
uint256 amount
);
// useful constant
address internal constant ZERO = address(0x0);
uint256 internal immutable startRate;
/**
@dev contract constructor
@param _presale1 address of presale1 contract
@param _presale2 address of presale2 contract
@param _sale address of final sale contract
@param _token address of BigSB token contract
*/
constructor(
address _presale1,
address _presale2,
address _sale,
address _token
) {
presale1 = _presale1;
presale2 = _presale2;
sale = _sale;
token = _token;
claimDateLimit = block.timestamp + 365 days; //max 1 year to take tokens
startRate = IReflect(_token).getRate();
}
// count tokens from all pre/sale contracts
function _allTokens(address user) internal view returns (uint256) {
// presale2 need manual handle because of "multiple ETH send" error
// "tokensBoughtOf" is also flawed, so we do all math there
uint256 amt = buggedTokens[user];
if (amt == 0) {
// calculate tokens at sale price $2630/ETH, $0.95/token
// function is returning ETH value in wei
amt = (IPresale2(presale2).ethDepositOf(user) * 2630 * 100) / 95;
// calculate tokens for USD at $0.95/token
// contract is returning USD with 0 decimals
amt += (IPresale2(presale2).usdDepositOf(user) * 100 ether) / 95;
}
// presale1 reader is returning ETH amount in wei, $0.65 / token, $1530/ETH
// yes, there is a typo in function name
amt += (IPresale1(presale1).blanceOf(user) * 1530 * 100) / 65;
// sale returning tokens, $1/token, ETH price from oracle at buy time
amt += ISale(sale).tokensBoughtOf(user);
return amt;
}
/**
Reader that can check how many tokens can be claimed by given address
@param user address to check
@return number of tokens (18 decimals)
*/
function canClaim(address user) external view returns (uint256) {
return _recalculate(_allTokens(user));
}
// recalculate amount of tokens via start rate
function _recalculate(uint256 tokens) internal view returns (uint256) {
uint256 rate = IReflect(token).getRate();
return (tokens * rate) / startRate;
}
/**
@dev claim BigSB tokens bought on any pre/sale
*/
function claim() external {
require(_morty[msg.sender] == ZERO, "Use claimFrom");
_claim(msg.sender, msg.sender);
}
/// Claim tokens from AMLed list
function claimAML() external {
uint256 amt = _aml[msg.sender];
require(amt > 0, "Not on AML list");
_aml[msg.sender] = 0;
amt = _recalculate(amt);
IERC20(token).transfer(msg.sender, amt);
emit TokensClaimed(msg.sender, msg.sender, amt);
}
/**
@dev Claim BigSB tokens bought on any pre/sale to different address
@param to address to which tokens will be claimed
*/
function claimTo(address to) external {
require(_morty[msg.sender] == ZERO, "Use claimFromTo");
_claim(msg.sender, to);
}
/**
@dev Claim BigSB tokens bought on any pre/sale from exchange
@param from sender address that ETH was send to pre/sale contract
*/
function claimFrom(address from) external {
address to = _morty[from];
require(msg.sender == to, "Wrong Morty");
_claim(from, to);
}
/**
@dev Claim BigSB tokens by ETH send from exchange to another address
@param from sender address that ETH was send
@param to address to which send claimed tokens
*/
function claimFromTo(address from, address to) external {
require(msg.sender == _morty[from], "Wrong Morty");
_claim(from, to);
}
// internal claim function, validate claim and send tokens to given address
function _claim(address from, address to)
internal
claimStart
notZeroAddress(to)
{
require(!isClaimed[from], "Already claimed!");
isClaimed[from] = true;
uint256 amt = _recalculate(_allTokens(from));
require(IERC20(token).transfer(to, amt), "Token transfer failed");
emit TokensClaimed(from, to, amt);
}
//
// viewers
//
function isReplacedBy(address user) external view returns (address) {
return _morty[user];
}
//
// useful modifiers
//
modifier notZeroAddress(address user) {
require(user != ZERO, "Can not use address 0x0");
_;
}
modifier claimStart() {
require(claimStarted, "Claiming process not started!");
_;
}
modifier claimNotStarted() {
require(!claimStarted, "Claiming process already started!");
_;
}
//
// Rick mode
//
/**
@dev add single address that need to be changed in claim process
@param bad address to replace
@param good new address that can claim tokens bought by "bad" address
*/
function addMorty(address bad, address good)
external
onlyOwner
claimNotStarted
{
_addMorty(bad, good);
}
/// internal add replacement address function used in singe and multi add function
function _addMorty(address bad, address good)
internal
notZeroAddress(good)
{
require(_morty[bad] == ZERO, "Morty already on list");
_morty[bad] = good;
}
/**
@dev add addresses that need to be replaced in claiming precess, ie send ETH from exchange
@param bad list of wrong send addresses
@param good list of address replacements
*/
function addMortys(address[] calldata bad, address[] calldata good)
external
onlyOwner
claimNotStarted
{
uint256 dl = bad.length;
require(dl == good.length, "Data size mismatch");
uint256 i;
for (i; i < dl; i++) {
_addMorty(bad[i], good[i]);
}
}
/**
@dev add single "bugged" user
@param user affected user address
@param tokens counted tokens for user from presale2
*/
function addBugged(address user, uint256 tokens)
external
onlyOwner
claimNotStarted
{
buggedTokens[user] = tokens;
}
/**
@dev add list of users affected by "many ETH send" bug via list
@param user list of users
@param amt list of corresponding tokens amount
*/
function addBuggedList(address[] calldata user, uint256[] calldata amt)
external
onlyOwner
claimNotStarted
{
uint256 dl = user.length;
require(dl == amt.length, "Data size mismatch");
uint256 i;
for (i; i < dl; i++) {
buggedTokens[user[i]] = amt[i];
}
}
// add data to ALMed user list
function addAML(address[] calldata user, uint256[] calldata tokens)
external
onlyOwner
claimNotStarted
{
uint256 dl = user.length;
require(dl == tokens.length, "Data size mismatch");
uint256 i;
for (i; i < dl; i++) {
_aml[user[i]] = tokens[i];
}
}
/// Enable claiming process
function enableClaim() external onlyOwner claimNotStarted {
claimStarted = true;
}
/**
@dev Function to recover accidentally send ERC20 tokens
@param erc20 ERC20 token address
*/
function rescueERC20(address erc20) external onlyOwner {
if (erc20 == token) {
require(block.timestamp > claimDateLimit, "Too soon");
}
uint256 amt = IERC20(erc20).balanceOf(address(this));
require(amt > 0, "Nothing to rescue");
IUsdt(erc20).transfer(owner, amt);
}
/**
@dev Function to recover any ETH send to contract
*/
function rescueETH() external onlyOwner {
payable(owner).transfer(address(this).balance);
}
}
//This is fine!
// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.7;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount)
external
returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender)
external
view
returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
// Reflection
interface IReflect {
function tokenFromReflection(uint256 rAmount)
external
view
returns (uint256);
function reflectionFromToken(uint256 tAmount, bool deductTransferFee)
external
view
returns (uint256);
function getRate() external view returns (uint256);
}
/// ChainLink ETH/USD oracle
interface IChainLink {
// chainlink ETH/USD oracle
// answer|int256 : 216182781556 - 8 decimals
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
/// USDT is not ERC-20 compliant, not returning true on transfers
interface IUsdt {
function transfer(address, uint256) external;
function transferFrom(
address,
address,
uint256
) external;
}
// Check ETH send to first presale
// Yes, there is a typo
interface IPresale1 {
function blanceOf(address user) external view returns (uint256 amt);
}
// Check tokens bought in second presale
// There is bug in ETH deposits, we need handle it
// Also "tokensBoughtOf" calculation is broken, so we do all math
interface IPresale2 {
function ethDepositOf(address user) external view returns (uint256 amt);
function usdDepositOf(address user) external view returns (uint256 amt);
}
// Check final sale tokens bought
interface ISale {
function tokensBoughtOf(address user) external view returns (uint256 amt);
}
interface IClaimSale {
function addLock(
address user,
uint256 reflection,
uint256 locktime
) external;
}
// SPDX-License-Identifier: UNLICENSE
pragma solidity ^0.8.7;
contract Owned {
address public owner;
address public newOwner;
event OwnershipChanged(address from, address to);
constructor() {
owner = msg.sender;
emit OwnershipChanged(address(0), msg.sender);
}
modifier onlyOwner() {
require(msg.sender == owner, "Only owner");
_;
}
// owner can give super-rights to someone
function giveOwnership(address user) external onlyOwner {
require(user != address(0), "User renounceOwnership");
newOwner = user;
}
// new owner need to accept
function acceptOwnership() external {
require(msg.sender == newOwner, "Only NewOwner");
emit OwnershipChanged(owner, newOwner);
owner = msg.sender;
delete newOwner;
}
}
{
"compilationTarget": {
"ClaimBigSB.sol": "ClaimBigSB"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_presale1","type":"address"},{"internalType":"address","name":"_presale2","type":"address"},{"internalType":"address","name":"_sale","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensClaimed","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"user","type":"address[]"},{"internalType":"uint256[]","name":"tokens","type":"uint256[]"}],"name":"addAML","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"addBugged","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"user","type":"address[]"},{"internalType":"uint256[]","name":"amt","type":"uint256[]"}],"name":"addBuggedList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"bad","type":"address"},{"internalType":"address","name":"good","type":"address"}],"name":"addMorty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"bad","type":"address[]"},{"internalType":"address[]","name":"good","type":"address[]"}],"name":"addMortys","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"canClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimAML","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimDateLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"claimFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"claimFromTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"claimTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"giveOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"isReplacedBy","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"name":"presale1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presale2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"erc20","type":"address"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sale","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]