[Ethernaut CTF] Naught Coin

0xDave·2022년 10월 6일
0

Ethereum

목록 보기
34/112

소스코드


// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';

 contract NaughtCoin is ERC20 {

  // string public constant name = 'NaughtCoin';
  // string public constant symbol = '0x0';
  // uint public constant decimals = 18;
  uint public timeLock = now + 10 * 365 days;
  uint256 public INITIAL_SUPPLY;
  address public player;

  constructor(address _player) 
  ERC20('NaughtCoin', '0x0')
  public {
    player = _player;
    INITIAL_SUPPLY = 1000000 * (10**uint256(decimals()));
    // _totalSupply = INITIAL_SUPPLY;
    // _balances[player] = INITIAL_SUPPLY;
    _mint(player, INITIAL_SUPPLY);
    emit Transfer(address(0), player, INITIAL_SUPPLY);
  }
  
  function transfer(address _to, uint256 _value) override public lockTokens returns(bool) {
    super.transfer(_to, _value);
  }

  // Prevent the initial owner from transferring tokens until the timelock has passed
  modifier lockTokens() {
    if (msg.sender == player) {
      require(now > timeLock);
      _;
    } else {
     _;
    }
  } 
} 

해결과제


NaughtCoin is an ERC20 token and you're already holding all of them. 
The catch is that you'll only be able to transfer them after a 10 year lockout period. 
Can you figure out how to get them out to another address so that you can transfer them freely? 
Complete this level by getting your token balance to 0.

  Things that might help

    The ERC20 Spec
    The OpenZeppelin codebase

락 걸려있는 코인 풀어서 송금하기

해결과정


Timelock 변수를 바꿀 수 있을까? lockTokens의 조건이 msg.sender == player라서 컨트랙트를 사용하면 안 될 것 같다. 그런데 tx.origin을 사용하면 컨트랙트를 사용해도 되지 않을까? --> 잘못된 접근 방법이었다. ERC20의 인터페이스를 먼저 살펴봤어야 했음.

IERC20

ERC20 토큰에서 사용 가능한 인터페이스는 위 사진에 나오는 것처럼 여러 함수와 이벤트들이 있다. 그 동안 토큰을 전송할 때 transfer만 사용하는 줄 알았는데 잘못 알고 있었다. 토큰을 전송하는 방법은 2가지다.

  1. transfer
  2. approve + transferFrom

1번은 말그대로 토큰을 단순히 전송할 때 사용한다. 2번은 토큰 소유자가 다른 계정(컨트랙트 혹은 주소)에 자신의 토큰 전송 권한을 위임한 후 전송 가능하게 하는 것이다. 흔히 유니스왑을 사용할 때 스왑하기 전에 토큰을 approve 한다는 것이 바로 이거다. 권한을 위임해야 유니스왑의 라우터가 내 소유의 토큰을 스왑할 수 있다. 그리고 transferFrom은 위임 받은 권한을 이용해 토큰을 전송할 수 있는 함수다. 이때, approve된 만큼만 전송 가능하다.

transferFrom

그렇다면 타임락이 걸린 토큰도 전송할 수 있을까? 답은 가능하다. 처음에 가능하다는 말을 듣고 머릿속이 복잡해졌다. 타임락은 애초에 효과가 없는 기능일까? 그런데 좀 더 생각해보니 핵심은 다른 곳에 있었다. 다시 소스코드를 천천히 살펴보면 현재 우리가 IERC20에서 override 해서 사용하는 함수는 transfer 뿐이다. 다르게 말해서 현재 lockTokens 조건에 제약이 걸려있는 함수는 transfer 밖에 없다는 것이다. 따라서 토큰을 전송할 수 있는 또 다른 방법인 approve + transferFrom을 사용하면 제약을 피해서 전송이 가능하다. 타임락의 효과는 제대로 작동하지만 transfer에 한해서 작동하는 것이였다.

이번 문제를 통해서 뒷통수를 쎄게 맞은 느낌이었다. 답을 봐도 이게 왜 답인지 이해가 안 됐었는데 제대로 이해하고 나니 기분이 너무 좋아졌다. 그 동안 모르고 있었던 transferFrom의 존재도 알게돼고, ERC20의 인터페이스도 살펴보면서 조금 더 이해할 수 있는 영역이 넓어진 것 같다. 아직 한참 멀었지만 그래도 기분은 좋다.

profile
Just BUIDL :)

0개의 댓글