美文网首页Dapp开发以太坊开发笔记专注学习区块链技术
【Ethereum 智能合约开发笔记】使用 MetaMask,

【Ethereum 智能合约开发笔记】使用 MetaMask,

作者: 安德森_Anderson | 来源:发表于2018-03-06 00:10 被阅读145次

    使用 web3 应该是开发 DApp 必须的,不管要查询 Ethereum 区块链状态、发送交易、呼叫智能合约都可以透过 web3。使用 web3 必须连结到 Ethereum 节点,之前我写了一篇文章介绍使用 Infura 提供的节点。其实常用的 Ethereum 浏览器钱包 — MetaMask 也有提供 web3 provider,用他提供的 provider 初始化 web3,就可以连上 MetaMask 提供的节点。参考以下两篇官方文件,我实作了简单的范例,并记录几个可能碰到的问题。

    MetaMask 官方文件:

    1. MetaMask Compatibility Guide
    2. Developing for MetaMask

    另外 MetaMask/mascara 提供在不安装 MetaMask 的环境下,使用 MetaMask 提供的 web3。

    使用范例

    写一个简单的 JavaScript 程式,使用 MetaMask 提供的 web3 provider 来初始化 web3:

    var Web3 = require('web3');
    // set the provider of web3
    if (typeof web3 !== 'undefined') { 
        console.debug(web3.currentProvider);
        web3 = new Web3(web3.currentProvider);
    } else {
        alert("No currentProvider for web3");
    }
    

    用 browserify 打包:

    browserify web3_init.js -o web3_bundle.js
    

    在 HTML file 中执行:

    <script src="js/web3_bundle.js"></script>
    

    再写个 HTML file 测试看看。希望透过 MetaMask 提供的 web3 取得:

    1. web3 的 API version
    2. 我的 MetaMask account
    <html>
      <body>
        <h2>Web3 API version</h2>
        <p id="p1"></p>
        <h2>My Account</h2>
        <p id="account"></p>
        <script src="js/web3_bundle.js"></script>
        <script>
          // Get API version
          var p1 = document.getElementById("p1");
          p1.innerHTML = web3.version.api;
          // Get my MetaMask account
          var account = document.getElementById("account");
          account.innerHTML = web3.eth.accounts;
      </body>
    </html>
    

    执行结果:


    可能碰到的问题

    1. 找不到 web3.currentProvider

    • 必须使用 http server,根据 MetaMask 官方文件

    Due to browser security restrictions, we can’t communicate with dapps running on file://. Please use a local server for development.

    • 必须确认启用 MetaMask extension。

    2. 无法取得 web3.eth.accounts

    必须用密码解锁 MetaMask,不然会回传 undefined 。

    3. 没有使用 callback

    MetaMask 官方文件表示所有提供的 web3 API 都是非同步,必须要传入 callback function,除了以下例外:

    • eth_accounts (web3.eth.accounts)
    • eth_coinbase (web3.eth.coinbase)
    • eth_uninstallFilter (web3.eth.uninstallFilter)
    • web3.eth.reset (uninstalls all filters)
    • net_version (web3.version.network)

    除了以上 API,我在使用时也有其他 API 不需要 callback。但确实碰到 API 是必需要用 callback,不然 MetaMask 会跳出 error。

    4) Web3 API 版本

    以上範例是使用 官方 wiki 的 API,版本是 0.2x.x。如果直接用 npm install web3 ,根據我的經驗會安裝的版本為 1.0.0,API 使用的方法會有些不同,使用方式請看 web3.js Doc

    使用 EthJS 呼叫合约

    EthJS 是另一个 Ethereum 的 JavaScript API,也是 MetaMask 开发者推荐的 JavaScript API。根据 EthJS 官方文件的描述:

    EthJS is a highly optimised, light-weight JS utility for Ethereum based on web3.js, but lighter, async only and using BN.js.

    EthJS 分为多个 module,如果要使用合约要安装这两个:

    npm install ethjs-query ethjs-contract --save
    

    同样使用 MetaMask 提供的 web3 provider 来初始化 EthJS:

    var Eth = require('ethjs-query');
    var EthContract = require('ethjs-contract');
    if (typeof web3 !== 'undefined') {
        eth = new Eth(web3.currentProvider);
        contract = new EthContract(eth);
        startApp();
    } else {
        alert("No currentProvider for web3");
    }
    

    使用 contract 初始化合约,一样需要合约的 ABI 和 address:

    function startApp() {
        const abi = [ { "constant": true, "inputs": [], "name": "data", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view",  "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "name": "_from", "type": "address" }, { "indexed": false, "name": "value", "type":    "uint256" } ], "name": "Set", "type": "event" }, { "constant": false, "inputs": [ { "name": "x", "type": "uint256" } ], "name": "set", "outputs": [],  "payable": false, "stateMutability": "nonpayable", "type": "function" } ];
        const addresss = '0x06e1c13546e04514a0cf8d842216a84745ac317a';
        const SimpleStorage = contract(abi);
        const simpleStorage = SimpleStorage.at(addresss);
        // Listen to clicks from a <button> that trigger a function call of contract 
    
        listenForClicks(simpleStorage);
    }
    

    写一个简单的 HTML file,有一个 input 栏位可以输入任意数值,和一个 button。

    <input id="data-value" type="text" placeholder="Enter a number">
    <button class="set">Set Data!</button>
    

    在写一个 JavaScript function 监听这个 button,按下 button 后会透过 EthJS 呼叫合约的 set(uint256),把合约中的状态 data 设为对应数值。要呼叫合约不需要知道 function signature,也不用自己建 transaction。就像使用 JavaScript 物件中的 function,像是: simpleStorage.set(param, {from: myAddr}, callback() {...})

    function listenForClicks(simpleStorage) {
        var button = document.querySelector('button.set');
        button.addEventListener('click', function() {
            var value = document.getElementById('data-value').value;
            simpleStorage.set(value, { from: "0x123abc000..." }, function(error, result) {
                if (error) {
                     console.debug(error);
                     return;
                }  
                // will return txHash as result
                console.debug(result);
            })
       })
    }
    

    用看看

    1. 任意输入一个数字后,按 Set Data!


      输入 20
    2. 跳出 MetaMask 的提醒视窗。MetaMask 提供介面让使用者授权交易的发送,点击 confirm 就可以发送这笔交易。


    3. 发送成功,取得 Transaction Hash。


    4. 等 transaction confirm 后,再去呼叫合约的 data(),就会得到更新后的值。一样可以透过 EthJS,像是这段简单的 code:

    simpleStorage.data(function(error, result) {
        // result[0] is a object of bn.js
        console.debug(result[0].toNumber());
    })
    
    // Return value
    20
    

    References

    相关文章

      网友评论

      • 安德森_Anderson:@梨涡浅笑_efc4 可呀
        8337ea5e8883:@安德森_Anderson 您的微信号是多少呢?
      • 8337ea5e8883:您好,看到您的文章质量非常高,想邀请您成为虫洞社区的首批优质内容签约作者。虫洞社区是专业的区块链技术学习社区。虫洞社区鼓励内容生产者产生高质量内容,并给予合理的回报,也希望能帮助内容消费者获得高质量的区块链内容,并让数字货币投资者获得有价值的投资洞见。同时,虫洞社区已经积累了大量的区块链深度从业者,便于作者建立个人品牌。不知道是否方便加您微信细聊?

      本文标题:【Ethereum 智能合约开发笔记】使用 MetaMask,

      本文链接:https://www.haomeiwen.com/subject/tfgkfftx.html