Solidity

Личный сайт Go-разработчика из Казани

Solidity lets you program on Ethereum, a blockchain-based virtual machine that allows the creation and execution of smart contracts, without requiring centralized or trusted parties.

Solidity is a statically typed, contract programming language that has similarities to JavaScript and C. Like objects in OOP, each contract contains state variables, functions, and common data types. Contract-specific features include modifier (guard) clauses, event notifiers for listeners, and custom global variables.

Some Ethereum contract examples include crowdfunding, voting, decentralized finance, and blind auctions.

There is a high risk and high cost of errors in Solidity code, so you must be very careful to test and slowly rollout. WITH THE RAPID CHANGES IN ETHEREUM, THIS DOCUMENT IS UNLIKELY TO STAY UP TO DATE, SO YOU SHOULD FOLLOW THE SOLIDITY CHAT ROOM AND ETHEREUM BLOG FOR THE LATEST. ALL CODE HERE IS PROVIDED AS IS, WITH SUBSTANTIAL RISK OF ERRORS OR DEPRECATED CODE PATTERNS.

Unlike other code, you may also need to add in design patterns like pausing, deprecation, and throttling usage to reduce risk. This document primarily discusses syntax, and so excludes many popular design patterns.

As Solidity and Ethereum are under active development, experimental or beta features are typically marked, and subject to change. Pull requests welcome.

Working with Remix and Metamask

One of the easiest ways to build, deploy, and test solidity code is by using the:

  1. Remix Web IDE
  2. Metamask wallet.

To get started, download the Metamask Browser Extension.

Once installed, we will be working with Remix. The below code will be pre-loaded, but before we head over there, let’s look at a few tips to get started with remix. Load it all by hitting this link.

  1. Choose the Solidity compiler

Solidity-in-remix

  1. Open the file loaded by that link

Solidity-choose-file

  1. Compile the file

Solidity-compile

  1. Deploy

Solidity-deploy

  1. Play with contracts

Solidity-deploy

You’ve deployed your first contract! Congrats!

You can test out and play with the functions defined. Check out the comments to learn about what each does.

For now, please continue to use the Remix VM unless instructed otherwise.

1// First, a simple Bank contract 2// Allows deposits, withdrawals, and balance checks 3 4// simple_bank.sol (note .sol extension) 5/* **** START EXAMPLE **** */ 6// A special comment is used at the top of the file to indicate 7// the license for the code, and the version of Solidity used 8// SPDX-License-Identifier: MIT 9 10// Declare the source file compiler version 11pragma solidity ^0.8.19; 12 13// Start with Natspec comment (the three slashes) 14// used for documentation - and as descriptive data for UI elements/actions 15 16/// @title SimpleBank 17/// @author nemild 18 19/* 'contract' has similarities to 'class' in other languages (class variables, 20inheritance, etc.) */ 21contract SimpleBank { // CapWords 22 // Declare state variables outside function, persist through life of contract 23 24 // dictionary that maps addresses to balances 25 mapping (address => uint) private balances; 26 27 // "private" means that other contracts can't directly query balances 28 // but data is still viewable to other parties on blockchain 29 30 address public owner; 31 // 'public' makes externally readable (not writeable) by users or contracts 32 33 // Events - publicize actions to external listeners 34 event LogDepositMade(address accountAddress, uint amount); 35 36 // Constructor, can receive one or many variables here; only one allowed 37 constructor() { 38 // msg provides details about the message that's sent to the contract 39 // msg.sender is contract caller (address of contract creator) 40 owner = msg.sender; 41 } 42 43 /// @notice Deposit ether into bank 44 /// @return The balance of the user after the deposit is made 45 function deposit() public payable returns (uint) { 46 // Use 'require' to test user inputs, 'assert' for internal invariants 47 // Here we are making sure that there isn't an overflow issue 48 // In modern versions of Solidity, this is automatically checked 49 require((balances[msg.sender] + msg.value) >= balances[msg.sender]); 50 51 balances[msg.sender] += msg.value; 52 // no "this." or "self." required with state variable 53 // all values set to data type's initial value by default 54 55 emit LogDepositMade(msg.sender, msg.value); // fire event 56 57 return balances[msg.sender]; 58 } 59 60 /// @notice Withdraw ether from bank 61 /// @dev This does not return any excess ether sent to it 62 /// @param withdrawAmount amount you want to withdraw 63 /// @return remainingBal 64 function withdraw(uint withdrawAmount) public returns (uint remainingBal) { 65 require(withdrawAmount <= balances[msg.sender]); 66 67 // Note the way we deduct the balance right away, before sending 68 // Every .transfer/.send from this contract can call an external function 69 // This may allow the caller to request an amount greater 70 // than their balance using a recursive call 71 // Aim to commit state before calling external functions, including .transfer/.send 72 balances[msg.sender] -= withdrawAmount; 73 74 // this automatically throws on a failure, which means the updated balance is reverted 75 payable(msg.sender).transfer(withdrawAmount); 76 77 return balances[msg.sender]; 78 } 79 80 /// @notice Get balance 81 /// @return The balance of the user 82 // 'view' (ex: constant) prevents function from editing state variables; 83 // allows function to run locally/off blockchain 84 function balance() view public returns (uint) { 85 return balances[msg.sender]; 86 } 87} 88// ** END EXAMPLE ** 89 90 91// Now, the basics of Solidity 92 93// 1. DATA TYPES AND ASSOCIATED METHODS 94// uint used for currency amount (there are no doubles 95// or floats) and for dates (in unix time) 96uint x; 97 98// int of 256 bits, cannot be changed after instantiation 99int constant a = 8; 100int256 constant a = 8; // same effect as line above, here the 256 is explicit 101uint constant VERSION_ID = 0x123A1; // A hex constant 102// with 'constant', compiler replaces each occurrence with actual value 103 104// All state variables (those outside a function) 105// are by default 'internal' and accessible inside contract 106// and in all contracts that inherit ONLY 107// Need to explicitly set to 'public' to allow external contracts to access 108int256 public a = 8; 109 110// For int and uint, can explicitly set space in steps of 8 up to 256 111// e.g., int8, int16, int24 112uint8 b; 113int64 c; 114uint248 e; 115 116// In older versions of solidity, doing addition could cause "overflow" 117// For example, for an addition, you'd do: 118uint256 c = a + b; 119assert(c >= a); 120// But modern versions of Solidity automatically check for overflow/underflow of integer math 121 122 123// No random functions built in, you can get a pseduo-random number by hashing the current blockhash, or get a truly random number using something like Chainlink VRF. 124// https://docs.chain.link/docs/get-a-random-number 125 126// Type casting 127int x = int(b); 128 129bool b = true; 130 131// Addresses - holds 20 byte/160 bit Ethereum addresses 132// No arithmetic allowed 133address public owner; 134 135// Types of accounts: 136// Contract account: address set on create (func of creator address, num transactions sent) 137// External Account: (person/external entity): address created from public key 138 139// Add 'public' field to indicate publicly/externally accessible 140// a getter is automatically created, but NOT a setter 141 142// All addresses can be sent ether 143owner.transfer(SOME_BALANCE); // fails and reverts on failure 144 145// Can also do a lower level .send call, which returns a false if it failed 146if (owner.send(amount)) {} // REMEMBER: wrap send in 'if', as contract addresses have 147// functions executed on send and these can fail 148// Also, make sure to deduct balances BEFORE attempting a send, as there is a risk of a recursive 149// call that can drain the contract 150 151// Can check balance 152owner.balance; // the balance of the owner (user or contract) 153 154 155// Bytes available from 1 to 32 156bytes1 a; // bytes1 is the explicit form 157bytes2 b; 158bytes32 c; 159 160// Dynamically sized bytes 161bytes m; // A special array, same as byte[] array (but packed tightly) 162// More expensive than byte1-byte32, so use those when possible 163 164// same as bytes, but does not allow length or index access (for now) 165string n = "hello"; // stored in UTF8, note double quotes, not single 166// string utility functions to be added in future 167// prefer bytes32/bytes, as UTF8 uses more storage 168 169// by default, all values are set to 0 on instantiation 170 171// Delete can be called on most types 172// (does NOT destroy value, but sets value to 0, the initial value) 173delete x; 174 175 176// Destructuring/Tuples 177(x, y) = (2, 7); // assign/swap multiple values 178 179 180// 2. DATA STRUCTURES 181// Arrays 182bytes32[5] nicknames; // static array 183bytes32[] names; // dynamic array 184names.push("John"); // adding an element (no longer returns length) 185// Length 186names.length; // get length 187// Note: Direct length assignment has been removed in newer Solidity versions 188 189// multidimensional array 190uint[][5] x; // arr with 5 dynamic array elements (opp order of most languages) 191 192// Dictionaries (any type to any other type) 193mapping (string => uint) public balances; 194balances["charles"] = 1; 195// balances["ada"] result is 0, all non-set key values return zeroes 196// 'public' allows following from another contract 197contractName.balances("charles"); // returns 1 198// 'public' created a getter (but not setter) like the following: 199function balances(string memory _account) public view returns (uint balance) { 200 return balances[_account]; 201} 202 203// Nested mappings 204mapping (address => mapping (address => uint)) public custodians; 205 206// To delete 207delete balances["John"]; 208delete balances; // sets all elements to 0 209 210// Unlike other languages, CANNOT iterate through all elements in 211// mapping, without knowing source keys - can build data structure 212// on top to do this 213 214// Structs 215struct Bank { 216 address owner; 217 uint balance; 218} 219Bank b = Bank({ 220 owner: msg.sender, 221 balance: 5 222}); 223// or 224Bank c = Bank(msg.sender, 5); 225 226c.balance = 5; // set to new value 227delete b; 228// sets to initial value, set all variables in struct to 0, except mappings 229 230// Enums 231enum State { Created, Locked, Inactive }; // often used for state machine 232State public state; // Declare variable from enum 233state = State.Created; 234// enums can be explicitly converted to ints 235uint createdState = uint(State.Created); // 0 236 237// Data locations: Memory vs. storage vs. calldata - all complex types (arrays, 238// structs) have a data location 239// 'memory' does not persist, 'storage' does 240// 'calldata' also does not persist, and is exclusively "read-only" meaning it cannot be modified 241// Default is 'storage' for local and state variables; 'memory' for func params 242// stack holds small local variables 243 244// for most types, can explicitly set which data location to use 245 246 247// 3. Simple operators 248// Comparisons, bit operators and arithmetic operators are provided 249// exponentiation: ** 250// exclusive or: ^ 251// bitwise negation: ~ 252 253 254// 4. Global Variables of note 255// ** this ** 256this; // address of contract 257// often used at end of contract life to transfer remaining balance to party 258this.balance; 259this.someFunction(); // calls func externally via call, not via internal jump 260 261// ** msg - Current message received by the contract ** ** 262msg.sender; // address of sender 263msg.value; // amount of ether provided to this contract in wei, the function should be marked "payable" 264msg.data; // bytes, complete call data 265 266// ** tx - This transaction ** 267tx.origin; // address of sender of the transaction 268tx.gasprice; // gas price of the transaction 269 270// ** block - Information about current block ** 271block.timestamp; // current time (approximately) (uses Unix time) 272// Note that this can be manipulated by miners, so use carefully 273 274block.number; // current block number 275block.difficulty; // current block difficulty 276block.blockhash(1); // returns bytes32, only works for most recent 256 blocks 277block.gasLimit(); 278 279// ** storage - Persistent storage hash ** 280storage['abc'] = 'def'; // maps 256 bit words to 256 bit words 281 282 283// 5. FUNCTIONS AND MORE 284// A. Functions 285// Simple function 286function increment(uint x) returns (uint) { 287 x += 1; 288 return x; 289} 290 291// Functions can return many arguments, 292// and by specifying returned arguments name explicit return is not needed 293function increment(uint x, uint y) returns (uint x, uint y) { 294 x += 1; 295 y += 1; 296} 297// Call previous function 298(uint a, uint b) = increment(1,1); 299 300// 'view' (alias for 'constant') 301// indicates that function does not/cannot change persistent vars 302// View function execute locally, not on blockchain 303// Noted: constant keyword will soon be deprecated. 304uint y = 1; 305 306function increment(uint x) view returns (uint x) { 307 x += 1; 308 y += 1; // this line would fail 309 // y is a state variable, and can't be changed in a view function 310} 311 312// 'pure' is more strict than 'view' or 'constant', and does not 313// even allow reading of state vars 314// The exact rules are more complicated, so see more about 315// view/pure: 316// http://solidity.readthedocs.io/en/develop/contracts.html#view-functions 317 318// 'Function Visibility specifiers' 319// These can be placed where 'view' is, including: 320// public - visible externally and internally (default for function) 321// external - only visible externally (including a call made with this.) 322// private - only visible in the current contract 323// internal - only visible in current contract, and those deriving from it 324 325// Generally, a good idea to mark each function explicitly 326 327// Functions hoisted - and can assign a function to a variable 328function a() { 329 function() internal z = b; 330 z(); 331} 332 333function b() { 334 335} 336 337// All functions that receive ether must be marked 'payable' 338function depositEther() public payable { 339 balances[msg.sender] += msg.value; 340} 341 342 343// Prefer loops to recursion (max call stack depth is 1024) 344// Also, don't setup loops that you haven't bounded, 345// as this can hit the gas limit 346 347// B. Events 348// Events are notify external parties; easy to search and 349// access events from outside blockchain (with lightweight clients) 350// typically declare after contract parameters 351 352// Typically, capitalized - and add Log in front to be explicit and prevent confusion 353// with a function call 354 355// Declare 356event LogSent(address indexed from, address indexed to, uint amount); // note capital first letter 357 358// Call 359emit LogSent(from, to, amount); 360 361/** 362 363For an external party (a contract or external entity), to watch using 364the Web3 JavaScript library: 365 366// The following is JavaScript code, not Solidity code 367Coin.LogSent().watch({}, '', function(error, result) { 368 if (!error) { 369 console.log("Coin transfer: " + result.args.amount + 370 " coins were sent from " + result.args.from + 371 " to " + result.args.to + "."); 372 console.log("Balances now:\n" + 373 "Sender: " + Coin.balances.call(result.args.from) + 374 "Receiver: " + Coin.balances.call(result.args.to)); 375 } 376} 377**/ 378 379// Common paradigm for one contract to depend on another (e.g., a 380// contract that depends on current exchange rate provided by another) 381 382// C. Modifiers 383// Modifiers validate inputs to functions such as minimal balance or user auth; 384// similar to guard clause in other languages 385 386// '_' (underscore) often included as last line in body, and indicates 387// function being called should be placed there 388modifier onlyAfter(uint _time) { require (block.timestamp >= _time); _; } 389modifier onlyOwner { require(msg.sender == owner); _; } 390// commonly used with state machines 391modifier onlyIfStateA (State currState) { require(currState == State.A); _; } 392 393// Append right after function declaration 394function changeOwner(newOwner) 395onlyAfter(someTime) 396onlyOwner() 397onlyIfState(State.A) 398{ 399 owner = newOwner; 400} 401 402// underscore can be included before end of body, 403// but explicitly returning will skip, so use carefully 404modifier checkValue(uint amount) { 405 _; 406 if (msg.value > amount) { 407 uint amountToRefund = amount - msg.value; 408 msg.sender.transfer(amountToRefund); 409 } 410} 411 412 413// 6. BRANCHING AND LOOPS 414 415// All basic logic blocks work - including if/else, for, while, break, continue 416// return - but no switch 417 418// Syntax same as JavaScript, but no type conversion from non-boolean 419// to boolean (comparison operators must be used to get the boolean val) 420 421// For loops that are determined by user behavior, be careful - as contracts have a maximal 422// amount of gas for a block of code - and will fail if that is exceeded 423// For example: 424for(uint x = 0; x < refundAddressList.length; x++) { 425 refundAddressList[x].transfer(SOME_AMOUNT); 426} 427 428// Two errors above: 429// 1. A failure on transfer stops the loop from completing, tying up money 430// 2. This loop could be arbitrarily long (based on the amount of users who need refunds), and 431// therefore may always fail as it exceeds the max gas for a block 432// Instead, you should let people withdraw individually from their subaccount, and mark withdrawn 433// e.g., favor pull payments over push payments 434 435 436// 7. OBJECTS/CONTRACTS 437 438// A. Calling external contract 439contract InfoFeed { 440 function info() payable returns (uint ret) { return 42; } 441} 442 443contract Consumer { 444 InfoFeed feed; // points to contract on blockchain 445 446 // Set feed to existing contract instance 447 function setFeed(address addr) { 448 // automatically cast, be careful; constructor is not called 449 feed = InfoFeed(addr); 450 } 451 452 // Set feed to new instance of contract 453 function createNewFeed() { 454 feed = new InfoFeed(); // new instance created; constructor called 455 } 456 457 function callFeed() { 458 // final parentheses call contract, can optionally add 459 // custom ether value or gas 460 feed.info{value: 10, gas: 800}(); 461 } 462} 463 464// B. Inheritance 465 466// Order matters, last inherited contract (i.e., 'def') can override parts of 467// previously inherited contracts 468contract MyContract is abc, def("a custom argument to def") { 469 470// Override function 471 function z() { 472 if (msg.sender == owner) { 473 def.z(); // call overridden function from def 474 super.z(); // call immediate parent overridden function 475 } 476 } 477} 478 479// abstract function 480function someAbstractFunction(uint x); 481// cannot be compiled, so used in base/abstract contracts 482// that are then implemented 483 484// C. Import 485 486import "filename"; 487import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol"; 488 489 490// 8. OTHER KEYWORDS 491 492// A. Selfdestruct 493// selfdestruct current contract, sending funds to address (often creator) 494selfdestruct(SOME_ADDRESS); 495 496// removes storage/code from current/future blocks 497// helps thin clients, but previous data persists in blockchain 498 499// Common pattern, lets owner end the contract and receive remaining funds 500function remove() { 501 if(msg.sender == creator) { // Only let the contract creator do this 502 selfdestruct(creator); // Makes contract inactive, returns funds 503 } 504} 505 506// May want to deactivate contract manually, rather than selfdestruct 507// (ether sent to selfdestructed contract is lost) 508 509 510// 9. CONTRACT DESIGN NOTES 511 512// A. Obfuscation 513// All variables are publicly viewable on blockchain, so anything 514// that is private needs to be obfuscated (e.g., hashed w/secret) 515 516// Steps: 1. Commit to something, 2. Reveal commitment 517keccak256("some_bid_amount", "some secret"); // commit 518 519// call contract's reveal function in the future 520// showing bid plus secret that hashes to SHA3 521reveal(100, "mySecret"); 522 523// B. Storage optimization 524// Writing to blockchain can be expensive, as data stored forever; encourages 525// smart ways to use memory (eventually, compilation will be better, but for now 526// benefits to planning data structures - and storing min amount in blockchain) 527 528// Cost can often be high for items like multidimensional arrays 529// (cost is for storing data - not declaring unfilled variables) 530 531// C. Data access in blockchain 532// Cannot restrict human or computer from reading contents of 533// transaction or transaction's state 534 535// While 'private' prevents other *contracts* from reading data 536// directly - any other party can still read data in blockchain 537 538// All data to start of time is stored in blockchain, so 539// anyone can observe all previous data and changes 540 541// D. Oracles and External Data 542// Oracles are ways to interact with your smart contracts outside the blockchain. 543// They are used to get data from the real world, send post requests, to the real world 544// or vise versa. 545 546// Time-based implementations of contracts are also done through oracles, as 547// contracts need to be directly called and can not "subscribe" to a time. 548// Due to smart contracts being decentralized, you also want to get your data 549// in a decentralized manner, otherwise you run into the centralized risk that 550// smart contract design matter prevents. 551 552// The easiest way to get and use pre-boxed decentralized data is with Chainlink Data Feeds 553// https://docs.chain.link/docs/get-the-latest-price 554// We can reference on-chain reference points that have already been aggregated by 555// multiple sources and delivered on-chain, and we can use it as a "data bank" 556// of sources. 557 558// You can see other examples making API calls here: 559// https://docs.chain.link/docs/make-a-http-get-request 560 561// And you can of course build your own oracle network, just be sure to know 562// how centralized vs decentralized your application is. 563 564// Setting up oracle networks yourself 565 566// E. Cron Job 567// Contracts must be manually called to handle time-based scheduling; can create external 568// code to regularly ping, or provide incentives (ether) for others to 569// 570 571// F. Observer Pattern 572// An Observer Pattern lets you register as a subscriber and 573// register a function which is called by the oracle (note, the oracle pays 574// for this action to be run) 575// Some similarities to subscription in Pub/sub 576 577// This is an abstract contract, both client and server classes import 578// the client should implement 579contract SomeOracleCallback { 580 function oracleCallback(int _value, uint _time, bytes32 info) external; 581} 582 583contract SomeOracle { 584 SomeOracleCallback[] callbacks; // array of all subscribers 585 586 // Register subscriber 587 function addSubscriber(SomeOracleCallback a) { 588 callbacks.push(a); 589 } 590 591 function notify(value, time, info) private { 592 for(uint i = 0;i < callbacks.length; i++) { 593 // all called subscribers must implement the oracleCallback 594 callbacks[i].oracleCallback(value, time, info); 595 } 596 } 597 598 function doSomething() public { 599 // Code to do something 600 601 // Notify all subscribers 602 notify(_value, _time, _info); 603 } 604} 605 606// Now, your client contract can addSubscriber by importing SomeOracleCallback 607// and registering with Some Oracle 608 609// G. State machines 610// see example below for State enum and inState modifier

Work with the full example below using the Remix VM in remix here.

1// *** EXAMPLE: A crowdfunding example (broadly similar to Kickstarter) *** 2// ** START EXAMPLE ** 3 4// CrowdFunder.sol 5// SPDX-License-Identifier: MIT 6pragma solidity ^0.8.19; 7 8/// @title CrowdFunder 9/// @author nemild 10contract CrowdFunder { 11 // Variables set on create by creator 12 address public creator; 13 address payable public fundRecipient; // creator may be different than recipient, and must be payable 14 uint public minimumToRaise; // required to tip, else everyone gets refund 15 string campaignUrl; 16 uint256 version = 1; 17 18 // Data structures 19 enum State { 20 Fundraising, 21 ExpiredRefund, 22 Successful 23 } 24 struct Contribution { 25 uint amount; 26 address payable contributor; 27 } 28 29 // State variables 30 State public state = State.Fundraising; // initialize on create 31 uint public totalRaised; 32 uint public raiseBy; 33 uint public completeAt; 34 Contribution[] contributions; 35 36 event LogFundingReceived(address addr, uint amount, uint currentTotal); 37 event LogWinnerPaid(address winnerAddress); 38 39 modifier inState(State _state) { 40 require(state == _state); 41 _; 42 } 43 44 modifier isCreator() { 45 require(msg.sender == creator); 46 _; 47 } 48 49 // Wait 24 weeks after final contract state before allowing contract destruction 50 modifier atEndOfLifecycle() { 51 require(((state == State.ExpiredRefund || state == State.Successful) && 52 completeAt + 24 weeks < block.timestamp)); 53 _; 54 } 55 56 function crowdFund( 57 uint timeInHoursForFundraising, 58 string memory _campaignUrl, 59 address payable _fundRecipient, 60 uint _minimumToRaise) 61 public 62 { 63 creator = msg.sender; 64 fundRecipient = _fundRecipient; 65 campaignUrl = _campaignUrl; 66 minimumToRaise = _minimumToRaise; 67 raiseBy = block.timestamp + (timeInHoursForFundraising * 1 hours); 68 } 69 70 function contribute() 71 public 72 payable 73 inState(State.Fundraising) 74 returns(uint256 id) 75 { 76 contributions.push( 77 Contribution({ 78 amount: msg.value, 79 contributor: payable(msg.sender) 80 }) // use array, so can iterate 81 ); 82 totalRaised += msg.value; 83 84 emit LogFundingReceived(msg.sender, msg.value, totalRaised); 85 86 checkIfFundingCompleteOrExpired(); 87 return contributions.length - 1; // return id 88 } 89 90 function checkIfFundingCompleteOrExpired() 91 public 92 { 93 if (totalRaised > minimumToRaise) { 94 state = State.Successful; 95 payOut(); 96 97 // could incentivize sender who initiated state change here 98 } else if ( block.timestamp > raiseBy ) { 99 state = State.ExpiredRefund; // backers can now collect refunds by calling getRefund(id) 100 } 101 completeAt = block.timestamp; 102 } 103 104 function payOut() 105 public 106 inState(State.Successful) 107 { 108 fundRecipient.transfer(address(this).balance); 109 emit LogWinnerPaid(fundRecipient); 110 } 111 112 function getRefund(uint256 id) 113 inState(State.ExpiredRefund) 114 public 115 returns(bool) 116 { 117 require(contributions.length > id && id >= 0 && contributions[id].amount != 0 ); 118 119 uint256 amountToRefund = contributions[id].amount; 120 contributions[id].amount = 0; 121 122 contributions[id].contributor.transfer(amountToRefund); 123 124 return true; 125 } 126 127 // Warning: "selfdestruct" has been deprecated. 128 // Note that, starting from the Cancun hard fork, the underlying opcode no longer deletes the code 129 // and data associated with an account and only transfers its Ether to the beneficiary, unless executed 130 // in the same transaction in which the contract was created (see EIP-6780). 131 132 // Any use in newly deployed contracts is strongly discouraged even if the new behavior is taken into account. 133 // Future changes to the EVM might further reduce the functionality of the opcode. 134 // function removeContract() 135 // public 136 // isCreator() 137 // atEndOfLifecycle() 138 // { 139 // selfdestruct(msg.sender); 140 // // creator gets all money that hasn't be claimed 141 // } 142} 143// ** END EXAMPLE **

Some more functions.

1// 10. OTHER NATIVE FUNCTIONS 2 3// Currency units 4// Currency is defined using wei, smallest unit of Ether 5uint minAmount = 1 wei; 6uint a = 1 finney; // 1 ether == 1000 finney 7// Other units, see: http://ether.fund/tool/converter 8 9// Time units 101 == 1 second 111 minutes == 60 seconds 12 13// Can multiply a variable times unit, as units are not stored in a variable 14uint x = 5; 15(x * 1 days); // 5 days 16 17// Careful about leap seconds/years with equality statements for time 18// (instead, prefer greater than/less than) 19 20// Cryptography 21// All strings passed are concatenated before hash action 22keccak256("ab", "cd"); 23ripemd160("abc"); 24sha256("def"); 25 26// 11. SECURITY 27 28// Bugs can be disastrous in Ethereum contracts - and even popular patterns in Solidity, 29// may be found to be antipatterns 30 31// See security links at the end of this doc 32 33// 12. LOW LEVEL FUNCTIONS 34// call - low level, not often used, does not provide type safety 35(bool success, bytes memory data) = someContractAddress.call( 36 abi.encodeWithSignature("function_name(string,string)", "arg1", "arg2") 37); 38 39// delegatecall - Code at target address executed in *context* of calling contract 40// provides library functionality 41(bool success, bytes memory data) = someContractAddress.delegatecall( 42 abi.encodeWithSignature("function_name()") 43); 44 45 46// 13. STYLE NOTES 47// Based on Python's PEP8 style guide 48// Full Style guide: http://solidity.readthedocs.io/en/develop/style-guide.html 49 50// Quick summary: 51// 4 spaces for indentation 52// Two lines separate contract declarations (and other top level declarations) 53// Avoid extraneous spaces in parentheses 54// Can omit curly braces for one line statement (if, for, etc) 55// else should be placed on own line 56 57 58// 14. NATSPEC COMMENTS 59// used for documentation, commenting, and external UIs 60 61// Contract natspec - always above contract definition 62/// @title Contract title 63/// @author Author name 64 65// Function natspec 66/// @notice information about what function does; shown when function to execute 67/// @dev Function documentation for developer 68 69// Function parameter/return value natspec 70/// @param someParam Some description of what the param does 71/// @return Description of the return value

Additional resources

Smart Contract Development Frameworks

Important libraries

  • OpenZeppelin: Libraries that provide common contract patterns (crowdfuding, safemath, etc)
  • Chainlink: Code that allows you to interact with external data

Sample contracts

Security

Style

Editors

Future To Dos

  • List of common design patterns (throttling, RNG, version upgrade)
  • Common security anti patterns

Feel free to send a pull request with any edits - or email nemild -/at-/ gmail