Last active
September 10, 2018 12:40
-
-
Save Malyugin-Anton/053ae58c7381a9a860b2785dfe3b7868 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.22; | |
import "./utils/SafeMath.sol"; | |
import "./HEROES.sol"; | |
contract Mentoring { | |
using SafeMath for uint256; | |
using SafeMath for uint32; | |
event BecomeMentor(uint256 mentorId); | |
event StartLecture(uint256 lectureId, | |
uint256 mentorId, | |
uint256 studentId, | |
uint32 levelUp, | |
uint256 levelPrice, | |
uint256 cost, | |
uint256 startedAt, | |
uint256 endsAt); | |
event BreakMentoring(uint256 mentorId); | |
event ChangeLevelPrice(uint256 mentorId, uint256 newLevelPrice); | |
event Withdraw(address to, uint256 amount); | |
struct Lecture { | |
uint256 mentorId; | |
uint256 studentId; | |
uint32 levelUp; | |
uint256 levelPrice; | |
uint256 cost; | |
uint256 startedAt; | |
uint256 endsAt; | |
} | |
address admin; | |
HEROES heroes; | |
address bank; | |
uint256 interest; | |
mapping(address => uint256) internal balances; | |
uint256 levelUpTime = 20 minutes; | |
mapping(uint256 => uint256) internal prices; | |
Lecture[] internal lectures; | |
/* tokenId => lecture index */ | |
mapping(uint256 => uint256) internal studentToLecture; | |
mapping(uint256 => uint256) internal mentorToLecture; | |
modifier onlyAdmin() { | |
require(msg.sender == admin); | |
_; | |
} | |
modifier onlyOwnerOf(uint256 _tokenId) { | |
require(heroes.ownerOf(_tokenId) == msg.sender); | |
_; | |
} | |
constructor (HEROES _heroes) public { | |
admin = msg.sender; | |
heroes = _heroes; | |
} | |
// БАНКИНГ | |
function () public payable { | |
require(bank != address(0)); | |
balances[bank] = balances[bank].add(msg.value); | |
} | |
function setBank(address _bank) external onlyAdmin { | |
require(_bank != address(0)); | |
bank = _bank; | |
} | |
/** | |
* Вывести деньги с аккаунта msg.sender | |
*/ | |
function withdraw(address _account) external { | |
require(_account != address(0)); | |
require(msg.sender == _account || msg.sender == admin); | |
uint256 balance = balances[_account]; | |
if (balance > 0) { | |
_account.transfer(balance); | |
balances[_account] = 0; | |
emit Withdraw(_account, balance); | |
} | |
} | |
/** | |
* Списать со счёта | |
*/ | |
function writeOff(address _account, uint256 _amount) | |
external | |
onlyAdmin | |
{ | |
require(balances[_account] >= _amount); | |
balances[bank] = balances[bank].add(_amount); | |
balances[_account] = balances[_account].sub(_amount); | |
} | |
/** | |
* Записать на счёт | |
*/ | |
function writeIn(address _account, uint256 _amount) | |
external | |
onlyAdmin | |
{ | |
require(balances[bank] >= _amount); | |
balances[_account] = balances[_account].add(_amount); | |
balances[bank] = balances[bank].sub(_amount); | |
} | |
/** | |
* Возвращает баланс указанного аккаунта. | |
*/ | |
function accountBalance(address _account) | |
external | |
returns (uint256) | |
{ | |
require(msg.sender == admin || msg.sender == _account); | |
return balances[_account]; | |
} | |
function _deposit(address _account, uint256 _amount) | |
internal | |
{ | |
uint256 bankInterest = _amount.div(100).mul(interest); | |
uint256 amount = _amount.sub(bankInterest); | |
balances[bank] = balances[bank].add(bankInterest); | |
balances[_account] = balances[_account].add(amount); | |
} | |
/** | |
* Устанавливает процент банка. | |
*/ | |
function setInterest(uint256 _interest) | |
external | |
onlyAdmin | |
{ | |
interest = _interest; | |
} | |
// MENTORING | |
/** | |
* Задаёт время апа одного левла | |
*/ | |
function setLevelUpTime(uint256 _newLevelUpTime) | |
external onlyAdmin | |
{ | |
levelUpTime = _newLevelUpTime; | |
} | |
/** | |
* Вернёт true если персонаж является ментором | |
*/ | |
function isMentor(uint256 _mentorId) | |
public view | |
returns (bool) | |
{ | |
uint256 lockedTo; | |
uint16 lockId; | |
(lockedTo, lockId) = heroes.getLock(_mentorId); | |
return _isMentor(lockedTo, lockId); | |
} | |
function _isMentor(uint256 _lockedTo, uint16 _lockId) | |
internal pure | |
returns (bool) | |
{ | |
return (_lockedTo == 0 && _lockId == 3); | |
} | |
/** | |
* Вернёт true если персонаж является студентом | |
*/ | |
function isStudent(uint256 _studentId) | |
public view | |
returns (bool) | |
{ | |
uint256 lockedTo; | |
uint16 lockId; | |
(lockedTo, lockId) = heroes.getLock(_studentId); | |
return _isStudent(lockedTo, lockId); | |
} | |
function _isStudent(uint256 _lockedTo, uint16 _lockId) | |
internal view | |
returns (bool) | |
{ | |
return (_lockId == 3 && now <= _lockedTo); | |
} | |
/** | |
* Вернёт true, если персонаж занят менторингом | |
*/ | |
function inMentoring(uint256 _tokenId) | |
public view | |
returns (bool) | |
{ | |
uint256 lockedTo; | |
uint16 lockId; | |
(lockedTo, lockId) = heroes.getLock(_tokenId); | |
return _inMentoring(lockedTo, lockId); | |
} | |
function _inMentoring(uint256 _lockedTo, uint16 _lockId) | |
internal view | |
returns (bool) | |
{ | |
return (_lockId == 3 | |
&& (now <= _lockedTo || 0 == _lockedTo)); | |
} | |
/** | |
* Вернёт true, если персонаж на занятии в текущий момент | |
*/ | |
function inLecture(uint256 _tokenId) | |
public view | |
returns (bool) | |
{ | |
uint256 asStudent = studentToLecture[_tokenId]; | |
uint256 asMentor = mentorToLecture[_tokenId]; | |
return ((asStudent != 0 && now <= lectures[asStudent].endsAt) | |
|| (asMentor != 0 || now <= lectures[asMentor].endsAt)); | |
} | |
/** | |
* Делает персонажа ментором, сохраняет стоимость | |
* его услуг в списке. | |
*/ | |
function becomeMentor(uint256 _mentorId, uint256 _levelPrice) | |
external onlyOwnerOf(_mentorId) | |
{ | |
require(heroes.isLocked(_mentorId) == false); | |
heroes.lock(_mentorId, 0, 3); | |
prices[_mentorId] = _levelPrice; | |
emit BecomeMentor(_mentorId); | |
emit ChangeLevelPrice(_mentorId, _levelPrice); | |
} | |
/** | |
* Меняет стоимость услуг ментора на поднятие одного уровня. | |
*/ | |
function changeLevelPrice(uint _mentorId, uint _newLevelPrice) | |
external onlyOwnerOf(_mentorId) | |
{ | |
require(isMentor(_mentorId)); | |
require(_newLevelPrice > 0); | |
prices[_mentorId] = _newLevelPrice; | |
emit ChangeLevelPrice(_mentorId, _newLevelPrice); | |
} | |
/** | |
* Останавливает менторство для персонажа-ментора. | |
*/ | |
function breakMentoring(uint _mentorId) | |
external onlyOwnerOf(_mentorId) | |
{ | |
// проверить что он ментор | |
require(inLecture(_mentorId) == false); | |
heroes.unlock(_mentorId, 3); | |
emit BreakMentoring(_mentorId); | |
} | |
/** | |
* Вернёт true, если ментор может тренировать студента. | |
*/ | |
function _raceIsSuitable(uint _mentorGenes, | |
uint _studentGenes) | |
internal pure | |
returns (bool) | |
{ | |
uint256 mentorRace = _mentorGenes & 0xFFFF; | |
uint256 studentRace = _studentGenes & 0xFFFF; | |
return (mentorRace == 1 | |
|| mentorRace == studentRace); | |
} | |
/** | |
* Вернёт уровень на который может поднять ментор | |
* конкретного студента. | |
*/ | |
function _calcLevelIncrease(uint32 _mentorLevel, | |
uint32 _studentLevel) | |
internal pure | |
returns (uint32) | |
{ | |
uint32 levelDiff = (_mentorLevel - _studentLevel); | |
return (levelDiff >> 1) + (levelDiff & 1); | |
} | |
/** | |
* Возващает полную стоимость обучения студента у | |
* конкретного ментора. | |
*/ | |
function calcCost(uint256 _mentorId, uint256 _studentId) | |
external view | |
returns (uint256) | |
{ | |
require(prices[_mentorId] != 0); | |
uint32 mentorLevel; | |
uint32 studentLevel; | |
(,,,,,,mentorLevel,,) = heroes.getCharacter(_mentorId); | |
(,,,,,,studentLevel,,) = heroes.getCharacter(_studentId); | |
return _calcCost(prices[_mentorId], | |
mentorLevel, | |
studentLevel); | |
} | |
function _calcCost(uint256 _levelPrice, | |
uint32 _mentorLevel, | |
uint32 _studentLevel) | |
internal pure | |
returns (uint256) | |
{ | |
require(1 <= (_mentorLevel - _studentLevel)); | |
uint32 levelIncrease = | |
_calcLevelIncrease(_mentorLevel, _studentLevel); | |
return levelIncrease.mul(_levelPrice); | |
} | |
function _calcEndsAt(uint256 _startsAt, | |
uint32 _mentorLevel, | |
uint32 _studentLevel) | |
internal view | |
returns (uint256) | |
{ | |
uint32 levelUp = | |
_calcLevelIncrease(_mentorLevel, _studentLevel); | |
return _startsAt + (levelUp * levelUpTime); | |
} | |
/** | |
* Запускает процесс обучения для указанного студента | |
* и ментора. | |
*/ | |
function startLecture(uint _mentorId, uint _studentId) | |
external payable onlyOwnerOf(_studentId) | |
{ | |
require(false == inLecture(_mentorId)); | |
require(false == inLecture(_studentId)); | |
require(true == isMentor(_mentorId)); | |
require(0 != prices[_mentorId]); | |
uint256 mentorGenes; | |
uint32 mentorLevel; | |
uint256 studentGenes; | |
uint32 studentLevel; | |
(mentorGenes,,,,,,mentorLevel,,) = | |
heroes.getCharacter(_mentorId); | |
(studentGenes,,,,,,studentLevel,,) = | |
heroes.getCharacter(_studentId); | |
// Check race | |
require(_raceIsSuitable(mentorGenes, studentGenes)); | |
// Конструируем структуру занятия | |
Lecture memory lecture = Lecture({ | |
mentorId: _mentorId, | |
studentId: _studentId, | |
levelUp: _calcLevelIncrease(mentorLevel, | |
studentLevel), | |
levelPrice: prices[_mentorId], | |
cost: _calcCost(prices[_mentorId], | |
mentorLevel, | |
studentLevel), | |
startedAt: now, | |
endsAt: _calcEndsAt(now, mentorLevel, studentLevel) | |
}); | |
uint256 lectureId = lectures.push(lecture); | |
studentToLecture[_studentId] = lectureId; | |
mentorToLecture[_mentorId] = lectureId; | |
for (uint32 i = 0; i < lecture.levelUp; i++) { | |
heroes.addWin(_studentId); | |
} | |
_deposit(heroes.ownerOf(_mentorId), msg.value); | |
emit StartLecture(lectureId, | |
_mentorId, | |
_studentId, | |
lecture.levelUp, | |
lecture.levelPrice, | |
lecture.cost, | |
lecture.startedAt, | |
lecture.endsAt); | |
} | |
/** | |
* Проверяет, что занятие существует | |
*/ | |
function lectureIsExists(uint256 _lectureId) | |
public view | |
returns (bool) | |
{ | |
return (_lectureId < lectures.length); | |
} | |
/** | |
* Вернёт занятие по ID | |
*/ | |
function getLecture(uint256 _lectureId) | |
external view | |
returns (uint256 mentorId, | |
uint256 studentId, | |
uint32 levelUp, | |
uint256 levelPrice, | |
uint256 cost, | |
uint256 startedAt, | |
uint256 endsAt) | |
{ | |
require(lectureIsExists(_lectureId)); | |
mentorId = lectures[_lectureId].mentorId; | |
studentId = lectures[_lectureId].studentId; | |
levelUp = lectures[_lectureId].levelUp; | |
levelPrice = lectures[_lectureId].levelPrice; | |
cost = lectures[_lectureId].cost; | |
startedAt = lectures[_lectureId].startedAt; | |
endsAt = lectures[_lectureId].endsAt; | |
} | |
/** | |
* Возвращает текущее занятие по токену. | |
*/ | |
function getCurrentLecture(uint _tokenId) | |
external view | |
returns (uint256 lectureId, | |
uint256 mentorId, | |
uint256 studentId, | |
uint32 levelUp, | |
uint256 levelPrice, | |
uint256 cost, | |
uint256 startedAt, | |
uint256 endsAt) | |
{ | |
uint256 asStudent = studentToLecture[_tokenId]; | |
uint256 asMentor = mentorToLecture[_tokenId]; | |
uint256 lastLectureId = asStudent > asMentor ? | |
asStudent : asMentor; | |
require(lectures[lastLectureId].endsAt > now); | |
lectureId = lastLectureId; | |
mentorId = lectures[lastLectureId].mentorId; | |
studentId = lectures[lastLectureId].studentId; | |
levelUp = lectures[lastLectureId].levelUp; | |
levelPrice = lectures[lastLectureId].levelPrice; | |
cost = lectures[lastLectureId].cost; | |
startedAt = lectures[lastLectureId].startedAt; | |
endsAt = lectures[lastLectureId].endsAt; | |
} | |
/** | |
* Вернёт параметры текущего занятия | |
*/ | |
function getCurrentLecture(uint _mentorId, uint _studentId) | |
external view | |
returns (uint256 levelUp, | |
uint256 levelPrice, | |
uint256 cost, | |
uint256 startedAt, | |
uint256 endsAt) | |
{ | |
uint256 asStudent = studentToLecture[_studentId]; | |
uint256 asMentor = mentorToLecture[_mentorId]; | |
require(asMentor != 0 && asStudent !=0); | |
require(asMentor == asStudent); | |
Lecture memory lecture = lectures[asMentor]; | |
require(now <= lecture.endsAt); | |
levelUp = lecture.levelUp; | |
levelPrice = lecture.levelPrice; | |
cost = lecture.cost; | |
startedAt = lecture.startedAt; | |
endsAt = lecture.endsAt; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Нужны только токен и менторство в данный момент.
Выгружать в VM можно только их.
В миграции менторства нужно в ручную прописать адрес перед её выгрузкой.
migrate -f 1 —to 2
// Тут прописываем адрес
migrate -f 5 —to 5
Примерно так будет выгрузка выглядеть.
Шаги могут быть такие:
Увидеть ошибку и постараться с ней разобраться