스마트컨트랙 폰지사기

요 근래 많은 사용자 수가 유입되고 있는 333ETH의 코드를 분석해 보자. 많은 폰지 사기들이 있어 왔지만 이렇게 코드로 확실히 그 모습을 드러내는 경우는 많지 않고 대부분 투자자를 모으지 못하고 끝나는데 333ETH는 출시된지 20일정도된 지금 상당한 자금을 모으고 있다.

컨트랙트 주소는 0x311f71389e3de68f7b2097ad02c6ad7b2dde4c71이다. 이 주소로 0.01 ETH 이상을 보내면 투자는 완료된다. 배당은 이 주소로 0ETH를 전송하면 보내준다. 아래 코드에 나와 있다.

function() public payable {
  // investor get him dividends
  if (msg.value == 0) {
    getMyDividends();
    return;
  }

  // sender do invest
  address a = msg.data.toAddr();
  address[3] memory refs;
  if (a.notZero()) {
    refs[0] = a;
    doInvest(refs); 
  } else {
    doInvest(refs);
  }
}

우선 doInvest를 살펴보자.

function doInvest(address[3] refs) public payable notOnPause balanceChanged {
  require(msg.value >= minInvesment, "msg.value must be >= minInvesment");
  require(address(this).balance <= maxBalance, "the contract eth balance limit");

  uint value = msg.value;
  // ref system works only once for sender-referral
  if (!m_referrals[msg.sender]) {
    // level 1
    if (notZeroNotSender(refs[0]) && m_investors.contains(refs[0])) {
      uint reward = m_refPercent.mul(value);
      assert(m_investors.addRefBonus(refs[0], reward)); // referrer 1 bonus
      m_referrals[msg.sender] = true;
      value = m_dividendsPercent.add(value); // referral bonus
      emit LogNewReferral(msg.sender, now, value);
      // level 2
      if (notZeroNotSender(refs[1]) && m_investors.contains(refs[1]) && refs[0] != refs[1]) { 
        assert(m_investors.addRefBonus(refs[1], reward)); // referrer 2 bonus
        // level 3
        if (notZeroNotSender(refs[2]) && m_investors.contains(refs[2]) && refs[0] != refs[2] && refs[1] != refs[2]) { 
          assert(m_investors.addRefBonus(refs[2], reward)); // referrer 3 bonus
        }
      }
    }
  }

  // commission
  adminAddr.transfer(m_adminPercent.mul(msg.value));
  payerAddr.transfer(m_payerPercent.mul(msg.value));    
  
  // write to investors storage
  if (m_investors.contains(msg.sender)) {
    assert(m_investors.addValue(msg.sender, value));
  } else {
    assert(m_investors.insert(msg.sender, value));
    emit LogNewInvestor(msg.sender, now, value); 
  }
  
  if (m_paysys.mode == Paymode.Pull)
    assert(m_investors.setPaymentTime(msg.sender, now));

  emit LogNewInvesment(msg.sender, now, value);   
  investmentsNum++;
}

앞부분은 referrall에 관한 부분으로 중요하지 않다.(추천인에게 일정 배당을 주는 것) 489, 490 라인에서 관리자가 자기꺼 먼저 챙긴다. 즉 투자자는 24시간이 지난 다음부터 0ETH를 contract로 전송해야 일 3.33%를 받지만 관리자는 투자즉시 17%를 빼간다. Admin이 10%, payer가 7%를 떼간다.

아무튼 이런식으로 돈을 떼가면 금방 자금이 바닥나게 되어 있는데 자금이 바닥날 경우를 살펴보자.

function getMyDividends() public notOnPause atPaymode(Paymode.Pull) balanceChanged {
  // check investor info
  InvestorsStorage.investor memory investor = getMemInvestor(msg.sender);
  require(investor.keyIndex > 0, "sender is not investor"); 
  if (investor.paymentTime < m_paysys.latestTime) {
    assert(m_investors.setPaymentTime(msg.sender, m_paysys.latestTime));
    investor.paymentTime = m_paysys.latestTime;
  }

  // calculate days after latest payment
  uint256 daysAfter = now.sub(investor.paymentTime).div(24 hours);
  require(daysAfter > 0, "the latest payment was earlier than 24 hours");
  assert(m_investors.setPaymentTime(msg.sender, now));

  // check enough eth 
  uint value = m_dividendsPercent.mul(investor.value) * daysAfter;
  if (address(this).balance < value + investor.refBonus) {
    nextWave();
    return;
  }

  // send dividends and ref bonus
  if (investor.refBonus > 0) {
    assert(m_investors.setRefBonus(msg.sender, 0));
    sendDividendsWithRefBonus(msg.sender, value, investor.refBonus);
  } else {
    sendDividends(msg.sender, value);
  }
}

450라인에 나와있다. 더이상 줄돈이 없게 되면 nextWave를 부른다.

function nextWave() private {
  m_investors = new InvestorsStorage();
  changePaymode(Paymode.Push);
  m_paysys.latestKeyIndex = m_investors.iterStart();
  investmentsNum = 0;
  waveStartup = now;
  m_nextWave = false;
  emit LogNextWave(now);
}

이 코드는 컨트랙트 마지막에 있다. 단순하다. 그냥 모든것을 리셋하고 다시 시작한다. 그동안 투자한 사람들은? 그동안 배당받은게 전부이고 다 날린거다.

이 컨트랙트는 나름 의미가 있다. 어느정도 성공하고 있기 때문에 폰지사기가 어떻게 끝나는지 분명한 수치로 아마도 영구히 블록체인에 기록되어 후세에 좋은 연구자료와 귀감이 될 것이다. 현재는 하루 1,000이더 정도 들어오고 500 정도 나가고 있다.

 

2 thoughts on “스마트컨트랙 폰지사기

Leave a Reply

Your email address will not be published. Required fields are marked *