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.
- Introduction to Basic Concepts
- Dependencies ready
- Develop smart contracts with cfxtruffle
- 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:
- When npm install, you need to specify the global installation through -g
- The name of the npm install package is
conflux-truffle
, and the installed command line program iscfxtruffle
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:
- 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.
- 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. - 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. - 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 directorymigrations
Contract deployment migration script directorytest
Unit Test Directorytruffle-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
- truffle documentation
- conflux-rust docker
- conflux rpc
- how to run a conflux local node
- Solidity document
- js-conflux-sdk
- conflux portal
- conflux scan
related database:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。