合约
优质
小牛编辑
141浏览
2023-12-01
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);
}
}