使用JavaScript編譯和部署以太坊智慧合約

買賣虛擬貨幣
以太坊智慧合約的發展在2018年呈指數級增長,2019年似乎將遵循這一趨勢。有些框架,如Truffle,可以幫助我們快速構建和維護智慧合約,如果您想讓親自動手體驗的話,我將解釋如何編譯您的智慧合約,並使用自己的指令碼將其部署到以太坊網路(Rinkeby、Ropsten或Mainnet)。注意:我將使用簡單的智慧合約,因為本文的目的只是展示如何編譯和部署指令碼。

專案具有以下結構:

資料夾合同包含我們的智慧合約(您可以根據需要擁有任意多個智慧合約)。對於這篇文章,我們將使用兩個簡單的智慧合約:

MyContractA.sol

MyContractA.sol

如您所見,我們有兩個檔案,其中一個包含兩個智慧合約,證明我們可以擁有任意數量的智慧合約。

指令碼編譯

現在,一旦我們有了初始專案結構和智慧合約,就可以開始構建編譯指令碼了。

該指令碼的目的是為每個合約生成一個JSON(在這種情況下,我們將使用三個JSON完成編譯過程),每個JSON都包含已編譯的合同資訊。 這些JSON將儲存在名為build /的輸出路徑中

構建指令碼的步驟如下:

建立構建/目錄。
獲取我們的合同來源。
編譯合同並將輸出寫入檔案。

第1步 - 建立build/資料夾。

這一步是最簡單的,因為我們只需要瞭解JavaScript的一些基礎知識(這裡不需要以太坊概念)。

const path = require('path');
const fs = require('fs-extra');

const builPath = path.resolve('ethereum', 'build');

const createBuildFolder = () => {
    fs.emptyDirSync(builPath);
}

現在要將所有檔案的來源都放到智慧合約資料夾中。 在這一步中,只需要JavaScript就不需要以太坊概念,但還是有點複雜。

const contracstFolderPath = path.resolve('ethereum', 'contracts');

const buildSources = () => {
  const sources = {};
  const contractsFiles = fs.readdirSync(contractsFolderPath);

  contractsFiles.forEach(file => {
    const contractFullPath = path.resolve(contractsFolderPath, file);
    sources[file] = {
      content: fs.readFileSync(contractFullPath, 'utf8')
    };
  });

  return sources;
}

對於contracts資料夾中的每個檔案,我們在sources物件中新增一個新欄位(我們將在步驟3中看到這個sources的用途),其中鍵是檔名,值是.sol檔案的內容。

第3步 - 編譯並寫入輸出

現在我們已經有了輸出資料夾和智慧合約的內容,是時候編譯它們了(是的!最後出現了以太坊部分)。

首先,我們必須定義一個物件,該物件將作為Solidity編譯器的資訊輸入。

const input = {
    language: 'Solidity',
    sources: buildSources(),
    settings: {
        outputSelection: {
            '*': {
                '*': [ 'abi', 'evm.bytecode' ]
            }
        }
    }
}

/* Sources example
  {
    'MyContractA.sol': {
      content: 'Our file content'
    },
    'MyContractB.sol': {
      content: 'Our file content'
    }
  }
*/

1. language:我們智慧合約的程式語言,目前是使用Solidity,但你也可以選擇其他程式語言(Viper)。
2. sources:我們合同的內容。
3. settings:此選項告訴編譯器我們想要生成哪些輸出欄位。 對於此示例,我選擇sources中的所有檔案生成abi和evm.bytecode。 這兩條資訊是部署階段所必需的。

一旦我們有了編譯器的配置物件,我們就可以執行它了。

const solc = require('solc');

const compileContracts = () => {
    const compiledContracts = JSON.parse(solc.compile(JSON.stringify(input))).contracts;

    for (let contract in compiledContracts) {
        for(let contractName in compiledContracts[contract]) {
            fs.outputJsonSync(
                path.resolve(builPath, `${contractName}.json`),
                compiledContracts[contract][contractName],
                {
                    spaces: 2
                }
            )
        }
    }
}

第一行獲取一個包含我們編譯的指令碼的物件。 兩個for迴圈允許我們在不同的JSON檔案中儲存單個.sol檔案中的智慧合約(在我們的例子中就像MyContractA.sol)。

最後一步是把這三部分連線在一起

(function run () {
    createBuildFolder();
    compileContracts();
})();

這樣我們就完成了編譯指令碼。如果我們執行它,專案結構應該如下所示:

我們已經gitignored build資料夾,因為沒有意義在Git下跟蹤它。

現在我們已經編輯了我們的智慧合約,是時候將它們部署到區塊鏈上了。

指令碼部署

是時候將我們的智慧合約部署到以太坊區塊鏈上了(在這種情況下,部署將針對Rinkeby,因此不會使用到主鏈上,但過程與其他以太坊區塊鏈類似)。

首先,我們需要兩件事來將智慧合約部署到區塊鏈:

1. 解鎖帳戶:由於我們需要使用gas來傳送將建立智慧合約的交易。
2. 連線到區塊鏈的節點:我們正在向網路傳送交易,因此我們需要連線到鏈上。

關於第一點,我們將使用HDWalletProvider,這個工具(感謝Truffle :))允許我們使用助記符十二個單詞短語解鎖帳戶並連線到以太坊節點。但是......節點在哪裡?好吧,我們可以做兩件事,執行我們自己的以太坊節點(這是我不推薦的事情,至少是為hobbie開發dApps)或使用Infura。 Infura是一項服務,它允許我們連線到以太坊網路,而無需執行我們自己的以太坊節點。所以,我們似乎已經涵蓋了兩點。

解鎖帳戶並連線到以太坊節點。

要使用Infura,我們需要在其頁面中註冊。它將生成我們需要使用其服務的API金鑰(它是完全免費的)。

我們將使用Web3JS與區塊鏈進行互動。 Web3需要提供程式來連線節點並與節點互動。這個提供程式是HDWalletProvider,我們來配置它和Web3。

const HDWalletProvider = require('truffle-hdwallet-provider');
const Web3 = require('web3');

const provider = new HDWalletProvider(
    'twelve words mnemonic',
    'https://rinkeby.infura.io/v3/API_KEY'
);

const web3 = new Web3(provider);

HDWalletProvider的第一個引數是我們的12個單詞助記詞。 這個短語允許提供者解鎖帳戶(它預設解鎖多個帳戶但我們此時只需要第一個),第二個引數告訴提供者乙太網節點在哪裡,在這種情況下我們透過Infura連線(如果 你使用自己的節點,它應該看起來像ws:// localhost:4535或你的節點在哪裡)。

最後我們在web3中設定了提供者。

透過正確配置web3,我們可以最終部署合同。

const compiledContract = require('../build/MyContractA.json');

(async () => {
    const accounts = await web3.eth.getAccounts();

    console.log(`Attempting to deploy from account: ${accounts[0]}`);

    const deployedContract = await new web3.eth.Contract(compiledContract.abi)
        .deploy({
            data: '0x' + compiledContract.evm.bytecode.object,
            arguments: [3, 5]
        })
        .send({
            from: accounts[0],
            gas: '2000000'
        });

    console.log(
        `Contract deployed at address: ${deployedContract.options.address}`
    );

    provider.engine.stop();
})();

首先,我們需要我們編譯的指令碼(我們只需要部署一個指令碼,但是其他流程是相同的,或者你可以構建一些邏輯來逐個編譯和部署)。

然後,在第8行中,我們使用Web3API建立智慧合約,並將智慧合約的介面傳遞給它。接下來,我們需要建立一個包含智慧合約資訊的部署事務:

1. data:合同的位元組程式碼。它以0x開頭表示它是十六進位制的。
2. arguments:我們的智慧合約建構函式的引數(如果建構函式沒有引數則不需要)。

建立事務後,我們將其傳送到以太坊區塊鏈,以便為節點處理它:

1. from:簽署交易併傳送的帳戶。在第4行中,我們獲得了HDWalletProvider生成和解鎖的帳戶以及12個單詞短語。
2. gas:我們想要用於傳送交易的最大gas量。
第18行的console.log對於獲取部署合同的地址很重要,這樣我們將來可以將其用於DAPP、用於其他合同等。

指令碼的最後一行告訴提供程式結束與以太坊節點的連線。

如果我們執行指令碼,一段時間後,我們將獲得如下跟蹤:

Contract deployed at address: 
0x64d30b804BC706dd54FF899127e39C687706ae4D

現在我們可以訪問EtherScan並檢視我們在區塊鏈中部署的智慧合約。

最後,我們已經部署了智慧合約,並且每個人都可以訪問。 我希望這篇文章有所幫助。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;