pragma solidity >=0.4.24;
contract Matrix {
struct User {
uint id;
address referrer;
uint personalMatrixCnt;
uint personalMatrixNum;
uint personalMatrixFills;
uint totalReferrals;
uint levelsOpen;
}
mapping(uint => uint) public LEVEL_PRICE;
mapping(uint => uint) public LEVEL_SLOTS;
mapping(uint => uint) public EXTRA_SLOTS;
mapping(address => User) public users;
mapping(uint => address) public binaryUsers;
mapping(uint => address) public usersById;
mapping(address => mapping (uint => uint)) public positionsByAddress;
mapping(address => uint) public positionsByAddressCnt;
mapping(uint => uint) public binaryPositionsLevels;
uint public lastUserId = 2;
uint public lastBinaryId = 1;
uint public lastPersonalMatrixId = 2;
address public owner;
uint REGISTRATION_COST = 0.05 ether;
event Registration(address indexed user, address indexed referrer, uint indexed userId, uint referrerId);
event LevelUpgraded(address indexed user, uint indexed userId, uint indexed level);
event LevelFilled(address indexed user, uint indexed userId, uint indexed level);
event Transfer(address indexed user, uint indexed userId, uint indexed amount);
function isUserExists(address user) public view returns (bool) {
return (users[user].id != 0);
}
constructor(address ownerAddress) public {
owner = ownerAddress;
User memory user = User({
id: 1,
referrer: address(0),
personalMatrixCnt: 0,
personalMatrixNum: 1,
personalMatrixFills: 0,
totalReferrals: 0,
levelsOpen: 1
});
users[ownerAddress] = user;
usersById[1] = ownerAddress;
LEVEL_PRICE[1] = 0.05 ether;
LEVEL_PRICE[2] = 0.1 ether;
LEVEL_PRICE[3] = 0.2 ether;
LEVEL_PRICE[4] = 1 ether;
LEVEL_PRICE[5] = 6 ether;
LEVEL_PRICE[6] = 50 ether;
LEVEL_PRICE[7] = 50 ether;
LEVEL_PRICE[8] = 100 ether;
LEVEL_PRICE[9] = 400 ether;
LEVEL_PRICE[10] = 1600 ether;
LEVEL_SLOTS[1] = 2;
LEVEL_SLOTS[2] = 4;
LEVEL_SLOTS[3] = 8;
LEVEL_SLOTS[4] = 16;
LEVEL_SLOTS[5] = 32;
LEVEL_SLOTS[6] = 2;
LEVEL_SLOTS[7] = 4;
LEVEL_SLOTS[8] = 8;
LEVEL_SLOTS[9] = 16;
LEVEL_SLOTS[10] = 32;
EXTRA_SLOTS[1] = 0;
EXTRA_SLOTS[2] = 1;
EXTRA_SLOTS[3] = 6;
EXTRA_SLOTS[4] = 20;
EXTRA_SLOTS[5] = 200;
EXTRA_SLOTS[6] = 200;
EXTRA_SLOTS[7] = 400;
EXTRA_SLOTS[8] = 2000;
EXTRA_SLOTS[9] = 16000;
EXTRA_SLOTS[10] = 124000;
}
function reg(address referrer) public payable {
registration(msg.sender, referrer);
}
function purchasePosition() public payable {
require(msg.value == 0.05 ether, "purchase cost 0.05");
require(isUserExists(msg.sender), "user not exists");
updateBinaryMatrix(msg.sender);
}
function registration(address userAddress, address referrerAddress) private {
require(msg.value == 0.1 ether, "registration cost 0.1");
require(!isUserExists(userAddress), "user exists");
require(isUserExists(referrerAddress), "referrer not exists");
uint32 size;
assembly {
size := extcodesize(userAddress)
}
require(size == 0, "cannot be a contract");
users[userAddress] = User({
id: lastUserId,
referrer: referrerAddress,
levelsOpen: 1,
personalMatrixCnt: 0,
personalMatrixFills: 0,
personalMatrixNum: lastPersonalMatrixId,
totalReferrals: 0
});
usersById[lastUserId] = userAddress;
lastUserId++;
lastPersonalMatrixId++;
updatePersonalMatrix(referrerAddress);
updateBinaryMatrix(userAddress);
emit Registration(userAddress, referrerAddress, users[userAddress].id, users[referrerAddress].id);
}
function updatePersonalMatrix(address referrer) private {
users[referrer].totalReferrals++;
if (users[referrer].personalMatrixCnt < 2) {
payRegDividends(referrer);
users[referrer].personalMatrixCnt++;
} else if (users[referrer].personalMatrixCnt == 2) {
updateBinaryMatrix(referrer);
users[referrer].personalMatrixCnt++;
} else {
if (users[referrer].referrer == address(0)) {
payRegDividends(referrer);
} else {
updatePersonalMatrix(users[referrer].referrer);
}
users[referrer].personalMatrixCnt = 0;
users[referrer].personalMatrixNum = lastPersonalMatrixId;
users[referrer].personalMatrixFills++;
lastPersonalMatrixId++;
}
}
function payRegDividends(address user) private {
emit Transfer(user, users[user].id, REGISTRATION_COST);
address(uint160(user)).transfer(REGISTRATION_COST);
}
function updateBinaryMatrix(address user) private {
positionsByAddress[user][positionsByAddressCnt[user]] = lastBinaryId;
positionsByAddressCnt[user]++;
binaryPositionsLevels[lastBinaryId] = 1;
binaryUsers[lastBinaryId] = user;
lastBinaryId++;
uint div = 1;
uint level = 0;
uint initIndex = lastBinaryId-1;
uint index = lastBinaryId-1;
while (level < 5) {
level++;
div *= 2;
if (index % div == div - 1) {
index = index / div;
if (index != 0) {
binaryPositionsLevels[index] = level;
fillLevel(binaryUsers[index], level);
} else {
return;
}
} else {
return;
}
}
index = initIndex;
while (level < 10) {
level++;
div *= 2;
if (index % div == div - 1) {
index = index / div;
if (index != 0) {
binaryPositionsLevels[index] = level;
fillLevel(binaryUsers[index], level);
} else {
return;
}
} else {
return;
}
}
}
function fillLevel(address user, uint level) private {
emit LevelFilled(user, users[user].id, level);
level = level + 1;
uint payment = LEVEL_PRICE[level - 1] * LEVEL_SLOTS[level - 1];
if (users[user].levelsOpen < level) {
users[user].levelsOpen++;
emit LevelUpgraded(user, users[user].id, level);
}
payment -= LEVEL_PRICE[level];
payment -= REGISTRATION_COST * EXTRA_SLOTS[level-1];
if (level > 2) {
emit Transfer(user, users[user].id, payment);
address(uint160(user)).transfer(payment);
}
uint i = 0;
while (i < EXTRA_SLOTS[level-1]) {
updateBinaryMatrix(user);
i++;
}
}
function bytesToAddress(bytes memory bys) private pure returns (address addr) {
assembly {
addr := mload(add(bys, 20))
}
}
}
{
"compilationTarget": {
"Matrix.sol": "Matrix"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"binaryPositionsLevels","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"EXTRA_SLOTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"referrer","type":"address"}],"name":"reg","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"lastUserId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"positionsByAddress","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"usersById","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastPersonalMatrixId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"binaryUsers","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"user","type":"address"}],"name":"isUserExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"purchasePosition","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"LEVEL_PRICE","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"LEVEL_SLOTS","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"users","outputs":[{"name":"id","type":"uint256"},{"name":"referrer","type":"address"},{"name":"personalMatrixCnt","type":"uint256"},{"name":"personalMatrixNum","type":"uint256"},{"name":"personalMatrixFills","type":"uint256"},{"name":"totalReferrals","type":"uint256"},{"name":"levelsOpen","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"positionsByAddressCnt","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastBinaryId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"ownerAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":true,"name":"referrer","type":"address"},{"indexed":true,"name":"userId","type":"uint256"},{"indexed":false,"name":"referrerId","type":"uint256"}],"name":"Registration","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":true,"name":"userId","type":"uint256"},{"indexed":true,"name":"level","type":"uint256"}],"name":"LevelUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":true,"name":"userId","type":"uint256"},{"indexed":true,"name":"level","type":"uint256"}],"name":"LevelFilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":true,"name":"userId","type":"uint256"},{"indexed":true,"name":"amount","type":"uint256"}],"name":"Transfer","type":"event"}]