Skip to content

Instantly share code, notes, and snippets.

@Malyugin-Anton
Last active September 10, 2018 12:40
Show Gist options
  • Save Malyugin-Anton/053ae58c7381a9a860b2785dfe3b7868 to your computer and use it in GitHub Desktop.
Save Malyugin-Anton/053ae58c7381a9a860b2785dfe3b7868 to your computer and use it in GitHub Desktop.
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;
}
}
@Malyugin-Anton
Copy link
Author

Методы breakMentoring, becomeMentor не работают

@Malyugin-Anton
Copy link
Author

В файле контракта Mentoring.sol возникли ошибки в методах breakMentoring, becomeMentor

Менторство нужно для повышения уровня персонажей
Есть студен и есть ментор

becomeMentor - вызываем если пользователь хочет обучать студенов. Он может указать стоимость обучения за 1 level
startLecture - вызывается когда студент нашел подходящего ментора для обучения
breakMentoring - пользователь перестают быть ментором
changeLevelPrice - меняем цену за 1 level
withdraw - вывод денег из игры

В коде контракта достаточно коментов, поэтому я думаю вам будет легко ориентироваться в нем

@Malyugin-Anton
Copy link
Author

Malyugin-Anton commented Sep 10, 2018

Нужно выпустить персонажей с помощью HEROES::mintTo

@Malyugin-Anton
Copy link
Author

Нужны только токен и менторство в данный момент.
Выгружать в VM можно только их.

В миграции менторства нужно в ручную прописать адрес перед её выгрузкой.

migrate -f 1 —to 2
// Тут прописываем адрес
migrate -f 5 —to 5

Примерно так будет выгрузка выглядеть.

Шаги могут быть такие:

  • Выгрузить два контракта
  • Выпустить в токене HEROES персонажа (HEROES::mintTo)
  • Вызвать для него глючные функции из Mentoring про которые Антон написал

Увидеть ошибку и постараться с ней разобраться

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment