/**
*
* __ _ __ __
* / _\_ __ ___ __ _ _ __| |_/ / /\ \ \__ _ _ _ _ __ _ _ _ __
* \ \| '_ ` _ \ / _` | '__| __\ \/ \/ / _` | | | | | '__| | | | '_ \
* _\ \ | | | | | (_| | | | |_ \ /\ / (_| | |_| |_| | | |_| | | | |
* \__/_| |_| |_|\__,_|_| \__| \/ \/ \__,_|\__, (_)_| \__,_|_| |_|
* |___/
* Version 2.0
* https://smartway.run/
*
**/
pragma solidity 0.5.13;
contract SmartWay {
struct User {
uint64 id;
uint64 referrerId;
address payable[] referrals;
mapping(uint8 => uint64) levelExpired;
}
SmartWay public oldSC = SmartWay(0x99280ceFeECcEAf2C5B1537Cd4eeb3B44c3c171F);
uint64 public oldSCUserId = 1;
uint8 public constant REFERRER_1_LEVEL_LIMIT = 2;
uint64 public constant PERIOD_LENGTH = 30 days;
address payable public ownerWallet;
uint64 public lastUserId;
mapping(uint8 => uint) public levelPrice;
mapping(uint => uint8) public priceLevel;
mapping(address => User) public users;
mapping(uint64 => address payable) public userList;
event Registration(address indexed user, address referrer);
event LevelBought(address indexed user, uint8 level);
event GetMoneyForLevel(address indexed user, address indexed referral, uint8 level);
event SendMoneyError(address indexed user, address indexed referral, uint8 level);
event LostMoneyForLevel(address indexed user, address indexed referral, uint8 level);
constructor(address payable owner) public {
_initData();
ownerWallet = msg.sender;
lastUserId++;
userList[lastUserId] = owner;
users[owner].id = lastUserId;
for(uint8 i = 1; i <= 12; i++) {
users[owner].levelExpired[i] = 77777777777;
}
}
function () external payable {
uint8 level = priceLevel[msg.value];
require(level != 0, 'Incorrect value sent');
if(users[msg.sender].id != 0)
return buyLevel(level);
require(level == 1, 'Please buy level 1 for 0.2 ETH');
address referrer = bytesToAddress(msg.data);
if(users[referrer].id != 0)
return regUser(users[referrer].id);
require(referrer == address(0));
}
function regUser(uint64 referrerId) public payable {
require(address(oldSC) == address(0), 'Initialize not finished');
require(users[msg.sender].id == 0, 'User exist');
require(referrerId > 0 && referrerId <= lastUserId, 'Incorrect referrer Id');
require(msg.value == levelPrice[1], 'Incorrect Value');
if(users[userList[referrerId]].referrals.length >= REFERRER_1_LEVEL_LIMIT) {
address freeReferrer = findFreeReferrer(userList[referrerId]);
referrerId = users[freeReferrer].id;
}
lastUserId++;
users[msg.sender] = User({
id: lastUserId,
referrerId: referrerId,
referrals: new address payable[](0)
});
userList[lastUserId] = msg.sender;
users[msg.sender].levelExpired[1] = uint64(now + PERIOD_LENGTH);
users[userList[referrerId]].referrals.push(msg.sender);
payForLevel(1, msg.sender);
emit Registration(msg.sender, userList[referrerId]);
}
function buyLevel(uint8 level) public payable {
require(users[msg.sender].id != 0, 'User is not exists');
require(level > 0 && level <= 12, 'Incorrect level');
require(msg.value == levelPrice[level], 'Incorrect Value');
for(uint8 i = level - 1; i > 0; i--) {
require(users[msg.sender].levelExpired[i] >= now, 'Buy the previous level');
}
if(users[msg.sender].levelExpired[level] == 0 || users[msg.sender].levelExpired[level] < now) {
users[msg.sender].levelExpired[level] = uint64(now + PERIOD_LENGTH);
} else {
users[msg.sender].levelExpired[level] += PERIOD_LENGTH;
}
payForLevel(level, msg.sender);
emit LevelBought(msg.sender, level);
}
function payForLevel(uint8 level, address user) private {
address payable referrer;
if (level%2 == 0) {
referrer = userList[users[userList[users[user].referrerId]].referrerId]; //extra variable will decrease aroud 50 recursion levels
} else {
referrer = userList[users[user].referrerId];
}
if(users[referrer].id == 0) {
referrer = userList[1];
}
if(users[referrer].levelExpired[level] >= now) {
if (referrer.send(levelPrice[level])) {
emit GetMoneyForLevel(referrer, msg.sender, level);
} else {
emit SendMoneyError(referrer, msg.sender, level);
}
} else {
emit LostMoneyForLevel(referrer, msg.sender, level);
payForLevel(level, referrer);
}
}
function _initData() private {
levelPrice[1] = 0.2 ether;
levelPrice[2] = 0.22 ether;
levelPrice[3] = 0.4 ether;
levelPrice[4] = 0.44 ether;
levelPrice[5] = 0.7 ether;
levelPrice[6] = 0.77 ether;
levelPrice[7] = 1.2 ether;
levelPrice[8] = 1.3 ether;
levelPrice[9] = 2 ether;
levelPrice[10] = 2.2 ether;
levelPrice[11] = 3 ether;
levelPrice[12] = 3.3 ether;
priceLevel[0.2 ether] = 1;
priceLevel[0.22 ether] = 2;
priceLevel[0.4 ether] = 3;
priceLevel[0.44 ether] = 4;
priceLevel[0.7 ether] = 5;
priceLevel[0.77 ether] = 6;
priceLevel[1.2 ether] = 7;
priceLevel[1.3 ether] = 8;
priceLevel[2 ether] = 9;
priceLevel[2.2 ether] = 10;
priceLevel[3 ether] = 11;
priceLevel[3.3 ether] = 12;
}
function findFreeReferrer(address _user) public view returns(address) {
if(users[_user].referrals.length < REFERRER_1_LEVEL_LIMIT)
return _user;
address[] memory referrals = new address[](256);
address[] memory referralsBuf = new address[](256);
referrals[0] = users[_user].referrals[0];
referrals[1] = users[_user].referrals[1];
uint32 j = 2;
while(true) {
for(uint32 i = 0; i < j; i++) {
if(users[referrals[i]].referrals.length < 1) {
return referrals[i];
}
}
for(uint32 i = 0; i < j; i++) {
if (users[referrals[i]].referrals.length < REFERRER_1_LEVEL_LIMIT) {
return referrals[i];
}
}
for(uint32 i = 0; i < j; i++) {
referralsBuf[i] = users[referrals[i]].referrals[0];
referralsBuf[j+i] = users[referrals[i]].referrals[1];
}
j = j*2;
for(uint32 i = 0; i < j; i++) {
referrals[i] = referralsBuf[i];
}
}
}
function syncWithOldSC(uint limit) public {
require(address(oldSC) != address(0), 'Initialize closed');
require(msg.sender == ownerWallet, 'Access denied');
for(uint i = 0; i < limit; i++) {
address payable user = oldSC.userList(oldSCUserId);
(uint64 id, uint64 referrerId) = oldSC.users(user);
if(id != 0) {
oldSCUserId++;
address ref = oldSC.userList(referrerId);
if(users[user].id == 0 && users[ref].id != 0) {
users[user].id = ++lastUserId;
users[user].referrerId = users[ref].id;
userList[lastUserId] = user;
users[ref].referrals.push(user);
for(uint8 j = 1; j <= 12; j++) {
uint levelExpired = oldSC.viewUserLevelExpired(user, j);
if (levelExpired > now) {
users[user].levelExpired[j] = uint64(levelExpired + 30 days);
}
}
emit Registration(user, ref);
}
}
else break;
}
}
function syncClose() external {
require(address(oldSC) != address(0), 'Initialize already closed');
require(msg.sender == ownerWallet, 'Access denied');
oldSC = SmartWay(0);
}
function viewUserReferral(address user) public view returns(address payable[] memory) {
return users[user].referrals;
}
function viewUserLevelExpired(address user, uint8 level) public view returns(uint) {
return users[user].levelExpired[level];
}
function bytesToAddress(bytes memory bys) private pure returns (address addr) {
assembly {
addr := mload(add(bys, 20))
}
}
}
{
"compilationTarget": {
"SmartWay.sol": "SmartWay"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address payable","name":"owner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"referral","type":"address"},{"indexed":false,"internalType":"uint8","name":"level","type":"uint8"}],"name":"GetMoneyForLevel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint8","name":"level","type":"uint8"}],"name":"LevelBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"referral","type":"address"},{"indexed":false,"internalType":"uint8","name":"level","type":"uint8"}],"name":"LostMoneyForLevel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"referrer","type":"address"}],"name":"Registration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"referral","type":"address"},{"indexed":false,"internalType":"uint8","name":"level","type":"uint8"}],"name":"SendMoneyError","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"PERIOD_LENGTH","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"REFERRER_1_LEVEL_LIMIT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint8","name":"level","type":"uint8"}],"name":"buyLevel","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"findFreeReferrer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastUserId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"levelPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oldSC","outputs":[{"internalType":"contract SmartWay","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oldSCUserId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ownerWallet","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"priceLevel","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint64","name":"referrerId","type":"uint64"}],"name":"regUser","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"syncClose","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"syncWithOldSC","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"userList","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"users","outputs":[{"internalType":"uint64","name":"id","type":"uint64"},{"internalType":"uint64","name":"referrerId","type":"uint64"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint8","name":"level","type":"uint8"}],"name":"viewUserLevelExpired","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"viewUserReferral","outputs":[{"internalType":"address payable[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"}]