以太坊开发文档11 - 合约使用
介绍
现在,您掌握了如何开始以及如何发送以太网的基础知识,现在是时候让您的双手黯然失色,以至于以太坊脱颖而出:智能合约。智能合约是生活在区块链上的一些代码,并按照它们被告知的方式执行命令。他们可以阅读其他合同,做出决定,发送以及执行其他合同。只要整个网络存在,合同就会存在并运行,只有在气体耗尽或程序自毁的情况下才会停止。
你可以用合同做什么?你几乎可以做任何事情,但对于这个指南,我们做一些简单的事情:你将通过众筹获得资金,如果成功,将提供一个只有服从自己的公民的,极其透明和民主的组织,永远不会离开其构成,不能被检查或关闭。而所有这些都在不到300行的代码中。
那么现在就开始吧。
Your first citizen: the greeter
现在你已经掌握了以太坊的基本知识,让我们进入你的第一个严肃的合同。前沿是一个很大的开放领域,有时你可能会感到孤独,所以我们的第一步就是创造一个自动的伴侣,当你感到孤独的时候迎接你。我们会称他为“温和”。
Greeter是一个智能的数字实体,它存在于区块链中,并能够根据其输入与任何与之交互的人进行交谈。它可能不是一个讲话者,但它是一个很好的倾听者。这是它的代码:
contract mortal {
/* Define variable owner of the type address*/
address owner;
/* this function is executed at initialization and sets the owner of the contract */
function mortal() { owner = msg.sender; }
/* Function to recover the funds on the contract */
function kill() { if (msg.sender == owner) suicide(owner); }
}
contract greeter is mortal {
/* define variable greeting of the type string */
string greeting;
/* this runs when the contract is executed */
function greeter(string _greeting) public {
greeting = _greeting;
}
/* main function */
function greet() constant returns (string) {
return greeting;
}
}
你会注意到这个代码中有两个不同的合约:“凡人”和“欢迎”。这是因为Solidity(我们使用的高级合同语言)具有继承性,这意味着一个契约可以继承另一个契约的特征。这对于简化编码非常有用,因为合同的常见特征不需要每次重写,所有合同都可以用更小,更易读的块来编写。所以只要声明迎宾者是凡人,你就继承了“凡人”契约的所有特征,并使迎宾者的代码简单易读。
继承特征“凡人”仅仅意味着迎宾合同可以被其所有者杀死,清理区块链,并在不再需要合同时收回锁定的资金。以太坊的契约默认为不死的,没有所有者,这意味着一旦被部署,作者就没有特殊的特权了。在部署之前考虑这一点。
安装编译器
在您能够部署它之前,您需要两件事情:编译代码和应用程序二进制接口,这是一种参考模板,用于定义如何与合同进行交互。
第一个你可以通过使用编译器。您应该在geth控制台中内置一个可靠的编译器。要测试它,请使用以下命令:
eth.getCompilers()
如果你安装了它,它应该输出如下所示:
["Solidity" ]
如果相反,该命令返回一个错误,那么你需要安装它。
使用在线编译器
如果你没有安装solC,我们有一个在线固体编译器可用。但请注意,如果编译器受到威胁,您的合同就不安全了。出于这个原因,如果你想使用在线编译器,我们鼓励你自己主持。
在Ubuntu上安装SolC
按控制+ c退出控制台(或键入退出)并返回到命令行。打开终端并执行这些命令:
sudo add-apt-repository ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install solc
which solc
注意最后一行给出的路径,你很快就会需要它。
在Mac OSX上安装SolC
您需要brew才能在您的Mac上安装
brew install cpp-ethereum
brew linkapps cpp-ethereum
which solc
注意最后一行给出的路径,你很快就会需要它。
在Windows上安装SolC
你需要巧克力才能安装solc。
cinst -pre solC-stable
Windows比这更复杂,你需要等一下。
如果你安装了SolC Solidity Compiler,你现在需要通过删除空格来重新格式化,以适应字符串变量(有一些在线工具可以做到这一点):
从源代码编译
git clone https://github.com/ethereum/cpp-ethereum.git
mkdir cpp-ethereum/build
cd cpp-ethereum/build
cmake -DJSONRPC=OFF -DMINER=OFF -DETHKEY=OFF -DSERPENT=OFF -DGUI=OFF -DTESTS=OFF -DJSCONSOLE=OFF ..
make -j4
make install
which solc
在Geth中链接你的编译器
现在返回到控制台,输入这个命令来安装solC,把path / to / solc替换成你在最后一个命令上得到的路径:
admin.setSolc("path/to/solc")
现在再次输入:
eth.getCompilers()
如果你现在安装了solC,那么恭喜你,你可以继续阅读。如果你不这样做,那么去我们的论坛或者subreddit,并且不要让这个过程变得简单。
编译你的合同
如果你安装了编译器,你现在需要通过删除换行符来重新格式化你的契约,以便它符合字符串变量(有一些在线工具可以做到这一点):
var greeterSource = "contract mortal { address owner; function mortal() { owner = msg.sender; } function kill() { if (msg.sender == owner) suicide(owner); } } contract greeter is mortal { string greeting; function greeter(string _greeting) public { greeting = _greeting; } function greet() constant returns (string) { return greeting; } }"
var greeterCompiled = web3.eth.compile.solidity(greeterSource)
你现在编译你的代码。现在您需要准备好进行部署,这包括设置一些变量,例如您的问候语。将下面的第一行编辑为比“Hello World!”更有趣的内容并执行这些命令:
var _greeting = "Hello World!"
var greeterContract = web3.eth.contract(greeterCompiled.greeter.info.abiDefinition);
var greeter = greeterContract.new(_greeting,{from:web3.eth.accounts[0], data: greeterCompiled.greeter.code, gas: 1000000}, function(e, contract){
if(!e) {
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
})
使用在线编译器
如果你没有安装solC,你可以简单地使用在线编译器。将上面的源代码复制到在线solidity编译器,然后您的编译代码应该出现在左侧窗格中。将标有Geth deploy的框中的代码复制到文本文件中。现在把第一行改成你的问候语:
var _greeting = "Hello World!"
现在,您可以将结果文本粘贴到您的geth窗口中。等待30秒,你会看到这样的消息:
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
您可能会被要求输入密码,因为您需要支付部署合同的天然气费用。这份合同估计需要17.2万个气体部署(根据在线固体编译器),在撰写本文时,测试网上的气体价格为每个气体1至10个微醚(绰号“szabo”= 1由wei中的12个零)。要知道以太网的最新价格,你可以在网络统计页面看到最新的天然气价格,并将这两个项目相乘。
请注意,该费用不支付给复仇开发商,而是去了矿工,谁运行谁保持网络运行的计算机的人。天然气价格是由当前的计算供求市场决定的。如果天然气价格太高,你可以成为矿工,降低你的要价。
在不到一分钟的时间内,你应该有一个合同地址的日志,这意味着你已经成功地部署了你的合同。您可以使用以下命令验证已部署的代码(已编译):
eth.getCode(greeter.address)
如果它返回“0x”以外的任何内容,那么恭喜!你的小家伙活着!如果再次创建合同(通过执行另一个eth.sendTransaction),它将被发布到一个新的地址。
运行Greeter
为了打电话给你的机器人,只需在你的终端上输入以下命令:
greeter.greet();
由于这个通话在区块链上没有任何变化,所以它立即返回并且没有任何天然气成本。你应该看到它返回你的问候语:
"Hello World!"
让其他人与您的代码进行交互
为了让其他人来运行你的合同,他们需要两件事:合同所在的地址和ABI(应用程序二进制接口),这是一种用户手册,描述了它的功能名称以及如何调用它们。为了让他们每个人都运行这些命令:
greeterCompiled.greeter.info.abiDefinition;
greeter.address;
然后你可以实例化一个JavaScript对象,可以用来调用连接到网络的任何机器上的契约。替换“ABI”和“地址”以在javascript中创建合同对象:
var greeter = eth.contract(ABI).at(Address);
这个特殊的例子可以通过简单的调用来实例化:
var greeter2 = eth.contract([{constant:false,inputs:[],name:"kill",outputs:[],type:"function"},{constant:true,inputs:[],name:"greet",outputs:[{name:"",type:"string"}],type:"function"},{inputs:[{name:"_greeting",type:"string"}],type:"constructor"}]).at("greeterAddress");
将greeterAddress替换为合同的地址。
提示:如果你的机器上没有正确的安装编译器,你可以从在线编译器获取ABI。为此,请使用下面的代码,仔细地用 编译器中的abi 替换greeterCompiled.greeter.info.abiDefinition。
清理后自己:
你必须非常高兴才能签下第一份合同,但是当业主继续写下更多的合同时,这种激动有时会消失,导致在区块链上看到放弃的合同。未来,区块链租金可能会实施,以增加区块链的可扩展性,但现在,成为一个好公民,并人道地放弃你的废弃机器人。
与上次不同,我们不会打电话,因为我们希望更改区块链上的某些内容。这要求将交易发送到网络,并要求付费。自杀是由网络补贴,所以它会比平常的交易成本低得多。
greeter.kill.sendTransaction({from:eth.accounts[0]})
您可以验证该行为是否完成,只要看看是否返回0:
eth.getCode(greeter.contractAddress)
请注意,每个合同都必须执行自己的kill子句。在这种特殊情况下,只有创建合同的帐户才能杀死它。
如果你不添加任何杀人条款,它可能永远永远(或至少在边境合同全部被清除之前)独立于你和任何地球上的边界,所以在你放置它之前,请检查你的当地法律对此的看法,包括技术出口方面的任何可能的限制,言论的限制以及可能的任何有关数字众生公民权利的立法。对待你的机器人人道。
为你的COIN注册一个名字
所提到的命令只工作,因为你有本地机器上实例化的token对象。如果你把令牌发给别人,他们将不能把它们向前移动,因为它们没有相同的对象,也不知道在哪里寻找你的合同或者调用它的功能。事实上,如果您重新启动控制台,这些对象将被删除,您一直在处理的合同将永远丢失。那么你如何在一台干净的机器上实例化合同呢?
有两种方法。让我们从快速和肮脏的开始,为您的朋友提供您的合同ABI的参考:
token = eth.contract([{constant:false,inputs:[{name:"receiver",type:"address"},{name:"amount",type:"uint256"}],name:"sendCoin",outputs:[{name:"sufficient",type:"bool"}],type:"function"},{constant:true,inputs:[{name:"",type:"address"}],name:"coinBalanceOf",outputs:[{name:"",type:"uint256"}],type:"function"},{inputs:[{name:"supply",type:"uint256"}],type:"constructor"},{anonymous:false,inputs:[{indexed:false,name:"sender",type:"address"},{indexed:false,name:"receiver",type:"address"},{indexed:false,name:"amount",type:"uint256"}],name:"CoinTransfer",type:"event"}]).at("0x4a4ce7844735c4b6fc66392b200ab6fe007cfca8")
只需将地址替换为您自己的令牌地址,那么使用此代码段的任何人都将立即可以使用您的合同。当然这只适用于这个特定的合约,所以让我们一步一步分析,看看如何改善这个代码,所以你可以在任何地方使用它。
所有帐户都通过其公共地址在网络中引用。但是地址很长,难以记录,难以记忆和不可改变。如果您希望能够以您的名字生成新账户,或者升级您的合约代码,最后一个特别重要。为了解决这个问题,有一个默认名称注册商合同,用于将长地址与简短的人性化名称相关联。
名称只能使用字母数字字符,不能包含空格。在将来的版本中,名称注册商可能会实施招标流程,以防止名字蹲下,但现在,它以先到先得的原则工作:只要没有其他人注册名称,就可以申请。
首先,如果你注册了一个名字,那么你最终不需要硬编码的地址。选择一个不错的硬币名称,并尝试为自己保留。首先,选择你的名字:
var tokenName = "MyFirstCoin"
然后,检查你的名字的可用性:
registrar.addr(tokenName)
如果该函数返回“0x00 ..”,你可以自己声称:
registrar.reserve.sendTransaction(tokenName, {from: eth.accounts[0]});
等待以前的交易被拿起。等待三十秒,然后尝试:
registrar.owner(myName)
如果它返回你的地址,这意味着你拥有这个名字,并能够将你的选择的名称设置为你想要的任何地址:
registrar.setAddress.sendTransaction(tokenName, token.address, true,{from: eth.accounts[0]});
您可以更换token.address为eth.accounts [0]如果你想用它作为个人的绰号。
等一下,这个交易也被拿起来测试一下:
registrar.addr("MyFirstCoin")
您可以通过输入名称而不是账户将交易发送给任何人或任何合约
eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("MyFirstCoin"), value: web3.toWei(1, "ether")})
提示:请勿将registrar.addr与registrar.owner混合使用。首先是名称指向哪个地址:任何人都可以将名称指向其他任何地方,就像任何人都可以将链接转发到google.com一样,但是只有名称的所有者才能更改和更新链接。您可以将两者设置为相同的地址。
这现在应该返回您的令牌地址,这意味着现在实例化的前面的代码可以使用名称而不是地址。
token = eth.contract([{constant:false,inputs:[{name:"receiver",type:"address"},{name:"amount",type:"uint256"}],name:"sendCoin",outputs:[{name:"sufficient",type:"bool"}],type:"function"},{constant:true,inputs:[{name:"",type:"address"}],name:"coinBalanceOf",outputs:[{name:"",type:"uint256"}],type:"function"},{inputs:[{name:"supply",type:"uint256"}],type:"constructor"},{anonymous:false,inputs:[{indexed:false,name:"sender",type:"address"},{indexed:false,name:"receiver",type:"address"},{indexed:false,name:"amount",type:"uint256"}],name:"CoinTransfer",type:"event"}]).at(registrar.addr("MyFirstCoin"))
这也意味着硬币的所有者可以通过指示注册商更新硬币到新的合同。当然,这将要求硬币持有人相信在registrar.owner(“MyFirstCoin”)设置的所有者
当然,这是一个相当不愉快的大块代码,只是为了让其他人与合同交互。有一些途径正在研究将合同ABI上传到网络,以便所有用户都需要的是合同名称。你可以阅读这些方法,但他们是非常实验性的,将来肯定会改变。
代币
什么是代币?代币比他们看起来更有趣和有用,它们本质上只是一个可交换的标志,但是可以变得更多,这取决于你如何使用它们。它的价值取决于你做什么:令牌可以用来控制访问(门票),可以用于组织(股)的投票权,可以是第三方持有的资产的占位符(所有权证书),甚至可以简单地用作社区(货币)内的价值交换。
您可以通过创建一个集中的服务器来完成所有这些工作,但是使用以太坊令牌合同可以带来一些免费的功能:一个是分散的服务,即使原始服务因任何原因而停止,仍然可以交换令牌。代码可以保证除了在原始代码中设置的代码外,永远不会创建代币。最后,通过让每个用户拥有自己的令牌,这就消除了单个服务器入侵可能导致数千客户资金流失的情况。
您可以在不同的区块链上创建自己的令牌,但在以太坊创建更容易 - 所以您可以将精力集中在创新上,使您的硬币脱颖而出,而且更安全,因为您的安全由所有矿工正在支持以太坊网络。最后,通过在Ethereum中创建您的令牌,您的钱币将与以太坊上运行的任何其他合同兼容。
代码
这是我们正在建立的合同的代码:
contract token {
mapping (address => uint) public coinBalanceOf;
event CoinTransfer(address sender, address receiver, uint amount);
/* Initializes contract with initial supply tokens to the creator of the contract */
function token(uint supply) {
coinBalanceOf[msg.sender] = supply;
}
/* Very simple trade function */
function sendCoin(address receiver, uint amount) returns(bool sufficient) {
if (coinBalanceOf[msg.sender] < amount) return false;
coinBalanceOf[msg.sender] -= amount;
coinBalanceOf[receiver] += amount;
CoinTransfer(msg.sender, receiver, amount);
return true;
}
}
如果你已经编程,你不会觉得它很难理解它是什么:它是一个合同,为合同的创造者产生一万个代币,然后允许任何有足够平衡的人把它发给别人。这些代币是最小的可交易单位,不能细分,但最终用户可以被100个单位细分为100个单位,所以拥有单个代币将占总数的0.01%。如果您的应用程序需要更细的原子可分性,那么只需增加初始发行量即可。
在这个例子中,我们声明变量“coinBalanceOf”是公开的,这将自动创建一个函数来检查任何账户的余额。
编译和部署
所以让我们来运行它!
var tokenSource = " contract token { mapping (address => uint) public coinBalanceOf; event CoinTransfer(address sender, address receiver, uint amount); /* Initializes contract with initial supply tokens to the creator of the contract */ function token(uint supply) { coinBalanceOf[msg.sender] = supply; } /* Very simple trade function */ function sendCoin(address receiver, uint amount) returns(bool sufficient) { if (coinBalanceOf[msg.sender] < amount) return false; coinBalanceOf[msg.sender] -= amount; coinBalanceOf[receiver] += amount; CoinTransfer(msg.sender, receiver, amount); return true; } }"
var tokenCompiled = eth.compile.solidity(tokenSource)
现在我们来设置合同,就像我们在上一节中所做的那样。将“初始供应”更改为您要创建的不可分割令牌的数量。如果你想拥有可分割的单位,你应该在用户的前端做这个,但是保持它们在最小单位的帐户。
var supply = 10000;
var tokenContract = web3.eth.contract(tokenCompiled.token.info.abiDefinition);
var token = tokenContract.new(
supply,
{
from:web3.eth.accounts[0],
data:tokenCompiled.token.code,
gas: 1000000
}, function(e, contract){
if(!e) {
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
})
在线编译器
如果你没有安装solC,你可以简单地使用在线编译器。将合同代码复制到在线solidity编译器,如果合同上没有错误,您应该看到标有Geth Deploy的文本框。将内容复制到文本文件,以便您可以更改第一行以设置初始供应,如下所示:
var supply = 10000;
现在,您可以将结果文本粘贴到您的geth窗口中。等待30秒,你会看到这样的消息:
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
查看余额看硬币转移
如果一切正常,你应该能够检查你自己的平衡:
token.coinBalanceOf(eth.accounts[0]) + " tokens"
它应该有合同发布后创建的所有10000个代币。由于没有任何其他定义的方式来发行新的硬币,这些都是永远存在的。
你可以设置一个观察者,在任何人使用你的合同发送一个硬币时作出反应。以下是你如何做到这一点:
var event = token.CoinTransfer({}, "", function(error, result){
if (!error)
console.log("Coin transfer: " + result.args.amount + " tokens were sent. Balances now are as following:
Sender: " + result.args.sender + " " + token.coinBalanceOf.call(result.args.sender) + " tokens
Receiver: " + result.args.receiver + " " + token.coinBalanceOf.call(result.args.receiver) + " tokens" )
});
发送代币
当然,如果你把它们全部囤积起来,那么这些标记就不是很有用,所以为了把它们发送给别人,使用这个命令:
token.sendCoin.sendTransaction(eth.accounts[1], 1000, {from: eth.accounts[0]})
如果朋友在注册商处注册了一个名字,您可以在不知道他们的地址的情况下发送它,
token.sendCoin.sendTransaction(registrar.addr("Alice"), 2000, {from: eth.accounts[0]})
请注意,我们的第一个函数coinBalanceOf直接在合同实例上直接调用,并返回一个值。这是可能的,因为这是一个简单的读取操作,不会导致状态改变,并且在本地和同步执行。我们的第二个函数sendCoin需要一个.sendTransaction()呼叫。由于这个功能是为了改变状态(写操作),它被作为一个交易发送到矿工被拾取的网络,并包含在规范区块链中。因此,所有参与者节点的共识状态将充分反映执行事务所导致的状态变化。发件人地址需要作为交易的一部分发送,以资助运行交易所需的燃料。现在,等一下,检查两个帐户余额:
token.coinBalanceOf.call(eth.accounts[0])/100 + "% of all tokens"
token.coinBalanceOf.call(eth.accounts[1])/100 + "% of all tokens"
token.coinBalanceOf.call(registrar.addr("Alice"))/100 + "% of all tokens"
改进建议
现在这个加密货币是相当有限的,因为只有10000个硬币,所有都由硬币的创造者控制,但你可以改变这一点。例如,您可以通过创建一个交易来奖励以太坊矿工,从而奖励发现当前街区的人:
mapping (uint => address) miningReward;
function claimMiningReward() {
if (miningReward[block.number] == 0) {
coinBalanceOf[block.coinbase] += 1;
miningReward[block.number] = block.coinbase;
}
}
你可以修改其他任何东西:也许奖励找到解决新难题的人,赢得一盘国际象棋,安装一个太阳能电池板 - 只要能够以某种方式转化为合同。或者,也许你想为你的个人国家建立一个中央银行,这样你就可以跟踪工作时间,所欠财产或控制财产。在这种情况下,您可能需要添加一项功能,以允许银行远程冻结资金并在需要时销毁代币。
为你的代币注册一个名字
所提到的命令只工作,因为你有本地机器上实例化的token对象。如果你把令牌发给别人,他们将不能把它们向前移动,因为它们没有相同的对象,也不知道在哪里寻找你的合同或者调用它的功能。事实上,如果您重新启动控制台,这些对象将被删除,您一直在处理的合同将永远丢失。那么你如何在一台干净的机器上实例化合同呢?
有两种方法。让我们从快速和肮脏的开始,为您的朋友提供您的合同ABI的参考:
token = eth.contract([{constant:false,inputs:[{name:"receiver",type:"address"},{name:"amount",type:"uint256"}],name:"sendCoin",outputs:[{name:"sufficient",type:"bool"}],type:"function"},{constant:true,inputs:[{name:"",type:"address"}],name:"coinBalanceOf",outputs:[{name:"",type:"uint256"}],type:"function"},{inputs:[{name:"supply",type:"uint256"}],type:"constructor"},{anonymous:false,inputs:[{indexed:false,name:"sender",type:"address"},{indexed:false,name:"receiver",type:"address"},{indexed:false,name:"amount",type:"uint256"}],name:"CoinTransfer",type:"event"}]).at("0x4a4ce7844735c4b6fc66392b200ab6fe007cfca8")
只需将地址替换为您自己的令牌地址,那么使用此代码段的任何人都将立即可以使用您的合同。当然这只适用于这个特定的合约,所以让我们一步一步分析,看看如何改善这个代码,所以你可以在任何地方使用它。
所有帐户都通过其公共地址在网络中引用。但是地址很长,难以记录,难以记忆和不可改变。如果您希望能够以您的名字生成新账户,或者升级您的合约代码,最后一个特别重要。为了解决这个问题,有一个默认名称注册商合同,用于将长地址与简短的人性化名称相关联。
名称只能使用字母数字字符,不能包含空格。在将来的版本中,名称注册商可能会实施招标流程,以防止名字蹲下,但现在,它以先到先得的原则工作:只要没有其他人注册名称,就可以申请。
首先,如果你注册了一个名字,那么你最终不需要硬编码的地址。选择一个不错的硬币名称,并尝试为自己保留。首先,选择你的名字:
var tokenName = "MyFirstCoin"
然后,检查你的名字的可用性:
registrar.addr(tokenName)
如果该函数返回“0x00 ..”,你可以自己声称:
registrar.reserve.sendTransaction(tokenName, {from: eth.accounts[0]});
等待以前的交易被拿起。等待三十秒,然后尝试:
registrar.owner(myName)
如果它返回你的地址,这意味着你拥有这个名字,并能够将你的选择的名称设置为你想要的任何地址:
registrar.setAddress.sendTransaction(tokenName, token.address, true,{from: eth.accounts[0]});
您可以更换token.address为eth.accounts [0]如果你想用它作为个人的绰号。
等一下,这个交易也被拿起来测试一下:
registrar.addr("MyFirstCoin")
您可以通过输入名称而不是账户将交易发送给任何人或任何合约
eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("MyFirstCoin"), value: web3.toWei(1, "ether")})
提示:请勿将registrar.addr与registrar.owner混合使用。首先是名称指向哪个地址:任何人都可以将名称指向其他任何地方,就像任何人都可以将链接转发到google.com一样,但是只有名称的所有者才能更改和更新链接。您可以将两者设置为相同的地址。
这现在应该返回您的令牌地址,这意味着现在实例化的前面的代码可以使用名称而不是地址。
token = eth.contract([{constant:false,inputs:[{name:"receiver",type:"address"},{name:"amount",type:"uint256"}],name:"sendCoin",outputs:[{name:"sufficient",type:"bool"}],type:"function"},{constant:true,inputs:[{name:"",type:"address"}],name:"coinBalanceOf",outputs:[{name:"",type:"uint256"}],type:"function"},{inputs:[{name:"supply",type:"uint256"}],type:"constructor"},{anonymous:false,inputs:[{indexed:false,name:"sender",type:"address"},{indexed:false,name:"receiver",type:"address"},{indexed:false,name:"amount",type:"uint256"}],name:"CoinTransfer",type:"event"}]).at(registrar.addr("MyFirstCoin"))
这也意味着硬币的所有者可以通过指示注册商更新硬币到新的合同。当然,这将要求硬币持有人相信在registrar.owner(“MyFirstCoin”)设置的所有者
当然,这是一个相当不愉快的大块代码,只是为了让其他人与合同交互。有一些途径正在研究将合同ABI上传到网络,以便所有用户都需要的是合同名称。你可以阅读这些方法,但他们是非常实验性的,将来肯定会改变。
学到更多
-
Meta硬币标准是对硬币和令牌合约的功能名称的建议标准化,以允许它们被自动添加到利用交易的其他以太坊合约中,例如交易或托管。
-
正式的打样是合同开发人员能够维护合同的一些不变特质的一种方式,比如硬币的总上限。尚未实施。
有时候一个好主意需要花费大量的资金和集体努力。你可以要求捐款,但捐赠者更愿意给予他们更确定的项目,以获得牵引力和适当的资金。众筹是一个理想的例子,你设定了一个目标和一个达到目标的最后期限。如果你错过了你的目标,那么这些捐款将被退回,从而降低捐献者的风险。由于代码是开放和可审计的,因此不需要集中的可信平台,因此每个人只需支付的费用就是燃气费。
在众筹中,通常会给予奖励。这将要求您获取每个人的联系信息,并跟踪谁拥有什么。但是,既然你刚刚创建了自己的令牌,为什么不使用它来跟踪奖品呢?这可以让捐赠者捐赠后立即拥有一些东西。他们可以安全地存储,但是如果他们意识到不再需要奖品,他们也可以出售或交易。如果你的想法是物理上的,那么在项目完成之后你所要做的就是把产品交给给你发回令牌的每个人。如果项目是数字化的,则令牌本身可以立即用于用户参与或获得项目入口。
代码
这个特定的众包合同的工作方式是,您为您的令牌设置一个汇率,然后捐助者将立即获得相当数量的代币换取以太币。你也将选择一个资金目标和期限:一旦这个截止日期结束,你可以ping合同,如果目标达成,它会把乙醚提出给你,否则它会回到捐助者。即使项目没有达到目标,捐助者也会保留自己的代币,作为他们帮助的证明。
contract token { mapping (address => uint) public coinBalanceOf; function token() {} function sendCoin(address receiver, uint amount) returns(bool sufficient) { } }
contract Crowdsale {
address public beneficiary;
uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price;
token public tokenReward;
Funder[] public funders;
event FundTransfer(address backer, uint amount, bool isContribution);
/* data structure to hold information about campaign contributors */
struct Funder {
address addr;
uint amount;
}
/* at initialization, setup the owner */
function Crowdsale(address _beneficiary, uint _fundingGoal, uint _duration, uint _price, token _reward) {
beneficiary = _beneficiary;
fundingGoal = _fundingGoal;
deadline = now + _duration * 1 minutes;
price = _price;
tokenReward = token(_reward);
}
/* The function without name is the default function that is called whenever anyone sends funds to a contract */
function () {
uint amount = msg.value;
funders[funders.length++] = Funder({addr: msg.sender, amount: amount});
amountRaised += amount;
tokenReward.sendCoin(msg.sender, amount / price);
FundTransfer(msg.sender, amount, true);
}
modifier afterDeadline() { if (now >= deadline) _ }
/* checks if the goal or time limit has been reached and ends the campaign */
function checkGoalReached() afterDeadline {
if (amountRaised >= fundingGoal){
beneficiary.send(amountRaised);
FundTransfer(beneficiary, amountRaised, false);
} else {
FundTransfer(0, 11, false);
for (uint i = 0; i < funders.length; ++i) {
funders[i].addr.send(funders[i].amount);
FundTransfer(funders[i].addr, funders[i].amount, false);
}
}
suicide(beneficiary);
}
}
设置参数
在我们进一步讨论之前,让我们先设置crowdsale的参数:
var _beneficiary = eth.accounts[1]; // create an account for this
var _fundingGoal = web3.toWei(100, "ether"); // raises 100 ether
var _duration = 30; // number of minutes the campaign will last
var _price = web3.toWei(0.02, "ether"); // the price of the tokens, in ether
var _reward = token.address; // the token contract address.
受益人提出将收到募集资金的新地址。资金目标是提高乙醚的数量。截止时间是在平均时间内测量的,平均时间为12秒,所以默认约为4周。价格是棘手的:但只需更改数量2的贡献者将收到每个乙醚捐赠的令牌数量。最后,奖励应该是你在上一节创建的令牌合同的地址。
在这个例子中,你正在销售所有曾经存在的代币的众多一半,换取100乙醚。谨慎决定这些参数,因为它们将在我们的指南的下一部分起到非常重要的作用。
部署
您知道钻取:如果您正在使用solC编译器,请删除换行符并在终端上复制以下命令:
var crowdsaleCompiled = eth.compile.solidity(" contract token { mapping (address => uint) public coinBalanceOf; function token() {} function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } contract Crowdsale { address public beneficiary; uint public fundingGoal; uint public amountRaised; uint public deadline; uint public price; token public tokenReward; Funder[] public funders; event FundTransfer(address backer, uint amount, bool isContribution); /* data structure to hold information about campaign contributors */ struct Funder { address addr; uint amount; } /* at initialization, setup the owner */ function Crowdsale(address _beneficiary, uint _fundingGoal, uint _duration, uint _price, token _reward) { beneficiary = _beneficiary; fundingGoal = _fundingGoal; deadline = now + _duration * 1 minutes; price = _price; tokenReward = token(_reward); } /* The function without name is the default function that is called whenever anyone sends funds to a contract */ function () { Funder f = funders[++funders.length]; f.addr = msg.sender; f.amount = msg.value; amountRaised += f.amount; tokenReward.sendCoin(msg.sender, f.amount/price); FundTransfer(f.addr, f.amount, true); } modifier afterDeadline() { if (now >= deadline) _ } /* checks if the goal or time limit has been reached and ends the campaign */ function checkGoalReached() afterDeadline { if (amountRaised >= fundingGoal){ beneficiary.send(amountRaised); FundTransfer(beneficiary, amountRaised, false); } else { FundTransfer(0, 11, false); for (uint i = 0; i < funders.length; ++i) { funders[i].addr.send(funders[i].amount); FundTransfer(funders[i].addr, funders[i].amount, false); } } suicide(beneficiary); } }");
var crowdsaleContract = web3.eth.contract(crowdsaleCompiled.Crowdsale.info.abiDefinition);
var crowdsale = crowdsaleContract.new(
_beneficiary,
_fundingGoal,
_duration,
_price,
_reward,
{
from:web3.eth.accounts[0],
data:crowdsaleCompiled.Crowdsale.code,
gas: 1000000
}, function(e, contract){
if(!e) {
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
} })
如果使用联机编译器将合同代码复制到联机solidity编译器,然后获取标有 Geth Deploy 的框的内容。由于您已经设置了参数,因此不需要对该文本进行任何更改,只需将生成的文本粘贴到geth窗口即可。
等待30秒,你会看到这样的消息:
Contract mined! address: 0xdaa24d02bad7e9d6a80106db164bad9399a0423e
如果您收到该提醒,那么您的代码应该在线。你可以随时仔细检查:
eth.getCode(crowdsale.address)
现在为您新创建的合同提供必要的令牌,以便它可以自动分配奖励给贡献者!
token.sendCoin.sendTransaction(crowdsale.address, 5000,{from: eth.accounts[0]})
在挑选交易之后,您可以检查众包地址所具有的令牌数量,以及所有其他变量:
"Current crowdsale must raise " + web3.fromWei(crowdsale.fundingGoal.call(), "ether") + " ether in order to send it to " + crowdsale.beneficiary.call() + "."
让一些观察者
每当你的众包收到新的资金时,你都希望得到提醒,所以贴上这个代码:
var event = crowdsale.FundTransfer({}, "", function(error, result){
if (!error)
if (result.args.isContribution) {
console.log("
New backer! Received " + web3.fromWei(result.args.amount, "ether") + " ether from " + result.args.backer )
console.log( "
The current funding at " +( 100 * crowdsale.amountRaised.call() / crowdsale.fundingGoal.call()) + "% of its goals. Funders have contributed a total of " + web3.fromWei(crowdsale.amountRaised.call(), "ether") + " ether.");
var timeleft = Math.floor(Date.now() / 1000)-crowdsale.deadline();
if (timeleft>3600) { console.log("Deadline has passed, " + Math.floor(timeleft/3600) + " hours ago")
} else if (timeleft>0) { console.log("Deadline has passed, " + Math.floor(timeleft/60) + " minutes ago")
} else if (timeleft>-3600) { console.log(Math.floor(-1*timeleft/60) + " minutes until deadline")
} else { console.log(Math.floor(-1*timeleft/3600) + " hours until deadline")
}
} else {
console.log("Funds transferred from crowdsale account: " + web3.fromWei(result.args.amount, "ether") + " ether to " + result.args.backer )
}
});
注册合同
你现在被设置。现在任何人都可以通过简单地把ether发送到众包地址来做出贡献,但为了使它更简单,让我们为你的销售注册一个名字。首先,为你的众包挑选一个名字:
var name = "mycrowdsale"
检查是否可用并注册:
registrar.addr(name)
registrar.reserve.sendTransaction(name, {from: eth.accounts[0]});
等待先前的交易被拿起,然后:
registrar.setAddress.sendTransaction(name, crowdsale.address, true,{from: eth.accounts[0]});
为众人贡献力量
对众包的贡献非常简单,甚至不需要实例化合同。这是因为群众对简单的以太存款有反应,所以任何一个把以太坊送到众包的人都会自动获得奖励。任何人都可以通过执行这个命令来做出贡献:
var amount = web3.toWei(5, "ether") // decide how much to contribute
eth.sendTransaction({from: eth.accounts[0], to: crowdsale.address, value: amount, gas: 1000000})
或者,如果您希望其他人发送,他们甚至可以使用名称注册服务商来提供:
eth.sendTransaction({from: eth.accounts[0], to: registrar.addr("mycrowdsale"), value: amount, gas: 500000})
现在等待一分钟,取出块,然后通过执行以下任一命令来检查合同是否收到以太:
web3.fromWei(crowdsale.amountRaised.call(), "ether") + " ether"
token.coinBalanceOf.call(eth.accounts[0]) + " tokens"
token.coinBalanceOf.call(crowdsale.address) + " tokens"
恢复资金
一旦通过期限,就必须唤醒合同,将资金发送给受益人或者发回给出资者(如果失败)。发生这种情况是因为在以太坊没有这样的活动循环或定时器,所以任何未来的交易都必须由某人来决定。
crowdsale.checkGoalReached.sendTransaction({from:eth.accounts[0], gas: 2000000})
您可以使用以下这些代码行来检查您的帐户:
web3.fromWei(eth.getBalance(eth.accounts[0]), "ether") + " ether"
web3.fromWei(eth.getBalance(eth.accounts[1]), "ether") + " ether"
token.coinBalanceOf.call(eth.accounts[0]) + " tokens"
token.coinBalanceOf.call(eth.accounts[1]) + " tokens"
一旦它完成了它的工作,众包实例就被设置为自毁,所以如果最终期限结束了,每个人都拿到了他们的奖金,那么合同就没有了,正如你所看到的那样:
eth.getCode(crowdsale.address)
于是,你们筹集了100多元,并成功地将你的原始硬币分发给了众多的捐助者。接下来你能做些什么呢?
到目前为止,您已经创建了一个可交易的标记,并成功地将其分发给了所有愿意帮助筹款100人的人。这一切都非常有趣,但这些令牌究竟是什么?为什么会有人想拥有或交换它有其他价值?如果你能说服你的新令牌是下一个大钱,也许别人会想要它,但是到目前为止,你的令牌本身没有价值。我们将通过创建您的第一个分散的自治组织或DAO来改变这种状况。
把DAO想象成一个国家的组织,一个政府的行政部门,或者像一个机构的机器人经理。DAO收到贵组织提出的资金,保持安全,并使用它来资助任何成员所需的资金。机器人是廉洁的,永远不会欺骗银行,永远不会制定秘密计划,绝不会将这笔钱用于其他成员投票之外的任何事情。DAO永远不会消失,永远不会逃跑,不能被其他人控制。
我们使用众包分发的令牌是唯一需要的公民文件。任何拥有任何令牌的人都可以创建投票。类似于作为公司的股东,令牌可以在公开市场上交易,投票权与选民持有的代币数量成正比。
花一点时间来想象这将允许的革命性的可能性,现在你可以自己做,在100行代码下:
代码
contract token { mapping (address => uint) public coinBalanceOf; function token() { } function sendCoin(address receiver, uint amount) returns(bool sufficient) { } }
contract Democracy {
uint public minimumQuorum;
uint public debatingPeriod;
token public voterShare;
address public founder;
Proposal[] public proposals;
uint public numProposals;
event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description);
event Voted(uint proposalID, int position, address voter);
event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
struct Proposal {
address recipient;
uint amount;
bytes32 data;
string description;
uint creationDate;
bool active;
Vote[] votes;
mapping (address => bool) voted;
}
struct Vote {
int position;
address voter;
}
function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) {
founder = msg.sender;
voterShare = token(_voterShareAddress);
minimumQuorum = _minimumQuorum || 10;
debatingPeriod = _debatingPeriod * 1 minutes || 30 days;
}
function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) {
if (voterShare.coinBalanceOf(msg.sender)>0) {
proposalID = proposals.length++;
Proposal p = proposals[proposalID];
p.recipient = _recipient;
p.amount = _amount;
p.data = _data;
p.description = _description;
p.creationDate = now;
p.active = true;
ProposalAdded(proposalID, _recipient, _amount, _data, _description);
numProposals = proposalID+1;
}
}
function vote(uint _proposalID, int _position) returns (uint voteID){
if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) {
Proposal p = proposals[_proposalID];
if (p.voted[msg.sender] == true) return;
voteID = p.votes.length++;
p.votes[voteID] = Vote({position: _position, voter: msg.sender});
p.voted[msg.sender] = true;
Voted(_proposalID, _position, msg.sender);
}
}
function executeProposal(uint _proposalID) returns (int result) {
Proposal p = proposals[_proposalID];
/* Check if debating period is over */
if (now > (p.creationDate + debatingPeriod) && p.active){
uint quorum = 0;
/* tally the votes */
for (uint i = 0; i < p.votes.length; ++i) {
Vote v = p.votes[i];
uint voteWeight = voterShare.coinBalanceOf(v.voter);
quorum += voteWeight;
result += int(voteWeight) * v.position;
}
/* execute result */
if (quorum > minimumQuorum && result > 0 ) {
p.recipient.call.value(p.amount)(p.data);
p.active = false;
} else if (quorum > minimumQuorum && result < 0) {
p.active = false;
}
ProposalTallied(_proposalID, result, quorum, p.active);
}
}
}
还有很多事情要做,但比看起来简单。您组织的规则非常简单:拥有至少一个令牌的任何人都可以创建提案,从该国的帐户中发送资金。经过一个星期的辩论和表决,如果它已经收到了总数达到100个以上的票数,并且有更多的批准,那么这些资金就会被发送出去。如果法定人数未达到或以平局结束,则投票保留至解决。否则,该提案被锁定并保留历史用途。
所以让我们回顾一下这意味着什么:在最后两节中,您创建了10,000个令牌,将其中的1000个发送给您控制的另一个帐户,2,000个给名为Alice的朋友,并通过众包发送给其中的5,000个。这意味着你不能再控制DAO中50%的选票,如果Alice和社区联手在一起,他们可以不支持迄今为止提出的100个醚的任何支出决定。这就是民主应该如何运作。如果你不想成为你的国家的一部分,你可以做的唯一的事情就是在分散的交易所卖掉你自己的代币,然后退出,但是你不能阻止别人这样做。
设置您的组织
所以打开你的控制台,让我们准备好最终把你的国家在线。首先,我们设置正确的参数,小心挑选它们:
var _voterShareAddress = token.address;
var _minimumQuorum = 10; // Minimun amount of voter tokens the proposal needs to pass
var _debatingPeriod = 60; // debating period, in minutes;
使用这些默认参数,任何具有任何令牌的人都可以提出关于如何花费组织资金的建议。提案有1小时的辩论时间,如果它至少有总票数的0.1%的票数,并且比拒绝票数多,那么它就会通过。小心挑选这些参数,因为将来您将无法更改它们。
var daoCompiled = eth.compile.solidity("contract token { mapping (address => uint) public coinBalanceOf; function token() { } function sendCoin(address receiver, uint amount) returns(bool sufficient) { } } contract Democracy { uint public minimumQuorum; uint public debatingPeriod; token public voterShare; address public founder; Proposal[] public proposals; uint public numProposals; event ProposalAdded(uint proposalID, address recipient, uint amount, bytes32 data, string description); event Voted(uint proposalID, int position, address voter); event ProposalTallied(uint proposalID, int result, uint quorum, bool active); struct Proposal { address recipient; uint amount; bytes32 data; string description; uint creationDate; bool active; Vote[] votes; mapping (address => bool) voted; } struct Vote { int position; address voter; } function Democracy(token _voterShareAddress, uint _minimumQuorum, uint _debatingPeriod) { founder = msg.sender; voterShare = token(_voterShareAddress); minimumQuorum = _minimumQuorum || 10; debatingPeriod = _debatingPeriod * 1 minutes || 30 days; } function newProposal(address _recipient, uint _amount, bytes32 _data, string _description) returns (uint proposalID) { if (voterShare.coinBalanceOf(msg.sender)>0) { proposalID = proposals.length++; Proposal p = proposals[proposalID]; p.recipient = _recipient; p.amount = _amount; p.data = _data; p.description = _description; p.creationDate = now; p.active = true; ProposalAdded(proposalID, _recipient, _amount, _data, _description); numProposals = proposalID+1; } else { return 0; } } function vote(uint _proposalID, int _position) returns (uint voteID){ if (voterShare.coinBalanceOf(msg.sender)>0 && (_position >= -1 || _position <= 1 )) { Proposal p = proposals[_proposalID]; if (p.voted[msg.sender] == true) return; voteID = p.votes.length++; Vote v = p.votes[voteID]; v.position = _position; v.voter = msg.sender; p.voted[msg.sender] = true; Voted(_proposalID, _position, msg.sender); } else { return 0; } } function executeProposal(uint _proposalID) returns (int result) { Proposal p = proposals[_proposalID]; /* Check if debating period is over */ if (now > (p.creationDate + debatingPeriod) && p.active){ uint quorum = 0; /* tally the votes */ for (uint i = 0; i < p.votes.length; ++i) { Vote v = p.votes[i]; uint voteWeight = voterShare.coinBalanceOf(v.voter); quorum += voteWeight; result += int(voteWeight) * v.position; } /* execute result */ if (quorum > minimumQuorum && result > 0 ) { p.recipient.call.value(p.amount)(p.data); p.active = false; } else if (quorum > minimumQuorum && result < 0) { p.active = false; } } ProposalTallied(_proposalID, result, quorum, p.active); } }");
var democracyContract = web3.eth.contract(daoCompiled.Democracy.info.abiDefinition);
var democracy = democracyContract.new(
_voterShareAddress,
_minimumQuorum,
_debatingPeriod,
{
from:web3.eth.accounts[0],
data:daoCompiled.Democracy.code,
gas: 3000000
}, function(e, contract){
if(!e) {
if(!contract.address) {
console.log("Contract transaction send: TransactionHash: " + contract.transactionHash " waiting to be mined...");
} else {
console.log("Contract mined! Address: " + contract.address);
console.log(contract);
}
}
})
如果使用联机编译器将合同代码复制到联机solidity编译器,然后获取标有 Geth Deploy 的框的内容。由于您已经设置了参数,因此不需要对该文本进行任何更改,只需将生成的文本粘贴到geth窗口即可。
等一下,直到矿工拿起来。这将花费你约85万瓦斯。一旦找到了,就可以实例化它并设置它,方法是将它指向先前创建的令牌合约的正确地址。
如果一切正常,您可以通过执行以下字符串来查看整个组织:
"This organization has " + democracy.numProposals() + " proposals and uses the token at the address " + democracy.voterShare() ;
如果一切都设置好了,那么你的DAO应该返回一个建议计数0和标记为“创建者”的地址。尽管还没有提议,DAO的创始人可以将令牌的地址更改为任何想要的。
注册您的组织名称
我们还要为合同注册一个名字,以便于访问(不要忘了在预订之前用registrar.addr(“nameYouWant”)检查您的名字可用性)
var name = "MyPersonalDemocracy"
registrar.reserve.sendTransaction(name, {from: eth.accounts[0]})
var democracy = eth.contract(daoCompiled.Democracy.info.abiDefinition).at(democracy.address);
democracy.setup.sendTransaction(registrar.addr("MyFirstCoin"),{from:eth.accounts[0]})
等待先前的交易被拿起,然后:
registrar.setAddress.sendTransaction(name, democracy.address, true,{from: eth.accounts[0]});
民主Watchbots
var event = democracy.ProposalAdded({}, "", function(error, result){
if (!error)
console.log("New Proposal #"+ result.args.proposalID +"!
Send " + web3.fromWei(result.args.amount, "ether") + " ether to " + result.args.recipient.substring(2,8) + "... for " + result.args.description )
});
var eventVote = democracy.Voted({}, "", function(error, result){
if (!error)
var opinion = "";
if (result.args.position > 0) {
opinion = "in favor"
} else if (result.args.position < 0) {
opinion = "against"
} else {
opinion = "abstaining"
}
console.log("Vote on Proposal #"+ result.args.proposalID +"!
" + result.args.voter + " is " + opinion )
});
var eventTally = democracy.ProposalTallied({}, "", function(error, result){
if (!error)
var totalCount = "";
if (result.args.result > 1) {
totalCount = "passed"
} else if (result.args.result < 1) {
totalCount = "rejected"
} else {
totalCount = "a tie"
}
console.log("Votes counted on Proposal #"+ result.args.proposalID +"!
With a total of " + Math.abs(result.args.result) + " out of " + result.args.quorum + ", proposal is " + totalCount + ". Proposal is " + (result.args.active? " still on the floor" : "archived") )
});
与DAO交互
当你对自己想要的东西感到满意之后,现在是时候把你从众筹中得到的所有东西都拿到你的新组织里去了:
eth.sendTransaction({from: eth.accounts[1], to: democracy.address, value: web3.toWei(100, "ether")})
这应该只需要一分钟,你的国家已经准备好了!现在,作为第一优先事项,您的组织需要一个漂亮的标志,但除非您是一名设计师,否则您不知道该怎么做。为了争辩,让我们假设你发现你的朋友鲍勃是一个很棒的设计师,他只愿意为了十个以上的人而做,所以你想要聘请他。
recipient = registrar.addr("bob");
amount = web3.toWei(10, "ether");
shortNote = "Logo Design";
democracy.newProposal.sendTransaction( recipient, amount, "", shortNote, {from: eth.accounts[0], gas:1000000})
一分钟之后,任何人都可以通过执行以下命令来检查提案收件人和金额:
"This organization has " + (Number(democracy.numProposals())+1) + " pending proposals";
密切关注这个组织
与大多数政府不同,贵国的政府是完全透明的,易于编程的。作为一个小型的演示,这里有一小段代码可以通过所有当前的建议,并打印出他们是谁和谁:
function checkAllProposals() {
console.log("Country Balance: " + web3.fromWei( eth.getBalance(democracy.address), "ether") );
for (i = 0; i< (Number(democracy.numProposals())); i++ ) {
var p = democracy.proposals(i);
var timeleft = Math.floor(((Math.floor(Date.now() / 1000)) - Number(p[4]) - Number(democracy.debatingPeriod()))/60);
console.log("Proposal #" + i + " Send " + web3.fromWei( p[1], "ether") + " ether to address " + p[0].substring(2,6) + " for "+ p[3] + ". Deadline:"+ Math.abs(Math.floor(timeleft)) + (timeleft>0?" minutes ago ":" minutes left ") + (p[5]? " Active":" Archived") );
}
}
checkAllProposals();
一个有关的公民可以很容易地写一个机器人周期性的区块链,然后公布所有提出的新提案,保证透明度。
现在你当然希望其他人能够对你的建议进行投票。您可以查看crowdsale教程注册您的合同应用程序的最佳方式,以便所有的用户需求是一个名字,但现在让我们使用更简单的版本。任何人都应该能够通过使用这个巨大的命令来在您的计算机上实例化本国的本地副本:
democracy = eth.contract( [{ constant: true, inputs: [{ name: "", type: "uint256" } ], name: "proposals", outputs: [{ name: "recipient", type: "address" }, { name: "amount", type: "uint256" }, { name: "data", type: "bytes32" }, { name: "descriptionHash", type: "bytes32" }, { name: "creationDate", type: "uint256" }, { name: "numVotes", type: "uint256" }, { name: "quorum", type: "uint256" }, { name: "active", type: "bool" } ], type: "function" }, { constant: false, inputs: [{ name: "_proposalID", type: "uint256" } ], name: "executeProposal", outputs: [{ name: "result", type: "uint256" } ], type: "function" }, { constant: true, inputs: [ ], name: "debatingPeriod", outputs: [{ name: "", type: "uint256" } ], type: "function" }, { constant: true, inputs: [ ], name: "numProposals", outputs: [{ name: "", type: "uint256" } ], type: "function" }, { constant: true, inputs: [ ], name: "founder", outputs: [{ name: "", type: "address" } ], type: "function" }, { constant: false, inputs: [{ name: "_proposalID", type: "uint256" }, { name: "_position", type: "int256" } ], name: "vote", outputs: [{ name: "voteID", type: "uint256" } ], type: "function" }, { constant: false, inputs: [{ name: "_voterShareAddress", type: "address" } ], name: "setup", outputs: [ ], type: "function" }, { constant: false, inputs: [{ name: "_recipient", type: "address" }, { name: "_amount", type: "uint256" }, { name: "_data", type: "bytes32" }, { name: "_descriptionHash", type: "bytes32" } ], name: "newProposal", outputs: [{ name: "proposalID", type: "uint256" } ], type: "function" }, { constant: true, inputs: [ ], name: "minimumQuorum", outputs: [{ name: "", type: "uint256" } ], type: "function" }, { inputs: [ ], type: "constructor" } ] ).at(registrar.addr("MyPersonalCountry"))
那么拥有任何代币的任何人都可以通过这样的方式对提案进行投票:
var proposalID = 0;
var position = -1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum
democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000});
var proposalID = 1;
var position = 1; // +1 for voting yea, -1 for voting nay, 0 abstains but counts as quorum
democracy.vote.sendTransaction(proposalID, position, {from: eth.accounts[0], gas: 1000000});
除非您更改了代码中的基本参数,否则任何提案都必须经过至
- 上一篇: php 运行jar 测试
- 下一篇: 开发者快速入门以太坊代币开发底层构架