contract SimpleAuction { // Parameters of the auction. Times are either // absolute unix timestamps (seconds since 1970-01-01) // or time periods in seconds. address public beneficiary; uint public auctionEnd;
// Current state of the auction. address public highestBidder; uint public highestBid;
// Allowed withdrawals of previous bids mapping(address => uint) pendingReturns;
// Set to true at the end, disallows any change bool ended;
// Events that will be fired on changes. event HighestBidIncreased(address bidder, uint amount); event AuctionEnded(address winner, uint amount);
// The following is a so-called natspec comment, // recognizable by the three slashes. // It will be shown when the user is asked to // confirm a transaction.
/// Create a simple auction with `_biddingTime` /// seconds bidding time on behalf of the /// beneficiary address `_beneficiary`. function SimpleAuction( uint _biddingTime, address _beneficiary ) public { beneficiary = _beneficiary; auctionEnd = now + _biddingTime; }
/// Bid on the auction with the value sent /// together with this transaction. /// The value will only be refunded if the /// auction is not won. function bid() public payable { // No arguments are necessary, all // information is already part of // the transaction. The keyword payable // is required for the function to // be able to receive Ether.
// Revert the call if the bidding // period is over. require(now <= auctionEnd);
// If the bid is not higher, send the // money back. require(msg.value > highestBid);
if (highestBid != 0) { // Sending back the money by simply using // highestBidder.send(highestBid) is a security risk // because it could execute an untrusted contract. // It is always safer to let the recipients // withdraw their money themselves. pendingReturns[highestBidder] += highestBid; } highestBidder = msg.sender; highestBid = msg.value; emit HighestBidIncreased(msg.sender, msg.value); }
/// Withdraw a bid that was overbid. function withdraw() public returns (bool) { uint amount = pendingReturns[msg.sender]; if (amount > 0) { // It is important to set this to zero because the recipient // can call this function again as part of the receiving call // before `send` returns. pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount)) { // No need to call throw here, just reset the amount owing pendingReturns[msg.sender] = amount; return false; } } return true; }
/// End the auction and send the highest bid /// to the beneficiary. function auctionEnd() public { // It is a good guideline to structure functions that interact // with other contracts (i.e. they call functions or send Ether) // into three phases: // 1. checking conditions // 2. performing actions (potentially changing conditions) // 3. interacting with other contracts // If these phases are mixed up, the other contract could call // back into the current contract and modify the state or cause // effects (ether payout) to be performed multiple times. // If functions called internally include interaction with external // contracts, they also have to be considered interaction with // external contracts.
// 1. Conditions require(now >= auctionEnd); // auction did not yet end require(!ended); // this function has already been called
/** * @dev Allows owner to remove an employee. * @param employeeId The id of the employee. */ function removeEmployee(address employeeId) public onlyOwner employee_exist(employeeId) { _settlePayment(employeeId); _totalSalary = _totalSalary.sub(employees[employeeId].salary); delete employees[employeeId]; }
contract Test { // This function is called for all messages sent to // this contract (there is no other function). // Sending Ether to this contract will cause an exception, // because the fallback function does not have the `payable` // modifier. function() public { x = 1; } uint x; }
// This contract keeps all Ether sent to it with no way // to get it back. contract Sink { function() public payable { } }
contract Caller { function callTest(Test test) public { test.call(0xabcdef01); // hash does not exist // results in test.x becoming == 1.
// The following will not compile, but even // if someone sends ether to that contract, // the transaction will fail and reject the // Ether. //test.send(2 ether); } }
函数重载
允许有相同名称但是不同参数的方法共存
1 2 3 4 5 6 7 8 9 10 11
pragma solidity ^0.4.16;
contract A { function f(uint _in) public pure returns (uint out) { out = 1; }
function f(uint _in, bytes32 _key) public pure returns (uint out) { out = 2; } }
function deposit(bytes32 _id) public payable { // Events are emitted using `emit`, followed by // the name of the event and the arguments // (if any) in parentheses. Any such invocation // (even deeply nested) can be detected from // the JavaScript API by filtering for `Deposit`. emit Deposit(msg.sender, _id, msg.value); } }
var abi = /* abi as generated by the compiler */; var ClientReceipt = web3.eth.contract(abi); var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */);
var event = clientReceipt.Deposit();
// watch for changes event.watch(function(error, result){ // result will contain various information // including the argumets given to the `Deposit` // call. if (!error) console.log(result); });
// Or pass a callback to start watching immediately var event = clientReceipt.Deposit(function(error, result) { if (!error) console.log(result); });
日志记录
log0, log1, log2, log3, log4…
1 2 3 4 5 6 7 8 9 10 11 12 13
pragma solidity ^0.4.10;
contract C { function f() public payable { bytes32 _id = 0x420042; log3( bytes32(msg.value), bytes32(0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20), bytes32(msg.sender), _id ); } }
contract Feline { function utterance() public returns (bytes32); }
接口
接口与抽象类似,但是还有更多的限制。
无法继承其他合同或接口。
无法定义构造函数。
无法定义变量。
无法定义结构。
无法定义枚举。
1 2 3 4 5
pragma solidity ^0.4.11;
interface Token { function transfer(address recipient, uint amount) public; }
库
部署在特定地址的公用函数
Using For
我理解类似apply或者中间件的意思,所有的参数使用先经过这个use 函数的处理。
1 2 3 4 5 6 7 8 9 10 11 12
contract C { using Set for Set.Data; // this is the crucial change Set.Data knownValues;
function register(uint value) public { // Here, all variables of type Set.Data have // corresponding member functions. // The following function call is identical to // `Set.insert(knownValues, value)` require(knownValues.insert(value)); } }