Truffle 是最流行的开发框架,能够在本地编译、部署智能合约,使命是让开发更容易。
Truffle 需要以太坊客户端支持,需要支持标准的 JSON RPC API。
Truffle 的源代码地址:
https://github.com/trufflesuite/truffle
适合 Truffle 开发的客户端
当开发基于 Truffle 的应用时,推荐使用EthereumJS TestRPC。它是一个完整的在内存中的区块链仅仅存在于你开发的设备上。相对于 Geth,TestRPC 它在执行交易时是实时返回,而不等待默认的出块时间,这样你可以快速验证你新写的代码,当出现错误时,也能即时反馈给你。它同时还是一个支持自动化测试的功能强大的客户端。Truffle 充分利用它的特性,能将测试运行时间提速近90%。
接下来的例子,我们会使用 Truffle 分别连接 Geth 和 TestRPC 测试智能合约的部署,首先我们先分别安装Truffle、Geth、TestRPC。
首先安装 Geth。详见前面的文章
安装 Truffle
npm install -g truffle
"dependencies": {
"mocha": "^4.1.0",
"original-require": "1.0.1",
"solc": "0.5.0"
},
npm uninstall -g truffle
npm install -g truffle
$>mkdir test_truffle
$>ls
mist test_truffle
$>cd test_truffle/
$>ls
$>truffle init
✔ Preparing to download
✔ Downloading
✔ Cleaning up temporary files
✔ Setting up box
Unbox successful. Sweet!
Commands:
Compile: truffle compile
Migrate: truffle migrate
Test contracts: truffle test
完成后,会产生下列这些目录:
$>truffle compile
Compiling your contracts...
====================
> Compiling ./contracts/Migrations.sol
> Artifacts written to /home/chen/chen/ethereum-wallet/test_truffle/build/contracts
> Compiled successfully using:
- solc: 0.5.0+commit.1d4f565a.Emscripten.clang
truffle compile --compile-all
import "./AnotherContract.sol";
pragma solidity ^0.4.17;
contract Hello_blake_top {
//say hello blake.top
function say() public pure returns (string) {
return "Hello blake.top";
}
// print name
function print(string name) public pure returns (string) {
return name;
}
}
migrations/1_initial_migration.js
部署脚本,将我们刚才创建的Hello_blake_top.sol 文件设置到发布配置文件中,内容如下:const Migrations = artifacts.require("Migrations");
const Hello_blake_top = artifacts.require("./Hello_blake_top.sol");
module.exports = function(deployer) {
deployer.deploy(Migrations);
deploy.deploy(Hello_blake_top);
};
将项目使用truffle compile命令进行编译,编译后的文件都放在了 ./build/contracts 目录下:
Hello_blake_top.sol 编译后的文件是 ./build/contracts/Hello_blake_top.json 中,后面在部署到 geth 中,我们会用到。
module.exports = {
networks: {
development: {
host: "localhost",
port: 8545,
network_id: "*"
}
}
};
接下来,我们会使用上面的智能合约,分别在 testRPC 和 geth 中进行部署测试。
truffle的智能合约项目部署,使用下面的命令:truffle migrate
这个命令会执行所有 migrations 目录下的 js 文件。如果之前执行过 truffle migrate 命令,再次执行,只会部署新的 js 文件,如果没有新的 js 文件,不会起任何作用。如果使用–reset 参数,则会重新的执行所有脚本的部署。
如果要部署到指定的网络,可以使用–network参数,例如:
truffle migrate --network live
多个网络的配置格式如下:
networks: {
development: {
host: "localhost",
port: 8545,
network_id: "*" // match any network
},
live: {
host: "178.25.19.88", // Random IP for example purposes (do not use)
port: 80,
network_id: 1, // Ethereum public network
// optional config values:
// gas Gas limit used for deploys. Default is 4712388
// gasPrice Gas price used for deploys. Default is 100000000000 (100 Shannon).
// from - default address to use for any transaction Truffle makes during migrations
// provider - web3 provider instance Truffle should use to talk to the Ethereum network.
// - if specified, host and port are ignored.
}
}
chen@ubuntu:~$ testrpc
EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)
Available Accounts
==================
(0) 0x14b1cf637d214963cd31c923711930aa7b97fd5b
(1) 0x8703ffa009e31e0eebf3aa2dacb32486e06077c0
(2) 0x2237e37056828dfb27e94a3274132a59ae5b4413
(3) 0x1744da91d3eca87fbcf2711740b12e62739965ec
(4) 0x3c35f08665a047f90ddce14d0f82b703a240a56f
(5) 0x2d4fa09b9f71d7b66a9c36d15eeda7311f49b837
(6) 0xc75df94d9a941cbab2a1297bd5770f0c036e4f89
(7) 0x7aaa5ff5f64970268183e06f56110a30571f753f
(8) 0x7c3b0b8193fff996b01bc77154fb91f3b361a646
(9) 0x2a5c667ba684bf0b7db61d7dec17751a6f6e03f8
Private Keys
==================
(0) 237fda9ce07f11cff672e58f633b514575613e96cb2653ea9d08ca69e882f042
(1) 50ea263a896e3b4ec3337ede58131e71dfdd71e7afa879b0957f3a3443b14b85
(2) dd251d5192bb0a73c1a9896f394099d646f6c8e2e96b88e7288f4e83d70a7392
(3) 3409d7a67896bbf2e6a8c9e414bb75284cf87fc66b9bb0e222cb8648a494709e
(4) e1229c76e7c1e5aad682c8b27da5d1a67171c7b3ad560fdb52cb1ae3855cc31d
(5) b627f6f491e8ed270733cd2483287cfa092d0b56b15de0f838ffc06257416c5b
(6) b25209ef82d3a44205d72b418b86476ac710afa1dcc582525954bc31db6c6832
(7) 20b540aa45c394306d38c1d37458d9c46d404311f822fc149fcd523c2e34d84d
(8) 838e1a99cca13ced482d9af2dbba6911a4ee3b676baa395a1462fd29fec070a5
(9) f586c3fe792d63b7459e399454d1798c21eb191db861aff67d9ec771cc22f83a
HD Wallet
==================
Mnemonic: virus bamboo couch ankle afraid glide family attend empty bulb stadium cricket
Base HD Path: m/44'/60'/0'/0/{account_index}
Listening on localhost:8545
通过 truffle migrate 命令,对合约进行部署。
测试部署成功的智能合约
truffle console
打开一个控制台和部署的合约进行交互。truffle(development)> var contract;
undefined
truffle(development)> Hello_mshk_top.deployed().then(function(instance){contract= instance;});
undefined
truffle(development)> contract.say()
'Hello blake'
truffle(development)> contract.print("hello,blake")
'hello,blake'
// Deploy a single contract without constructor arguments
deployer.deploy(A);
// Deploy a single contract with constructor arguments
deployer.deploy(A, arg1, arg2, ...);
// Don't deploy this contract if it has already been deployed
deployer.deploy(A, {overwrite: false});
// Set a maximum amount of gas and `from` address for the deployment
deployer.deploy(A, {gas: 4612388, from: "0x...."});
// Deploy multiple contracts, some with arguments and some without.
// This is quicker than writing three `deployer.deploy()` statements as the deployer
// can perform the deployment as a single batched request.
deployer.deploy([
[A, arg1, arg2, ...],
B,
[C, arg1]
]);
// External dependency example:
//
// For this example, our dependency provides an address when we're deploying to the
// live network, but not for any other networks like testing and development.
// When we're deploying to the live network we want it to use that address, but in
// testing and development we need to deploy a version of our own. Instead of writing
// a bunch of conditionals, we can simply use the `overwrite` key.
deployer.deploy(SomeDependency, {overwrite: false});
更多的情况可以参见:https://truffleframework.com/docs/truffle/getting-started/running-migrations
https://blog.csdn.net/xq723310/article/details/82904178
https://blog.csdn.net/ITleaks/article/details/82218485
https://www.jianshu.com/p/b680b9558b22
pragma solidity ^0.4.16;
contract Token{
uint256 public totalSupply;
function balanceOf(address _owner) public constant returns (uint256 balance);
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns
(bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
function allowance(address _owner, address _spender) public constant returns
(uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256
_value);
}
contract TokenDemo is Token {
string public name;
uint8 public decimals;
string public symbol;
mapping (address => uint256) public balances;
mapping (address => mapping (address => uint256)) allowed;
constructor(uint256 _initialAmount, string _tokenName, uint8 _decimalUnits, string _tokenSymbol) public {
totalSupply = _initialAmount * 10 ** uint256(_decimalUnits);
balances[msg.sender] = totalSupply;
name = _tokenName;
decimals = _decimalUnits;
symbol = _tokenSymbol;
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);
require(_to != 0x0);
balances[msg.sender] -= _value;//从消息发送者账户中减去token数量_value
balances[_to] += _value;//往接收账户增加token数量_value
emit Transfer(msg.sender, _to, _value);//触发转币交易事件
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns
(bool success) {
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value);
balances[_to] += _value;//接收账户增加token数量_value
balances[_from] -= _value; //支出账户_from减去token数量_value
allowed[_from][msg.sender] -= _value;//消息发送者可以从账户_from中转出的数量减少_value
emit Transfer(_from, _to, _value);//触发转币交易事件
return true;
}
function balanceOf(address _owner) public constant returns (uint256 balance) {
return balances[_owner];
}
function approve(address _spender, uint256 _value) public returns (bool success)
{
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {
return allowed[_owner][_spender];//允许_spender从_owner中转出的token数
}
}
pragma solidity ^0.4.24;
contract Ownable {
address public owner;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
}
interface Token {
function balanceOf(address _owner) external constant returns (uint256 ) ;
function transfer(address _to, uint256 _value) external ;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
}
contract Airdropper is Ownable {
function AirTransfer(address[] _recipients, uint _values, address _tokenAddress) onlyOwner public returns (bool) {
require(_recipients.length > 0);
Token token = Token(_tokenAddress);
for(uint j = 0; j < _recipients.length; j++){
token.transfer(_recipients[j], _values);
}
return true;
}
function withdrawalToken(address _tokenAddress) onlyOwner public {
Token token = Token(_tokenAddress);
token.transfer(owner, token.balanceOf(this));
}
}