채굴 가능한 토큰(mineable token), ERC918
이더리움의 ERC20 스펙을 통해서 토큰을 만드는 것이 성행하게 되면서, 암호화폐 세계에서 대부분의 토큰 분배방식이 ICO, Initial Coin Offering의 형태로 진행되고 있습니다.
ICO의 프로세스에 대해서 코드레벨로 설명 드리자면 이렇습니다.
(1) 토큰 창업자 팀이 OpenZeppelin 깃허브에 있는 ERC20 코드 스펙을 가져온다.
(2) (1)에서 가져온 ERC20 코드를 상속받은 후 totalSupply(총 발행량), 토큰의 이름등을 설정해준다.
위 코드는 ERC20 토큰 중 하나인 QASH의 예입니다. 프로그래밍을 모르더라도 영어 단어들만 보면 쉽게 이해할 수 있습니다. 전체 다 볼 필요없이, 드래그 되어있는 부분들만 보면 됩니다.
-----
contract QASHToken ...
- "위 코드는 QASHToken 이라고 하는 이름의 스마트 컨트랙트 코드입니다."
string public name;
- "name 이라는 이름에 곧 제가 정할 토큰의 이름이 들어갈 것입니다. 아직은 값이 없습니다."
uint8 public decimals;
- "decimals 라는 이름에 곧 제가 정할 토큰의 자리수가 들어갈 것입니다. 아직은 값이 없습니다."
string public symbol;
- "symbol이라는 이름에 곧 제가 정할 토큰의 symbol, (예를들면 BTC, ETH 같은) 이 들어갈 것입니다. 아직은 값이 없습니다."
balances[msg.sender] = _totalSupply
- 이 컨트랙트를 이더리움 블록체인에 배포한 사람(balances[msg.sender])에게 _totalSupply에 설정된 모든 토큰을 할당해줍니다.
totalSupply = _totalSupply
- 이 컨트랙트의 totalSupply를 _totalSupply에 정한 값으로 설정합니다.
name = _name;
- 이 컨트랙트의 name을 _name에 정한 값으로 설정합니다.
symbol = _symbol;
- 이 컨트랙트의 symbol을 _symbol에 정한 값으로 설정합니다.
decimals = _decimals;
- 이 컨트랙트의 decimals를 _decimals에 정한 값으로 설정합니다.
-----
아마, 이 QASHToken 이라는 컨트랙트를 만들어서 이더리움 블록체인에 배포한 사람은, 이런 방식으로 배포했을 것입니다.
-----
QASHToken(
1000000000 // 토큰 총 발행량 (_totalSupply)
'QASH Token' // 이 토큰의 이름 QASH
'QASH' // 이 토큰의 Symbol
6 // 이 토큰의 자리 수
)
-----
보시면 아시겠지만, 이렇게 해서 결국 10억개의 QASH Token이 만들어진 것입니다. 그리고 만들어진 QASH Token의 모두는 일단 이 컨트랙트를 만든사람에게 할당되었습니다.
토큰이 만들어지는게 정말 별 것 없습니다. 마치 성경에서 "빛이 있으라!" 하면 빛이 생기는 그런 느낌이죠
다시 ICO의 프로세스로 돌아와서..
(3) 크라우드 세일 시작
현재 컨트랙트 배포자에게 있는 10억개의 토큰을 크라우드 세일할 수 있는 컨트랙트를 만듭니다. 보통 ICO하는 홈페이지들에 1ETH = 14730 QASH 이런 식으로 적혀있는데요, 이 뜻은, 말 그대로 "이 크라우드 세일 컨트랙트에 1ETH를 보내면 14730 QASH를 주겠다." 라는 뜻입니다.
크라우드 세일 참여자는 자기가 원하는 만큼의 토큰을 이더리움을 통해서 받아가게 되고, 이 이더리움은 일단 크라우드 세일 컨트랙트에 보내지게 됩니다. 그리고 그 크라우드 세일 컨트랙트에 들어있는 모든 잔액은 역시 컨트랙트의 주인이 출금할 수 있는 형태입니다.
바로 이 지점에서 많은 사건 사고들이 생기는데요.
1) 먹튀
흔히 볼 수 있는 사고는 먹튀사고입니다. 크라우드 세일 컨트랙트에 이더리움을 보내서 내가 이에 해당하는 토큰을 받았는데, 실제 ICO 진행하는 팀이 진지하게 프로젝트를 하는 팀이 아니라 단순히 이더리움만 받기 위해서 그럴싸한 홈페이지를 만들거나 한 경우죠, 이 때 세일 참여자는 1이더리움에 해당하는 만큼의 xxxx 양의 토큰을 대신 받았지만 사실상 그 토큰은 전혀 의미없는 토큰이 되는 경우입니다.
2) 컨트랙트 주소 사기
안타까운 경우인데, 실제 프로젝트 진행하는 ICO팀이 성실하게 일을 하려는 팀인데, Slack이나 트위터, 텔레그램 등의 채널에 "이 크라우드 세일의 컨트랙트 주소는 ~~~입니다" 라고 잘못 퍼트려서 실제 크라우드 세일 컨트랙트의 주소로 돈을 보내는게 아니라 전혀 팀과 관계없는 사람의 주소로 돈을 보내게 되어서 사기를 당하는 경우입니다. 이 때 세일 참여자는 전혀 프로젝트와 관계없는 사람에게 그냥 돈을 줘버린것입니다. 스마트 컨트랙트 상의 보이스피싱같은 것이죠.
3) 토큰 보유자 비율 조작
이 경우는 고객들에게 직접적인 피해를 주는 사기는 아닙니다만, ICO 홈페이지에 보면 Token Distribution이라고 토큰분배비율에 대해서 적어놓은 것이 있습니다. 양심적이게 보이기 위해서 "우리 팀은 토큰 분배비율중 적은 양만 가져간다" 라는 식으로 파이 그래프를 적어놓는 팀들이 있고, 그 외에는 커뮤니티에 대부분 분배한다~ 등등의 말을 적어놓는 경우가 있는데요.
뭐 Team 10%, Community 40%, Public Sale 30%, Partnership 20% 보통 이런 형태로 적어놓습니다.
하지만, 위에서 봤듯이 처음 토큰이 생성될 때 모든 토큰의 양이 컨트랙트 배포자에게 가기 때문에, 사실 팀에서 직접 여러 계정을 만들어서 그 계정에 각각 40%, 20%, 10%에 해당하는 비율의 토큰을 보내놓아서 결국 etherscan에서 조회했을 때, 토큰 보유자들의 비율이 한 곳에 치중되어있지 않게끔 보이게 할 수 있습니다. 그런데 사실 그 '토큰 보유자'라고 되어있는 주소들은 사실 한 사람의 주소일 수 있는 것인 상황입니다.
이렇게 대부분의 ICO 방식에서는 이런 크고 작은 사건 사고들이 발생합니다. 그렇다면 이런 조금 위험한 분배방식 말고 다른 분배방식은 없을까요?
기존 ICO 방식에 우려를 하는 사람들에게서 요즘 인기를 얻고 있는 방식으로 IMO라는 분배방식이 있습니다. Initial Mining Offering이라는 방식으로, 말 그대로 '채굴'을 통해서 토큰을 분배하는 방식입니다.
'채굴'이란 쉽게 말해서, "어떤 문제를 풀고, 그 문제를 푼 것에 대한 보상을 준다" 라고 이해하면 됩니다.
그렇다면 "채굴을 통해서 토큰을 분배하는 방식"이라 함은, "어떤 문제를 풀고, 그 문제를 푼 것에 대한 보상으로 X 토큰을 준다." 라고 이해할 수 있습니다.
별 거 아닌 것 처럼 보이지만, 기존 ICO와 비교해서 분배방식의 색다른 변화를 가져올 수 있습니다.
위에서 본 것 처럼 ICO의 경우는 "토큰이 있으라!" 하면 토큰이 그냥 생기는 구조고 정말 잘 되면 너무 쉽게 돈을 벌 수 있는 구조입니다. 또, ICO 컨트랙트를 만든 배포자에게 너무나 큰 권한이 부여되죠.
하지만 IMO는 조금 다릅니다. "토큰이 있으라!" 방식이 불가능합니다.
"토큰이 있으라!" 라고 하려면 문제를 풀고 정답을 맞춰야 합니다. 이 말은 즉, 토큰 컨트랙트를 만든 사람도 자기가 토큰을 전부 가져갈 수가 없다는 말이 됩니다. 문제를 풀어야 하기 때문이죠.
바로 이런 IMO 분배방식을 채택한 토큰을 ERC 918 토큰이라고 부릅니다.
위에서 보시는 사진은 ERC918 토큰의 스펙입니다. 그냥 단순 '그림'으로서 감상하시면 되고, 우리가 볼 것은 mint라고 되어있는 함수만 보면 됩니다.
여기서 말하는 mint란 "화폐를 주조하다"라는 뜻의 그 mint입니다. 즉 토큰을 발행한다는 것입니다.
여기서도 역시 드래그 되어있는 부분만 보면 되는데요, 보통의 '채굴'에서 문제를 푸는 방식은 결국 'nonce'라고 하는 랜덤한 임의의 값을 마구 집어넣어서 이게 정답인지 확인하는 방식으로 문제를 풉니다.
즉, 문제를 풀 고 정답을 제출할 때 , 문제의 정답란에 쓰는 값이 'nonce' 값인 것이죠. 틀리면 지우개로 지우고 또 다시 다른 값을 넣어서 정답을 제출하는 구조입니다.
그럼 위의 사진에서 드래그 된 부분을 각각 보겠습니다.
------
hash(nonce)
- "nonce라는 값을 문제의 정답란에 제출한다." 라는 뜻입니다.
uint rewardAmount = _reward();
- 문제를 맞춘 보상으로 얼만큼의 토큰을 줄지를 결정합니다.
tokensMinted += rewardAmount;
- 결국 문제를 맞춘 사람이 보상을 받았다는 것은, 발행된 토큰의 총량이 증가했다는 것을 의미하기 때문에 그 만큼의 값을 채워넣어 줍니다.
------
즉 위의 사진은 앞서 말했던 "문제를 풀고 보상으로 토큰을 가져간다" 라는 뜻의 문장을 단순히 코드로 써놓은 것 뿐입니다.
그렇다면 의문이 드는 지점이 있습니다. 도대체 어떤 문제를 푸는 것인지?
ERC918의 문제는 위에서 보는 것과 같습니다.
(1) nonce값,
(2) 문제를 푸는 사람의 이더리움 주소,
(3)현재 이더리움의 블락넘버
(1), (2), (3)을 수학적으로 조합(keccak256 해쉬)해서 'difficultyTarget' 이라고 되어있는 값보다 작게 나오면 정답
이런 방식의 문제입니다.
(이 문제를 당연히 사람이 푸는게아니라 컴퓨터, 그중에서도 특히 그래픽카드나 ASIC이 대신해서 풀어줍니다.)
이렇게 실제 ERC918의 코드를 보면서 새로운 분배방식을 알아봤는데요. 채굴을 통해 토큰이 발행되고~ 무슨 nonce를 정답으로 제출하고~ 어려운 말 같지만 결국 ERC918이 하려는 말은 간단합니다. "토큰을 발행하려면 일을 해라."
현재 ERC918 스펙을 채택한 토큰은 2018년 6월 6일 기준 5개 입니다.
(0xBTC, 0xCATE, 0xZibit, RamenCoin, 0xDogecoin)
그 중 가장 활발한 프로젝트인 0xBTC에서 한 말은 다음과 같습니다.
You can fake email address,
You can fake account holders,
You can (even) fake people,
But, you can't fake hashpower.
해쉬파워는 속일 수 없다.
앞으로 토큰 분배방식에 어떤 변화가 일어날지 기대됩니다. :)
// Q & A
Q. mint 함수가 결국 '문제를 푸는' 함수인데, 그럼 문제 풀 때마다 트랜잭션을 계속 날려야 하나?
A. ERC918의 mint 함수는 실제로 문제를 풀 때 사용하는 것이 아닙니다.
실제로 문제를 풀 때 mint 함수를 호출하면 계속해서 그 transaction fee를 지불해야하기때문에 문제를 풀 때마다 일정량의 돈을 낸다는 뜻이 됩니다.
그럴 필요없이, ERC918에서 푸는 문제는 위의 사진에서 볼 수 있듯이 결국,
```
keccak256(nonce, minerEtherAddress, challengeNumber) < difficultyTarget
```
만 풀면되기때문에, 블록체인 바깥(오프체인)에서 충분히 풀 수 있는 문제입니다.
따라서 오프체인에서 문제를 풀고 진짜 정답을 찾았을 때 비로소 mint 함수에 정답 nonce값을 넣는 방식으로 해서 transaction fee는 정말 문제를 풀었을 때 한 번만 내면 되는 구조로 사용하실 수 있습니다. :)
실제로 0xbitcoin 마이닝에 관심있으신 분들은 0xbitcoin-miner 깃허브를 참조하시면 됩니다.