在Remix上构建简单的⽔龙头合约
编写⽔龙头合约
对于我们的第⼀个例⼦,我们将编写⼀个控制⽔龙头的合约。我们已经在 Ropsten 测试⽹络上使⽤了⼀个⽔龙头来测试 ether。⽔龙头是⼀件相对简单的事情:它会向任何要求的地址发出以太,并且可以定期重新填充。当然,我们可以将⽔龙头实施为由⼈(或 Web服务器)控制的钱包,不过现在我们的⽬标是学习智能合约,所以我们将编写实施⽔龙头的Solidity 合同:
Faucet.sol:实施⽔龙头的 Solidity 合同
pragma solidity ^0.4.19;
contract Faucet {
// Give out ether to anyone who asks
function withdraw(uint withdraw_amount)public{
// Limit withdrawal amount
require(withdraw_amount <=100000000000000000);
// Send the amount to the address that requested it
ansfer(withdraw_amount);
}
// Accept any incoming amount
function()public payable {}
}
接下来,我们声明⽔龙头合约的第⼀个功能:
function withdraw(uint withdraw_amount)public{
该函数名为 withdraw,它接受⼀个名为 withdraw_amount 的⽆符号整数(uint)参数。它被声明为公共函数,这意味着它可以被其他合约调⽤。函数定义遵循花括号:
require(withdraw_amount <=100000000000000000);
提现功能的第⼀部分设定了提款限额。它使⽤内置的 Solidity 函数 require 来测试⼀个前提条件,即 withdraw_amount ⼩于或等于100000000000000000 wei,这是 ether 的基本单位,相当于 0.1 ether。如果使⽤⼤于该数量的 withdraw_amount 调⽤ withdraw 函数,则此处的 require 函数将导致合约执⾏停⽌并因异常⽽失败。
solidity
这部分合约是我们⽔龙头的主要逻辑。它通过限制提款来控制合约之外的资⾦流动。这是⼀个⾮常简单的控制,但可以让你⼀瞥可编程区块链的⼒量:控制资⾦的去中⼼化软件。
接下来是实际提现:
ansfer(withdraw_amount);
这⾥有⼀些神奇的东西:msg 对象,这是所有合约都可以访问的输⼊之⼀。它表⽰触发此合约执⾏的交易。属性 sender 是交易的发件⼈地址。函数传递是⼀个内置函数,它将以太从合约传递到调⽤它的地址。向后读,这意味着转移到触发此合约执⾏的 msg 的发送者。传递函数将⾦额作为其唯⼀参数。我们将 withdraw_amount 值作为参数传递给上⾯⼏⾏声明的 withdraw 函数。下⼀⾏是结束⼤括号,表⽰我们的 withdraw 函数定义的结束。下⾯我们再声明⼀个功能:
function()public payable {}
此函数是所谓的“回退”或默认函数,如果触发合约的交易未命名合约中的任何已声明函数或任何函数或未包含数据,则调⽤此函数。合约可以有⼀个这样的默认函数(没有名称),它通常是接收以太的函数。这就是为什么它被定义为公共和默认函数,这意味着它可以接受以太合约。除了接受以太之外,它没有做任何事情,如花括号{}中的空定义所⽰。如果我们创建⼀个将 ether 发送到合约地址的交易,就好像它是钱包⼀样,这个函数将处理它。
在我们的默认函数下⾯是最后的结束花括号,它表⽰了合约 Faucet 的定义结束。
编译⽔龙头合约
现在我们有了第⼀个⽰例合约,我们需要使⽤ Solidity 编译器将 Solidity 代码转换为EVM 字节码,因此它可以由 EVM 执⾏。
使⽤ Chrome 浏览器导航到 Remix IDE:
在区块链上部署合同
所以我们写了合约。我们把它编译成字节码。现在,我们需要在以太坊区块链上“注册”合约。我们将使⽤ Ropsten 测试⽹来测试我们的合约,这就是我们想要记录的区块链。在区块链上注册合约涉及创建⼀个特殊交易,其⽬的地是⼀个“零地址”,也就是地址为:
0x0000000000000000000000000000000000000000。
零地址是⼀个特殊地址,告诉以太坊区块链我们想要注册合约。不过我们不需要⼿动输⼊这么多个 0,Remix IDE 将为我们处理所有这些并将交易发送到 MetaMask。
⾸先,切换到“Run”选项卡,然后在“Environment”下拉选择框中选择“Injected
Web3”。这将 Remix IDE 连接到 MetaMask 钱包,并通过 MetaMask 连接到 Ropsten测试⽹络。⼀旦你这样做,你可以在环境下看到“Ropsten”。此外,在帐户选择框中,它显⽰你的钱包的地址:
现在,稍微等⼀下:在 Ropsten 上部署合约⼤约需要 15 到 30 秒。它和主⽹完全⼀样采⽤了 PoW 的机制,出块的时间⼤概是 15 秒。创建合约后,它将显⽰在“Run”选项卡的底部:
在区块浏览器中查看合同地址
现在,我们已经在 Ropsten 区块链上记录了⼀份合约,我们可以看到它有⼀个以太坊地址。让我们在 herscan.io 区块浏览器上查看它,看看合约是什么样的。
在⼀个标签中打开 Remix,稍后我们会再次回顾它。现在,将浏览器导航到
提现我们的合约
接下来,让我们从⽔龙头中提取⼀些资⾦。要提现,我们必须构造⼀个调⽤ withdraw函数的交易,并将
withdraw_amount 参数传递给它。为了使事情变得简单,Remix 将为我们构建该交易,MetaMask 将提供它以供我们批准。
返回 Remix 选项卡,查看“Run”选项卡下的合约。你应该看到⼀个标有“Withdraw”的红⾊框,其中包含⼀个标记为 uint256 withdraw_amount 的字段条⽬:
这是合约的 Remix 接⼝。它允许我们构造调⽤合约中定义的函数的交易。我们将输⼊withdraw_amount 并单击“Withdraw”按钮以⽣成交易。
⾸先,让我们弄清⼀下 withdraw_amount。我们想尝试提现 0.1 以太,这是我们合约允许的最⼤⾦额。请记住,以太坊中的所有货币值都在内部以 wei 表⽰,⽽我们的提现功能期望 withdraw_amount 也以 wei 计价。我们想要的数量是 0.1 以太, 这是100000000000000000 wei(1 后跟 17 个零)。
由于 JavaScript 的限制,Remix ⽆法处理⼤到 10 ^ 17 的数字。相反,我们将它括在双引号中,以允许 Remix 将其作为字符串接收并将其作为 BigNumber 进⾏操作。如果我们不将它括在引号中,则 Remix I
DE 将⽆法处理它并显⽰“Error encoding arguments:Error:Assertion failed”,好在 Remix 会帮我们做⾃动转换
在 withdraw_amount 框中键⼊ 100000000000000000,然后单击“Withdraw”按钮:
MetaMask 将弹出⼀个交易窗⼝供你批准。点击“Confirm”将你的提款调⽤发送给合约。
等⼀下,然后重新加载 etherscan 区块资源管理器,以查看在⽔龙头合约地址历史记录中的交易。