亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Ether.js構建一個簡單的DApp

發布時間:2021-12-13 21:35:47 來源:億速云 閱讀:249 作者:柒染 欄目:互聯網科技

今天就跟大家聊聊有關如何使用Ether.js構建一個簡單的DApp,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。

如果你已經在以太坊上開發過DApp,那你在前端JavaScript中可能用過web3.js。Ethers.js則是一個輕量級的web3.js替代品,我們將學習如何使用Ether.js構建一個簡單的DApp。

與Web3.js相比,Ethers.js有很多優點,其中我最喜歡的一個特性是Ethers.js提供的狀態和密鑰管理。Web3的設計場景是DApp應該連接到一個本地節點,由這個節點負責保存密鑰、簽名交易并與以太坊區塊鏈交互。現實并不是這樣的,絕大多數用戶不會在本地運行一個geth節點。Metamask在瀏覽器 應用中有效地模擬了這種節點環境,因此絕大多數web3應用需要使用Metamask來保存密鑰、簽名交易并完成與以太坊的交互。

Ethers.js采取了不同的設計思路,它提供給開發者更多的靈活性。Ethers.js將“節點”拆分為兩個不同的角色:

  • 錢包:負責密鑰保存和交易簽名

  • 提供器:負責以太坊網絡的匿名連接、狀態檢查和交易發送

1、編譯、部署智能合約

在這個教程中我們將與一個ERC20智能合約交互,你需要在機器里先安裝nodejs和npm。

1.1 創建項目文件夾

首先創建一個文件夾ethers-template,然后再這個文件夾里再創建另一個contracts文件夾:

~$ mkdir -p ethers-template/contracts

1.2 初始化npm配置

然后進入ethers-template目錄初始化npm配置:

~$ cd ethers-template
~/ethers-template$ npm init -y

1.3 創建項目配置文件

接下來創建一個config.json文件保存你的項目配置:

{
  "private_key": "24C4FE6063E62710EAD956611B71825B778B041B18ED53118CE5DA5F02E494BA",
  "network": "kovan",
  "ERC20": "0x0DEd9F7D82a24099F09AF7831CaB61B31Df10487",
  "name": "Kanchan Coin",
  "symbol": "SNK",
  "total_supply": "1000000000000000000000000",
  "decimals": 18
}

說明如下:

  • private_key:賬戶私鑰,將使用這個私鑰對應的賬戶在指定網絡上部署智能合約。

  • network:要接入的以太坊網絡,ethers.js支持以下網絡:

    • homestead:主網

    • rinkeby

    • ropsten

    • kovan

    • goerli

  • ERC20:聲明要交互的已部署合約,可選

  • name/symbol/decimals:ERC20合約的參數

1.4 安裝ethers.js

現在可以安裝ethers.js:

~/ethers-template$ npm install --save ethers

1.5 安裝編譯合約需要的npm包

為了編譯合約,我們還需要安裝solc和fs-extra:

~/ethers-template$ npm install fs-extra@8.1.0 solc@0.5.11 --save

1.6 創建ERC20合約代碼

在contracts目錄下創建文件erc20.sol:

~/ethers-template$ touch contracts/erc20.sol

并按如下內容修改:

pragma solidity ^0.5.0;

contract ERC20 {
    
    using SafeMath for uint256;
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
    event Transfer(address indexed from, address indexed to, uint tokens);
    mapping(address => uint256) balances;
    mapping(address => mapping (address => uint256)) allowed;
    string public symbol;
    uint8 public decimals;
    string public  name;
    uint256 private _totalSupply;

    constructor(uint8 _decimals, string memory _symbol, string memory _name, uint256 _total_supply) public{
        decimals = _decimals;
        symbol = _symbol;
        name = _name;
        _totalSupply = _total_supply;
        balances[msg.sender] = _totalSupply;
    }

    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }    

    function balanceOf(address tokenOwner) public view returns (uint) {
        return balances[tokenOwner];
    }

    function transfer(address receiver, uint numTokens) public returns (bool) {
        require(numTokens <= balances[msg.sender]);
        balances[msg.sender] = balances[msg.sender].sub(numTokens);
        balances[receiver] = balances[receiver].add(numTokens);
        emit Transfer(msg.sender, receiver, numTokens);
        return true;
    }

    function approve(address delegate, uint numTokens) public returns (bool) {
        allowed[msg.sender][delegate] = numTokens;
        emit Approval(msg.sender, delegate, numTokens);
        return true;
    }

    function allowance(address owner, address delegate) public view returns (uint) {
        return allowed[owner][delegate];
    }

    function transferFrom(address owner, address buyer, uint numTokens) public returns (bool) {
        require(numTokens <= balances[owner]);    
        require(numTokens <= allowed[owner][msg.sender]);
    
        balances[owner] = balances[owner].sub(numTokens);
        allowed[owner][msg.sender] = allowed[owner][msg.sender].sub(numTokens);
        balances[buyer] = balances[buyer].add(numTokens);
        emit Transfer(owner, buyer, numTokens);
        return true;
    }
}

library SafeMath { 
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
      assert(b <= a);
      return a - b;
    }
    
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
      uint256 c = a + b;
      assert(c >= a);
      return c;
    }
}

1.7 編寫合約編譯腳本

下面的代碼使用solc編譯合約文件,將其保存為compile.js:

const path = require('path');
const fs = require('fs-extra');
const solc = require('solc');
const config = require('./config.json');

const sourceFolderPath = path.resolve(__dirname, 'contracts');
const buildFolderPath = path.resolve(__dirname, 'build');

const getContractSource = contractFileName => {
  const contractPath = path.resolve(__dirname, 'contracts', contractFileName);
  const source = fs.readFileSync(contractPath, 'utf8');
  return source;
};

let sources = {};

fs.readdirSync(sourceFolderPath).forEach(contractFileName => {
  sources = {
    ...sources,
    [contractFileName]: {
      content: getContractSource(contractFileName)
    }
  }
});

const input = {
    language: 'Solidity',
    sources,
    settings: {
        outputSelection: {
            '*': {
                '*': [ '*' ]
            }
        }
    }
}

console.log('\nCompiling contracts...');
const output = JSON.parse(solc.compile(JSON.stringify(input)));
console.log('Done');

let shouldBuild = true;

if (output.errors) {
  console.error(output.errors);
  // throw '\nError in compilation please check the contract\n';
  for(error of output.errors) {
    if(error.severity === 'error') {
      shouldBuild = false;
      throw 'Error found';
      break;
    }
  }
}

if(shouldBuild) {
  console.log('\nBuilding please wait...');

  fs.removeSync(buildFolderPath);
  fs.ensureDirSync(buildFolderPath);

  for (let contractFile in output.contracts) {
    for(let key in output.contracts[contractFile]) {
      fs.outputJsonSync(
        path.resolve(buildFolderPath, `${key}.json`),
        {
          abi: output.contracts[contractFile][key]["abi"],
          bytecode: output.contracts[contractFile][key]["evm"]["bytecode"]["object"]
        },
        {
          spaces:2,
          EOL: "\n" 
        }
      );
    }
  }
  console.log('Build finished successfully!\n');
} else {
  console.log('\nBuild failed\n');
}

上面的代碼將讀入并編譯contracts目錄中的所有合約文件,然后將編譯得到的abi和字節碼保存為json文件。

1.8 編譯合約

現在我們使用compile.js來編譯erc20.sol合約:

~/ethers-template$ node compile.js

編譯結束后,我們得到如下的目錄結構;

+ethers-template
    +compile.js
    +contracts
        -erc20.sol
    +build
        -ERC.json
        -Context.json
        -IERC20.sjon
        -SafeMath.json
   -package.json

1.9 編寫合約部署腳本

創建文件deploy.js:

~/ethers-template$ touch deploy.js

然后按如下內容修改:

const startTimestamp = Date.now();
const ethers = require('ethers');
const config = require('./config.json');
const fs = require('fs-extra');

const provider = ethers.getDefaultProvider(config["network"]);

const wallet = new ethers.Wallet(config["private_key"], provider);
console.log(`Loaded wallet ${wallet.address}`);

let compiled = require(`./build/${process.argv[2]}.json`);

(async() => {
  console.log(`\nDeploying ${process.argv[2]} in ${config["network"]}...`);
  let contract = new ethers.ContractFactory(
    compiled.abi,
    compiled.bytecode,
    wallet
  );

  let instance =  await contract.deploy(config["decimals"], config["symbol"], config["name"], config["total_supply"]);
  console.log(`deployed at ${instance.address}`)
  config[`${process.argv[2]}`] = instance.address
  console.log("Waiting for the contract to get mined...")
  await instance.deployed()
  console.log("Contract deployed")
  fs.outputJsonSync(
    'config.json',
    config,
    {
      spaces:2,
      EOL: "\n" 
    }
  );

})();

注意:

  1. 上面代碼中的默認網絡是kovan測試網

  2. 在這個測試網中,你的賬號需要一些以太幣來支付部署交易的手續費

  3. 將使用config.json中的private_key來部署合約

1.10 部署合約

運行deploy.js腳本時,需要在命令行傳入要部署的合約名稱ERC20:

~/ethers-template$ node deploy.js ERC20

輸出結果如下:

Loaded wallet 0xC8e1F3B9a0CdFceF9fFd2343B943989A22517b26
Deploying ERC20 in kovan...
deployed at 0x77Bb3546f5ee356E4026BaA96b7DDf22141bd77B
Waiting for the contract to get mined...
Contract deployed

在與合約交互時需要合約部署地址,上面的代碼會自動將合約部署地址保存到config.json文件中。

2、與智能合約交互

在這個教程中,我們使用ES6來編寫合約交互代碼,然后使用webpack和babel將ES6代碼轉換為ES5代碼。

2.1 安裝ES6構建工具

首先安裝這些依賴項:

~/ethers-template$ npm i webpack webpack-cli @babel/core \
                          @babel/plugin-proposal-object-rest-spread \
                          @babel/preset-env babel-loader \
                          babel-polyfill -D

2.2 編寫前端腳本

創建一個文件app.js:

~/ethers-template$ touch app.js

然后按照如下代碼修改:

const ethers = require('ethers');
const config = require('./config.json');

// Import the json file from build to get the abi
const erc_json = require('./build/ERC20.json'); //import the json of the contract which you want to interact

// You can use any standard network name
//  - "homestead"
//  - "rinkeby"
//  - "ropsten"
//  - "kovan"
//  - "goerli"
const provider = ethers.getDefaultProvider(config['network']);

// Make a wallet instance using private key and provider
const wallet = new ethers.Wallet(config['private_key'] , provider);

const address = config["ERC20"];
const abi = erc_json.abi;

erc20 = new ethers.Contract( address , abi , wallet );

document.getElementById("send").onsubmit = async function(e) {
    e.preventDefault();
    let address = document.getElementById("address").value;
    document.getElementById("status").innerText = "Waiting for transaction to get published...";
	let tx = await erc20.functions.transfer(address, "1000000000000000000");
    let tx_hash = tx.hash;
	let node = document.createElement("LI");
	let link = document.createElement("A");
	link.target = "_blank";
	link.href = `https://${config["network"]}.etherscan.io/tx/` + tx_hash;
	let textnode = document.createTextNode(tx_hash);
	link.appendChild(textnode);
	node.appendChild(link);
	document.getElementById("transactions").appendChild(node);
    document.getElementById("status").innerText = "Waiting for transaction to be mined...";
    await tx.wait();
    document.getElementById("status").innerText = "Transaction confirmed";
    return false;
};

首先我們需要指定要使用的網絡/提供器:

const provider = ethers.getDefaultProvider(config['network']);

為了與合約交互,我們需要2個東西:

  • 合約部署地址

  • 合約ABI接口

在上面app.js中,我們從配置文件引入了合約地址,從合約編譯結果目錄中引入了合約ABI:

//import the json of the contract which you want to interact
const erc_json = require('./build/ERC20.json'); 
const config = require('./config.json');
const address = config["ERC20"];
const abi = erc_json.abi;

2.3 創建錢包實例

為了創建合約實例,我們需要先創建一個錢包實例,這樣不管什么時候調用setter方法,都需要一個私鑰來簽名交易。在ethers.js中,你只需要創建錢包,所有的setter方法就會由這個錢包簽名。

const wallet = new ethers.Wallet(config['private_key'] , provider);

你也可以使用keystore和助記詞來創建一個錢包。如果你希望用這個錢包與智能合約交互,你還需要傳入提供器。如果你只是想用私鑰簽名消息,那么就不需要提供器了。

erc20 = new ethers.Contract( address , abi , wallet );

上面的代碼創建了一個合約實例,然后你就可以像這樣調用合約函數:

erc20.functions.function_name_in_smart_contract(parameters);

小白備注:在ERC20中定義了一個函數transfer,它的參數是轉賬地址和代幣數量。下面的代碼調用了合約的transfer函數,錢包將簽名這個交易,然后發布到指定的網絡中:

erc20.functions.transfer(address, "1000000000000000000");

注意:無論任何時候你要創建一個交易,錢包里都需要以太幣來支付交易手續費。

2.4 修改啟動腳本

在package.json中添加如下內容:

"deploy": "node compile.js && node deploy.js ERC20", 
"build": "webpack — mode production',

修改后的package.json看起來是這樣:

{
  "name": "ethers-template",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "deploy": "node compile.js && node deploy.js ERC20",
    "build": "webpack --mode production",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ethers": "^4.0.37",
    "fs-extra": "^8.1.0",
    "solc": "^0.5.11"
  },
  "devDependencies": {
    "@babel/core": "^7.6.0",
    "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
    "@babel/preset-env": "^7.6.0",
    "babel-loader": "^8.0.6",
    "babel-polyfill": "^6.26.0",
    "webpack": "^4.40.2",
    "webpack-cli": "^3.3.9",
    "webpack-dev-server": "^3.8.1"
  }
}

如果你后續修改了智能合約,就需要重新編譯和部署。可以用一個命令來完成合約的編譯和部署:

~/ethers-template$ npm run deploy

這個命令會自動修改配置文件和合約構件文件。這樣在與合約交互時,你就不需要修改合約地址或者ABI接口了。

如果你修改了app.js,也需要重新構建前端代碼:

~/ethers-template$ npm run build

這會生成新的發布版本:dist/bundle.js。

2.5 創建宿主html文件

創建一個新的文件index.html:

~/ethers-template$ touch index.html

按如下內容修改:

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8"/>
        <title>Ethers Template</title>
        <style>
body {
    padding-top: 75px;
}
        .search-container {
            width: 490px;
            display: block;
            margin: 0 auto;
        }
        input#address {
            margin: 0 auto;
            width: 100%;
            height: 45px;
            padding: 0 20px;
            font-size: 1rem;
            border: 1px solid #D0CFCE;
            outline: none;
        }
        .center {
            text-align: center;
        }
        ol {
            counter-reset: list;
            list-style: none;
        }
        li {
            counter-increment: list;
            margin-bottom: 10px;
        }
        li::before {
            content: counter(list, decimal-leading-zero);
            background: #2b4353;
            font-family: Arial, sans-serif;
            color: #fff;
            font-size: 13px;
            text-align: center;
            border-radius: 50%;
            width: 2.2em;
            height: 2.2em;
            line-height: 2.3em;
            display: inline-block;
            margin-right: 1em;
        }
        .button {
            background-color: #4CAF50;
            border: none;
            color: white;
            padding: 15px 32px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: 19px;
            cursor: pointer;
        }
        </style>
    </head>

    <body>
        <div class="center">
            <h2>Ethers Template</h2>
            <form class="search-container" id="send">
                <input type="text" id="address" placeholder="Enter you address to get kanchan Coin">
                <button type="submit" class="button">Send</button>
            </form>
            <h3>Status:</h3>
            <p id="status"></p>
            <h3>Transactions</h3>
            <ol id="transactions">
            </ol>
        </div>
        <script src="dist/bundle.js"></script>
    </body>
</html>

現在你的文件夾看起來就是這樣了:

如何使用Ether.js構建一個簡單的DApp

其中build文件夾將在運行compile.js之后自動創建,而dist 文件夾是在npm run build執行后自動創建。

用瀏覽器訪問看起來是這樣:

如何使用Ether.js構建一個簡單的DApp

看完上述內容,你們對如何使用Ether.js構建一個簡單的DApp有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

浙江省| 临夏市| 东乌珠穆沁旗| 常山县| 克东县| 南丰县| 翁源县| 南雄市| 宁夏| 杨浦区| 舟曲县| 保靖县| 游戏| 铜鼓县| 那坡县| 衡水市| 永定县| 宜昌市| 泌阳县| 绥江县| 潼关县| 且末县| 皮山县| 永宁县| 昭苏县| 彝良县| 屏东市| 商都县| 西城区| 江川县| 雷波县| 卢氏县| 庄河市| 九寨沟县| 蓬安县| 金堂县| 江源县| 二手房| 怀集县| 赞皇县| 原阳县|