pragma solidity ^0.4.25; contract DecentralizationSmartGames{ using SafeMath for uint256; string public constant name = "Decentralization Smart Games"; string public constant symbol = "DSG"; uint8 public constant decimals = 18; uint256 public constant tokenPrice = 0.00065 ether; uint256 public totalSupply; /* Total number of existing DSG tokens */ uint256 public divPerTokenPool; /* Trigger for calculating dividends on "Pool dividends" program */ uint256 public divPerTokenGames; /* Trigger for calculating dividends on "Games dividends" program */ uint256 private developmentBalance; /* Balance that is used to support the project and games development */ uint256 private charityBalance; /* Balance that is used for charity */ address[2] private owners; /* Addresses of the contract owners */ address[2] public candidates; /* Addresses of the future contract owners */ /**structFee public fee - Structure where all percentages of the distribution of incoming funds are stored * uint8 fee.r0 - First referrer - 6% * uint8 fee.r1 - Second referrer - 4% * uint8 fee.r2 - Third referrer - 3% * uint8 fee.r3 - Fourth referrer - 2% * uint8 fee.r4 - Fifth referrer - 1% * uint8 fee.charity - Charity - 1% * uint8 fee.development - For game development and project support - 18% * uint8 fee.buy - For buying DSG tokens - 65% */ structFee public fee = structFee(6,4,3,2,1,1,18,65); /**structDividends public totalDividends - Structure where general dividend payments are kept * uint256 totalDividends.referrer - Referrer Dividends * uint256 totalDividends.games - Games Dividends * uint256 totalDividends.pool - Pool Dividends */ structDividends public totalDividends = structDividends(0,0,0); mapping (address => mapping (address => uint256)) private allowed; /**mapping (address => structAccount) private account - Investors accounts data * uint256 account[address].tokenBalance - Number of DSG tokens on balance * uint256 account[address].ethereumBalance - The amount of ETH on balance (dividends) * uint256 account[address].lastDivPerTokenPool - The trigger of last dividend payment upon the "Pool dividends" program * uint256 account[address].lastDivPerTokenGames - The trigger of last dividend payment upon the "Games dividends" program * uint256 account[address].totalDividendsReferrer - Total amount of dividends upon the "Referrer dividends" program * uint256 account[address].totalDividendsGames - Total amount of dividends upon the "Games dividends" program * uint256 account[address].totalDividendsPool -Total amount of dividends upon the "Pool dividends" program * uint256 account[address].lastActivity - Timestamp of last activity in the contract * address[5] account[address].referrer - Array of all the referrers * bool account[address].active - True, if the account is active */ mapping (address => structAccount) private account; mapping (address => bool) private games; /* Список контрактов, от которых разрешено получать дивиденды */ struct structAccount { uint256 tokenBalance; uint256 ethereumBalance; uint256 lastDivPerTokenPool; uint256 lastDivPerTokenGames; uint256 totalDividendsReferrer; uint256 totalDividendsGames; uint256 totalDividendsPool; uint256 lastActivity; address[5] referrer; bool active; } struct structFee{ uint8 r1; uint8 r2; uint8 r3; uint8 r4; uint8 r5; uint8 charity; uint8 development; uint8 buy; } struct structDividends{ uint256 referrer; uint256 games; uint256 pool; } /* Разрешаем, если адрес не является 0х */ modifier check0x(address address0x) { require(address0x != address(0), "Address is 0x"); _; } /* Разрешаем, если на балансе токенов DSG >= amountDSG */ modifier checkDSG(uint256 amountDSG) { require(account[msg.sender].tokenBalance >= amountDSG, "You don't have enough DSG on balance"); _; } /* Разрешаем, если на балансе ETH >= amountETH */ modifier checkETH(uint256 amountETH) { require(account[msg.sender].ethereumBalance >= amountETH, "You don't have enough ETH on balance"); _; } /* Разрешаем, если функцию вызывает один из владельцев контракта */ modifier onlyOwners() { require(msg.sender == owners[0] || msg.sender == owners[1], "You are not owner"); _; } /* Разрешаем, если распродажа еще активна */ modifier sellTime() { require(now >= 1548178914, "The sale has not started"); require(now <= 1556668800, "The sale is over"); _; } /* Активируем аккаунт */ modifier activateAccount() { account[msg.sender].lastActivity = now; _; } /* Выплачиваем дивиденды по программе "Pool Dividends" */ modifier payPD(address sender) { uint256 poolDividends = getPoolDividends(); if(poolDividends > 0 && account[sender].active == true){ account[sender].totalDividendsPool = account[sender].totalDividendsPool.add(poolDividends); account[sender].ethereumBalance = account[sender].ethereumBalance.add(poolDividends); } _; account[sender].lastDivPerTokenPool = divPerTokenPool; } /* Выплачиваем дивиденды по программе "Games Dividends" */ modifier payGD(address sender) { uint256 gameDividends = getGameDividends(); if(gameDividends > 0 && account[sender].active == true){ account[sender].totalDividendsGames = account[sender].totalDividendsGames.add(gameDividends); account[sender].ethereumBalance = account[sender].ethereumBalance.add(gameDividends); } _; account[sender].lastDivPerTokenGames = divPerTokenGames; } /**Присваиваем двух основладельцев контракта, у которых рефереры являються из же адреса * Так же активием их аккаунты */ constructor(address owner2) public{ address owner1 = msg.sender; owners[0] = owner1; owners[1] = owner2; account[owner1].active = true; account[owner2].active = true; account[owner1].referrer = [owner1, owner1, owner1, owner1, owner1]; account[owner2].referrer = [owner2, owner2, owner2, owner2, owner2]; } /**buy() - функция покупки токенов DSG. * Активна только определенный промежуток времену, указаный в sellTime() * Выплачиваем дивиденды по программе Pool Dividends * Выплачиваем дивиденды по программе Games Dividends * address referrerAddress - Адрес реферера который пригласил в проект * require - Минимальная покупка 100 DSG или 0.1 ETH */ function buy(address referrerAddress) payPD(msg.sender) payGD(msg.sender) sellTime activateAccount public payable { require(msg.value > 0.1 ether, "Minimum investment is 0.1 ETH"); uint256 forTokensPurchase = msg.value.mul(fee.buy).div(100); /* 65% */ uint256 forDevelopment = msg.value.mul(fee.development).div(100); /* 18% */ uint256 forCharity = msg.value.mul(fee.charity).div(100); /* 1% */ uint256 tokens = forTokensPurchase.mul(1e18).div(tokenPrice); /* Считаем количество токенов DSG (1ETH = 1000 DSG) */ setReferrer(referrerAddress, msg.sender); /* Назначаем рефереров */ mint(msg.sender, tokens); /* Создаем новые токены DSG и начисляем на баланс */ setProjectDividends(forDevelopment, forCharity); /* Начисляем ETH на балансы проекта (18%, 1%) */ distribution(msg.sender, msg.value.mul(fee.r1).div(100), 0); /* Начисляем дивиденды первому рефереру - 6% */ distribution(msg.sender, msg.value.mul(fee.r2).div(100), 1); /* Начисляем дивиденды второму рефереру - 4% */ distribution(msg.sender, msg.value.mul(fee.r3).div(100), 2); /* Начисляем дивиденды третьему рефереру - 3% */ distribution(msg.sender, msg.value.mul(fee.r4).div(100), 3); /* Начисляем дивиденды четвертому рефереру - 2% */ distribution(msg.sender, msg.value.mul(fee.r5).div(100), 4); /* Начисляем дивиденды пятому рефереру - 1% */ emit onBuy(msg.sender, msg.value, tokens, totalSupply, now); } /**reinvest() - функция реинвестирования дивидендов. * Активна только определенный промежуток времену, указаный в sellTime() * Выплачиваем дивиденды по программе Pool Dividends - payPD(msg.sender) * Выплачиваем дивиденды по программе Games Dividends - payGD(msg.sender) * Проверяем, есть ли данное количество ETH у инвестора в контракте - checkETH(amountEthereum) * address amountEthereum - Количество ETH отправлен для реинвестирования (дивиденды) */ function reinvest(uint256 amountEthereum) payPD(msg.sender) payGD(msg.sender) checkETH(amountEthereum) sellTime activateAccount public { uint256 tokens = amountEthereum.mul(1e18).div(tokenPrice); /* Считаем количество токенов DSG (1ETH = 1000 DSG) */ mint(msg.sender, tokens); /* Создаем новые токены DSG и начисляем на баланс */ account[msg.sender].ethereumBalance = account[msg.sender].ethereumBalance.sub(amountEthereum);/* Уменшаем количество ETH у инвестора */ emit onReinvest(msg.sender, amountEthereum, tokens, totalSupply, now); } /**reinvest() - функция реинвестирования дивидендов. * Проверяем достаточно ли токенов DSG на балансе - checkDSG(amountTokens) * Выплачиваем дивиденды по программе Pool Dividends - payPD(msg.sender) * Выплачиваем дивиденды по программе Games Dividends - payGD(msg.sender) * address amountEthereum - Количество ETH отправлен для реинвестирования (дивиденды) * require - Проверяем, есть ли данное количество ETH у инвестора в контракте */ function sell(uint256 amountTokens) payPD(msg.sender) payGD(msg.sender) activateAccount checkDSG(amountTokens) public { uint256 ethereum = amountTokens.mul(tokenPrice).div(1e18);/* Считаем количество ETH (1000 DSG = 1ETH) */ account[msg.sender].ethereumBalance = account[msg.sender].ethereumBalance.add(ethereum);/* Уменшаем количество ETH у инвестора */ burn(msg.sender, amountTokens);/* Сжигаем токены */ emit onSell(msg.sender, amountTokens, ethereum, totalSupply, now); } /**withdraw() - функция вывода ETH инвестора с контракта * Выплачиваем дивиденды по программе Pool Dividends - payPD(msg.sender) * Выплачиваем дивиденды по программе Games Dividends - payGD(msg.sender) * Проверяем, есть ли данное количество ETH у инвестора в контракте - checkETH(amountEthereum) * address amountEthereum - Количество ETH запрошены для вывода */ function withdraw(uint256 amountEthereum) payPD(msg.sender) payGD(msg.sender) checkETH(amountEthereum) activateAccount public { msg.sender.transfer(amountEthereum); /* Отправляем ETH */ account[msg.sender].ethereumBalance = account[msg.sender].ethereumBalance.sub(amountEthereum);/* Уменшаем количество ETH у инвестора */ emit onWithdraw(msg.sender, amountEthereum, now); } /**gamingDividendsReception() - функция которая принимает и распределяет дивиденды по программе "Games Dividends" * require - если адрес игры не прописан в mapping games, транзакцию будет откланено */ function gamingDividendsReception() payable external{ require(getGame(msg.sender) == true, "Game not active"); uint256 eth = msg.value; uint256 forDevelopment = eth.mul(19).div(100); /* На поддержку проекта - 19% */ uint256 forInvesotrs = eth.mul(80).div(100); /* Всем держателям DSG - 80% */ uint256 forCharity = eth.div(100); /* На Благотворительность - 80% */ setProjectDividends(forDevelopment, forCharity); /* Распределяем дивиденды на поддержку проекта */ setGamesDividends(forInvesotrs); /* Распределяем игровые дивиденды */ } /**distribution() - функция распределения дивидендов по программе "Referrer Dividends" * При минимальной покупке в диапазоне от 100 до 9999 DSG * Открыт только первый уровень реферальной программы и предлагается плавающий процент, который зависит от суммы вложения. * Формула - ETH * DSG / 10000 = % * ETH - количество Ethereum, которое инвестор должен был получить, если бы баланс был >= 10000 DSG (6%) * DSG - количество токенов на балансе реферера, которому начисляются проценты. * 10000 - минимальное количество токенов, при котором открываются все процентные уровни. * Начисления со все остальных уровней идут по схеме: * - Первый уровень - плавающий процент, зависящий от суммы владения * - Второй уровень - на всех по программе "Pool dividends" * - Третий уровень - на всех по программе "Pool dividends" * - Четвертый уровень - на всех по программе "Pool dividends" * - Пятый уровень - на всех по программе "Pool dividends" * При 10000 DSG на балансе и более вся реферальная система будет активирована и инвестор получит все проценты со всех уровней * Функция автоматически проверяет баланс DSG у инвестора на момент распределения дивидендов, это значит что реферальная * программа может автоматически активироваться полностью или деактивироваться в зависимости от баланса DSG на момент распределения * address senderAddress - адрес реферала, который отправляет дивиденды своему рефереру * uint256 eth - количесто ETH которое реферер должен отправить рефереру * uint8 k - номер реферера */ function distribution(address senderAddress, uint256 eth, uint8 k) private{ address referrer = account[senderAddress].referrer[k]; uint256 referrerBalance = account[referrer].tokenBalance; uint256 senderTokenBalance = account[senderAddress].tokenBalance; uint256 minReferrerBalance = 10000e18; if(referrerBalance >= minReferrerBalance){ setReferrerDividends(referrer, eth);/* Отправляем рефереру его процент */ } else if(k == 0 && referrerBalance < minReferrerBalance && referrer != address(0)){ uint256 forReferrer = eth.mul(referrerBalance).div(minReferrerBalance);/* Считаем плавающий процент */ uint256 forPool = eth.sub(forReferrer);/* Остаток от максимального процента */ setReferrerDividends(referrer, forReferrer);/* Отправляем рефереру его процент */ setPoolDividends(forPool, senderTokenBalance);/* Начисляем дивиденды всем держателям токена DSG */ } else{ setPoolDividends(eth, senderTokenBalance);/* Если реферал 0х - Начисляем дивиденды всем держателям токена DSG */ } } /* setReferrerDividends() - функция которая отправляет рефереру дивиденды */ function setReferrerDividends(address referrer, uint256 eth) private { account[referrer].ethereumBalance = account[referrer].ethereumBalance.add(eth); account[referrer].totalDividendsReferrer = account[referrer].totalDividendsReferrer.add(eth); totalDividends.referrer = totalDividends.referrer.add(eth); } /**setReferrer() - функция которая назначает рефереров покупателю * address referrerAddress - адрес реферера который пригласил инвестора в проект * address senderAddress - адрес покупателя * Функция присваивает рефереров только один раз при покупке токенов * Рефереров нельзя больше изменить * require(referrerAddress != senderAddress) - Проверяет не является ли покупатель сам себе реферером * require(account[referrerAddress].active == true || referrerAddress == address(0)) * Проверяет существует ли реферер в проеке */ function setReferrer(address referrerAddress, address senderAddress) private { if(account[senderAddress].active == false){ require(referrerAddress != senderAddress, "You can't be referrer for yourself"); require(account[referrerAddress].active == true || referrerAddress == address(0), "Your referrer was not found in the contract"); account[senderAddress].referrer = [ referrerAddress, /* Реферер который пригласил инвестора */ account[referrerAddress].referrer[0], account[referrerAddress].referrer[1], account[referrerAddress].referrer[2], account[referrerAddress].referrer[3] ]; account[senderAddress].active = true; /* Активируем аккаунт */ emit onReferrer( senderAddress, account[senderAddress].referrer[0], account[senderAddress].referrer[1], account[senderAddress].referrer[2], account[senderAddress].referrer[3], account[senderAddress].referrer[4] ); } } /**setRefsetProjectDividendserrer() - функция выплаты дивиденов на поддержку проекта * uint256 forDevelopment - на поддержку проекта - 18% * uint256 forCharity - на Благотворительность - 1% */ function setProjectDividends(uint256 forDevelopment, uint256 forCharity) private{ developmentBalance = developmentBalance.add(forDevelopment); charityBalance = charityBalance.add(forCharity); } /**setPoolDividends() - функция равномерного распределения дивиденов всем держателям DSG по программе "Pool Dividends" * Во время распределения дивиденов в расчет не береться количество токенов которые есть на балансе покупателя, * так как он не участвует в распределения дивиденов * uint256 amountEthereum - количество ETH которое должно распределиться всем держателям DSG * uint256 userTokens - количество DSG которое есть на балансе покупателя */ function setPoolDividends(uint256 amountEthereum, uint256 userTokens) private{ if(amountEthereum > 0){ divPerTokenPool = divPerTokenPool.add(amountEthereum.mul(1e18).div(totalSupply - userTokens)); totalDividends.pool = totalDividends.pool.add(amountEthereum); } } /**setGamesDividends() - функция равномерного распределения дивиденов всем держателям DSG по программе "Games Dividends" * uint256 amountEthereum - количество ETH которое должно распределиться всем держателям DSG */ function setGamesDividends(uint256 amountEthereum) private{ if(amountEthereum > 0){ divPerTokenGames = divPerTokenGames.add(amountEthereum.mul(1e18).div(totalSupply)); totalDividends.games = totalDividends.games.add(amountEthereum); } } /**setGame() - функция добавления нового адреса игрового контракта, от которого можно принимать дивиденды * address gameAddress - адрес игрового контракта * bool active - если TRUE, тогда принимаются дивиденды */ function setGame(address gameAddress, bool active) onlyOwners public returns(bool){ games[gameAddress] = active; return true; } /**getPoolDividends() - функция расчета дивидендов для инвестора по программе "Pool Dividends" * returns(uint256) - возвращает то количество ETH, которое было насчитано инвестору * и которое ему еще не были выплачены */ function getPoolDividends() public view returns(uint256) { uint newDividendsPerToken = divPerTokenPool.sub(account[msg.sender].lastDivPerTokenPool); if(newDividendsPerToken > 0){ return account[msg.sender].tokenBalance.mul(newDividendsPerToken).div(1e18); } } /**getGameDividends() - функция расчета дивидендов для инвестора по программе "Games Dividends" * returns(uint256) - возвращает то количество ETH, которое было насчитано инвестору, * и которое ему еще не были выплачены */ function getGameDividends() public view returns(uint256) { uint newDividendsPerToken = divPerTokenGames.sub(account[msg.sender].lastDivPerTokenGames); if(newDividendsPerToken > 0){ return account[msg.sender].tokenBalance.mul(newDividendsPerToken).div(1e18); } } /* getAccountData() - функция которая возвращает все данные ивестора */ function getAccountData() public view returns( uint256 tokenBalance, uint256 ethereumBalance, uint256 lastDivPerTokenPool, uint256 lastDivPerTokenGames, uint256 totalDividendsPool, uint256 totalDividendsReferrer, uint256 totalDividendsGames, uint256 lastActivity, address[5] memory referrer, bool active) { return( account[msg.sender].tokenBalance, account[msg.sender].ethereumBalance, account[msg.sender].lastDivPerTokenPool, account[msg.sender].lastDivPerTokenGames, account[msg.sender].totalDividendsPool, account[msg.sender].totalDividendsReferrer, account[msg.sender].totalDividendsGames, account[msg.sender].lastActivity, account[msg.sender].referrer, account[msg.sender].active ); } /* getContractBalance() - функция которая возвращает баланс контракта */ function getContractBalance() view public returns (uint256) { return address(this).balance; } /* getGame() - функция которая возвращает активна ли адрес игрового котракта или нет */ function getGame(address gameAddress) view public returns (bool) { return games[gameAddress]; } /* getDevelopmentBalance() - функция которая возвращает баланс который идет на поддержку проекта */ function getDevelopmentBalance() view public onlyOwners returns(uint256){ return developmentBalance; } /* getCharityBalance() - функция которая возвращает баланс которые идет на Благотворительность */ function getCharityBalance() view public onlyOwners returns(uint256){ return charityBalance; } /* getCharityBalance() - функция которая возвращает адреса всех основателей контракта */ function getOwners() onlyOwners view public returns(address, address) { return (owners[0], owners[1]); } /* getCharityBalance() - функция которая назначает будущего основателя контракта */ function transferOwnership(address candidate, uint8 k) check0x(candidate) onlyOwners public { candidates[k] = candidate; } /* getCharityBalance() - функция которая подтверждает нового основателя контракта и назначает его */ function confirmOwner(uint8 k) public { require(msg.sender == candidates[k], "You are not candidate"); owners[k] = candidates[k]; delete candidates[k]; } /* getCharityBalance() - функция вывода средств на Благотворительность */ function charitytWithdraw(address recipient) onlyOwners check0x(recipient) public { recipient.transfer(charityBalance); delete charityBalance; } /* getCharityBalance() - функция вывода средств на поддержку проекта */ function developmentWithdraw(address recipient) onlyOwners check0x(recipient) public { recipient.transfer(developmentBalance); delete developmentBalance; } /* activateAccountNow() - которая продолжает активацию аккаунта */ function activateAccountNow() activateAccount public returns(bool){ return true; } /**inactiveAccountDistribution() - функция распределения средств неактивного аккаунта всем держателям токена по програме "Pool Dividends" * Во время вызова таки функций как: buy(), reinvest(), sell(), withdraw(), activateAccountNow() обновляеться account[address].lastActivity * Если инвестор будет не активен в течении 90 дней или 7776000 секунд, основатели могут вызвать даную функцию * И распределить все средства даного аккаунта всем держателям DSG * Даная функция реализована для предотвращения заморозки средств в контракте в случаи утраты доступу к кошельку * Выплачиваем дивиденды по программе Pool Dividends - payPD(msg.sender) * Выплачиваем дивиденды по программе Games Dividends - payGD(msg.sender) * address inactiveAccount - адрес аккаунта который нужно проверить на неактивность. Если аккаунт не активен * больше 7776000 секунд или 90 дней, функция активируеться. */ function inactiveAccountDistribution(address inactiveAccount) onlyOwners payPD(inactiveAccount) payGD(inactiveAccount) public { require(now.sub(account[inactiveAccount].lastActivity) > 7776000, "Account is active"); uint256 tokens = account[inactiveAccount].tokenBalance; uint256 ethereum = account[inactiveAccount].ethereumBalance; uint256 tokensToEthereum = tokens.mul(tokenPrice).div(1e18); delete account[inactiveAccount].ethereumBalance; setPoolDividends(ethereum.add(tokensToEthereum), tokens); burn(inactiveAccount, tokens); } /* balanceOf() - функция которая возвращает количество токенов DSG на балансе (ERC20 standart) */ function balanceOf(address owner) public view returns(uint256) { return account[owner].tokenBalance; } /* allowance() - функция проверяет сколько spender может тратить токенов пользовтеля owner (ERC20 standart) */ function allowance(address owner, address spender) public view returns(uint256) { return allowed[owner][spender]; } /* transferTo() - функция отправляет токены DSG другому пользователю (ERC20 standart) */ function transferTo(address to, uint256 value) public returns(bool) { transfer(msg.sender, to, value); return true; } /* transferTo() - функция которая разрешает пользователю тратить n-количество токенов адресу spender (ERC20 standart) */ function approve(address spender, uint256 value) check0x(spender) checkDSG(value) public returns(bool) { allowed[msg.sender][spender] = value; emit Approval(msg.sender, spender, value); return true; } /* transferFrom() - функция отправляет токены с одного адреса на другой, только тому адресу, который дал разрешение (ERC20 standart) */ function transferFrom(address from, address to, uint256 value) public returns(bool) { uint256 oldValue = allowed[from][msg.sender]; require(oldValue > 0, "The value should be greater than zero"); require(oldValue <= value, "Value more than you are allowed to use"); allowed[from][msg.sender] = oldValue.sub(value); transfer(from, to, value); emit Approval(from, msg.sender, allowed[from][msg.sender]); return true; } /* transferFrom() - функция отправки токенов (ERC20 standart) */ function transfer(address from, address to, uint256 value) checkDSG(value) check0x(to) private { account[from].tokenBalance = account[from].tokenBalance.sub(value); account[to].tokenBalance = account[to].tokenBalance.add(value); emit Transfer(from, to, value); } /* transferFrom() - функция создания токенов (ERC20 standart) */ function mint(address customerAddress, uint256 value) check0x(customerAddress) private { totalSupply = totalSupply.add(value); account[customerAddress].tokenBalance = account[customerAddress].tokenBalance.add(value); emit Transfer(address(0), customerAddress, value); } /* transferFrom() - функция сжигания токенов (ERC20 standart) */ function burn(address customerAddress, uint256 value) check0x(customerAddress) private { totalSupply = totalSupply.sub(value); account[customerAddress].tokenBalance = account[customerAddress].tokenBalance.sub(value); emit Transfer(customerAddress, address(0), value); } event onBuy( address indexed customerAddress, uint256 inputEthereum, uint256 outputToken, uint256 totalSupply, uint256 timestamp ); event onSell( address indexed customerAddress, uint256 amountTokens, uint256 outputEthereum, uint256 totalSupply, uint256 timestamp ); event onReinvest( address indexed customerAddress, uint256 amountEthereum, uint256 outputToken, uint256 totalSupply, uint256 timestamp ); event onWithdraw( address indexed customerAddress, uint256 indexed amountEthereum, uint256 timestamp ); event onReferrer( address indexed customerAddress, address referrer0, address referrer1, address referrer2, address referrer3, address referrer4 ); event Transfer( address indexed from, address indexed to, uint tokens ); event Approval( address indexed tokenOwner, address indexed spender, uint tokens ); } library SafeMath { function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "Mul error"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "Div error"); uint256 c = a / b; return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "Sub error"); uint256 c = a - b; return c; } function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "Add error"); return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "Mod error"); return a % b; } }
0.4.18