Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
pragma solidity ^0.4.11;
//Глобальные переменные:
contract PreMasterNode {
// Владелец контракта
address public owner;
// Работник для ручного расчета вознаграждений
address public worker;
// start: status = true;
// stop : status = false;
// Работает контракт или нет
bool public status = false;
// Объем Зефира на ноду
uint public constant etzPerNode = 20000 * 10 ** 18;
// Вознаграждение местернод за блок
uint public constant rewardPerBlock = 1 * 10 ** 18;
// Количество мастренод
uint nodeCount = 0;
// Адреса, работающие с контрактом
address[] entries;
// Номер блока на котором были распределены награды последний раз
uint public blockOrigin;
// Номер блока на котором контракт был запущен
uint public blockStart;
// Номер блока, на котором контракт был установлен
uint public blockStop;
// Баланс владельца
uint public ownerBalance = 0;
// Общая распределенная награда
uint public accBlockReward;
// Set manualwork = true when entries. length > 300
// Флаг ручной обработки наград - рекомендуется установить, когда количество юзеров будет больше 300
bool public manualWork = false;
// manualwork state
uint public pendingPerNodeReward = 0; // Ожидаемая награда за блок для ручного распределения
uint32 public pendingEntriesStart = 0; // Индекс первого аккаунта распределения наград
uint32 public pendingEntriesEnd = 0; // Индекс последнего аккаунта распределения наград
// Описание юзера
struct user {
// Флаг регистрации
bool registered;
// Сколько у него нод
uint nodes;
// Полученная награда юзера
uint blockReward;
// Баланс
uint balance;
}
// Пользователи контракта
mapping(address => user) users;
// Логирование вывода средств и перевода
// event
event userWithdraw(address addr, uint amount);
event userCharge(address addr, uint amount, uint newBalance);
// Модификатор - только для владельца
modifier onlyOwner() {
if (msg. sender!= owner)
{
revert();
}
_;
}
// Модификатор - только для работника
modifier onlyWorker() {
if (msg. sender!= owner || msg. sender!= worker)
{
revert();
}
_;
}
// Создание контракта - первичная установка владельца и работника
function PreMasterNode() public {
owner = msg. sender;
worker = msg. sender;
}
// Получить количество нод
function getNodeCount() constant public returns (uint) {
return nodeCount;
}
// Установка нового владельца
function setOwner(address newOwner) onlyOwner public returns (address) {
owner = newOwner;
return owner;
}
// Установка нового работника
function setWorker(address newWorker) onlyOwner public returns (address) {
worker = newWorker;
return worker;
}
// Остановка контракта - доступна только если контракт работает, при остановке считаются награды за блок
function stop() onlyOwner public {
require(status);
autoRewards();
blockStop = block. number;
status = false;
}
// Сменить тип работы контракта - с ручного на автомат и обратно
function switchWorkMode() onlyOwner public {
manualWork = !manualWork;
}
// Запуск контракта - доступна только если контракт не работает
function start() onlyOwner public {
require(!status);
blockOrigin = block. number;
blockStart = blockOrigin;
blockStop = 0;
status = true;
}
function releasedRewards() constant public returns (uint) {
if (manualWork) return accBlockReward;
else return calcReward() + accBlockReward;
}
// Получить количество адресов пользователей
function getEntriesLength() constant public returns (uint) {
return entries. length;
}
// Получить информацию о пользователе. Возвращает флаг регистрации, количество нод, награду и баланс. Если выключена ручная обработка наград, еще предсказывает награду.
function getMyInfo(address addr) public constant returns (bool reg, uint myNodes, uint myReward, uint myBalance) {
user storage u = users[addr];
if (nodeCount > 0 && !manualWork) {
myReward = u. blockReward + ((calcReward() / nodeCount) * u. nodes);
if (myReward > address(this).balance) {
myReward = address(this).balance;
}
} else {
myReward = u. blockReward;
}
myBalance = u. balance;
myNodes = u. nodes;
reg = u. registered;
}
// Ручное распределение наград. Доступна только Работнику
// Не срабатывает если: 1. Баланс Владельца = 0
// 2. Выключена обработка вручную
// 4. Количество нод = 0
//
// Работает в 2 этапа:
// 1. Рассчитывает награду. Определяет награду на ноду. Инициализирует набор аккаунтов для распределения наград (от нуля до последнего аккаунта).
// 2. Пачками по 100 штук накидывает аккаунтам награду, списывает ее со счета Владельца и добавляет ее в общий распределенный пул, если она может быть списана со счета Владельца.
function manualRewards() public onlyWorker returns (bool) {
require(ownerBalance > 0 && manualWork && nodeCount > 0);
uint32 gap = pendingEntriesEnd - pendingEntriesStart;
if (gap == 0) {
uint allReward = calcReward();
blockOrigin = block. number;
pendingPerNodeReward = allReward / nodeCount;
pendingEntriesStart = 0;
pendingEntriesEnd = uint32(entries. length);
} else if (gap > 0) {
uint32 begin = pendingEntriesStart;
uint32 end = pendingEntriesEnd;
if (gap > 100) {
end = begin + 100;
pendingEntriesStart = end;
} else {
pendingEntriesStart = pendingEntriesEnd;
}
for (uint32 i = begin; i < end; i++) {
user storage u = users[entries[i]];
uint myReward = pendingPerNodeReward * u. nodes;
if (myReward > 0 && ownerBalance >= myReward)
{
ownerBalance -= myReward;
accBlockReward += myReward;
u. blockReward += myReward;
}
}
}
return true;
}
// Автоматическое распределение наград
// Не срабатывает если: 1. Баланс Владельца = 0
// 2. Включена обработка вручную
// 3. Контракт выключен
// 4. Количество нод = 0
// Рассчитывается награда. Эта награда вычитается из баланса Владельца и прибавляется к количеству общей распределенной награды.
// Рассчитывается награда на ноду. Сохраняется последний блок расчета наград. Общая награда делится между нодами юзеров.
function autoRewards() private returns (bool) {
if (ownerBalance == 0 || manualWork || !status || nodeCount == 0) return false;
uint allReward = calcReward();
ownerBalance -= allReward;
accBlockReward += allReward;
uint perNodeReward = allReward / nodeCount;
blockOrigin = block. number;
uint32 length = uint32(entries. length);
for (uint32 i = 0; i < length; i++) {
user storage u = users[entries[i]];
if (u. nodes > 0)
{
u. blockReward += perNodeReward * u. nodes;
}
}
return true;
}
// Получить баланс контракта
function getContractBalance() public constant returns (uint) {
return address(this).balance;
}
// Расчет наград
// Рассчитывается количество блоков с момента последнего подсчета. Если контракт был остановлен (поведение если не был запущен не понятно) - награда = 0
// Если контракт запущен и были блоки с последнего подсчета, и их количество меньше 5 000 000 и есть ноды, то наградой считается количество блоков, умноженное на награду за блок
// Если эта награда превышает баланс Владельца - то наградой считается баланс владельца
function calcReward() constant internal returns (uint) {
uint blockGap;
if (blockStop > 0 && blockOrigin < blockStop) {
blockGap = blockStop - blockOrigin;
} else if (blockStop > 0) {
blockGap = 0;
} else {
blockGap = block. number - blockOrigin;
}
if (status && blockGap > 0 && blockGap < 5000000 && nodeCount > 0) {
uint reward = blockGap * rewardPerBlock;
if (reward > ownerBalance) {
return ownerBalance;
} else {
return reward;
}
}
return 0;
}
// Зачисление зефира на контракт. 3 режима работы:
// А) Если плательщик = Вдаделец:
// Если перевод не нулевой - пополняется счет Владельца на эту сумму
// Иначе если номер блока больше 8 000 000, то в случае, когда контракт отключен, Владельцу возвращается его баланс с баланса контракта
// Иначе в случае выключенного контракта и наличия денег на счете Владельца, если баланс контракта меньше баланса Владельца, то с контракта выводится все деньги и размер счета Владельца уменьшается на эту сумму
// Если баланс контракта больше либо равен балансу Владельца, то с контракта выводится объем счета владельца и счет обнуляется
// Б) Если не Владелец и перевод нулевой
// Если есть ноды - автосчитаем награды. Объем для вывода = баланс пользователя + награда пользователя (если он больше баланса контракта, то объем для вывода уменьшается на баланс контракта)
// Уменьшаем общий объем нод на ноды юзера. Обнуляем юзера. И переводим ему объем для вывода с баланса контракта. Логируем, что юзер вывел такой-то объем денег
// В) Если не Владелец и перевод не нулевой
// Считаем сколько нод было у юзера согласно его балансу, считаем сколько будет нод у юзера, при новом балансе
// Если юзер не зарегистрирован и текущее количество его нод > 0, то ставим флаг регистрации
// Если количество нод увеличилось, то:
// 1. если раньше не было нод, будем считать награды с этого блока, иначе считаем награды
// 2. увеличиваем общее количество нод на новые ноды юзера и сохраняем новое количество нод юзера
// Обновляем баланс юзера и логируем юзера, сколько он перевел и его общий баланс
function() payable public {
user storage u = users[msg. sender];
if (msg. sender == owner) {
if (msg. value > 0) {
ownerBalance += msg. value;
} else if (block. number > 8000000) {
require(!status);
owner. transfer(ownerBalance);
} else {
require(!status && ownerBalance > 0);
uint maxBalance = address(this).balance;
if (maxBalance < ownerBalance) {
owner. transfer(maxBalance);
ownerBalance -= maxBalance;
} else {
owner. transfer(ownerBalance);
ownerBalance = 0;
}
}
} else if (msg. value == 0 && u. balance > 0 && nodeCount >= u. nodes) {
if (u. nodes > 0) {
autoRewards();
}
uint amount = u. balance + u. blockReward;
if (address(this).balance < amount) {
amount = address(this).balance;
}
// Set rewards
nodeCount -= u. nodes;
// Reset user data
u. nodes = 0;
u. balance = 0;
u. blockReward = 0;
// transfer
msg. sender. transfer(amount);
emit userWithdraw(msg. sender, amount);
} else if (msg. value > 0) {
uint orginNodes = u. balance / etzPerNode;
uint currentNodes = (u. balance + msg. value) / etzPerNode;
if (!u. registered && currentNodes > 0) {
u. registered = true;
entries. push(msg. sender);
}
if (currentNodes > orginNodes) {
if (nodeCount == 0) {
blockOrigin = block. number;
} else {
autoRewards();
}
nodeCount += (currentNodes - orginNodes);
u. nodes = currentNodes;
}
u. balance += msg. value;
emit userCharge(msg. sender, msg. value, u. balance);
}
}
// Возвращает список адресов юзеров. Возвращает общее количество и первые 20 адресов с номера, который был передан в параметрах
function getAddresses(uint startPos) public constant returns (uint length, address[20] data) {
length = uint(entries. length);
for (uint i = 0; i < 20 && (i + startPos) < length; i++) {
data[i] = entries[i + startPos];
}
}
}


