블록체인2017.07.11 15:06


코인 사용하기


토큰을 배포하면 토큰 목록에 추가되고 총 잔액이 계정에 표시된다. 토큰을 보내려면 보내기 탭으로 이동하여 토큰이 포함 된 계정을 선택하라. 계정에있는 토큰은 이더 아래에 나열된다. 그들을 선택하고 보내려는 토큰의 양을 입력하라.

다른 사람의 토큰을 추가하려면 계약 탭으로 이동하여 토큰보기를 클릭하라. 예를 들어, 감시 목록에 Unicorn (🦄) 토큰을 추가하려면 주소 0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7을 추가하기 만하면 나머지 정보가 자동으로로드된다. 확인을 클릭하면 토큰이 추가된다.

유니콘 토큰은 Ethereum Foundation이 관리하는 주소 0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359에 기부 한 사람들을 위해 독점적으로 만들어지는 기념품이다. 이에 대해 더 알고 싶다면 여기를 읽어보아라.


이더리움으로 토큰을 발행하는 방법을 배웠다. 원하는 토큰을 만들 수 있다. 하지만 토큰으로 무엇을 할 수 있을까? 회사의 주식이 가능합니다. 또한 중앙위원회를 사용하여 인플레이션을 제어하기 위해 새로운 동전을 ㅂ라행 할 시기에 투표할 수 있다. 또한 crowdsale을 통해 어떤문제를 위해 돈을 모으기 위해 사용가능 하다. 다음엔 무엇을 만들래?

신고
Posted by 삼스
블록체인2017.07.11 14:54

전체 코드


pragma solidity ^0.4.2;

contract owned {

    address public owner;


    function owned() {

        owner = msg.sender;

    }


    modifier onlyOwner {

        if (msg.sender != owner) throw;

        _;

    }


    function transferOwnership(address newOwner) onlyOwner {

        owner = newOwner;

    }

}


contract tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); }


contract token {

    /* Public variables of the token */

    string public standard = 'Token 0.1';

    string public name;

    string public symbol;

    uint8 public decimals;

    uint256 public totalSupply;


    /* This creates an array with all balances */

    mapping (address => uint256) public balanceOf;

    mapping (address => mapping (address => uint256)) public allowance;


    /* This generates a public event on the blockchain that will notify clients */

    event Transfer(address indexed from, address indexed to, uint256 value);


    /* Initializes contract with initial supply tokens to the creator of the contract */

    function token(

        uint256 initialSupply,

        string tokenName,

        uint8 decimalUnits,

        string tokenSymbol

        ) {

        balanceOf[msg.sender] = initialSupply;              // Give the creator all initial tokens

        totalSupply = initialSupply;                        // Update total supply

        name = tokenName;                                   // Set the name for display purposes

        symbol = tokenSymbol;                               // Set the symbol for display purposes

        decimals = decimalUnits;                            // Amount of decimals for display purposes

    }


    /* Send coins */

    function transfer(address _to, uint256 _value) {

        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough

        if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows

        balanceOf[msg.sender] -= _value;                     // Subtract from the sender

        balanceOf[_to] += _value;                            // Add the same to the recipient

        Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place

    }


    /* Allow another contract to spend some tokens in your behalf */

    function approve(address _spender, uint256 _value)

        returns (bool success) {

        allowance[msg.sender][_spender] = _value;

        return true;

    }


    /* Approve and then communicate the approved contract in a single tx */

    function approveAndCall(address _spender, uint256 _value, bytes _extraData)

        returns (bool success) {    

        tokenRecipient spender = tokenRecipient(_spender);

        if (approve(_spender, _value)) {

            spender.receiveApproval(msg.sender, _value, this, _extraData);

            return true;

        }

    }


    /* A contract attempts to get the coins */

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {

        if (balanceOf[_from] < _value) throw;                 // Check if the sender has enough

        if (balanceOf[_to] + _value < balanceOf[_to]) throw;  // Check for overflows

        if (_value > allowance[_from][msg.sender]) throw;   // Check allowance

        balanceOf[_from] -= _value;                          // Subtract from the sender

        balanceOf[_to] += _value;                            // Add the same to the recipient

        allowance[_from][msg.sender] -= _value;

        Transfer(_from, _to, _value);

        return true;

    }


    /* This unnamed function is called whenever someone tries to send ether to it */

    function () {

        throw;     // Prevents accidental sending of ether

    }

}


contract MyAdvancedToken is owned, token {


    uint256 public sellPrice;

    uint256 public buyPrice;


    mapping (address => bool) public frozenAccount;


    /* This generates a public event on the blockchain that will notify clients */

    event FrozenFunds(address target, bool frozen);


    /* Initializes contract with initial supply tokens to the creator of the contract */

    function MyAdvancedToken(

        uint256 initialSupply,

        string tokenName,

        uint8 decimalUnits,

        string tokenSymbol

    ) token (initialSupply, tokenName, decimalUnits, tokenSymbol) {}


    /* Send coins */

    function transfer(address _to, uint256 _value) {

        if (balanceOf[msg.sender] < _value) throw;           // Check if the sender has enough

        if (balanceOf[_to] + _value < balanceOf[_to]) throw; // Check for overflows

        if (frozenAccount[msg.sender]) throw;                // Check if frozen

        balanceOf[msg.sender] -= _value;                     // Subtract from the sender

        balanceOf[_to] += _value;                            // Add the same to the recipient

        Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place

    }



    /* A contract attempts to get the coins */

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {

        if (frozenAccount[_from]) throw;                        // Check if frozen            

        if (balanceOf[_from] < _value) throw;                 // Check if the sender has enough

        if (balanceOf[_to] + _value < balanceOf[_to]) throw;  // Check for overflows

        if (_value > allowance[_from][msg.sender]) throw;   // Check allowance

        balanceOf[_from] -= _value;                          // Subtract from the sender

        balanceOf[_to] += _value;                            // Add the same to the recipient

        allowance[_from][msg.sender] -= _value;

        Transfer(_from, _to, _value);

        return true;

    }


    function mintToken(address target, uint256 mintedAmount) onlyOwner {

        balanceOf[target] += mintedAmount;

        totalSupply += mintedAmount;

        Transfer(0, this, mintedAmount);

        Transfer(this, target, mintedAmount);

    }


    function freezeAccount(address target, bool freeze) onlyOwner {

        frozenAccount[target] = freeze;

        FrozenFunds(target, freeze);

    }


    function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {

        sellPrice = newSellPrice;

        buyPrice = newBuyPrice;

    }


    function buy() payable {

        uint amount = msg.value / buyPrice;                // calculates the amount

        if (balanceOf[this] < amount) throw;               // checks if it has enough to sell

        balanceOf[msg.sender] += amount;                   // adds the amount to buyer's balance

        balanceOf[this] -= amount;                         // subtracts amount from seller's balance

        Transfer(this, msg.sender, amount);                // execute an event reflecting the change

    }


    function sell(uint256 amount) {

        if (balanceOf[msg.sender] < amount ) throw;        // checks if the sender has enough to sell

        balanceOf[this] += amount;                         // adds the amount to owner's balance

        balanceOf[msg.sender] -= amount;                   // subtracts the amount from seller's balance

        if (!msg.sender.send(amount * sellPrice)) {        // sends ether to the seller. It's important

            throw;                                         // to do this last to avoid recursion attacks

        } else {

            Transfer(msg.sender, this, amount);            // executes an event reflecting on the change

        }               

    }

}


배포


아래로 스크롤하면 배포에 드는 예상 비용이 표시된다. 원한다면 작은 수수료를 설정하도록 슬라이더를 변경할 수 있지만 가격이 평균 시장 가격보다 너무 낮으면 거래가 성사되는데 더 오래 걸릴 수 있다. 배포를 클릭하고 암호를 입력한다. 몇 초 후에 대시 보드로 리디렉션되고 최신 트랜잭션에 "계약 생성"이라고 표시된다. 누군가가 거래를 선택하기까지 잠깐 기다리면 얼마나 많은 다른 노드가 거래를보고 확인했는지 나타내는 푸른 색 직사각형이 보일 것이다. 확인 사항이 많을수록 코드가 배포되었음을 확신 할 수 있다. 



Admin 페이지 링크를 클릭하면 새로 만든 통화로 원하는 모든 것을 할 수있는 세계에서 가장 간단한 중앙 은행 대시 보드를 이용할 수 있다.

계약서 읽기 아래 왼쪽에는 무료로 계약 정보를 읽을 수있는 모든 옵션과 기능이 있다. 토큰에 소유자가 있으면 여기에 주소가 표시된다. 해당 주소를 복사하여 잔액에 붙여 넣으면 모든 계정의 잔액이 표시된다 (잔액은 토큰이있는 계정 페이지에도 자동으로 표시됨).

오른쪽 계약서에 쓰기에서 어떤 방식으로든 블록 체인을 변경하거나 변경할 수있는 모든 기능을 볼 수 있다. 이것들은 가스를 소비 할 것이다. 새로운 동전을 만들 수있는 계약을 만든 경우 "민트 토큰"이라는 기능이 있어야한다. 그것을 선택한다.



새 통화가 생성 될 주소를 선택한 다음 금액을 입력한다 (소숫점이 2로 설정된 경우 금액 뒤에 2 개의 숫자를 추가하여 정확한 수량을 생성한다). 선택에서 소유자로 설정된 계정을 실행하고 이더 금액을 0으로두고 실행을 누른다.

몇 가지 확인 후 수취인 잔액은 새로운 금액을 반영하도록 업데이트된다. 그러나 수령인 지갑에 자동으로 표시되지 않을 수 있다. 사용자 정의 토큰을 인식하려면 지갑을 수동으로 감시 목록에 추가해야 한다. 토큰 주소를 복사한다 (관리자 페이지에서 사본 주소를 누르면된다). 아직 계약 탭으로 이동하지 않았다면 시계 토큰을 누른 다음 주소를 추가한다. 표시되는 이름, 기호 및 십진수는 최종 사용자가 사용자 정의 할 수 있다. 특히 비슷한 (또는 동일한) 이름을 가진 다른 토큰이있는 경우에 유용합니다. 기본 아이콘은 변경 가능하지 않으므로 토큰을 보내고받을 때 주의해야 한다. 토큰을 모방하지 않으면 실제 거래를 처리 할 수 있습니다.



신고
Posted by 삼스
블록체인2017.07.07 17:49


토큰 기능 개선


암호화토큰은 코드를 만지지도 않고 바로 만들어 배포할 수 있다. 하지만 진짜 마술은 커스터마이징하면서 발생한다. 이번 장에서는 토큰에 추가 할 수있는 함수에 대한 제안을 제공하여 사용자의 필요에 더 적합하게 만든다.


중앙화된 관리자


dapp이 기본적으로 분산되어 있지만 원한다면 중앙화된 관리자를 가질수 없다는것을 의미하지는 않는다. 중앙에서 어떤 제약조건을 강제하고 싶을 수 있다. 이런 기능을 추가할 수 있으며 시작시에 추가할 수 있다 이는 모든 토큰 소유자는 게임을 소유하기로 결정하기전에 게임의 규칙을 정확하게 알 수 있다.


그러려면 화폐에 대한 중안컨트롤러가 필요하다. 이는 단순한 계정이 될수 있지만 또 한 컨트랙트로 가능하며 토큰을 생성하는데 이 컨트랙트에 따라서 결정이 되게 된다. 투표권을 부여할 수 있는 민주적단체이거나 토큰 주인에게 제한적인 능력만을 부여 할 수 있다.



contract owned {

    address public owner;


    function owned() {

        owner = msg.sender;

    }


    modifier onlyOwner {

        if (msg.sender != owner) throw;

        _;

    }


    function transferOwnership(address newOwner) onlyOwner {

        owner = newOwner;

    }

}


이것은 소유할 수 있는 계약에 대한 아주 기본적인 코드이가. 다음 단계로 컨트렉트에 추가한다.


contract MyToken is owned {

    /* the rest of the contract as usual */


이는 MyToken의 내부 어디에서든 owner와 modifier onlyOwner에 접근이 가능하다는 것을 의미한다. transferOwnership이라는 함수를 가지고 있다. 이 정보가 아주 중요하기 때문에 컨트랙트 시작시 셋업할 수 있다.


function MyToken(

    uint256 initialSupply,

    string tokenName,

    uint8 decimalUnits,

    string tokenSymbol,

    address centralMinter

    ) {

    if(centralMinter != 0 ) owner = centralMinter;


CENTERAL MINT


회전되고 있는 동전의 양이 바뀌길 원한다고 가정하자. 이것은 실제로 금괴인증서나 정부통화같은 블록체인이 아닌 자산(off blockchain asset)를 나타내며 가상 재고가 실제 재고를 반영하도록 하려는 경우이다.이는 통화보유자가 토큰 가격을 통제하기를 원하고 회전되고 있는 통화를 더 발행하거나 제거하려는 경우도 해당된다.


먼저 해야할것은 totalSuplly를 추가하고 초기화하는것이다.


contract MyToken {

    uint256 public totalSupply;


    function MyToken(...) {

        totalSupply = initialSupply;

        ...

    }

    ...

}


이제 새함수를 추가하여 소유자가 새로운 토큰을 만들수 있게 한다.


function mintToken(address target, uint256 mintedAmount) onlyOwner {

    balanceOf[target] += mintedAmount;

    totalSupply += mintedAmount;

    Transfer(0, owner, mintedAmount);

    Transfer(owner, target, mintedAmount);

}


함수명 뒤에 onlyOwner를 주의깊게 봐야한다. 이는 앞서 정의한 mofifier onlyOwner에서 상속되어 컴파일되어 재작성될것이라는것을 의미한다. 이 함수의 코드는 mofifier함수의 밑줄 부분에 삽입될것이다. 이는 이 함수가 해당 계정에 의해서만 호출되고 owner로 셋팅될것을 의미한다. 이 코드만 추가하면 더 많은 코인을 생성할 수 있다.


자산의 동결


토큰의 사용유형에 따라 사용할 수 있는 사람과 할수 없는 사람에 대한 규칙적인 제한이 필요할 수 있다. 그러려면 자산을 동결하거나 해재하는 파라메터를 컨트랙트에 추가해야 한다.


아래 변수와 함수를 아무데나 컨트랙트내에 추가한다. 아무데나 가능하지만 다른 이벤트나 매핑과 함께 배치하는게 좋다.


mapping (address => bool) public frozenAccount;

event FrozenFunds(address target, bool frozen);


function freezeAccount(address target, bool freeze) onlyOwner {

    frozenAccount[target] = freeze;

    FrozenFunds(target, freeze);

}


이 코드로 기본적으로 미동결상태인 모든 계좌를 Freeze Account를 호출함으로써 동결할 수 있다. 불행히도 동결은 아무런 효과가 없다. 왜냐하면 transfer함수에 아무것도 추가하지 않았기 때문에, 그래서 다음과 같이 해야 한다.


function transfer(address _to, uint256 _value) {

    if (frozenAccount[msg.sender]) throw;


이제 동결된 계좌는 자금은 있지만 송금은 할  수 없다. 디폴트는 미동결계좌이나 원한다면 화이트리스트를 관리하면서 원할 때 계좌를 동결할 수 있다. frozenAccount를 approvedAccount로 변경하여 적용이 가능하다.


if (!approvedAccount[msg.sender]) throw;


자동 구매 및 판매


지금까지 토큰을 평가하기 위해 유틸리티와 신뢰에 의존했다. 하지만 원한다면 자동으로 시장의 가치를 기준으로 구입하는 펀드를 만들어 토큰의 가치를 이더(또는 다른 토큰)로 뒷받침 할 수 있다.


먼저 구매와 판매가격을 셋팅한다.


uint256 public sellPrice;

uint256 public buyPrice;


function setPrices(uint256 newSellPrice, uint256 newBuyPrice) onlyOwner {

    sellPrice = newSellPrice;

    buyPrice = newBuyPrice;

}


이것은 가격에 접근가능하게 하며 자주 변하지 않는다. 이를 변경하려면 트랜잭션을 싱행하면서 이더를 소비하게 되기 때문이다. 변동가격을 일정하게 유지하려면 표준데이터피드를 참고하라.


다음은 구매와 판매함수를 작성한다.


function buy() payable returns (uint amount){

    amount = msg.value / buyPrice;                     // calculates the amount

    if (balanceOf[this] < amount) throw;               // checks if it has enough to sell

    balanceOf[msg.sender] += amount;                   // adds the amount to buyer's balance

    balanceOf[this] -= amount;                         // subtracts amount from seller's balance

    Transfer(this, msg.sender, amount);                // execute an event reflecting the change

    return amount;                                     // ends function and returns

}


function sell(uint amount) returns (uint revenue){

    if (balanceOf[msg.sender] < amount ) throw;        // checks if the sender has enough to sell

    balanceOf[this] += amount;                         // adds the amount to owner's balance

    balanceOf[msg.sender] -= amount;                   // subtracts the amount from seller's balance

    revenue = amount * sellPrice;

    if (!msg.sender.send(revenue)) {                   // sends ether to the seller: it's important

        throw;                                         // to do this last to prevent recursion attacks

    } else {

        Transfer(msg.sender, this, amount);             // executes an event reflecting on the change

        return revenue;                                 // ends function and returns

    }

}


이게 새로운 토큰을 생성하지 않고 계약주체의 잔액을 변경한다는것을 주의깊게 보아야 한다. 계약은 토큰과 이더모두 그리고 계약소유자를 보유할 수 있으나 가격을 설정하거나 유효한경우 일부 토큰을 생성한다. 이는 은행의 토큰이나 이더를 건드릴수는 없다. 이 계약에서 펀드를 이동시킬수 있는 유일한 방법은 구매나 판매을 하는것 뿐이다.


가격을 구매 및 판매하는것은 이더내에서 설정되지 않고 유로나 달라의 cent나 비트코인의 satoshi같은 단위인 wei가 있다. 1 이더는 1000000000000000000 wei(10경)이다. 따라서 이더로 토큰을 설정할때 18개의 0을 넣어야 한다. 무쟈게 많다. 10경이니..


컨트랙트를 샐성할 때 시장에있는 모든 토큰을 다시 구매할 수 있도록 충분한 양의 이더를 보내야 한다.그렇지 않으면 컨트랙트가 파산하여 사용자가 토큰을 판매 할 수 없게됩니다.


위 샘플에서는 단일 중앙구매자와 판매자간의 컨트랙트를 설명했지만 좀더 흥미롭게 다른 사람이 다른 가격을 입찰하거나 외부에서 가격을 직접로드할 수 있습니다.


자동리필


이더리움에서 트랜잭셕이 일어날때마다 채굴자에게 일정비율의 요금을 지불하게 되는데 이 값은 컨트랙트에서 계산되어진다. 순간적으로 수수료는 이더로만 지불되므로 토큰의 모든 사용자는 이더를 필요로 한다. 소유자가 필요한 비용이 지불할 수 있을 때 까지 수수료보다 적은 잔액을 가진 계좌의 토큰은 정지(stick)됩니다. 하지만 어떤 경우에는 유저가 이더리움, 블록체인 또는 이더리움을 어떻게 얻을 수 있는지 몰라도 되기를 원할 수 있다. 이 경우 한가지 가능한 접근방법은 잔액이 너무 적게되면 자동으로 채워질 수 있게 하는것이다.


이렇게 하기 위해서는 먼저 임계치값을 변수로 생성해야 하며 변경할 수 있게 해야 한다. 5 finney(0.005 ether)로 설정해보자


uint minBalanceForAccounts;


function setMinBalance(uint minimumBalanceInFinney) onlyOwner {

     minBalanceForAccounts = minimumBalanceInFinney * 1 finney;

}


그리고 transfer함수를 수정한다.


/* Send coins */

function transfer(address _to, uint256 _value) {

    ...

    if(msg.sender.balance<minBalanceForAccounts)

        sell((minBalanceForAccounts-msg.sender.balance)/sellPrice);

}


송금인이 수취인에게 수수료를 지불할 수 있도록 변경할수도 있다.


/* Send coins */

function transfer(address _to, uint256 _value) {

    ...

    if(_to.balance<minBalanceForAccounts)

        _to.send(sell((minBalanceForAccounts-_to.balance)/sellPrice));

}


이러면 토큰을 받는 계좌가 수수료를 지불하는데 필요한 이더보다 적게 수수료를 지불하지 않습니다.


작업검증


수학공식을 코인과 엮는 몇가지 방안이 있다. 가장 간단한 방법은 이더로 "병합된 광산(채굴)"로 만드는것이다. 다시 말해 이더리움에서 블록을 발견한 사람은 누구나 그 불록에 대한 보상 기능을 호출하면 코인에서 보상을 받을것이다. 블록을 찾은 광부를 지칭하는 coinbase 키워드로 이를 수행할 수 있다.


function giveBlockReward() {

    balanceOf[block.coinbase] += 1;

}


이것은 또한 수식을 추가할 수 있는데 누구든 이를 수행하면 보상에서 승리할 수 있다. 다음 예에서 당신은 포인트를 얻는 현재 도전의 큐빅루트를 계산해야 하고 다음 도전을 설정할 수 있는 권한을 얻는다.


uint currentChallenge = 1; // Can you figure out the cubic root of this number?


function rewardMathGeniuses(uint answerToCurrentReward, uint nextChallenge) {

    if (answerToCurrentReward**3 != currentChallenge) throw; // If answer is wrong do not continue

    balanceOf[msg.sender] += 1;         // Reward the player

    currentChallenge = nextChallenge;   // Set the next challenge

}


물론 계산을 누군가의 머리로 하는것은 많이 어렵지만 계산기는 아주 쉽다.그래서 이 게임은 컴퓨터로는 금방 끝난다. 또한 마지막 승자가 다음 도전을 고를수 있기 때문에 다른 플레이어에게는 공정하지 않다. 인간에게는 쉽지만 기게로는 매우 어렵지만 스크립트로 코딩하는것을 매우 어렵다. 대신에 더 공정한 시스템은 기계가 할 수 있는것은 매우 어렵지만 기계가 검증하기가 그리 어렵지는 않다. 가장 적절한 후보는 도전자가 주어진 난이도보다 낮은 해시를 찾을때 까지 여러 숫자의 해시를 생성해야 하는 해시 도전을 만드는것이다.

이 프로세스는 1997년 Adam Back에 의해 hashcash로 처음 제안되었고 2008년에 satosi nakamoto의 비트코인에서 구현되었습니다. 이더리움은 보안모델을 위해 이러한 시스템을 사용하여 출시되었지만 작업증명보안모델에서 혼합된 모델(링크탭하여 더 알아보세요)로 이동하려고 계획하고 있습니다.

해싱을 코인의 랜덤발행형태로 하려는 경우 작업방행증명이 있는 자신의 이더기반 통화를 만들수 있다.


bytes32 public currentChallenge;                         // The coin starts with a challenge

uint public timeOfLastProof;                             // Variable to keep track of when rewards were given

uint public difficulty = 10**32;                         // Difficulty starts reasonably low


function proofOfWork(uint nonce){

    bytes8 n = bytes8(sha3(nonce, currentChallenge));    // Generate a random hash based on input

    if (n < bytes8(difficulty)) throw;                   // Check if it's under the difficulty


    uint timeSinceLastProof = (now - timeOfLastProof);  // Calculate time since last reward was given

    if (timeSinceLastProof <  5 seconds) throw;         // Rewards cannot be given too quickly

    balanceOf[msg.sender] += timeSinceLastProof / 60 seconds;  // The reward to the winner grows by the minute


    difficulty = difficulty * 10 minutes / timeSinceLastProof + 1;  // Adjusts the difficulty


    timeOfLastProof = now;                              // Reset the counter

    currentChallenge = sha3(nonce, currentChallenge, block.blockhash(block.number-1));  // Save a hash that will be used as the next proof

}


생성자함수도 변경해야 한다.


    timeOfLastProof = now;


컨트랙트가 온란인상태가 되면 "작업 증명"기능을 선택하고 nonce필드에 원하는 번호르 추가하여 실행해라. 확인 창이 "데이터를 실행할 수 없습니다"라는 빨간색 경고 메시지가 나타나면 거래가 진행될때까지 다른 번호를 선택하라. 이 프로세스는 임의적이다. 하나를 찾으면 마지막 보상이 주어지기 때문에 매 순간마다 1토큰을 받게되며 도전난이도는 보상당 평균 10분을 목표로 위아래로 조정된다.

보상을 제공하는 번호를 찾으려는 이 과정을 채굴이라고 부른다. 난이도가 올라가면 숫자를 찾기가 어려울 수 있지만 발견한것을 확인하는것은 항상 쉽다.



신고
Posted by 삼스

티스토리 툴바