以太坊發幣智能合約代碼簡單介紹:
發幣代碼如下(https://ethereum.org/token#the-code網站中獲得):
pragma solidity ^0.4.16; interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; } contract TokenERC20 { // Public variables of the token string public name; string public symbol; uint8 public decimals = 18; // 18 decimals is the strongly suggested default, avoid changing it 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); // This notifies clients about the amount burnt event Burn(address indexed from, uint256 value); /** * Constructor function * * Initializes contract with initial supply tokens to the creator of the contract */ function TokenERC20( uint256 initialSupply, string tokenName, string tokenSymbol ) public { totalSupply = initialSupply * 10 ** uint256(decimals); // Update total supply with the decimal amount balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes } /** * Internal transfer, only can be called by this contract */ function _transfer(address _from, address _to, uint _value) internal { // Prevent transfer to 0x0 address. Use burn() instead require(_to != 0x0); // Check if the sender has enough require(balanceOf[_from] >= _value); // Check for overflows require(balanceOf[_to] + _value > balanceOf[_to]); // Save this for an assertion in the future uint previousBalances = balanceOf[_from] + balanceOf[_to]; // Subtract from the sender balanceOf[_from] -= _value; // Add the same to the recipient balanceOf[_to] += _value; Transfer(_from, _to, _value); // Asserts are used to use static analysis to find bugs in your code. They should never fail assert(balanceOf[_from] + balanceOf[_to] == previousBalances); } /** * Transfer tokens * * Send `_value` tokens to `_to` from your account * * @param _to The address of the recipient * @param _value the amount to send */ function transfer(address _to, uint256 _value) public { _transfer(msg.sender, _to, _value); } /** * Transfer tokens from other address * * Send `_value` tokens to `_to` on behalf of `_from` * * @param _from The address of the sender * @param _to The address of the recipient * @param _value the amount to send */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { require(_value <= allowance[_from][msg.sender]); // Check allowance allowance[_from][msg.sender] -= _value; _transfer(_from, _to, _value); return true; } /** * Set allowance for other address * * Allows `_spender` to spend no more than `_value` tokens on your behalf * * @param _spender The address authorized to spend * @param _value the max amount they can spend */ function approve(address _spender, uint256 _value) public returns (bool success) { allowance[msg.sender][_spender] = _value; return true; } /** * Set allowance for other address and notify * * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it * * @param _spender The address authorized to spend * @param _value the max amount they can spend * @param _extraData some extra information to send to the approved contract */ function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) { tokenRecipient spender = tokenRecipient(_spender); if (approve(_spender, _value)) { spender.receiveApproval(msg.sender, _value, this, _extraData); return true; } } /** * Destroy tokens * * Remove `_value` tokens from the system irreversibly * * @param _value the amount of money to burn */ function burn(uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value); // Check if the sender has enough balanceOf[msg.sender] -= _value; // Subtract from the sender totalSupply -= _value; // Updates totalSupply Burn(msg.sender, _value); return true; } /** * Destroy tokens from other account * * Remove `_value` tokens from the system irreversibly on behalf of `_from`. * * @param _from the address of the sender * @param _value the amount of money to burn */ function burnFrom(address _from, uint256 _value) public returns (bool success) { require(balanceOf[_from] >= _value); // Check if the targeted balance is enough require(_value <= allowance[_from][msg.sender]); // Check allowance balanceOf[_from] -= _value; // Subtract from the targeted balance allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance totalSupply -= _value; // Update totalSupply Burn(_from, _value); return true; } }
使用的是以太坊生態鏈提供的語言solidity
我們來分析每段代碼的用處。
contract MyToken { /* This creates an array with all balances */ mapping (address => uint256) public balanceOf; }
這段代碼建立了 地址 => 余額 關聯數組,並定義為public keyword,意思是在以太坊生態鏈中任何客戶端都可以訪問它,查詢每個地址的余額。
這部分代碼創建了一個合約,你可以立馬就公布到以太坊生態鏈中,合同會立馬生效,但沒啥用:它雖然是一個合同,可以查詢每個地址的余額--但是你並沒有在此合同中創造幣,所以查詢每一個地址都會返回0(關於這個合同)。那么我們接下來就要在此合同內補充以下代碼起到發幣的作用:
function MyToken() { balanceOf[msg.sender] = 21000000; }
請注意,函數MyToken與contract MyToken具有相同的名稱。這是非常重要的,如果您重命名一個,您也必須重命名另一個:這是一個特殊的啟動函數,它只運行一次,並且只有當契約第一次上傳到網絡時才運行 (初始化函數)。此函數第一次運行會設置發布此合約地址的余額為2100萬。
2100萬這個值可以定義為參數,定義成參數后用戶就可以在發布合約時自己根據實際應用設置幣的總額。代碼如下:
function MyToken(uint256 initialSupply) public { balanceOf[msg.sender] = initialSupply; }
至此你就可以通過上面的代碼實現發布自己的erc20幣,高興不。但並沒有卵用,因為這個幣只有你自己這個地址擁有,沒辦法發給其他的地址,意味着不能流通。接下來我們就需要讓它可以轉發。在合約代碼加入下面這個函數:
/* Send coins */ function transfer(address _to, uint256 _value) { /* Add and subtract new balances */ balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; }
這是一個非常簡單的函數:它需要兩個參數:一個接收地址i,一個金額值,當有人調用它時,它將從發送方余額中減去_value並將其添加到_to balance。現在有一個明顯的問題:如果這個人想要發送比它擁有的更多的東西會發生什么?由於我們不想在這個特殊的合同中處理債務,我們只是簡單地做一個快速檢查,如果發件人沒有足夠的資金,合同的執行就會停止。它還可以檢查溢出,避免有一個如此大的數字,使它再次變為零。
要中止合約中轉幣的執行,可以返回 或 復原。對於發送方sender來講,前者消耗的gas更少,但在以太坊生態鏈中會記錄合同中任何的改變(交易)哪怕是失敗的。所以采用復原操作,取消合約的執行,恢復交易可能產生的任何變化(其實就是把幣還給sender),比較遺憾的是會消耗掉sender為了執行合約所提供的gas。好在 以太坊錢包 有檢測某筆交易會不會失敗,會根據檢測結果作出警告,從而防止發出這種失敗的交易損失以太坊。下面就是加了檢測的代碼:
function transfer(address _to, uint256 _value) { /* Check if sender has balance and for overflows */ require(balanceOf[msg.sender] >= _value && balanceOf[_to] + _value >= balanceOf[_to]); /* Add and subtract new balances */ balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; }
現在缺少的是關於合同的一些基本信息。在不久的將來,這可以由一個令牌注冊表來處理,但是現在我們將直接將它們添加到合同中:
string public name; string public symbol; uint8 public decimals;
現在我們更新構造函數,允許在開始時設置所有這些變量:
/* Initializes contract with initial supply tokens to the creator of the contract */ function MyToken(uint256 initialSupply, string tokenName, string tokenSymbol, uint8 decimalUnits) { balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes decimals = decimalUnits; // Amount of decimals for display purposes }
最后,我們現在需要一些所謂的事件。這些是特殊的、空的函數,可以通過調用這些函數來幫助像Ethereum錢包這樣的客戶跟蹤契約中發生的活動。事件應該以大寫字母開頭。在合同開始時加上這條線來宣布事件:
event Transfer(address indexed from, address indexed to, uint256 value);
事件定義好了,還要在transfer函數中加上以下兩行事件才能正常運行:記得
/* Notify anyone listening that this transfer took place */ Transfer(msg.sender, _to, _value);
注意 事件定義的event Transfer() 要和函數中定義的Transfe(msg.sender, _to, _value)名稱一樣.
現在的代碼幾乎把發token的必備條件准備好了。
標准的token代碼已經准備好了,我們可以使用mist進行部署了,還有一些功能這里就不寫了,因為我也不會,😁