/**
*
* __ _ __ __
* / _\_ __ ___ __ _ _ __| |_/ / /\ \ \__ _ _ _ _ __ _ _ _ __
* \ \| '_ ` _ \ / _` | '__| __\ \/ \/ / _` | | | | | '__| | | | '_ \
* _\ \ | | | | | (_| | | | |_ \ /\ / (_| | |_| |_| | | |_| | | | |
* \__/_| |_| |_|\__,_|_| \__| \/ \/ \__,_|\__, (_)_| \__,_|_| |_|
* |___/
* Version 2.3
* https://smartway.run/
*
**/
pragma solidity 0.5.15;
contract SmartWay {
struct User {
uint64 id;
uint64 referrerId;
address payable[] referrals;
mapping(uint8 => uint64) levelExpired;
}
bool public sync = false;
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);
require(referrer != address(0), 'must be a referrer in extra data');
regUser(users[referrer].id);
}
function regUser(uint64 referrerId) public payable {
require(sync, '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 recoveryUsers(address payable[] calldata _users, uint64[] calldata _referrerIds) external {
require(!sync, 'Initialize already closed');
require(msg.sender == ownerWallet, 'Access denied');
for(uint64 i = 0; i < _users.length; i++) {
userList[lastUserId+i+1] = _users[i];
users[_users[i]].id = lastUserId+i+1;
users[_users[i]].referrerId = _referrerIds[i];
users[userList[_referrerIds[i]]].referrals.push(_users[i]);
}
lastUserId += uint64(_users.length);
}
function recoveryLevel(uint8 _level, address payable[] calldata _users, uint64[] calldata _timestamps) external {
require(!sync, 'Initialize already closed');
require(msg.sender == ownerWallet, 'Access denied');
for(uint64 i = 0; i < _users.length; i++) {
users[_users[i]].levelExpired[_level] = _timestamps[i];
}
}
function syncClose() external {
require(!sync, 'Initialize already closed');
require(msg.sender == ownerWallet, 'Access denied');
sync = true;
}
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": "istanbul",
"libraries": {},
"optimizer": {
"enabled": false,
"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":"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":"uint8","name":"_level","type":"uint8"},{"internalType":"address payable[]","name":"_users","type":"address[]"},{"internalType":"uint64[]","name":"_timestamps","type":"uint64[]"}],"name":"recoveryLevel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address payable[]","name":"_users","type":"address[]"},{"internalType":"uint64[]","name":"_referrerIds","type":"uint64[]"}],"name":"recoveryUsers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint64","name":"referrerId","type":"uint64"}],"name":"regUser","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"sync","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"syncClose","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"}]