如何在Conflux網路中使用js-conflux-sdk來構建一個簡單的DApp

Conflux中文社群發表於2021-12-30

在這篇文章/教程中,我將展示如何使用js-conflux-sdk來構建一個簡單的DApp。

通過使用js-conflux-sdk這一基於JavaScript語言的整合開發庫配合npm包管理,能夠開發基於Conflux網路的DApp,開發編譯部署感興趣的智慧合約到Conflux網路中。希望通過本文的記錄與整理,為更多對Conflux這一高效能公鏈感興趣的同學們嘗試使用js-conflux-sdk更加方便的開發自己所感興趣的專案提供可能。

相較於web3,js-conflux-sdk對其邏輯進行了一系列改進與優化,本文將重點介紹使用該SDK開發呼叫相關智慧合約的方法。如果您熟悉編寫智慧合約的方法,能夠利用智慧合約做更多有意思的事情。

環境配置

首先您需要安裝nodejs作為執行環境,參考文件完成對nodejs環境的部署操作。

  1. 選擇您希望存放DAPP的資料夾作為您的工作目錄
  2. 在工作目錄下執行npm的init命令以建立 package.json 檔案,該檔案能夠幫助您儲存專案名稱、專案版本、專案描述、入口點檔案、專案依賴資訊等關鍵資訊:

    npm init -y
  3. package.json 檔案內容需要滿足您的專案配置,此處為我建立的DAPP所對應的內容:
{
  "name": "contract-project",
  "version": "1.0.0",
  "description": "smart Contract",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Yumingyuan",
  "license": "ISC"
}

此外需要通過npm包管理工具在專案路徑下安裝一些必要的依賴包,其命令如下:

npm install solc@0.5.11

通過@操作符控制安裝的版本,以確保編譯器與我們的程式碼相容。

  1. 此外還需要通過npm命令在同一工作目錄下安裝JavaScript Conflux Software Development Kit
npm install js-conflux-sdk

安裝完後,您會發現在相應的目錄下出現了一個資料夾 node_modules,他是在安裝sdk時自動生成的。

嘗試開發

  1. 如果需要編寫智慧合約,我們還需要嘗試使用Solidity這門面向智慧合約且為了實現智慧合約而建立的高階程式語言開發智慧合約。Solidity檔案的對應字尾為sol,為了方便進行開發,我們在專案資料夾下建立了一個contracts資料夾。並將我們編寫的智慧合約程式碼存入 ./contracts/test.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. 嘗試Solidity程式設計的方式可以是使用Remix,可以通過將自己編寫的test.sol檔案上傳至Remix進行編譯,但我們看到了另外一個有意思的方法(後續步驟有說明),固此處截圖僅為樣例:

test.sol at Remix

  1. 有位外國大佬,他編寫了一份專門可以用於編譯 sol 的JS指令碼,其內容如下,我們將它儲存為 compile.js 並將我們編寫的 test.sol 檔案放入 ./contracts/test.sol 下,同時將 compile.js 放在 ./ 下,這段程式碼的邏輯是讀取 contracts 資料夾內合約並儲存其abi和bytecode為json檔案,儲存到專案 ./build 資料夾下:
const path = require('path');
const fs = require('fs-extra');
const solc = require('solc');

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


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

let sources = {};

var walk = function (dir) {
    var results = [];
    var list = fs.readdirSync(dir);
    list.forEach(function (file) {
        file = dir + '/' + file;
        var stat = fs.statSync(file);
        if (stat && stat.isDirectory()) {
            results = results.concat(walk(file));
        } else {
            if (file.substr(file.length - 4, file.length) === ".sol") {
                sources = {
                    ...sources,
                    [file]: {
                        content: getContractSource(file)
                    }
                };
            }
            results.push(file);
        }
    });
    return results;
};
walk(sourceFolderPath);

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');
}
  1. 通過在命令列執行 compile.js 編譯 ./Contracts/test.sol
node compile.js

編譯成功情況下的執行結果如下:

node_compile

  1. 可以看一下 ./build 資料夾內的資料,發現該編譯工具生成了一個檔案 ERC20.jsonSafeMath.json ,其中 ERC20.json 的內容如下:
{
  "abi": [
    {
      "constant": true,
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "internalType": "address",
          "name": "delegate",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "numTokens",
          "type": "uint256"
        }
      ],
      "name": "approve",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "totalSupply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "buyer",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "numTokens",
          "type": "uint256"
        }
      ],
      "name": "transferFrom",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "decimals",
      "outputs": [
        {
          "internalType": "uint8",
          "name": "",
          "type": "uint8"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [
        {
          "internalType": "address",
          "name": "tokenOwner",
          "type": "address"
        }
      ],
      "name": "balanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "symbol",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "internalType": "address",
          "name": "receiver",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "numTokens",
          "type": "uint256"
        }
      ],
      "name": "transfer",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "delegate",
          "type": "address"
        }
      ],
      "name": "allowance",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "_decimals",
          "type": "uint8"
        },
        {
          "internalType": "string",
          "name": "_symbol",
          "type": "string"
        },
        {
          "internalType": "string",
          "name": "_name",
          "type": "string"
        },
        {
          "internalType": "uint256",
          "name": "_total_supply",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "tokenOwner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "spender",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "tokens",
          "type": "uint256"
        }
      ],
      "name": "Approval",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "tokens",
          "type": "uint256"
        }
      ],
      "name": "Transfer",
      "type": "event"
    }
  ],
  "bytecode": "60806040523480156200001157600080fd5b506040516200100f3803806200100f833981810160405260808110156200003757600080fd5b8101908080519060200190929190805160405193929190846401000000008211156200006257600080fd5b838201915060208201858111156200007957600080fd5b82518660018202830111640100000000821117156200009757600080fd5b8083526020830192505050908051906020019080838360005b83811015620000cd578082015181840152602081019050620000b0565b50505050905090810190601f168015620000fb5780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200011f57600080fd5b838201915060208201858111156200013657600080fd5b82518660018202830111640100000000821117156200015457600080fd5b8083526020830192505050908051906020019080838360005b838110156200018a5780820151818401526020810190506200016d565b50505050905090810190601f168015620001b85780820380516001836020036101000a031916815260200191505b506040526020018051906020019092919050505083600360006101000a81548160ff021916908360ff1602179055508260029080519060200190620001ff9291906200026f565b508160049080519060200190620002189291906200026f565b50806005819055506005546000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050506200031e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002b257805160ff1916838001178555620002e3565b82800160010185558215620002e3579182015b82811115620002e2578251825591602001919060010190620002c5565b5b509050620002f29190620002f6565b5090565b6200031b91905b8082111562000317576000816000905550600101620002fd565b5090565b90565b610ce1806200032e6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461022557806370a082311461024957806395d89b41146102a1578063a9059cbb14610324578063dd62ed3e1461038a57610093565b806306fdde0314610098578063095ea7b31461011b57806318160ddd1461018157806323b872dd1461019f575b600080fd5b6100a0610402565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100e05780820151818401526020810190506100c5565b50505050905090810190601f16801561010d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101676004803603604081101561013157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104a0565b604051808215151515815260200191505060405180910390f35b610189610592565b6040518082815260200191505060405180910390f35b61020b600480360360608110156101b557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059c565b604051808215151515815260200191505060405180910390f35b61022d610917565b604051808260ff1660ff16815260200191505060405180910390f35b61028b6004803603602081101561025f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061092a565b6040518082815260200191505060405180910390f35b6102a9610972565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102e95780820151818401526020810190506102ce565b50505050905090810190601f1680156103165780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103706004803603604081101561033a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610a10565b604051808215151515815260200191505060405180910390f35b6103ec600480360360408110156103a057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bf2565b6040518082815260200191505060405180910390f35b60048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104985780601f1061046d57610100808354040283529160200191610498565b820191906000526020600020905b81548152906001019060200180831161047b57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000600554905090565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548211156105e957600080fd5b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111561067257600080fd5b6106c3826000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7990919063ffffffff16565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061079482600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7990919063ffffffff16565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610865826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c9090919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b600360009054906101000a900460ff1681565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60028054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a085780601f106109dd57610100808354040283529160200191610a08565b820191906000526020600020905b8154815290600101906020018083116109eb57829003601f168201915b505050505081565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115610a5d57600080fd5b610aae826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7990919063ffffffff16565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b41826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c9090919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600082821115610c8557fe5b818303905092915050565b600080828401905083811015610ca257fe5b809150509291505056fea265627a7a72315820b72443db895a78ba6a5792887a143c1eef3b80737abde5b746129f115dbde05164736f6c634300050b0032"
}

這還沒完,您需要在其中找到 bytecode 並將這一鍵對應的值前增加 0x ,增加後的效果如下:

{
  "abi": [
    {
      "constant": true,
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "internalType": "address",
          "name": "delegate",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "numTokens",
          "type": "uint256"
        }
      ],
      "name": "approve",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "totalSupply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "buyer",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "numTokens",
          "type": "uint256"
        }
      ],
      "name": "transferFrom",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "decimals",
      "outputs": [
        {
          "internalType": "uint8",
          "name": "",
          "type": "uint8"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [
        {
          "internalType": "address",
          "name": "tokenOwner",
          "type": "address"
        }
      ],
      "name": "balanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [],
      "name": "symbol",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "constant": false,
      "inputs": [
        {
          "internalType": "address",
          "name": "receiver",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "numTokens",
          "type": "uint256"
        }
      ],
      "name": "transfer",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "constant": true,
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "delegate",
          "type": "address"
        }
      ],
      "name": "allowance",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint8",
          "name": "_decimals",
          "type": "uint8"
        },
        {
          "internalType": "string",
          "name": "_symbol",
          "type": "string"
        },
        {
          "internalType": "string",
          "name": "_name",
          "type": "string"
        },
        {
          "internalType": "uint256",
          "name": "_total_supply",
          "type": "uint256"
        }
      ],
      "payable": false,
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "tokenOwner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "spender",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "tokens",
          "type": "uint256"
        }
      ],
      "name": "Approval",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "tokens",
          "type": "uint256"
        }
      ],
      "name": "Transfer",
      "type": "event"
    }
  ],
  "bytecode": "0x60806040523480156200001157600080fd5b506040516200100f3803806200100f833981810160405260808110156200003757600080fd5b8101908080519060200190929190805160405193929190846401000000008211156200006257600080fd5b838201915060208201858111156200007957600080fd5b82518660018202830111640100000000821117156200009757600080fd5b8083526020830192505050908051906020019080838360005b83811015620000cd578082015181840152602081019050620000b0565b50505050905090810190601f168015620000fb5780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200011f57600080fd5b838201915060208201858111156200013657600080fd5b82518660018202830111640100000000821117156200015457600080fd5b8083526020830192505050908051906020019080838360005b838110156200018a5780820151818401526020810190506200016d565b50505050905090810190601f168015620001b85780820380516001836020036101000a031916815260200191505b506040526020018051906020019092919050505083600360006101000a81548160ff021916908360ff1602179055508260029080519060200190620001ff9291906200026f565b508160049080519060200190620002189291906200026f565b50806005819055506005546000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550505050506200031e565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002b257805160ff1916838001178555620002e3565b82800160010185558215620002e3579182015b82811115620002e2578251825591602001919060010190620002c5565b5b509050620002f29190620002f6565b5090565b6200031b91905b8082111562000317576000816000905550600101620002fd565b5090565b90565b610ce1806200032e6000396000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063313ce56711610066578063313ce5671461022557806370a082311461024957806395d89b41146102a1578063a9059cbb14610324578063dd62ed3e1461038a57610093565b806306fdde0314610098578063095ea7b31461011b57806318160ddd1461018157806323b872dd1461019f575b600080fd5b6100a0610402565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100e05780820151818401526020810190506100c5565b50505050905090810190601f16801561010d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101676004803603604081101561013157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104a0565b604051808215151515815260200191505060405180910390f35b610189610592565b6040518082815260200191505060405180910390f35b61020b600480360360608110156101b557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061059c565b604051808215151515815260200191505060405180910390f35b61022d610917565b604051808260ff1660ff16815260200191505060405180910390f35b61028b6004803603602081101561025f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061092a565b6040518082815260200191505060405180910390f35b6102a9610972565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102e95780820151818401526020810190506102ce565b50505050905090810190601f1680156103165780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103706004803603604081101561033a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610a10565b604051808215151515815260200191505060405180910390f35b6103ec600480360360408110156103a057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bf2565b6040518082815260200191505060405180910390f35b60048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156104985780601f1061046d57610100808354040283529160200191610498565b820191906000526020600020905b81548152906001019060200180831161047b57829003601f168201915b505050505081565b600081600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000600554905090565b60008060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020548211156105e957600080fd5b600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111561067257600080fd5b6106c3826000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7990919063ffffffff16565b6000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061079482600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7990919063ffffffff16565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610865826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c9090919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b600360009054906101000a900460ff1681565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60028054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610a085780601f106109dd57610100808354040283529160200191610a08565b820191906000526020600020905b8154815290600101906020018083116109eb57829003601f168201915b505050505081565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115610a5d57600080fd5b610aae826000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7990919063ffffffff16565b6000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b41826000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c9090919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600082821115610c8557fe5b818303905092915050565b600080828401905083811015610ca257fe5b809150509291505056fea265627a7a72315820b72443db895a78ba6a5792887a143c1eef3b80737abde5b746129f115dbde05164736f6c634300050b0032"
}

為了方便大家比較差異,只能把內容全部貼到這裡,還請大家包容理解,請您一定要找到這個差異並在編譯後新增 0x 否則,在後續部署合約時,會出現錯誤。abi和bytecode都寫在同一個json檔案內的好處是,我們只需要讀取 ERC20.json 檔案就可以使用它們呼叫Conflux建立智慧合約

  1. 智慧合約編譯完了,我們需要把它部署到Conflux網路中,還需要您花一些時間做如下的準備工作:
  2. 參考如何建立Conflux網頁錢包建立屬於您自己的Conflux錢包;
  3. 登入錢包後,點選頁面中 申領測試幣 按鈕,申請100CFX測試幣,後續部署合約需要進行消費;
  4. 點選左側欄目中的 錢包私鑰 獲取您的私鑰,這個私鑰僅僅用於部署合約,不要告訴別人,因為可以直接通過私鑰進入到您的錢包,不能進行公開。
  5. 編寫 deploy.js ,其目的是將所寫合約部署到Conflux網路,且部署的位置就是您填寫私鑰對應的合約地址(後續會有講解哦,不要著急!)
// 填寫您的私鑰地址,為了減少資訊洩露,我使用的測試賬戶私鑰後20位已使用星號進行替代處理,不要複製我的哈!
const PRIVATE_KEY = '0x2772b19636f1d183a9a2a0d27da2a1d0efb97637b425********************';
// 合約地址
const CONTRACT = '';
const { Conflux } = require('js-conflux-sdk');
const compiled = require(`./build/${process.argv[2]}.json`);
const config = require('./config.json');

async function main() {
  const cfx = new Conflux({
    url: 'http://main.confluxrpc.org',
  });
  const account = cfx.Account(PRIVATE_KEY); // create account instance
  console.log(account.address); 

  // create contract instance
  const contract = cfx.Contract({
      
    abi: compiled.abi,
    bytecode: compiled.bytecode,
  });
  //console.log(contract.address)
  const receipt = await contract.constructor(config["decimals"], config["symbol"], config["name"], config["total_supply"])
    .sendTransaction({ from: account })
    .confirmed();
  console.log("recv:"+receipt.contractCreated); 
}
main().catch(e => console.error(e));

需要說明的是:nonce是賬戶的交易序號每次一發起交易(包括部署合約)會使用一個nonce成功後nonce自增1,而如果交易執行不成功時nonce不會自增1(在這裡指定了nonce,您也可以把它刪除以使用Conflux的預設值),再次部署的時候,因為系統中已存在一個錯誤而不能執行的nonce,會報nonce已存在錯誤執行效果如下圖所示:

nonce_error

const config = require('./config.json'); 語句所讀取的 config.json 檔案內容如下所示,其中private_key使用與 deploy.js 相同的私鑰:

{
  "private_key": "2772b19636f1d183a9a2a0d27da2a1d0efb97637b425********************",
  "network": "homestead",
  "ERC20": "0x0DEd9F7D82a24099F09AF7831CaB61B31Df10487",
  "name": "Kanchan Coin",
  "symbol": "SNK",
  "total_supply": "1000000000000000000000000",
  "decimals": 18
}

部署與呼叫

  1. 執行 deploy.js 的方法如下:
node deploy.js <contract_name>

以我們撰寫的合約為例,方法如下:

node deploy.js ERC20

需要說明的是 ERC20 是命令列引數,通過 deploy.js 內的程式碼 process.argv[2] 獲得,幫助我們程式去 ./contracts/ 資料夾內尋找名為 test.json 並進行部署,其輸出結果如下圖所示:

  1. 通過程式回顯 recv:0x846ba74923c670a5aec4e58b7551396b9bed5658 獲取到了我們部署合約的地址為 0x846ba74923c670a5aec4e58b7551396b9bed5658 ,使用該地址繼續編寫 call.js 程式碼,訪問並呼叫合約:
const { Conflux, util } = require('js-conflux-sdk');
//合約持有者地址
const public_address = '0x17b38613e633c2b8fb4686a3a62b9b782ac5e0ca';
// 部署合約地址的地址,與0x17b38613e633c2b8fb4686a3a62b9b782ac5e0ca關聯:上面已經進行解釋
const contractAddress = '0x846ba74923c670a5aec4e58b7551396b9bed5658';
const PRIVATE_KEY = '0x2772b19636f1d183a9a2a0d27da2a1d0efb97637b425********************';
const compiled = require(`./build/ERC20.json`)
async function main() {
  const cfx = new Conflux({
    url: 'http://main.confluxrpc.org',
  });
  const contract = cfx.Contract({
    address : contractAddress,
    abi: compiled.abi,
  });
  // 檢視供應總量
  let result = await contract.totalSupply();
  console.log("Total supply:"  + result.toString());
  const account = cfx.Account(PRIVATE_KEY);
  
  //檢視賬戶餘額
  let balance = await contract.balanceOf(public_address);
  console.log("address:"+public_address+" have balance:"+balance.toString());//這是部署合約的賬戶公開地址
  
  //嘗試進行交易
  let allowance_result=await contract.allowance(public_address,'0x1941E3137aDDf02514cBFeC292710463d41e8196');
  console.log("tx:"+allowance_result);
  
  approve_result=await contract.approve(transfer_address,1000);
  console.log("approve result:"+approve_result);
  //嘗試進行轉賬操作
  let transfer_balance=await contract.balanceOf(transfer_address);
  console.log("address:"+transfer_address+" have balance:"+transfer_balance.toString());
  
  await contract.transfer(transfer_address,100).sendTransaction({
      from: account
  }).confirmed();
  
  let transfer_balance_after=await contract.balanceOf(transfer_address);
  console.log("after transfer address:"+transfer_address+" have balance:"+transfer_balance_after.toString());
  
}
main().catch(e => console.error(e));
  1. 呼叫結果如下 :

transfer

後記

  1. 經過上述環境配置這一波操作後,我們的 package.json 檔案內容也有所改變:

    {
      "name": "contract-project",
      "version": "1.0.0",
      "description": "smart Contract",
      "main": "index.js",
      "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "Yumingyuan",
      "license": "ISC",
      "dependencies": {
     "ethers": "^5.0.3",
     "fs-extra": "^9.0.1",
     "js-conflux-sdk": "^0.10.3",
     "solc": "^0.5.11"
      }
    }
  2. 專案的路徑檔案樹如下所示:

    +Contract-project
     -call.js
     -compile.js
     -config.json
     -deploy.js
     +build
         -ERC20.json
         -SafeMath.json
     +contracts
         -test.sol
    -package.json
    -package-lock.json

感謝社群小夥伴:餘銘緣的辛苦整理~
鳴謝:刺客panpan 兩位大佬的指導與幫助。

相關文章