mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
commit
252bd142b9
@ -61,65 +61,65 @@ This means that cyclic creation dependencies are impossible.
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract OwnedToken {
|
contract OwnedToken {
|
||||||
// TokenCreator is a contract type that is defined below.
|
// TokenCreator is a contract type that is defined below.
|
||||||
// It is fine to reference it as long as it is not used
|
// It is fine to reference it as long as it is not used
|
||||||
// to create a new contract.
|
// to create a new contract.
|
||||||
TokenCreator creator;
|
TokenCreator creator;
|
||||||
address owner;
|
address owner;
|
||||||
bytes32 name;
|
bytes32 name;
|
||||||
// This is the constructor which registers the
|
// This is the constructor which registers the
|
||||||
// creator and the assigned name.
|
// creator and the assigned name.
|
||||||
function OwnedToken(bytes32 _name) {
|
function OwnedToken(bytes32 _name) {
|
||||||
owner = msg.sender;
|
owner = msg.sender;
|
||||||
// We do an explicit type conversion from `address`
|
// We do an explicit type conversion from `address`
|
||||||
// to `TokenCreator` and assume that the type of
|
// to `TokenCreator` and assume that the type of
|
||||||
// the calling contract is TokenCreator, there is
|
// the calling contract is TokenCreator, there is
|
||||||
// no real way to check that.
|
// no real way to check that.
|
||||||
creator = TokenCreator(msg.sender);
|
creator = TokenCreator(msg.sender);
|
||||||
name = _name;
|
name = _name;
|
||||||
}
|
}
|
||||||
function changeName(bytes32 newName) {
|
function changeName(bytes32 newName) {
|
||||||
// Only the creator can alter the name --
|
// Only the creator can alter the name --
|
||||||
// the comparison is possible since contracts
|
// the comparison is possible since contracts
|
||||||
// are implicitly convertible to addresses.
|
// are implicitly convertible to addresses.
|
||||||
if (msg.sender == creator) name = newName;
|
if (msg.sender == creator) name = newName;
|
||||||
}
|
}
|
||||||
function transfer(address newOwner) {
|
function transfer(address newOwner) {
|
||||||
// Only the current owner can transfer the token.
|
// Only the current owner can transfer the token.
|
||||||
if (msg.sender != owner) return;
|
if (msg.sender != owner) return;
|
||||||
// We also want to ask the creator if the transfer
|
// We also want to ask the creator if the transfer
|
||||||
// is fine. Note that this calls a function of the
|
// is fine. Note that this calls a function of the
|
||||||
// contract defined below. If the call fails (e.g.
|
// contract defined below. If the call fails (e.g.
|
||||||
// due to out-of-gas), the execution here stops
|
// due to out-of-gas), the execution here stops
|
||||||
// immediately.
|
// immediately.
|
||||||
if (creator.isTokenTransferOK(owner, newOwner))
|
if (creator.isTokenTransferOK(owner, newOwner))
|
||||||
owner = newOwner;
|
owner = newOwner;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract TokenCreator {
|
contract TokenCreator {
|
||||||
function createToken(bytes32 name)
|
function createToken(bytes32 name)
|
||||||
returns (OwnedToken tokenAddress)
|
returns (OwnedToken tokenAddress)
|
||||||
{
|
{
|
||||||
// Create a new Token contract and return its address.
|
// Create a new Token contract and return its address.
|
||||||
// From the JavaScript side, the return type is simply
|
// From the JavaScript side, the return type is simply
|
||||||
// "address", as this is the closest type available in
|
// "address", as this is the closest type available in
|
||||||
// the ABI.
|
// the ABI.
|
||||||
return new OwnedToken(name);
|
return new OwnedToken(name);
|
||||||
}
|
}
|
||||||
function changeName(OwnedToken tokenAddress, bytes32 name) {
|
function changeName(OwnedToken tokenAddress, bytes32 name) {
|
||||||
// Again, the external type of "tokenAddress" is
|
// Again, the external type of "tokenAddress" is
|
||||||
// simply "address".
|
// simply "address".
|
||||||
tokenAddress.changeName(name);
|
tokenAddress.changeName(name);
|
||||||
}
|
}
|
||||||
function isTokenTransferOK(
|
function isTokenTransferOK(
|
||||||
address currentOwner,
|
address currentOwner,
|
||||||
address newOwner
|
address newOwner
|
||||||
) returns (bool ok) {
|
) returns (bool ok) {
|
||||||
// Check some arbitrary condition.
|
// Check some arbitrary condition.
|
||||||
address tokenAddress = msg.sender;
|
address tokenAddress = msg.sender;
|
||||||
return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff);
|
return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.. index:: ! visibility, external, public, private, internal
|
.. index:: ! visibility, external, public, private, internal
|
||||||
@ -179,9 +179,9 @@ return parameter list for functions.
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract c {
|
contract c {
|
||||||
function f(uint a) private returns (uint b) { return a + 1; }
|
function f(uint a) private returns (uint b) { return a + 1; }
|
||||||
function setData(uint a) internal { data = a; }
|
function setData(uint a) internal { data = a; }
|
||||||
uint public data;
|
uint public data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Other contracts can call `c.data()` to retrieve the value of
|
Other contracts can call `c.data()` to retrieve the value of
|
||||||
@ -209,7 +209,7 @@ it is a state variable and if it is accessed externally
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract test {
|
contract test {
|
||||||
uint public data = 42;
|
uint public data = 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
The next example is a bit more complex:
|
The next example is a bit more complex:
|
||||||
@ -217,16 +217,16 @@ The next example is a bit more complex:
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract complex {
|
contract complex {
|
||||||
struct Data { uint a; bytes3 b; mapping(uint => uint) map; }
|
struct Data { uint a; bytes3 b; mapping(uint => uint) map; }
|
||||||
mapping(uint => mapping(bool => Data[])) public data;
|
mapping(uint => mapping(bool => Data[])) public data;
|
||||||
}
|
}
|
||||||
|
|
||||||
It will generate a function of the following form::
|
It will generate a function of the following form::
|
||||||
|
|
||||||
function data(uint arg1, bool arg2, uint arg3) returns (uint a, bytes3 b)
|
function data(uint arg1, bool arg2, uint arg3) returns (uint a, bytes3 b)
|
||||||
{
|
{
|
||||||
a = data[arg1][arg2][arg3].a;
|
a = data[arg1][arg2][arg3].a;
|
||||||
b = data[arg1][arg2][arg3].b;
|
b = data[arg1][arg2][arg3].b;
|
||||||
}
|
}
|
||||||
|
|
||||||
Note that the mapping in the struct is omitted because there
|
Note that the mapping in the struct is omitted because there
|
||||||
@ -247,41 +247,41 @@ inheritable properties of contracts and may be overridden by derived contracts.
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract owned {
|
contract owned {
|
||||||
function owned() { owner = msg.sender; }
|
function owned() { owner = msg.sender; }
|
||||||
address owner;
|
address owner;
|
||||||
|
|
||||||
// This contract only defines a modifier but does not use
|
// This contract only defines a modifier but does not use
|
||||||
// it - it will be used in derived contracts.
|
// it - it will be used in derived contracts.
|
||||||
// The function body is inserted where the special symbol
|
// The function body is inserted where the special symbol
|
||||||
// "_" in the definition of a modifier appears.
|
// "_" in the definition of a modifier appears.
|
||||||
// This means that if the owner calls this function, the
|
// This means that if the owner calls this function, the
|
||||||
// function is executed and otherwise, an exception is
|
// function is executed and otherwise, an exception is
|
||||||
// thrown.
|
// thrown.
|
||||||
modifier onlyowner { if (msg.sender != owner) throw; _ }
|
modifier onlyowner { if (msg.sender != owner) throw; _ }
|
||||||
}
|
}
|
||||||
contract mortal is owned {
|
contract mortal is owned {
|
||||||
// This contract inherits the "onlyowner"-modifier from
|
// This contract inherits the "onlyowner"-modifier from
|
||||||
// "owned" and applies it to the "close"-function, which
|
// "owned" and applies it to the "close"-function, which
|
||||||
// causes that calls to "close" only have an effect if
|
// causes that calls to "close" only have an effect if
|
||||||
// they are made by the stored owner.
|
// they are made by the stored owner.
|
||||||
function close() onlyowner {
|
function close() onlyowner {
|
||||||
selfdestruct(owner);
|
selfdestruct(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contract priced {
|
contract priced {
|
||||||
// Modifiers can receive arguments:
|
// Modifiers can receive arguments:
|
||||||
modifier costs(uint price) { if (msg.value >= price) _ }
|
modifier costs(uint price) { if (msg.value >= price) _ }
|
||||||
}
|
}
|
||||||
contract Register is priced, owned {
|
contract Register is priced, owned {
|
||||||
mapping (address => bool) registeredAddresses;
|
mapping (address => bool) registeredAddresses;
|
||||||
uint price;
|
uint price;
|
||||||
function Register(uint initialPrice) { price = initialPrice; }
|
function Register(uint initialPrice) { price = initialPrice; }
|
||||||
function register() costs(price) {
|
function register() costs(price) {
|
||||||
registeredAddresses[msg.sender] = true;
|
registeredAddresses[msg.sender] = true;
|
||||||
}
|
}
|
||||||
function changePrice(uint _price) onlyowner {
|
function changePrice(uint _price) onlyowner {
|
||||||
price = _price;
|
price = _price;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Multiple modifiers can be applied to a function by specifying them in a
|
Multiple modifiers can be applied to a function by specifying them in a
|
||||||
@ -305,8 +305,8 @@ for array and struct types and not possible for mapping types).
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract C {
|
contract C {
|
||||||
uint constant x = 32**22 + 8;
|
uint constant x = 32**22 + 8;
|
||||||
string constant text = "abc";
|
string constant text = "abc";
|
||||||
}
|
}
|
||||||
|
|
||||||
This has the effect that the compiler does not reserve a storage slot
|
This has the effect that the compiler does not reserve a storage slot
|
||||||
@ -336,24 +336,24 @@ possible.
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract Test {
|
contract Test {
|
||||||
function() { x = 1; }
|
function() { x = 1; }
|
||||||
uint x;
|
uint x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This contract rejects any Ether sent to it. It is good
|
// This contract rejects any Ether sent to it. It is good
|
||||||
// practise to include such a function for every contract
|
// practise to include such a function for every contract
|
||||||
// in order not to loose Ether.
|
// in order not to loose Ether.
|
||||||
contract Rejector {
|
contract Rejector {
|
||||||
function() { throw; }
|
function() { throw; }
|
||||||
}
|
}
|
||||||
|
|
||||||
contract Caller {
|
contract Caller {
|
||||||
function callTest(address testAddress) {
|
function callTest(address testAddress) {
|
||||||
Test(testAddress).call(0xabcdef01); // hash does not exist
|
Test(testAddress).call(0xabcdef01); // hash does not exist
|
||||||
// results in Test(testAddress).x becoming == 1.
|
// results in Test(testAddress).x becoming == 1.
|
||||||
Rejector r = Rejector(0x123);
|
Rejector r = Rejector(0x123);
|
||||||
r.send(2 ether);
|
r.send(2 ether);
|
||||||
// results in r.balance == 0
|
// results in r.balance == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,17 +400,17 @@ All non-indexed arguments will be stored in the data part of the log.
|
|||||||
::
|
::
|
||||||
|
|
||||||
contract ClientReceipt {
|
contract ClientReceipt {
|
||||||
event Deposit(
|
event Deposit(
|
||||||
address indexed _from,
|
address indexed _from,
|
||||||
bytes32 indexed _id,
|
bytes32 indexed _id,
|
||||||
uint _value
|
uint _value
|
||||||
);
|
);
|
||||||
function deposit(bytes32 _id) {
|
function deposit(bytes32 _id) {
|
||||||
// Any call to this function (even deeply nested) can
|
// Any call to this function (even deeply nested) can
|
||||||
// be detected from the JavaScript API by filtering
|
// be detected from the JavaScript API by filtering
|
||||||
// for `Deposit` to be called.
|
// for `Deposit` to be called.
|
||||||
Deposit(msg.sender, _id, msg.value);
|
Deposit(msg.sender, _id, msg.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
The use in the JavaScript API would be as follows:
|
The use in the JavaScript API would be as follows:
|
||||||
@ -425,17 +425,17 @@ The use in the JavaScript API would be as follows:
|
|||||||
|
|
||||||
// watch for changes
|
// watch for changes
|
||||||
event.watch(function(error, result){
|
event.watch(function(error, result){
|
||||||
// result will contain various information
|
// result will contain various information
|
||||||
// including the argumets given to the Deposit
|
// including the argumets given to the Deposit
|
||||||
// call.
|
// call.
|
||||||
if (!error)
|
if (!error)
|
||||||
console.log(result);
|
console.log(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Or pass a callback to start watching immediately
|
// Or pass a callback to start watching immediately
|
||||||
var event = clientReceipt.Deposit(function(error, result) {
|
var event = clientReceipt.Deposit(function(error, result) {
|
||||||
if (!error)
|
if (!error)
|
||||||
console.log(result);
|
console.log(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
.. index:: ! log
|
.. index:: ! log
|
||||||
@ -452,10 +452,10 @@ as topics. The event call above can be performed in the same way as
|
|||||||
::
|
::
|
||||||
|
|
||||||
log3(
|
log3(
|
||||||
msg.value,
|
msg.value,
|
||||||
0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20,
|
0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20,
|
||||||
msg.sender,
|
msg.sender,
|
||||||
_id
|
_id
|
||||||
);
|
);
|
||||||
|
|
||||||
where the long hexadecimal number is equal to
|
where the long hexadecimal number is equal to
|
||||||
@ -502,7 +502,7 @@ Details are given in the following example.
|
|||||||
// accessed externally via `this`, though.
|
// accessed externally via `this`, though.
|
||||||
contract mortal is owned {
|
contract mortal is owned {
|
||||||
function kill() {
|
function kill() {
|
||||||
if (msg.sender == owner) selfdestruct(owner);
|
if (msg.sender == owner) selfdestruct(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,12 +611,12 @@ Derived contracts need to provide all arguments needed for
|
|||||||
the base constructors. This can be done at two places::
|
the base constructors. This can be done at two places::
|
||||||
|
|
||||||
contract Base {
|
contract Base {
|
||||||
uint x;
|
uint x;
|
||||||
function Base(uint _x) { x = _x; }
|
function Base(uint _x) { x = _x; }
|
||||||
}
|
}
|
||||||
contract Derived is Base(7) {
|
contract Derived is Base(7) {
|
||||||
function Derived(uint _y) Base(_y * _y) {
|
function Derived(uint _y) Base(_y * _y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Either directly in the inheritance list (`is Base(7)`) or in
|
Either directly in the inheritance list (`is Base(7)`) or in
|
||||||
@ -667,13 +667,13 @@ Abstract Contracts
|
|||||||
Contract functions can lack an implementation as in the following example (note that the function declaration header is terminated by `;`)::
|
Contract functions can lack an implementation as in the following example (note that the function declaration header is terminated by `;`)::
|
||||||
|
|
||||||
contract feline {
|
contract feline {
|
||||||
function utterance() returns (bytes32);
|
function utterance() returns (bytes32);
|
||||||
}
|
}
|
||||||
|
|
||||||
Such contracts cannot be compiled (even if they contain implemented functions alongside non-implemented functions), but they can be used as base contracts::
|
Such contracts cannot be compiled (even if they contain implemented functions alongside non-implemented functions), but they can be used as base contracts::
|
||||||
|
|
||||||
contract Cat is feline {
|
contract Cat is feline {
|
||||||
function utterance() returns (bytes32) { return "miaow"; }
|
function utterance() returns (bytes32) { return "miaow"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
If a contract inherits from an abstract contract and does not implement all non-implemented functions by overriding, it will itself be abstract.
|
If a contract inherits from an abstract contract and does not implement all non-implemented functions by overriding, it will itself be abstract.
|
||||||
@ -716,35 +716,35 @@ more advanced example to implement a set).
|
|||||||
function insert(Data storage self, uint value)
|
function insert(Data storage self, uint value)
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
if (self.flags[value])
|
if (self.flags[value])
|
||||||
return false; // already there
|
return false; // already there
|
||||||
self.flags[value] = true;
|
self.flags[value] = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function remove(Data storage self, uint value)
|
function remove(Data storage self, uint value)
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
if (!self.flags[value])
|
if (!self.flags[value])
|
||||||
return false; // not there
|
return false; // not there
|
||||||
self.flags[value] = false;
|
self.flags[value] = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function contains(Data storage self, uint value)
|
function contains(Data storage self, uint value)
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
return self.flags[value];
|
return self.flags[value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contract C {
|
contract C {
|
||||||
Set.Data knownValues;
|
Set.Data knownValues;
|
||||||
function register(uint value) {
|
function register(uint value) {
|
||||||
// The library functions can be called without a
|
// The library functions can be called without a
|
||||||
// specific instance of the library, since the
|
// specific instance of the library, since the
|
||||||
// "instance" will be the current contract.
|
// "instance" will be the current contract.
|
||||||
if (!Set.insert(knownValues, value))
|
if (!Set.insert(knownValues, value))
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
// In this contract, we can also directly access knownValues.flags, if we want.
|
// In this contract, we can also directly access knownValues.flags, if we want.
|
||||||
}
|
}
|
||||||
|
|
||||||
Of course, you do not have to follow this way to use
|
Of course, you do not have to follow this way to use
|
||||||
@ -774,8 +774,8 @@ encoding of the address of the library contract.
|
|||||||
|
|
||||||
Restrictions for libraries in comparison to contracts:
|
Restrictions for libraries in comparison to contracts:
|
||||||
|
|
||||||
- no state variables
|
- no state variables
|
||||||
- cannot inherit nor be inherited
|
- cannot inherit nor be inherited
|
||||||
|
|
||||||
(these might be lifted at a later point)
|
(these might be lifted at a later point)
|
||||||
|
|
||||||
@ -845,63 +845,63 @@ Let us rewrite the set example from the
|
|||||||
function insert(Data storage self, uint value)
|
function insert(Data storage self, uint value)
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
if (self.flags[value])
|
if (self.flags[value])
|
||||||
return false; // already there
|
return false; // already there
|
||||||
self.flags[value] = true;
|
self.flags[value] = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function remove(Data storage self, uint value)
|
function remove(Data storage self, uint value)
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
if (!self.flags[value])
|
if (!self.flags[value])
|
||||||
return false; // not there
|
return false; // not there
|
||||||
self.flags[value] = false;
|
self.flags[value] = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
function contains(Data storage self, uint value)
|
function contains(Data storage self, uint value)
|
||||||
returns (bool)
|
returns (bool)
|
||||||
{
|
{
|
||||||
return self.flags[value];
|
return self.flags[value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract C {
|
contract C {
|
||||||
using Set for Set.Data; // this is the crucial change
|
using Set for Set.Data; // this is the crucial change
|
||||||
Set.Data knownValues;
|
Set.Data knownValues;
|
||||||
function register(uint value) {
|
function register(uint value) {
|
||||||
// Here, all variables of type Set.Data have
|
// Here, all variables of type Set.Data have
|
||||||
// corresponding member functions.
|
// corresponding member functions.
|
||||||
// The following function call is identical to
|
// The following function call is identical to
|
||||||
// Set.insert(knownValues, value)
|
// Set.insert(knownValues, value)
|
||||||
if (!knownValues.insert(value))
|
if (!knownValues.insert(value))
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
It is also possible to extend elementary types in that way::
|
It is also possible to extend elementary types in that way::
|
||||||
|
|
||||||
library Search {
|
library Search {
|
||||||
function indexOf(uint[] storage self, uint value) {
|
function indexOf(uint[] storage self, uint value) {
|
||||||
for (uint i = 0; i < self.length; i++)
|
for (uint i = 0; i < self.length; i++)
|
||||||
if (self[i] == value) return i;
|
if (self[i] == value) return i;
|
||||||
return uint(-1);
|
return uint(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract C {
|
contract C {
|
||||||
using Search for uint[];
|
using Search for uint[];
|
||||||
uint[] data;
|
uint[] data;
|
||||||
function append(uint value) {
|
function append(uint value) {
|
||||||
data.push(value);
|
data.push(value);
|
||||||
}
|
}
|
||||||
function replace(uint _old, uint _new) {
|
function replace(uint _old, uint _new) {
|
||||||
// This performs the library function call
|
// This performs the library function call
|
||||||
uint index = data.find(_old);
|
uint index = data.find(_old);
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
data.push(_new);
|
data.push(_new);
|
||||||
else
|
else
|
||||||
data[index] = _new;
|
data[index] = _new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Note that all library calls are actual EVM function calls. This means that
|
Note that all library calls are actual EVM function calls. This means that
|
||||||
|
Loading…
Reference in New Issue
Block a user