Solidity的合约类似于面向对象语言中的类。它们包含存放持久化数据的状态变量和可修改这些变量的函数。调用不同的合约实例上的函数将执行EVM函数调用,从而切换上下文,使得状态变量不可访问。
创建合约(Creating Contracts)
合约可以从“外部”创建,也可以由Solidity合约创立。
像Remix这类IDE,可以用UI界面使创建过程无缝连接。
最好在Ethereum上以编程方式通过Web3.js创建合约。到今天为止,它有一种叫做web3.eth.Contract的方法来帮助合约的创建。
当创建一个合约时,它的构造函数被执行一次。构造函数是可选的。只允许一个构造函数,这意味着不支持重载。
在内部,构造函数的参数要放在在合约代码编译成的ABI之后,但是如果使用Web3.js
,则不必关心这一点。
如果是一个合约要创立另外一个合约,被创立的合约的源码(和二进制代码)要能被创立者知晓。这意味着循环创建依赖就成为不可能的事情。
pragma solidity ^0.4.16;
contract OwnedToken {
// TokenCreator是在下面定义的合约类型
// 若它本身不用于创建新的合约的话,它就是一个引用
TokenCreator creator;
address owner;
bytes32 name;
// 这个是记载创建者者和赋值名称的构造函数
function OwnedToken(bytes32 _name) {
owner = msg.sender;
// 我们做一次由`address`到`TokenCreator` 的显式转换,
// 确保调用合约的类型是 TokenCreator,(因为没有办法来检测这一点)
creator = TokenCreator(msg.sender);
name = _name;
}
function changeName(bytes32 newName) {
// 仅仅是创立者可以改变名称--
// 因为合约是隐式转换成地址上,所以这种比较是可能的
if (msg.sender == creator) name = newName;
}
function transfer(address newOwner) {
// 只有当前合约所有者可以转移 token
if (msg.sender != owner) return;
// 我们还要询问合约创建者"转移是否成功"
// 注意这会调用合约定义在下面的函数
// 如果函数调用失败,(如gas用完了等原因)
// 程序的执行将立刻停止
if (creator.isTokenTransferOK(owner, newOwner))
owner = newOwner;
}}
contract TokenCreator {
function createToken(bytes32 name)
returns (OwnedToken tokenAddress)
{
// 创立一个新的Token合约,并且返回它的地址
// 从 JavaScript观点看,返回的地址类型是"address"
// 这个是和ABI最接近的类型
return new OwnedToken(name);
}
function changeName(OwnedToken tokenAddress, bytes32 name) {
// "tokenAddress" 的外部类型也是"address".
tokenAddress.changeName(name);
}
function isTokenTransferOK(
address currentOwner,
address newOwner
) returns (bool ok) {
// 检查各种条件
address tokenAddress = msg.sender;
return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff);
}
}