🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 合约 Solidity中合约有点类似面向对象语言中的类。合约中有用于数据持久化的`状态变量(state variables)`,和可以操作他们的函数。调用另一个合约实例的函数时,会执行一个EVM函数调用,这个操作会切换执行时的上下文,这样,前一个合约的`状态变量(state variables)`就不能访问了。 ## 创建合约 合约可以通过Solidity,或不通过Solidity创建。当合约创建时,一个和合约同名的函数(构造器函数)会调用一次,用于初始化。 构造器函数是可选的。仅能有一个构造器,所以不支持重载。 如果不通过Solidity,我们可以通过`web3.js`,使用JavaScript的API来完成合约创建: ``` // Need to specify some source including contract name for the data param below var source = "contract CONTRACT_NAME { function CONTRACT_NAME(unit a, uint b) {} }"; // The json abi array generated by the compiler var abiArray = [ { "inputs":[ {"name":"x","type":"uint256"}, {"name":"y","type":"uint256"} ], "type":"constructor" }, { "constant":true, "inputs":[], "name":"x", "outputs":[{"name":"","type":"bytes32"}], "type":"function" } ]; var MyContract_ = web3.eth.contract(source); MyContract = web3.eth.contract(MyContract_.CONTRACT_NAME.info.abiDefinition); // deploy new contract var contractInstance = MyContract.new( 10, 11, {from: myAccount, gas: 1000000} ); ``` 具体内部实现里,构造器的参数是紧跟在合约代码的后面,但如果你使用`web3.js`,可以不用关心这样的细节。 如果一个合约要创建另一个合约,它必须要知道源码。这意味着循环创建依赖是不可能的。 ``` pragma solidity ^0.4.0; contract OwnedToken { // TokenCreator is a contract type that is defined below. // It is fine to reference it as long as it is not used // to create a new contract. TokenCreator creator; address owner; bytes32 name; // This is the constructor which registers the // creator and the assigned name. function OwnedToken(bytes32 _name) { // State variables are accessed via their name // and not via e.g. this.owner. This also applies // to functions and especially in the constructors, // you can only call them like that ("internall"), // because the contract itself does not exist yet. owner = msg.sender; // We do an explicit type conversion from `address` // to `TokenCreator` and assume that the type of // the calling contract is TokenCreator, there is // no real way to check that. creator = TokenCreator(msg.sender); name = _name; } function changeName(bytes32 newName) { // Only the creator can alter the name -- // the comparison is possible since contracts // are implicitly convertible to addresses. if (msg.sender == address(creator)) name = newName; } function transfer(address newOwner) { // Only the current owner can transfer the token. if (msg.sender != owner) return; // We also want to ask the creator if the transfer // is fine. Note that this calls a function of the // contract defined below. If the call fails (e.g. // due to out-of-gas), the execution here stops // immediately. if (creator.isTokenTransferOK(owner, newOwner)) owner = newOwner; } } contract TokenCreator { function createToken(bytes32 name) returns (OwnedToken tokenAddress) { // Create a new Token contract and return its address. // From the JavaScript side, the return type is simply // "address", as this is the closest type available in // the ABI. return new OwnedToken(name); } function changeName(OwnedToken tokenAddress, bytes32 name) { // Again, the external type of "tokenAddress" is // simply "address". tokenAddress.changeName(name); } function isTokenTransferOK( address currentOwner, address newOwner ) returns (bool ok) { // Check some arbitrary condition. address tokenAddress = msg.sender; return (keccak256(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); } } ```