The Complete Guide to Using cfxtruffle

Truffle is a well-known smart contract development tool in the Ethereum ecosystem. It provides practical functions such as compilation, linking, testing, and deployment, and is loved by the majority of Solidity developers.
As a new generation of high-performance public chain, Conflux not only achieves two orders of magnitude performance improvement under the premise of complete decentralization, but also realizes a virtual machine compatible with EVM.
It means that Dapp developers can develop applications on the Conflux network without learning a new development language.
In order to improve the contract development experience of Conflux, the official also recently migrated and transformed Truffle and created Conflux-Truffle to support the contract development of Conflux.
This article will introduce in detail how to use Conflux Truffle to develop Conflux smart contracts, from the environment construction, project creation, development, compilation, testing, deployment, one by one.

  1. Introduction to Basic Concepts
  2. Dependencies ready
  3. Develop smart contracts with cfxtruffle
  4. Reference documentation

Introduction to Basic Concepts

The blockchain world is decentralized, all participating nodes have the same data, and everyone is equal. The organization of data on the blockchain is as follows: first, multiple transactions are packaged together to form a block,
Then the blocks are linked according to the sequence to form a chain, so it is called a blockchain. The original blockchain (bitcoin chain) only supports transfers, so there is only one application (bitcoin).
Ethereum has pioneered the addition of EVM functions and has Turing integrity, so various decentralized applications (Dapps) can be freely developed on it.

Epoch & storageLimit

The traditional blockchain ledger is a single chain, and each block has a number from front to back, which is called a block number. conflux has developed a new ledger structure: tree graph, which achieves high throughput, Low latency.

In the tree graph ledger structure, if you only look at the parent side, it is a Tree, and if the parent side refers to both sides, it is a Graph. It is this structure that allows the conflux network to emit blocks concurrently, i.e. multiple blocks can
are generated after a certain block. So there is no concept of block number in Conflux.
But in order to achieve total order, Conflux starts from the genesis block through the GHAST rule, and selects the heaviest subtree block as the pivot block among all its sub-blocks, and all the pivot blocks are chained together to form a chain
Defined as pivot chain, if you only look at the pivot chain, it is consistent with the ordinary blockchain structure. On this chain, an Epoch is defined based on each pivot block, so you can put the
Epoch is understood as a concept corresponding to block number, but there may be multiple blocks in each epoch in conflux.

In the real world, sending a transfer transaction requires paying a fee to the bank, sending a transaction in Bitcoin requires paying a fee to the miner, and the same is true in Ethereum. Specifically, transactions on the Ethereum network are ultimately handled by miners
Executed by the running EVM, gas is used to measure the workload of a transaction (which can be understood as the working hours of the work). The transaction sender can specify the price that is willing to pay for each workload, namely gasPrice, when sending a transaction.
So the final transaction fee is gas * gasPrice.
The gas specified when sending a transaction is a limit value, that is, the sender is willing to pay so much gas for a transaction. be executed.

In the Dapp system, transaction execution requires miners to perform calculations and pay for computing resources, but also requires miners to store the state of the contract, so it needs to pay for storage resources. When sending transactions in the Conflux system, you also need to store the state
Mortgage a part of the fee, so when sending a transaction in conflux, there will be one more storageLimit parameter than Ethereum, which is used to set the upper limit of the fee that is willing to be mortgaged for a certain transaction. The cost of staking after the contract frees up the used storage space
will also be refunded.

Dapp

All the states of traditional apps are stored in the database of the centralized server. To query and modify the state, you can directly execute SQL operations in the database through the API. Although the speed is fast, there are problems such as random data tampering and privacy leakage.
Dapps are applications that run on the blockchain system and are called decentralized applications. The application state is stored on the blockchain system, the state query needs to go through the network, and the state change can only be done by sending a transaction

Wallet

In traditional Internet applications, services are accessed through accounts, but the data is essentially stored on the service provider's server. In the blockchain world, all transactions need to be sent through wallets, such as MetaMask of Ethereum and Portal of Conflux.
In the wallet you can check balances, send transactions, interact with Dapps, claim testnet tokens, and more.
In fact, the essence is that the private key of your account is stored in the wallet. In the blockchain world, only the private key can sign and send transactions.
The private key should only be kept by yourself and not known by others.

Dependencies ready

Before developing smart contracts, you need to prepare some development environments.

NPM

npm is a package management tool for node.js. Because cfxtruffle is developed using node, it needs to be installed using npm.
npm is included in the installation package of node, as long as node is installed successfully, npm will be installed successfully.
To install node, you can directly download the official installation package, or use nvm ,
After installation, you can check the version with the following command:

$ node -v
$ npm -v

cfxtruffle

After the npm installation is successful, you can install cfxtruffle.

$ npm install -g conflux-truffle
# 安装完成之后, 可使用如下命令测试
$ cfxtruffle -v

There are two points to note:

  1. When npm install, you need to specify the global installation through -g
  2. The name of the npm install package is conflux-truffle , and the installed command line program is cfxtruffle

conflux-rust docker

To debug the development contract, you need to run a local node. The easiest way to run is to use docker to run the 161e4e2c30e241 conflux-rust image. In this way, you do not need to compile the program yourself and prepare the configuration file. You only need to have the docker environment installed locally.

# 下载 conflux-rust docker 镜像
$ docker pull confluxchain/conflux-rust
# 启动节点
$ docker run -p 12537:12537 --name cfx-node confluxchain/conflux-rust

A simple command starts a local Conflux node, and the node will create 10 local accounts at the same time, each account will be allocated 1000 CFX for contract deployment and interaction, and these accounts will be automatically unlocked.
After the conflux-rust image is started, cfxtruffle can directly use it to deploy and interact with contracts.

Of course, you can compile your own or download-node, custom configuration file, then run the local node, concrete can be found this introduction .
Of course, after the nodes are running, you need to manually create local accounts, transfer them to them to have a balance, and manually unlock them.

instruction:

  1. Local accounts can be created using the node command line (conflux account new) or local rpc, and local accounts can be accessed by the node program and used directly for transaction signing.
  2. The local account can cfx_sendTransaction . The signature operation of the transaction is completed by the node, and no prior signature is required. It is very convenient to develop Dapp locally.
  3. For security, the local account needs to be unlocked before sending transactions directly. You can cfx_sendTransaction , or you can call unlock rpc to unlock the account in advance.
  4. The current cfxtruffle requires a conflux-rust image of version 0.6.0 or higher to be used.

conflux portal

Conflux portal is a browser plugin wallet that supports browsers such as Chrome and Firefox. Click the link on the official website to download and install (may need to overturn the wall).

After installation, the wallet can switch between different conflux networks. Of course, it can also connect to the local network, and can claim test network tokens. If the contract is tested locally, it can be deployed to the test network for testing.

Develop smart contracts with cfxtruffle

After the environment is ready, you can use cfxtruffle to develop smart contracts. We will use cfxtruffle to develop a coin contract with minting and transfer functions.

First look at all the commands of cfxtruffle:

$ cfxtruffle -h
Usage: cfxtruffle <command> [options]

Commands:
  compile   Compile contract source files
  config    Set user-level configuration options
  console   Run a console with contract abstractions and commands available
  create    Helper to create new contracts, migrations and tests
  debug     Interactively debug any transaction on the blockchain
  deploy    (alias for migrate)
  exec      Execute a JS module within this Conflux-Truffle environment
  help      List all commands or provide information about a specific command
  init      Initialize new and empty Conflux project
  install   Install a package from the Conflux Package Registry
  migrate   Run migrations to deploy contracts
  networks  Show addresses for deployed contracts on each network
  obtain    Fetch and cache a specified compiler
  opcode    Print the compiled opcodes for a given contract
  publish   Publish a package to the Conflux Package Registry
  run       Run a third-party command
  test      Run JavaScript and Solidity tests
  unbox     Download a Conflux-Truffle Box, a pre-built Conflux-Truffle project
  version   Show version number and exit
  watch     Watch filesystem for changes and rebuild the project automatically

See more at http://truffleframework.com/docs

We can also view help for a specific command:

$ cfxtruffle help create

Create project

The first step we need to create a cfxtruffle base project:

# 创建一个空项目
$ cfxtruffle init project-name
# 查看项目目录结构
$ cd project-name && tree
.
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js

3 directories, 3 files

The newly created project has the following folders and files:

  • contracts solidity contract code directory
  • migrations Contract deployment migration script directory
  • test Unit Test Directory
  • truffle-config.js cfxtruffle configuration file (js file)

In addition, cfxtruffle also provides many more functional project templates (box) or scaffolding. Using templates will save a lot of initialization work:

$ mkdir project-name && cd project-name
$ cfxtruffle unbox metacoin

You can go to the official box ) list to see if there is a template that meets your needs.

Note: These two commands may need to overturn the wall in China.

add contract

The init command will simply create an empty project containing a base Migrations contract and its migration script.
We need to add new files to develop new contracts. The create command can be used to create all files related to a contract, including contract source (contract), deployment script (migration), and test script (test).
Its usage is: cfxtruffle create <artifact_type> <ArtifactName>

Now let's create the source file for the Coin contract

$ cfxtruffle create contract Coin

After the above command is executed, a Coin.sol file will be created in the contracts directory, where we can write solidity code.
The following is the solidity of the Coin contract, which realizes the functions of minting, transferring, and balance query.

pragma solidity ^0.5.10;

contract Coin {
    // An `address` is comparable to an email address - it's used to identify an account on Ethereum.
    // Addresses can represent a smart contract or an external (user) accounts.
    // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
    address public owner;

    // A `mapping` is essentially a hash table data structure.
    // This `mapping` assigns an unsigned integer (the token balance) to an address (the token holder).
    // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
    mapping (address => uint) public balances;

    // Events allow for logging of activity on the blockchain.
    // Ethereum clients can listen for events in order to react to contract state changes.
    // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
    event Transfer(address from, address to, uint amount);

    // Initializes the contract's data, setting the `owner`
    // to the address of the contract creator.
    constructor() public {
        // All smart contracts rely on external transactions to trigger its functions.
        // `msg` is a global variable that includes relevant data on the given transaction,
        // such as the address of the sender and the ETH value included in the transaction.
        // Learn more: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
        owner = msg.sender;
    }

    // Creates an amount of new tokens and sends them to an address.
    function mint(address receiver, uint amount) public {
        // `require` is a control structure used to enforce certain conditions.
        // If a `require` statement evaluates to `false`, an exception is triggered,
        // which reverts all changes made to the state during the current call.
        // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions

        // Only the contract owner can call this function
        require(msg.sender == owner, "You are not the owner.");

        // Ensures a maximum amount of tokens
        require(amount < 1e60, "Maximum issuance succeeded");

        // Increases the balance of `receiver` by `amount`
        balances[receiver] += amount;
    }

    // Sends an amount of existing tokens from any caller to an address.
    function transfer(address receiver, uint amount) public {
        // The sender must have enough tokens to send
        require(amount <= balances[msg.sender], "Insufficient balance.");

        // Adjusts token balances of the two addresses
        balances[msg.sender] -= amount;
        balances[receiver] += amount;

        // Emits the event defined earlier
        emit Transfer(msg.sender, receiver, amount);
    }
}

The specific properties and methods of the contract are as follows:

  • owner attribute: the contract owner, only the contract owner can perform the minting operation. The owner has a public attribute, so a corresponding method is automatically created to query the owner of the contract
  • balances property: balance, map type, used to store account balance information,
  • constructor method: This method will only be executed once when the contract is created, and will not be executed after that. It is mainly used to set the initial state of the contract
  • mint method: minting coins, which can generate a specified amount of coins for an address
  • Transfer method: transfer, transfer to another account
  • Transfer event: Whenever a transfer operation occurs, this event will be triggered.

compile

Solidity is a high-level language, and its syntax refers to C++, python, js, but solidity cannot be deployed directly and needs to be compiled first.
This is actually similar to a C++ program, which needs to be compiled into a binary program to execute.
The compiler of solc can be installed and used separately, but compile is integrated in cfxtruffle and can be used directly.

# 编译合约
$ cfxtruffle compile
# 首次执行,会创建一个 build 目录,编译后的内容会保存在该目录于合约对应的 json 文件中。

After solidity is compiled, bytecode and abi (the description of the external interface of the Application Binary Interface contract) will be generated, both of which will be used during deployment.
In the json file generated by cfxtruffle after compilation, the file contains the bytecode, abi, ast, name and other information of the contract, which will be used in subsequent deployment, debugging and other steps.

truffle-config.js

truffle-config.js is the configuration file of the project, which is very important. Many cfxtruffle commands use the configuration here.

module.exports = {
  networks: {
    development: {
     host: "127.0.0.1",     // Localhost (default: none)
     port: 12537,            // Standard Conflux port (default: none)
     network_id: "*",       // Any network (default: none)
    },
  },
}

The most important configuration item is networks, which is used to configure the network for cfxtruffle deployment interaction, and the development network is used by default.
In addition, you can also configure test, compiler and other information, see official document

local deployment

When the contract is developed, it will be deployed and tested on the local node first. Earlier we introduced how to use docker to start a local node. The started node can be used for local deployment and testing.
The migrate mainly used for contract deployment (deploy is an alias for migrate).
migrations folder is used to store migration scripts. These scripts manage the deployment of contracts. Usually, each contract corresponds to a migration script.
After the cfxtruffle project is created, there will be a Migrations.sol contract and its corresponding migration script.
This contract is mainly used to record the deployment serial number (integer serial number) of the contract on the chain.
Every time the migrate command is executed, it will go to the chain to query the location of the last deployment, and then determine whether there are new contracts that need to be deployed.

Migrations.sol contract code is as follows:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.21 <0.7.0;

contract Migrations {
  address public owner;
  uint public last_completed_migration;

  constructor() public {
    owner = msg.sender;
  }

  modifier restricted() {
    if (msg.sender == owner) _;
  }

  function setCompleted(uint completed) public restricted {
    last_completed_migration = completed;
  }
}

Now let's add a Coin contract deployment script using the create command

$ cfxtruffle create migration Coin
# 生成的 migration 脚本文件名中,会包含一个时间戳数字,我们需要手动改为递增的序号比如 2_coin.js

Then you can add the following code in it

// require the Coin artifact
const Coin = artifacts.require("Coin")
module.exports = function(deployer) {
  // when `deploy` command run, will execute code here
  deployer.deploy(Coin);
};

After the setup is complete, you can run the deployment command

$ cfxtruffle deploy
...
...
2_coin.js
=========

   Deploying 'Coin'
   ----------------
   > transaction hash:    0xd001fb34df8e634e21d7d225bfd0da6128237cd74f170fbc97ad820098ceaeff
   > Blocks: 0            Seconds: 0
   > contract address:    0x8DCe85c454d401318C03956529674b9E2B8E8680
   > block number:        1608
   > block timestamp:     1595475207
   > account:             0x1357DA1577f40EE27aE8870C7f582bD345C65A1c
   > balance:             997.71313608
   > gas used:            437390 (0x6ac8e)
   > gas price:           20 GDrip
   > value sent:          0 CFX
   > total cost:          0.0087478 CFX


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:           0.0087478 CFX


Summary
=======
> Total deployments:   2
> Final cost:          0.01221746 CFX

After the deploy command is executed, the result of the deployment will be output, such as transaction hash, contract address, cost, etc.

contract interaction

After the contract is deployed, we usually need to interact with the contract, such as querying the status, initiating transfers, and so on. cfxtruffle contains the console command, which can open an interactive command line environment,
This environment provides contract JS objects, account lists, and js-conflux-sdk instances and utils, which are very convenient.
You can instantiate the contract object in it, and then interact with the contract through the instance object, such as: query the status, modify the balance, etc.
The following is an example of a Coin contract interaction:

$ cfxtruffle console
cfxtruffle(development)> .help  # 查看帮助
cfxtruffle(development)> Object.keys(global) # 查看console环境,可用的全局对象: accounts, cfx, cfxutil, Coin, Migrations
# 实例一个 Coin 合约, 调用合约对象的 deployed() 方法
cfxtruffle(development)> let coin = await Coin.deployed()
# 查看合约的 owner 是谁
cfxtruffle(development)> let owner = await coin.owner()
cfxtruffle(development)> owner
'0x1357DA1577f40EE27aE8870C7f582bD345C65A1c'
# 查看所有可用 account
cfxtruffle(development)> accounts
[
  '0x1357DA1577f40EE27aE8870C7f582bD345C65A1c',
  '0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56',
  '0x1f69a930B6A4F2BC5Ac03B79A88af9f6bBa0d137'
]
# 查询余额
cfxtruffle(development)> let balance = await coin.balances('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c')
cfxtruffle(development)> balance.toString()
# 铸造新币
cfxtruffle(development)> await coin.mint('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c', 10000)
cfxtruffle(development)> balance = await coin.balances('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c')
cfxtruffle(development)> balance.toString()
'10000'
# 转账
cfxtruffle(development)> await coin.transfer('0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56', 100)
cfxtruffle(development)> balance = await coin.balances('0x1357DA1577f40EE27aE8870C7f582bD345C65A1c')
cfxtruffle(development)> balance.toString()
'9900'
# 指定交易的 gasPrice
cfxtruffle(development)> await coin.transfer('0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56', 100, {gasPrice: '0x100'})
# 集成的 cfx 对象是一个 js-conlfux-sdk 实例
cfxtruffle(development)> await cfx.getBalance('0x148A9696F8DCf4d6cB01eC80F1047a3476bA5C56')
cfxtruffle(development)> await cfx.getNextNonce("0xbbd9e9be525ab967e633bcdaeac8bd5723ed4d6b")
# cfxutil
cfxtruffle(development)> let drip = cfxutil.unit.fromCFXToGDrip(0.1)
cfxtruffle(development)> let randomKey = cfxutil.sign.randomPrivateKey()
# 
cfxtruffle(development)> .exit
  • In addition, you can deploy new contracts in the console, instantiate contracts with specified addresses, estimateGas, etc. For detailed interaction methods of contracts, please refer to here document
  • In addition, in the console, you can directly execute the cfxtruffle command: networks, compile etc.
  • Note: cfxtruffle currently does not support the develop command

contract test

cfxtruffle has a built-in test framework (Mocha & Chai), which can write js and solidity tests, and all test codes are located in the test folder.
Next use the create command to create a test file.

$ cfxtruffle create test Coin

In it you can add the following code

const Coin = artifacts.require("Coin");
// 注意:这里使用 contract 而不是 describe
contract("Coin", function(accounts) {
  it("should assert true", async function() {
    let instance = await Coin.deployed();
    await instance.mint(accounts[0], 10000)
    let balance = await instance.balances(accounts[0]);
    assert.equal(balance.toString(), '10000', "10000 wasn't in the first account");
  });
});

Then use the test command to execute the test

$ cfxtruffle test

Every time cfxtruffle runs a test, a new contract (clean-room) will be deployed completely. For details on how to write test code, please refer to the test writing instructions of js and solidity

Deploy to remote nodes

The contract is developed locally. After the test is completed, you can try to deploy it to the test network, or release the contract to the main network. cfxtruffle also supports remote deployment.
First, you need to add a new network configuration such as testnet to the project configuration file, and set the host and port inside.
Then you need to set the privateKeys field, which is an array of private keys (the remote deployment can only sign locally).

testnet: {
    host: "wallet-testnet-jsonrpc.conflux-chain.org",
    port: 12537,            
    network_id: "*",       
    // 注意:从 portal 获取的私钥需要添加 0x 前缀,privateKeys 也可以指定单个 key,若配置了私钥,请注意不要将代码上传到公开代码仓储中。
    privateKeys: ['your-private-key']  
},

The test environment deposit button of Conflux portal provides a CFX faucet, which can claim some test environment tokens for contract deployment.

Then you can deploy the contract to the specified network by specifying --network when executing the deploy command

$ cfxtruffle deploy --network testnet

Execute external scripts or commands

cfxtruffle also provides two commands, run exec , which can be used to execute external scripts, in which some logic for interacting with contracts can be written, which is very useful in many cases.

You can add a script get-balance.js to the project root directory with the following content

const Coin = artifacts.require("Coin");
module.exports = async function(callback) {
    try {
        let instance = await Coin.deployed();
        let accounts = await cfx.getAccounts();
        let balance = await instance.balances(accounts[0]);
        console.log(`balance of ${accounts[0]} is: ${balance.toString()}`);
    } catch(e) {
        console.error(e);
    }
    callback();
}

Then you can use the exec command to execute it

$ cfxtruffle exec ./get-balance.js

run command can be used to execute the truffle plugin:

$ npm install --save-dev truffle-plugin-hello

and add a declaration for the plugin in truffle-config.js

module.exports = {
  /* ... rest of truffle-config */

  plugins: [
    "truffle-plugin-hello"
  ]
}

Then you can use the run command to execute

$ cfxtruffle run hello

Now there are some contract verify, lint, coverage and other plug-ins on npm that can be used directly. Of course, you can also write your own plug-ins. For details, see here

Summarize

So far, we have used cfxtruffle to develop a Coin smart contract from beginning to end. The usage of each function and other advanced commands are not described in detail. You can refer to the official documentation of truffle.
As a new generation of public chain, Conflux will be fully launched on the main network. I hope that all smart contract developers will experience its flying performance. I also hope that more and more applications can be born on the Conflux network.
Enabling the true digitization of trust.

refer to

  1. truffle documentation
  2. conflux-rust docker
  3. conflux rpc
  4. how to run a conflux local node
  5. Solidity document
  6. js-conflux-sdk
  7. conflux portal
  8. conflux scan

related database:


Conflux中文社区
66 声望18 粉丝

Conflux网址:[链接]