풀이

일단 solve() 함수를 살펴보면

function solve(uint256 _gameId) external payable {
    uint256 _userLevel = getUserLevel((tx.origin), _gameId);
    require(_userLevel == 2, "not max level");
    require(msg.value >= 1e18, "mint price is 1 eth");
    solved = 1;
}

다음과 같이 2가지 조건을 통과해야 문제를 풀 수 있다

  1. level == 2
  2. 1이더 이상 보유

근데 문제에서 준 주소의 밸런스를 확인해보면 10이더를 제공해준다. 따라서 level == 2 를 달성하는데 포커스를 둔다

function levelUp(uint256 _gameId) external {
    UserInfo storage user = users[msg.sender];
    uint256 _userLevel = user.level[_gameId];
    _isMaxLevel(_userLevel);
    uint256 _userExp = user.exp[_gameId];
    uint256 _userExpCap = user.expCap;

    require(_userExp >= _userExpCap, "not enough exp");

    user.level[_gameId] += 1;
    user.exp[_gameId] = _userExp - _userExpCap;
    user.expCap = _getLevelExpCap(_userLevel + 1);
}

levelUp 하는 함수를 살펴보면 exp가 필요한 것을 확인할 수 있다.

exp를 올릴 수 있는 방법을 찾아보자

function addNGReferral(address _referral) external {
    UserInfo storage user = users[msg.sender];
    require(!user.ng_referral[_referral], "already referral");
    uint256 _activeUser = _isEligible(_referral);
    int256 _rb;
    assembly {
        if extcodesize(_referral) { revert(0, 0) }
        switch _activeUser
        case 0 { _rb := sub(0, 1) }
        default { _rb := add(0, 1) }
    }
    user.ng_referralBonus += _rb;
}

addNGReferral() 함수를 살펴보면 assembly 쪽에서 _activeUser 의 값을 0으로 만들면 _rb를 -1로 만들 수 있는 것을 확인했다

function _isEligible(address _user) internal view returns (uint256) {
    return payable(_user).balance >= 1e18 ? 0 : 1;
}

_isEligible() 함수를 살펴보면 이더가 1개 이상있을경우 0을 반환한다. 근데 문제에서 10이더를 제공해주기 때문에 이 값을 0이 반환되고 최종적으로 _rb == 1 이 될 것이다.

그 후, feed() 함수를 호출하고

function feed(uint256 _gameId) external actionTotalValidation(_gameId) {
    UserInfo storage user = users[msg.sender];
    GameInfo storage game = user.games[_gameId];
    uint256 _userLevel = user.level[_gameId];

    require(!_isActionEnable(_gameId), "only one feed per round");

    game.actionGuage -= 1;
    user.exp[_gameId] += calculateActionExp(_userLevel, GameAction.Feed, 0);
    game.actionEnable = true;
    game.curAction = GameAction.Feed;
}