天天看點

006 以太坊錢包開發-發放token、token轉賬

私鍊發放token

編寫代币合約代碼

打開官方網站:https://www.ethereum.org/token#minimum-viable-token ,拷貝官方标準合約代碼。

pragma solidity ^;

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

contract TokenERC20 {
    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public decimals = ;
    // 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 generates a public event on the blockchain that will notify clients
    event Approval(address indexed _owner, address indexed _spender, 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
     */
    constructor(
        uint256 initialSupply,
        string tokenName,
        string tokenSymbol
    ) public {
        totalSupply = initialSupply *  ** 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 != );
        // 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;
        emit 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 returns (bool success) {
        _transfer(msg.sender, _to, _value);
        return true;
    }

    /**
     * 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;
        emit Approval(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
        emit 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
        emit Burn(_from, _value);
        return true;
    }
}
           

name : 代币名稱

symbol: 代币符号

decimals: 代币小數點位數,代币的最小機關, 18表示我們可以擁有 .0000000000000000001機關個代币。

totalSupply() : 發行代币總量。

balanceOf(): 檢視對應賬号的代币餘額。

transfer(): 實作代币交易,用于給使用者發送代币(從我們的賬戶裡)。

transferFrom(): 實作代币使用者之間的交易。

allowance(): 控制代币的交易,如可交易賬号及資産。

approve(): 允許使用者可花費的代币數。

下載下傳 Ethereum Wallet

下載下傳Ethereum Wallet : https://github.com/ethereum/mist/releases

006 以太坊錢包開發-發放token、token轉賬

安裝完成後,通過指令啟動 Ethereum Wallet 用戶端。

首先使用

geth

啟動私有網絡

然後通過指令啟動 Ethereum Wallet

–rpc 的值如何擷取?

可以通過啟動私鍊的控制台,檢視ipc檔案的路徑,如下圖所示:

006 以太坊錢包開發-發放token、token轉賬

部署代币合約

006 以太坊錢包開發-發放token、token轉賬

部署代币合約,設定代币發行數量、名字

006 以太坊錢包開發-發放token、token轉賬

點選 DEPLOY 部署合約

006 以太坊錢包開發-發放token、token轉賬

需要在

geth

目錄下啟動挖礦。

檢視合約位址和合約Abi

006 以太坊錢包開發-發放token、token轉賬

web3 調用代币轉賬

調用合約實作代币轉賬

修改

utils/web3helper

建立合約。

getContract() {

        const web3 = module.exports.getWeb3()
        // 定義合約abi
        const contractAbi = [ { "constant": true, "inputs": [], "name": "name", "outputs": [ { "name": "", "type": "string", "value": "kongyixueyuan" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x06fdde03" }, { "constant": false, "inputs": [ { "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" } ], "name": "approve", "outputs": [ { "name": "success", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0x095ea7b3" }, { "constant": true, "inputs": [], "name": "totalSupply", "outputs": [ { "name": "", "type": "uint256", "value": "10000000000000000000000000" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x18160ddd" }, { "constant": false, "inputs": [ { "name": "_from", "type": "address" }, { "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" } ], "name": "transferFrom", "outputs": [ { "name": "success", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0x23b872dd" }, { "constant": true, "inputs": [], "name": "decimals", "outputs": [ { "name": "", "type": "uint8", "value": "18" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x313ce567" }, { "constant": false, "inputs": [ { "name": "_value", "type": "uint256" } ], "name": "burn", "outputs": [ { "name": "success", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0x42966c68" }, { "constant": true, "inputs": [ { "name": "", "type": "address" } ], "name": "balanceOf", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x70a08231" }, { "constant": false, "inputs": [ { "name": "_from", "type": "address" }, { "name": "_value", "type": "uint256" } ], "name": "burnFrom", "outputs": [ { "name": "success", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0x79cc6790" }, { "constant": true, "inputs": [], "name": "symbol", "outputs": [ { "name": "", "type": "string", "value": "kyb" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0x95d89b41" }, { "constant": false, "inputs": [ { "name": "_to", "type": "address" }, { "name": "_value", "type": "uint256" } ], "name": "transfer", "outputs": [ { "name": "success", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0xa9059cbb" }, { "constant": false, "inputs": [ { "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }, { "name": "_extraData", "type": "bytes" } ], "name": "approveAndCall", "outputs": [ { "name": "success", "type": "bool" } ], "payable": false, "stateMutability": "nonpayable", "type": "function", "signature": "0xcae9ca51" }, { "constant": true, "inputs": [ { "name": "", "type": "address" }, { "name": "", "type": "address" } ], "name": "allowance", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function", "signature": "0xdd62ed3e" }, { "inputs": [ { "name": "initialSupply", "type": "uint256", "index": , "typeShort": "uint", "bits": "256", "displayName": "initial Supply", "template": "elements_input_uint", "value": "10000000" }, { "name": "tokenName", "type": "string", "index": , "typeShort": "string", "bits": "", "displayName": "token Name", "template": "elements_input_string", "value": "kongyixueyuan" }, { "name": "tokenSymbol", "type": "string", "index": , "typeShort": "string", "bits": "", "displayName": "token Symbol", "template": "elements_input_string", "value": "kyb" } ], "payable": false, "stateMutability": "nonpayable", "type": "constructor", "signature": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "from", "type": "address" }, { "indexed": true, "name": "to", "type": "address" }, { "indexed": false, "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event", "signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "_owner", "type": "address" }, { "indexed": true, "name": "_spender", "type": "address" }, { "indexed": false, "name": "_value", "type": "uint256" } ], "name": "Approval", "type": "event", "signature": "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "from", "type": "address" }, { "indexed": false, "name": "value", "type": "uint256" } ], "name": "Burn", "type": "event", "signature": "0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5" } ]
        // 合約位址
        const contractAddress = "0xF2B6b76f1d0Ea4dC8ca543765640224819af3aA2"

        const myContract = new web3.eth.Contract(contractAbi,contractAddress)

        return myContract
    }
           

在 controllers 中 建立

token.js

檔案,通過調用合約實作代币轉賬 ,代碼如下:

const web3 = require("../utils/web3helper").getWeb3()
const BigNumber = require('bignumber.js');
const myContract = require("../utils/web3helper").getContract()

module.exports = {

    async sendTokenTransaction (ctx) {
        let returnResult = {
            code: ,
            msg: '成功!',
            data: {}
        }

        const data = ctx.request.body

        const currentAccount = data.currAccount
        const privateKey = data.privateKey
        const reciptAccount = data.reciptAccount
        const txValue = data.txValue
        // 擷取指定賬戶位址的交易數
        let nonce = await web3.eth.getTransactionCount(currentAccount);

        // 擷取設定的位數
        const decimals = await myContract.methods.decimals().call()
        // 将輸入的值 轉為 最小機關的值
        const value = BigNumber(txValue * Math.pow(,decimals));
        const txData = myContract.methods.transfer(reciptAccount, value).encodeABI();

        // 擷取目前gasprice
        let gasPrice = await web3.eth.getGasPrice();

        // 以太币轉賬參數    
        let txParms = {
            from: currentAccount,
            // 合約位址
            to: myContract.options.address,
            nonce: nonce,
            gasPrice: gasPrice,
            data: txData // 當使用代币轉賬或者合約調用時
        }

        // 擷取一下預估gas
        let gas = await web3.eth.estimateGas(txParms);
        txParms.gas = gas;
        // 用密鑰對賬單進行簽名
        let signTx = await web3.eth.accounts.signTransaction(txParms,privateKey)

        // 将簽過名的賬單進行發送
        try {
            await web3.eth.sendSignedTransaction(signTx.rawTransaction, function(error, hash){
                if (!error) {
                    returnResult.data.hash = hash
                } else {
                    returnResult.code = "101"
                    returnResult.msg = "失敗!"
                    returnResult.data.error = error.message

                }
            })
        } catch (error) {
            console.log(error)
        }

        ctx.body = returnResult
    }
}
           

代币轉賬和以太币轉賬方法類似,隻有兩點不同:

  • 轉賬參數

    txParms

    to

    為合約的位址
  • 轉賬參數

    txParms

    中 需要設定

    data

    的值

修改路由配置

代币轉賬添加路由配置,修改

routers/index.js

,添加如下代碼:

const tokenController = require("../controllers/token")

router.post('/token/send', tokenController.sendTokenTransaction)
           

修改轉賬頁面

修改

view/transaction.html

中的代碼。

轉賬币種選擇加入

kyb

的選項。

<div class="form-group">
        <label for="txValue">轉賬金額</label>
        <div class="input-group mb-3">
            <input type="text" class="form-control" id="txValue" placeholder="">
            <div class="input-group-append">
                <select id="tokenType">
                    <option value="eth">ETH</option>
                    <option value="kyb">KYB</option>
                </select>
            </div>
        </div>
    </div>
           

修改轉賬

sendTransaction

方法

if (tokenType == "kyb"){
            $.post("/token/send",params,function(res){
                if (res.code == ) {
                    alert("交易成功!")
                    $("#txHashDiv").show()
                    $("#txHash").html(res.data.hash)
                } else {
                    alert("交易失敗!"+res.data.error)
                }
            })
        }  
           

擷取賬戶中的代币金額

修改

controllers/account.js

添加

getTokenBalance

擷取代币的資訊。

async getTokenBalance(account){

        let returnResult = {
            balance: ,
            symbol: 'kongyixueyuan'
        }

        // 代币小數點位數
        const decimals = await myContract.methods.decimals().call()
        // 代币符号
        const symbol = await myContract.methods.symbol().call()
        const tokenBalance = await myContract.methods.balanceOf(account.address).call()
        const tokenBalanceNum = tokenBalance / Math.pow(,decimals)

        returnResult.balance = tokenBalanceNum
        returnResult.symbol = symbol

       return returnResult
    }
           

修改 getAccountByKeystore 和 getAccountByPrivatekey 方法,添加擷取代币的代碼:

const tokenResult = await module.exports.getTokenBalance(account)
returnResult.data.tokenBalance = tokenResult.balance
returnResult.data.tokenSymbol = tokenResult.symbol
           

項目運作

啟動私鍊網絡

使用

geth

啟動私有網絡

開啟本地挖礦

啟動項目

$ cd myWallet
$ node index.js
           

通路 http://localhost:3000/transaction 檢視項目:

006 以太坊錢包開發-發放token、token轉賬

源碼下載下傳

https://github.com/didianV5/web3EthWallet/tree/master/006_myWallet

關注我

006 以太坊錢包開發-發放token、token轉賬