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:
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.
- Choose the Solidity compiler
- Open the file loaded by that link
- Compile the file
- Deploy
- Play with contracts
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 ¶
- Solidity Docs
- Cyfrin Updraft (Learn solidity development)
- Chainlink Beginner Tutorials
- Smart Contract Best Practices
- Browser-based Solidity Editor
- Modular design strategies for Ethereum Contracts
- Chainlink Documentation
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 ¶
- Dapp Bin
- Defi Example
- Solidity Baby Step Contracts
- ConsenSys Contracts
- State of Dapps
- Security Codebase Examples
Security ¶
- Smart Contract Security Curriculum
- Smart Contract Security Reports Database
- Thinking About Smart Contract Security
- Smart Contract Security
- Hacking Distributed Blog
Style ¶
- Solidity Style Guide: Ethereum’s style guide is heavily derived from Python’s PEP 8 style guide.
Editors ¶
- Remix
- Emacs Solidity Mode
- Vim Solidity
- Editor Snippets (Ultisnips format)
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